From 2775fba97d6457cdd4a24f389d42d2acf93138c1 Mon Sep 17 00:00:00 2001 From: NFLua Team <> Date: Mon, 25 May 2020 11:32:41 -0300 Subject: [PATCH 01/48] Import states and luautil from NFLua --- luautil.h | 81 +++++++++++++++ states.c | 293 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ states.h | 63 ++++++++++++ 3 files changed, 437 insertions(+) create mode 100644 luautil.h create mode 100644 states.c create mode 100644 states.h diff --git a/luautil.h b/luautil.h new file mode 100644 index 000000000..fb3eb0bcd --- /dev/null +++ b/luautil.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2017-2019 CUJO LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _LUA_UTIL_H +#define _LUA_UTIL_H + +#include +#include + +typedef const struct {} luaU_id[1]; + +static inline int luaU_pushudata(lua_State *L, void *ud) +{ + return lua_rawgetp(L, LUA_REGISTRYINDEX, ud) == LUA_TUSERDATA; +} + +static inline void luaU_registerudata(lua_State *L, int v) +{ + void *ud = lua_touserdata(L, v); + lua_pushvalue(L, v); + lua_rawsetp(L, LUA_REGISTRYINDEX, ud); +} + +static inline void luaU_unregisterudata(lua_State *L, void *ud) +{ + lua_pushnil(L); + lua_rawsetp(L, LUA_REGISTRYINDEX, ud); +} + +static inline void luaU_setregval(lua_State *L, luaU_id id, void *v) +{ + if (v) lua_pushlightuserdata(L, v); + else lua_pushnil(L); + lua_rawsetp(L, LUA_REGISTRYINDEX, id); +} + +static inline void *luaU_getregval(lua_State *L, luaU_id id) +{ + void *v; + + lua_rawgetp(L, LUA_REGISTRYINDEX, id); + v = lua_touserdata(L, -1); + lua_pop(L, 1); + + return v; +} + +#define luaU_setenv(L, env, st) { \ + st **penv = (st **)lua_getextraspace(L); \ + *penv = env; } + +#define luaU_getenv(L, st) (*((st **)lua_getextraspace(L))) + +static inline int luaU_pusherr(lua_State *L, const char *err) +{ + lua_pushnil(L); + lua_pushstring(L, err); + return 2; +} + +#define luaU_dostring(L, b, s, n) \ + (luaL_loadbufferx(L, b, s, n, "t") || luaU_pcall(L, 0, 0)) + +int luaU_pcall(lua_State *L, int nargs, int nresults); + +#endif /* _LUA_UTIL_H */ diff --git a/states.c b/states.c new file mode 100644 index 000000000..293f547dc --- /dev/null +++ b/states.c @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2017-2019 CUJO LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include +#include +#include +#include + +#include + +#include "luautil.h" +#include "xt_lua.h" +#include "states.h" +#include "netlink.h" +#include "kpi_compat.h" + +#ifndef NFLUA_SETPAUSE +#define NFLUA_SETPAUSE 100 +#endif /* NFLUA_SETPAUSE */ + +extern int luaopen_memory(lua_State *); +extern int luaopen_conn(lua_State *); +extern int luaopen_netlink(lua_State *); +extern int luaopen_packet(lua_State *); +extern int luaopen_timer(lua_State *); + +static const luaL_Reg libs[] = { + {"memory", luaopen_memory}, + {"conn", luaopen_conn}, + {"netlink", luaopen_netlink}, + {"packet", luaopen_packet}, + {"timer", luaopen_timer}, + {NULL, NULL} +}; + +static inline int name_hash(void *salt, const char *name) +{ + int len = strnlen(name, NFLUA_NAME_MAXSIZE); + return kpi_full_name_hash(salt, name, len) & (XT_LUA_HASH_BUCKETS - 1); +} + +static bool refcount_dec_and_lock_bh(kpi_refcount_t *r, spinlock_t *lock) +{ + if (kpi_refcount_dec_not_one(r)) + return false; + + spin_lock_bh(lock); + if (!kpi_refcount_dec_and_test(r)) { + spin_unlock_bh(lock); + return false; + } + + return true; +} + +struct nflua_state *nflua_state_lookup(struct xt_lua_net *xt_lua, + const char *name) +{ + struct hlist_head *head; + struct nflua_state *state; + + if (xt_lua == NULL) + return NULL; + + head = &xt_lua->state_table[name_hash(xt_lua, name)]; + kpi_hlist_for_each_entry_rcu(state, head, node) { + if (!strncmp(state->name, name, NFLUA_NAME_MAXSIZE)) + return state; + } + return NULL; +} + +static void state_destroy(struct xt_lua_net *xt_lua, struct nflua_state *s) +{ + hlist_del_rcu(&s->node); + atomic_dec(&xt_lua->state_count); + + spin_lock_bh(&s->lock); + if (s->L != NULL) { + lua_close(s->L); + s->L = NULL; + } + spin_unlock_bh(&s->lock); + + nflua_state_put(s); +} + +static void *lua_alloc(void *ud, void *ptr, size_t osize, size_t nsize) +{ + struct nflua_state *s = ud; + void *nptr = NULL; + + /* osize doesn't represent the object old size if ptr is NULL */ + osize = ptr != NULL ? osize : 0; + + if (nsize == 0) { + s->curralloc -= osize; + kfree(ptr); + } else if (s->curralloc - osize + nsize > s->maxalloc) { + pr_warn_ratelimited("maxalloc limit %zu reached on state %.*s\n", + s->maxalloc, NFLUA_NAME_MAXSIZE, s->name); + } else if ((nptr = krealloc(ptr, nsize, GFP_ATOMIC)) != NULL) { + s->curralloc += nsize - osize; + } + + return nptr; +} + +static int state_init(struct nflua_state *s) +{ + const luaL_Reg *lib; + + s->L = lua_newstate(lua_alloc, s); + if (s->L == NULL) + return -ENOMEM; + + luaU_setenv(s->L, s, struct nflua_state); + luaL_openlibs(s->L); + + for (lib = libs; lib->name != NULL; lib++) { + luaL_requiref(s->L, lib->name, lib->func, 1); + lua_pop(s->L, 1); + } + + /* fixes an issue where the Lua's GC enters a vicious cycle. + * more info here: https://marc.info/?l=lua-l&m=155024035605499&w=2 + */ + lua_gc(s->L, LUA_GCSETPAUSE, NFLUA_SETPAUSE); + + return 0; +} + +struct nflua_state *nflua_state_create(struct xt_lua_net *xt_lua, + size_t maxalloc, const char *name) +{ + struct hlist_head *head; + struct nflua_state *s = nflua_state_lookup(xt_lua, name); + int namelen = strnlen(name, NFLUA_NAME_MAXSIZE); + + pr_debug("creating state: %.*s maxalloc: %zd\n", namelen, name, + maxalloc); + + if (s != NULL) { + pr_err("state already exists: %.*s\n", namelen, name); + return NULL; + } + + if (atomic_read(&xt_lua->state_count) >= NFLUA_MAX_STATES) { + pr_err("could not allocate id for state %.*s\n", namelen, name); + pr_err("max states limit reached or out of memory\n"); + return NULL; + } + + if (maxalloc < NFLUA_MIN_ALLOC_BYTES) { + pr_err("maxalloc %zu should be greater then MIN_ALLOC %zu\n", + maxalloc, NFLUA_MIN_ALLOC_BYTES); + return NULL; + } + + if ((s = kzalloc(sizeof(struct nflua_state), GFP_ATOMIC)) == NULL) { + pr_err("could not allocate nflua state\n"); + return NULL; + } + + INIT_HLIST_NODE(&s->node); + spin_lock_init(&s->lock); + s->dseqnum = 0; + s->maxalloc = maxalloc; + s->curralloc = 0; + s->xt_lua = xt_lua; + memcpy(&(s->name), name, namelen); + + if (state_init(s)) { + pr_err("could not allocate a new lua state\n"); + kfree(s); + return NULL; + } + + spin_lock_bh(&xt_lua->state_lock); + head = &xt_lua->state_table[name_hash(xt_lua, name)]; + hlist_add_head_rcu(&s->node, head); + kpi_refcount_inc(&s->users); + atomic_inc(&xt_lua->state_count); + spin_unlock_bh(&xt_lua->state_lock); + + pr_debug("new state created: %.*s\n", namelen, name); + return s; +} + +int nflua_state_destroy(struct xt_lua_net *xt_lua, const char *name) +{ + struct nflua_state *s = nflua_state_lookup(xt_lua, name); + + if (s == NULL || kpi_refcount_read(&s->users) > 1) + return -1; + + spin_lock_bh(&xt_lua->state_lock); + state_destroy(xt_lua, s); + spin_unlock_bh(&xt_lua->state_lock); + + return 0; +} + +int nflua_state_list(struct xt_lua_net *xt_lua, nflua_state_cb cb, + unsigned short *total) +{ + struct hlist_head *head; + struct nflua_state *s; + int i, ret = 0; + + spin_lock_bh(&xt_lua->state_lock); + + *total = atomic_read(&xt_lua->state_count); + + for (i = 0; i < XT_LUA_HASH_BUCKETS; i++) { + head = &xt_lua->state_table[i]; + kpi_hlist_for_each_entry_rcu(s, head, node) { + if ((ret = cb(s, total)) != 0) + goto out; + } + } + +out: + spin_unlock_bh(&xt_lua->state_lock); + return ret; +} + +void nflua_state_destroy_all(struct xt_lua_net *xt_lua) +{ + struct hlist_head *head; + struct hlist_node *tmp; + struct nflua_state *s; + int i; + + spin_lock_bh(&xt_lua->state_lock); + for (i = 0; i < XT_LUA_HASH_BUCKETS; i++) { + head = &xt_lua->state_table[i]; + kpi_hlist_for_each_entry_safe(s, tmp, head, node) { + state_destroy(xt_lua, s); + } + } + spin_unlock_bh(&xt_lua->state_lock); +} + +bool nflua_state_get(struct nflua_state *s) +{ + return kpi_refcount_inc_not_zero(&s->users); +} + +void nflua_state_put(struct nflua_state *s) +{ + struct xt_lua_net *xt_lua; + + if (WARN_ON(s == NULL)) + return; + + xt_lua = s->xt_lua; + if (refcount_dec_and_lock_bh(&s->users, &xt_lua->rfcnt_lock)) { + kfree(s); + spin_unlock_bh(&xt_lua->rfcnt_lock); + } +} + +void nflua_states_init(struct xt_lua_net *xt_lua) +{ + int i; + atomic_set(&xt_lua->state_count, 0); + spin_lock_init(&xt_lua->state_lock); + spin_lock_init(&xt_lua->rfcnt_lock); + for (i = 0; i < XT_LUA_HASH_BUCKETS; i++) + INIT_HLIST_HEAD(&xt_lua->state_table[i]); +} + +void nflua_states_exit(struct xt_lua_net *xt_lua) +{ + nflua_state_destroy_all(xt_lua); +} diff --git a/states.h b/states.h new file mode 100644 index 000000000..9c556c584 --- /dev/null +++ b/states.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2017-2019 CUJO LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef NFLUA_STATES_H +#define NFLUA_STATES_H + +#include "kpi_compat.h" + +#include + +#define NFLUA_NAME_MAXSIZE 64 + +struct xt_lua_net; + +struct nflua_state { + struct hlist_node node; + lua_State *L; + struct xt_lua_net *xt_lua; + spinlock_t lock; + kpi_refcount_t users; + u32 dseqnum; + size_t maxalloc; + size_t curralloc; + unsigned char name[NFLUA_NAME_MAXSIZE]; +}; + +typedef int (*nflua_state_cb)(struct nflua_state *s, unsigned short *total); + +struct nflua_state *nflua_state_create(struct xt_lua_net *xt_lua, + size_t maxalloc, const char *name); + +int nflua_state_destroy(struct xt_lua_net *xt_lua, const char *name); + +struct nflua_state *nflua_state_lookup(struct xt_lua_net *xt_lua, + const char *name); + +int nflua_state_list(struct xt_lua_net *xt_lua, nflua_state_cb cb, + unsigned short *total); + +void nflua_state_destroy_all(struct xt_lua_net *xt_lua); + +bool nflua_state_get(struct nflua_state *s); +void nflua_state_put(struct nflua_state *s); + +void nflua_states_init(struct xt_lua_net *xt_lua); +void nflua_states_exit(struct xt_lua_net *xt_lua); + +#endif /* NFLUA_STATES_H */ From 2b9aeb02b4e8c49fe68acfd06174772dd9a41381 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Tue, 23 Jun 2020 14:50:18 -0300 Subject: [PATCH 02/48] Adapt NFLua states management to Lunatik --- Makefile | 22 +++--- doc/klua_doc.md | 65 ++++++++++++++++ luautil.h | 10 ++- lunatik_core.c | 16 +++- states.c | 194 ++++++++++++++++++++---------------------------- states.h | 55 +++++++------- 6 files changed, 207 insertions(+), 155 deletions(-) create mode 100644 doc/klua_doc.md diff --git a/Makefile b/Makefile index 9d6b82a3b..0fee9af97 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -ccflags-y += -D_LUNATIK -D_KERNEL -I$(src) -D_CONFIG_FULL_PANIC +ccflags-y += -D_LUNATIK -D_KERNEL -I$(src) -D_CONFIG_FULL_PANIC -DLUNATIK_UNUSED asflags-y += -D_LUNATIK -D_KERNEL ifeq ($(ARCH), $(filter $(ARCH),i386 x86)) @@ -26,15 +26,17 @@ endif obj-$(CONFIG_LUNATIK) += lunatik.o -lunatik-objs += lua/lapi.o lua/lcode.o lua/lctype.o lua/ldebug.o lua/ldo.o \ - lua/ldump.o lua/lfunc.o lua/lgc.o lua/llex.o lua/lmem.o \ - lua/lobject.o lua/lopcodes.o lua/lparser.o lua/lstate.o \ - lua/lstring.o lua/ltable.o lua/ltm.o \ - lua/lundump.o lua/lvm.o lua/lzio.o lua/lauxlib.o lua/lbaselib.o \ - lua/lbitlib.o lua/lcorolib.o lua/ldblib.o lua/lstrlib.o \ - lua/ltablib.o lua/lutf8lib.o lua/loslib.o lua/lmathlib.o lua/linit.o \ - lua/loadlib.o \ - arch/$(ARCH)/setjmp.o util/modti3.o lunatik_core.o +lua-objs = lua/lapi.o lua/lcode.o lua/lctype.o lua/ldebug.o lua/ldo.o \ + lua/ldump.o lua/lfunc.o lua/lgc.o lua/llex.o lua/lmem.o \ + lua/lobject.o lua/lopcodes.o lua/lparser.o lua/lstate.o \ + lua/lstring.o lua/ltable.o lua/ltm.o \ + lua/lundump.o lua/lvm.o lua/lzio.o lua/lauxlib.o lua/lbaselib.o \ + lua/lbitlib.o lua/lcorolib.o lua/ldblib.o lua/lstrlib.o \ + lua/ltablib.o lua/lutf8lib.o lua/loslib.o lua/lmathlib.o lua/linit.o \ + lua/loadlib.o + +lunatik-objs += $(lua-objs) \ + arch/$(ARCH)/setjmp.o util/modti3.o lunatik_core.o states.o ifeq ($(shell [ "${VERSION}" -lt "4" ] && [ "${VERSION}${PATCHLEVEL}" -lt "312" ] && echo y),y) lunatik-objs += util/div64.o diff --git a/doc/klua_doc.md b/doc/klua_doc.md new file mode 100644 index 000000000..cf31a030a --- /dev/null +++ b/doc/klua_doc.md @@ -0,0 +1,65 @@ +# Lunatik API Documentation + +This document provides a documentation of the portion of Lunatik responsable for thread-safe states management. One API is provided to user in order to access all operations related to states management. + +The API is based on the data structure `lunatik_State` which is used to perform all needed operations. + +## The `lunatik_state` struct + +Defined at `states.h` as: + +```c +typedef struct lunatik_state { + struct hlist_node node; + lua_State *L; + spinlock_t lock; + refcount_t users; + size_t maxalloc; + size_t curralloc; + unsigned char name[LUNATIK_NAME_MAXSIZE]; +} lunatik_State; +``` + +The elements in the struct has the following meaning: + + **`struct hlist_node node`** + +Is a variable used by kernel hash table API to storage the `lunatik_State` structure. + +**`lua_State L`** + +Is the Lua state used by Lunatik to do all operations related to Lua. + +**`spinlock_t lock`** + +Is a spinlock variable used to manage concurrency control. + +**`refcount_t users`** + +Represents how many users are referring to a given `lunatik_State`. + +**`size_t maxalloc`** + +Represents the maximum memory that the lua state `L` can use. + +**`size_t curralloc`** + +Represents the current memory that the lua state `L` is using. + +**`unsigned char name[LUNATIK_NAME_MAXSIZE]`** + +Is the unique identifier to `lunatik_State`, used to search it in the kernel hash table, note that this is limited by `LUNATIK_NAME_MAXSIZE`. + +## Functions offered by the API + +**`lunatik_State *lunatik_statelookup(const char *name);`** + +Searches for a `lunatik_State` with the name `name`. If a state with that name is found returns a pointer to the `lunatik_State` or `NULL` otherwise. + +**`lunatik_State *lunatik_newstate(size_t maxalloc, const char *name)`** + +Creates a `lunatik_State` with the max memory usage defined by `maxalloc` and a unique identifier to acess such state defined by `name`. Return a pointer to `lunatik_State` represeting the lunatik state or `NULL` if any errors occours during the creation. + +**`int lunatik_close(const char *name)`** + +Searchs and close a `lunatik_State`, returns `0` if no errors occours during this operation or `-1` otherwise. diff --git a/luautil.h b/luautil.h index fb3eb0bcd..476318a6c 100644 --- a/luautil.h +++ b/luautil.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2020 Matheus Rodrigues * Copyright (C) 2017-2019 CUJO LLC * * This program is free software; you can redistribute it and/or modify @@ -19,8 +20,10 @@ #ifndef _LUA_UTIL_H #define _LUA_UTIL_H -#include -#include +#include "lua/lua.h" +#include "lua/lauxlib.h" + +#ifndef LUNATIK_UNUSED typedef const struct {} luaU_id[1]; @@ -59,11 +62,13 @@ static inline void *luaU_getregval(lua_State *L, luaU_id id) return v; } +#endif /*LUNATIK_UNUSED*/ #define luaU_setenv(L, env, st) { \ st **penv = (st **)lua_getextraspace(L); \ *penv = env; } +#ifndef LUNATIK_UNUSED #define luaU_getenv(L, st) (*((st **)lua_getextraspace(L))) static inline int luaU_pusherr(lua_State *L, const char *err) @@ -79,3 +84,4 @@ static inline int luaU_pusherr(lua_State *L, const char *err) int luaU_pcall(lua_State *L, int nargs, int nresults); #endif /* _LUA_UTIL_H */ +#endif /* LUNATIK_UNUSED */ diff --git a/lunatik_core.c b/lunatik_core.c index 4e9cc625d..65bb977d2 100644 --- a/lunatik_core.c +++ b/lunatik_core.c @@ -1,4 +1,5 @@ /* +* Copyright (c) 2020 Matheus Rodrigues * Copyright (c) 2017-2019 CUJO LLC. * * Permission is hereby granted, free of charge, to any person obtaining @@ -27,6 +28,8 @@ #include "lua/lauxlib.h" #include "lua/lualib.h" +#include "states.h" + EXPORT_SYMBOL(lua_checkstack); EXPORT_SYMBOL(lua_xmove); EXPORT_SYMBOL(lua_atpanic); @@ -165,13 +168,24 @@ EXPORT_SYMBOL(luaopen_string); EXPORT_SYMBOL(luaopen_table); EXPORT_SYMBOL(luaopen_utf8); +EXPORT_SYMBOL(lunatik_newstate); +EXPORT_SYMBOL(lunatik_close); +EXPORT_SYMBOL(lunatik_statelookup); +EXPORT_SYMBOL(lunatik_stateget); +EXPORT_SYMBOL(lunatik_stateput); + +extern void lunatik_statesinit(void); +extern void lunatik_closeall(void); + static int __init modinit(void) { - return 0; + lunatik_statesinit(); + return 0; } static void __exit modexit(void) { + lunatik_closeall(); } module_init(modinit); diff --git a/states.c b/states.c index 293f547dc..db806b2ef 100644 --- a/states.c +++ b/states.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2020 Matheus Rodrigues * Copyright (C) 2017-2019 CUJO LLC * * This program is free software; you can redistribute it and/or modify @@ -21,75 +22,42 @@ #include #include #include +#include +#include -#include +#include "lua/lualib.h" #include "luautil.h" -#include "xt_lua.h" #include "states.h" -#include "netlink.h" -#include "kpi_compat.h" - -#ifndef NFLUA_SETPAUSE -#define NFLUA_SETPAUSE 100 -#endif /* NFLUA_SETPAUSE */ - -extern int luaopen_memory(lua_State *); -extern int luaopen_conn(lua_State *); -extern int luaopen_netlink(lua_State *); -extern int luaopen_packet(lua_State *); -extern int luaopen_timer(lua_State *); - -static const luaL_Reg libs[] = { - {"memory", luaopen_memory}, - {"conn", luaopen_conn}, - {"netlink", luaopen_netlink}, - {"packet", luaopen_packet}, - {"timer", luaopen_timer}, - {NULL, NULL} -}; + +#ifndef LUNATIK_SETPAUSE +#define LUNATIK_SETPAUSE 100 +#endif /* LUNATIK_SETPAUSE */ + +static struct lunatik_session session; static inline int name_hash(void *salt, const char *name) { - int len = strnlen(name, NFLUA_NAME_MAXSIZE); - return kpi_full_name_hash(salt, name, len) & (XT_LUA_HASH_BUCKETS - 1); + int len = strnlen(name, LUNATIK_NAME_MAXSIZE); + return full_name_hash(salt, name, len) & (LUNATIK_HASH_BUCKETS - 1); } -static bool refcount_dec_and_lock_bh(kpi_refcount_t *r, spinlock_t *lock) +lunatik_State *lunatik_statelookup(const char *name) { - if (kpi_refcount_dec_not_one(r)) - return false; - - spin_lock_bh(lock); - if (!kpi_refcount_dec_and_test(r)) { - spin_unlock_bh(lock); - return false; - } + lunatik_State *state; + int key = name_hash(&session, name); - return true; -} - -struct nflua_state *nflua_state_lookup(struct xt_lua_net *xt_lua, - const char *name) -{ - struct hlist_head *head; - struct nflua_state *state; - - if (xt_lua == NULL) - return NULL; - - head = &xt_lua->state_table[name_hash(xt_lua, name)]; - kpi_hlist_for_each_entry_rcu(state, head, node) { - if (!strncmp(state->name, name, NFLUA_NAME_MAXSIZE)) + hash_for_each_possible_rcu(session.states_table, state, node, key) { + if (!strncmp(state->name, name, LUNATIK_NAME_MAXSIZE)) return state; } return NULL; } -static void state_destroy(struct xt_lua_net *xt_lua, struct nflua_state *s) +static void state_destroy(lunatik_State *s) { - hlist_del_rcu(&s->node); - atomic_dec(&xt_lua->state_count); + hash_del_rcu(&s->node); + atomic_dec(&(session.states_count)); spin_lock_bh(&s->lock); if (s->L != NULL) { @@ -98,12 +66,12 @@ static void state_destroy(struct xt_lua_net *xt_lua, struct nflua_state *s) } spin_unlock_bh(&s->lock); - nflua_state_put(s); + lunatik_stateput(s); } static void *lua_alloc(void *ud, void *ptr, size_t osize, size_t nsize) { - struct nflua_state *s = ud; + lunatik_State *s = ud; void *nptr = NULL; /* osize doesn't represent the object old size if ptr is NULL */ @@ -114,7 +82,7 @@ static void *lua_alloc(void *ud, void *ptr, size_t osize, size_t nsize) kfree(ptr); } else if (s->curralloc - osize + nsize > s->maxalloc) { pr_warn_ratelimited("maxalloc limit %zu reached on state %.*s\n", - s->maxalloc, NFLUA_NAME_MAXSIZE, s->name); + s->maxalloc, LUNATIK_NAME_MAXSIZE, s->name); } else if ((nptr = krealloc(ptr, nsize, GFP_ATOMIC)) != NULL) { s->curralloc += nsize - osize; } @@ -122,36 +90,38 @@ static void *lua_alloc(void *ud, void *ptr, size_t osize, size_t nsize) return nptr; } -static int state_init(struct nflua_state *s) +static int state_init(lunatik_State *s) { + #ifndef LUNATIK_UNUSED const luaL_Reg *lib; + #endif /*LUNATIK_UNUSED*/ s->L = lua_newstate(lua_alloc, s); if (s->L == NULL) return -ENOMEM; - luaU_setenv(s->L, s, struct nflua_state); + luaU_setenv(s->L, s, lunatik_State); luaL_openlibs(s->L); + #ifndef LUNATIK_UNUSED for (lib = libs; lib->name != NULL; lib++) { luaL_requiref(s->L, lib->name, lib->func, 1); lua_pop(s->L, 1); } + #endif /* fixes an issue where the Lua's GC enters a vicious cycle. * more info here: https://marc.info/?l=lua-l&m=155024035605499&w=2 */ - lua_gc(s->L, LUA_GCSETPAUSE, NFLUA_SETPAUSE); + lua_gc(s->L, LUA_GCSETPAUSE, LUNATIK_SETPAUSE); return 0; } -struct nflua_state *nflua_state_create(struct xt_lua_net *xt_lua, - size_t maxalloc, const char *name) +lunatik_State *lunatik_newstate(size_t maxalloc, const char *name) { - struct hlist_head *head; - struct nflua_state *s = nflua_state_lookup(xt_lua, name); - int namelen = strnlen(name, NFLUA_NAME_MAXSIZE); + lunatik_State *s = lunatik_statelookup(name); + int namelen = strnlen(name, LUNATIK_NAME_MAXSIZE); pr_debug("creating state: %.*s maxalloc: %zd\n", namelen, name, maxalloc); @@ -161,29 +131,29 @@ struct nflua_state *nflua_state_create(struct xt_lua_net *xt_lua, return NULL; } - if (atomic_read(&xt_lua->state_count) >= NFLUA_MAX_STATES) { + if (atomic_read(&(session.states_count)) >= LUNATIK_HASH_BUCKETS) { pr_err("could not allocate id for state %.*s\n", namelen, name); pr_err("max states limit reached or out of memory\n"); return NULL; } - if (maxalloc < NFLUA_MIN_ALLOC_BYTES) { + if (maxalloc < LUNATIK_MIN_ALLOC_BYTES) { pr_err("maxalloc %zu should be greater then MIN_ALLOC %zu\n", - maxalloc, NFLUA_MIN_ALLOC_BYTES); + maxalloc, LUNATIK_MIN_ALLOC_BYTES); return NULL; } - if ((s = kzalloc(sizeof(struct nflua_state), GFP_ATOMIC)) == NULL) { + if ((s = kzalloc(sizeof(lunatik_State), GFP_ATOMIC)) == NULL) { pr_err("could not allocate nflua state\n"); return NULL; } - INIT_HLIST_NODE(&s->node); spin_lock_init(&s->lock); + #ifndef LUNATIK_UNUSED s->dseqnum = 0; + #endif s->maxalloc = maxalloc; s->curralloc = 0; - s->xt_lua = xt_lua; memcpy(&(s->name), name, namelen); if (state_init(s)) { @@ -192,32 +162,32 @@ struct nflua_state *nflua_state_create(struct xt_lua_net *xt_lua, return NULL; } - spin_lock_bh(&xt_lua->state_lock); - head = &xt_lua->state_table[name_hash(xt_lua, name)]; - hlist_add_head_rcu(&s->node, head); - kpi_refcount_inc(&s->users); - atomic_inc(&xt_lua->state_count); - spin_unlock_bh(&xt_lua->state_lock); + spin_lock_bh(&(session.statestable_lock)); + hash_add_rcu(session.states_table, &(s->node), name_hash(&session, name)); + refcount_inc(&s->users); + atomic_inc(&(session.states_count)); + spin_unlock_bh(&(session.statestable_lock)); pr_debug("new state created: %.*s\n", namelen, name); return s; } -int nflua_state_destroy(struct xt_lua_net *xt_lua, const char *name) +int lunatik_close(const char *name) { - struct nflua_state *s = nflua_state_lookup(xt_lua, name); + lunatik_State *s = lunatik_statelookup(name); - if (s == NULL || kpi_refcount_read(&s->users) > 1) + if (s == NULL || refcount_read(&s->users) > 1) return -1; - spin_lock_bh(&xt_lua->state_lock); - state_destroy(xt_lua, s); - spin_unlock_bh(&xt_lua->state_lock); + spin_lock_bh(&(session.statestable_lock)); + state_destroy(s); + spin_unlock_bh(&(session.statestable_lock)); return 0; } -int nflua_state_list(struct xt_lua_net *xt_lua, nflua_state_cb cb, +#ifndef LUNATIK_UNUSED +int lunatik_state_list(struct xt_lua_net *xt_lua, nflua_state_cb cb, unsigned short *total) { struct hlist_head *head; @@ -240,54 +210,50 @@ int nflua_state_list(struct xt_lua_net *xt_lua, nflua_state_cb cb, spin_unlock_bh(&xt_lua->state_lock); return ret; } +#endif -void nflua_state_destroy_all(struct xt_lua_net *xt_lua) +void lunatik_closeall(void) { - struct hlist_head *head; struct hlist_node *tmp; - struct nflua_state *s; - int i; + lunatik_State *s; + int bkt; - spin_lock_bh(&xt_lua->state_lock); - for (i = 0; i < XT_LUA_HASH_BUCKETS; i++) { - head = &xt_lua->state_table[i]; - kpi_hlist_for_each_entry_safe(s, tmp, head, node) { - state_destroy(xt_lua, s); - } + spin_lock_bh(&(session.statestable_lock)); + hash_for_each_safe (session.states_table, bkt, tmp, s, node) { + state_destroy(s); } - spin_unlock_bh(&xt_lua->state_lock); + spin_unlock_bh(&(session.statestable_lock)); } -bool nflua_state_get(struct nflua_state *s) +inline bool lunatik_stateget(lunatik_State *s) { - return kpi_refcount_inc_not_zero(&s->users); + return refcount_inc_not_zero(&s->users); } -void nflua_state_put(struct nflua_state *s) +void lunatik_stateput(lunatik_State *s) { - struct xt_lua_net *xt_lua; + refcount_t *users = &s->users; + spinlock_t *refcnt_lock = &(session.rfcnt_lock); if (WARN_ON(s == NULL)) return; + + if (refcount_dec_not_one(users)) + return; - xt_lua = s->xt_lua; - if (refcount_dec_and_lock_bh(&s->users, &xt_lua->rfcnt_lock)) { - kfree(s); - spin_unlock_bh(&xt_lua->rfcnt_lock); - } -} - -void nflua_states_init(struct xt_lua_net *xt_lua) -{ - int i; - atomic_set(&xt_lua->state_count, 0); - spin_lock_init(&xt_lua->state_lock); - spin_lock_init(&xt_lua->rfcnt_lock); - for (i = 0; i < XT_LUA_HASH_BUCKETS; i++) - INIT_HLIST_HEAD(&xt_lua->state_table[i]); + spin_lock_bh(refcnt_lock); + if (!refcount_dec_and_test(users)) + goto out; + + kfree(s); +out: + spin_unlock_bh(refcnt_lock); } -void nflua_states_exit(struct xt_lua_net *xt_lua) +void lunatik_statesinit(void) { - nflua_state_destroy_all(xt_lua); + atomic_set(&(session.states_count), 0); + spin_lock_init(&(session.statestable_lock)); + spin_lock_init(&(session.rfcnt_lock)); + hash_init(session.states_table); } diff --git a/states.h b/states.h index 9c556c584..17a6a7682 100644 --- a/states.h +++ b/states.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2020 Matheus Rodrigues * Copyright (C) 2017-2019 CUJO LLC * * This program is free software; you can redistribute it and/or modify @@ -16,48 +17,46 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef NFLUA_STATES_H -#define NFLUA_STATES_H +#ifndef LUNATIK_STATES_H +#define LUNATIK_STATES_H -#include "kpi_compat.h" +#include "lua/lua.h" -#include +#define LUNATIK_NAME_MAXSIZE 64 +#define LUNATIK_MIN_ALLOC_BYTES (32 * 1024UL) +#define LUNATIK_HASH_BUCKETS 32 -#define NFLUA_NAME_MAXSIZE 64 - -struct xt_lua_net; +struct lunatik_session { + struct hlist_head states_table[LUNATIK_HASH_BUCKETS]; + spinlock_t statestable_lock; + spinlock_t rfcnt_lock; + atomic_t states_count; +}; -struct nflua_state { +typedef struct lunatik_state { struct hlist_node node; lua_State *L; - struct xt_lua_net *xt_lua; spinlock_t lock; - kpi_refcount_t users; - u32 dseqnum; + refcount_t users; size_t maxalloc; size_t curralloc; - unsigned char name[NFLUA_NAME_MAXSIZE]; -}; + unsigned char name[LUNATIK_NAME_MAXSIZE]; +} lunatik_State; +#ifndef LUNATIK_UNUSED typedef int (*nflua_state_cb)(struct nflua_state *s, unsigned short *total); +#endif /*LUNATIK_UNUSED*/ -struct nflua_state *nflua_state_create(struct xt_lua_net *xt_lua, - size_t maxalloc, const char *name); - -int nflua_state_destroy(struct xt_lua_net *xt_lua, const char *name); - -struct nflua_state *nflua_state_lookup(struct xt_lua_net *xt_lua, - const char *name); +lunatik_State *lunatik_newstate(size_t maxalloc, const char *name); +int lunatik_close(const char *name); +lunatik_State *lunatik_statelookup(const char *name); +#ifndef LUNATIK_UNUSED int nflua_state_list(struct xt_lua_net *xt_lua, nflua_state_cb cb, unsigned short *total); +#endif /*LUNATIK_UNUSED*/ -void nflua_state_destroy_all(struct xt_lua_net *xt_lua); - -bool nflua_state_get(struct nflua_state *s); -void nflua_state_put(struct nflua_state *s); - -void nflua_states_init(struct xt_lua_net *xt_lua); -void nflua_states_exit(struct xt_lua_net *xt_lua); +bool lunatik_stateget(lunatik_State *s); +void lunatik_stateput(lunatik_State *s); -#endif /* NFLUA_STATES_H */ +#endif /* LUNATIK_STATES_H */ From c1c757b1e918db7d37af79ba8f3f5d28f2526820 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Tue, 14 Jul 2020 14:44:25 -0300 Subject: [PATCH 03/48] Operations per namespace implementation --- lunatik_core.c | 61 ++++++++++++++++++++++++++++++++ states.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++- states.h | 4 +++ 3 files changed, 160 insertions(+), 1 deletion(-) diff --git a/lunatik_core.c b/lunatik_core.c index 65bb977d2..a72e2b626 100644 --- a/lunatik_core.c +++ b/lunatik_core.c @@ -23,6 +23,9 @@ */ #ifdef __linux__ #include +#include +#include +#include #include "lua/lua.h" #include "lua/lauxlib.h" @@ -174,18 +177,76 @@ EXPORT_SYMBOL(lunatik_statelookup); EXPORT_SYMBOL(lunatik_stateget); EXPORT_SYMBOL(lunatik_stateput); +EXPORT_SYMBOL(lunatik_netnewstate); +EXPORT_SYMBOL(lunatik_netclose); +EXPORT_SYMBOL(lunatik_netstatelookup); + extern void lunatik_statesinit(void); extern void lunatik_closeall(void); +extern void state_destroy(lunatik_State *s); + +static int lunatik_netid __read_mostly; + +struct lunatik_session *klua_pernet(struct net *net) +{ + return (struct lunatik_session *)net_generic(net,lunatik_netid); +} + +static int __net_init lunatik_sessioninit(struct net *net) +{ + struct lunatik_session *session = klua_pernet(net); + + atomic_set(&(session->states_count), 0); + spin_lock_init(&(session->statestable_lock)); + spin_lock_init(&(session->rfcnt_lock)); + hash_init(session->states_table); + + return 0; +} + +static void __net_exit lunatik_sessionend(struct net *net) +{ + struct lunatik_session *session; + lunatik_State *s; + struct hlist_node *tmp; + int bkt; + + session = klua_pernet(net); + + spin_lock_bh(&(session->statestable_lock)); + + hash_for_each_safe(session->states_table, bkt, tmp, s, node) { + state_destroy(s); + } + + spin_unlock_bh(&(session->statestable_lock)); +} + +static struct pernet_operations klua_net_ops = { + .init = lunatik_sessioninit, + .exit = lunatik_sessionend, + .id = &lunatik_netid, + .size = sizeof(struct lunatik_session), +}; static int __init modinit(void) { + int ret; + lunatik_statesinit(); + + if ((ret = register_pernet_subsys(&klua_net_ops))) { + pr_err("Failed to register pernet operations\n"); + return ret; + } + return 0; } static void __exit modexit(void) { lunatik_closeall(); + unregister_pernet_subsys(&klua_net_ops); } module_init(modinit); diff --git a/states.c b/states.c index db806b2ef..e9cedf071 100644 --- a/states.c +++ b/states.c @@ -54,7 +54,7 @@ lunatik_State *lunatik_statelookup(const char *name) return NULL; } -static void state_destroy(lunatik_State *s) +void state_destroy(lunatik_State *s) { hash_del_rcu(&s->node); atomic_dec(&(session.states_count)); @@ -257,3 +257,97 @@ void lunatik_statesinit(void) spin_lock_init(&(session.rfcnt_lock)); hash_init(session.states_table); } + +lunatik_State *lunatik_netstatelookup(struct lunatik_session *session, const char *name) +{ + + lunatik_State *state; + int key; + if (session == NULL) + return NULL; + + key = name_hash(session,name); + + hash_for_each_possible_rcu(session->states_table, state, node, key) { + if (!strncmp(state->name, name, LUNATIK_NAME_MAXSIZE)) + return state; + } + return NULL; +} + +lunatik_State *lunatik_netnewstate(struct lunatik_session *session, size_t maxalloc, const char *name) +{ + + lunatik_State *s = lunatik_netstatelookup(session, name); + int namelen = strnlen(name, LUNATIK_NAME_MAXSIZE); + + pr_debug("creating state: %.*s maxalloc: %zd\n", namelen, name, + maxalloc); + + if (s != NULL) { + pr_err("state already exists: %.*s\n", namelen, name); + return NULL; + } + + if (atomic_read(&(session->states_count)) >= LUNATIK_HASH_BUCKETS) { + pr_err("could not allocate id for state %.*s\n", namelen, name); + pr_err("max states limit reached or out of memory\n"); + return NULL; + } + + if (maxalloc < LUNATIK_MIN_ALLOC_BYTES) { + pr_err("maxalloc %zu should be greater then MIN_ALLOC %zu\n", + maxalloc, LUNATIK_MIN_ALLOC_BYTES); + return NULL; + } + + if ((s = kzalloc(sizeof(lunatik_State), GFP_ATOMIC)) == NULL) { + pr_err("could not allocate nflua state\n"); + return NULL; + } + + spin_lock_init(&s->lock); + s->maxalloc = maxalloc; + s->curralloc = 0; + memcpy(&(s->name), name, namelen); + + if (state_init(s)) { + pr_err("could not allocate a new lua state\n"); + kfree(s); + return NULL; + } + + spin_lock_bh(&(session->statestable_lock)); + hash_add_rcu(session->states_table, &(s->node), name_hash(session,name)); + refcount_inc(&(s->users)); + atomic_inc(&(session->states_count)); + spin_unlock_bh(&(session->statestable_lock)); + + pr_debug("new state created: %.*s\n", namelen, name); + return s; +} + +int lunatik_netclose(struct lunatik_session *session, const char *name) +{ + lunatik_State *s = lunatik_netstatelookup(session,name); + + if (s == NULL || refcount_read(&s->users) > 1) + return -1; + + spin_lock_bh(&(session->statestable_lock)); + + hash_del_rcu(&s->node); + atomic_dec(&(session->states_count)); + + spin_lock_bh(&s->lock); + if (s->L != NULL) { + lua_close(s->L); + s->L = NULL; + } + spin_unlock_bh(&s->lock); + lunatik_stateput(s); + + spin_unlock_bh(&(session->statestable_lock)); + + return 0; +} diff --git a/states.h b/states.h index 17a6a7682..d552052f6 100644 --- a/states.h +++ b/states.h @@ -59,4 +59,8 @@ int nflua_state_list(struct xt_lua_net *xt_lua, nflua_state_cb cb, bool lunatik_stateget(lunatik_State *s); void lunatik_stateput(lunatik_State *s); +lunatik_State *lunatik_netnewstate(struct lunatik_session *session, size_t maxalloc, const char *name); +int lunatik_netclose(struct lunatik_session *session, const char *name); +lunatik_State *lunatik_netstatelookup(struct lunatik_session *session, const char *name); + #endif /* LUNATIK_STATES_H */ From 962380799d06fae6a3502c387f7e5414d118cae8 Mon Sep 17 00:00:00 2001 From: NFLuaTeam <> Date: Tue, 14 Jul 2020 16:23:18 -0300 Subject: [PATCH 04/48] Import luautil from NFLua --- luautil.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 luautil.c diff --git a/luautil.c b/luautil.c new file mode 100644 index 000000000..fb3ea76c4 --- /dev/null +++ b/luautil.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2017-2019 CUJO LLC. + * Copyright (C) 1994-2018 Lua.org, PUC-Rio. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "luautil.h" + +static int msghandler(lua_State *L) +{ + const char *msg = lua_tostring(L, 1); + if (msg == NULL) { + if (luaL_callmeta(L, 1, "__tostring") && + lua_type(L, -1) == LUA_TSTRING) + return 1; + else + msg = lua_pushfstring(L, "(error object is a %s value)", + luaL_typename(L, 1)); + } + luaL_traceback(L, L, msg, 1); + return 1; +} + +int luaU_pcall(lua_State *L, int nargs, int nresults) +{ + int status; + int base = lua_gettop(L) - nargs; + lua_pushcfunction(L, msghandler); + lua_insert(L, base); + status = lua_pcall(L, nargs, nresults, base); + lua_remove(L, base); + return status; +} From 8a1bbb22154f7ee556f8c65aeae4883a4cede2d3 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Tue, 14 Jul 2020 16:40:36 -0300 Subject: [PATCH 05/48] Netlink implementation --- lunatik_core.c | 12 +-- netlink.c | 251 +++++++++++++++++++++++++++++++++++++++++++++++ netlink_common.h | 38 +++++++ 3 files changed, 295 insertions(+), 6 deletions(-) create mode 100644 netlink.c create mode 100644 netlink_common.h diff --git a/lunatik_core.c b/lunatik_core.c index a72e2b626..e67ed1fe0 100644 --- a/lunatik_core.c +++ b/lunatik_core.c @@ -187,14 +187,14 @@ extern void state_destroy(lunatik_State *s); static int lunatik_netid __read_mostly; -struct lunatik_session *klua_pernet(struct net *net) +struct lunatik_session *lunatik_pernet(struct net *net) { return (struct lunatik_session *)net_generic(net,lunatik_netid); } static int __net_init lunatik_sessioninit(struct net *net) { - struct lunatik_session *session = klua_pernet(net); + struct lunatik_session *session = lunatik_pernet(net); atomic_set(&(session->states_count), 0); spin_lock_init(&(session->statestable_lock)); @@ -211,7 +211,7 @@ static void __net_exit lunatik_sessionend(struct net *net) struct hlist_node *tmp; int bkt; - session = klua_pernet(net); + session = lunatik_pernet(net); spin_lock_bh(&(session->statestable_lock)); @@ -222,7 +222,7 @@ static void __net_exit lunatik_sessionend(struct net *net) spin_unlock_bh(&(session->statestable_lock)); } -static struct pernet_operations klua_net_ops = { +static struct pernet_operations lunatik_net_ops = { .init = lunatik_sessioninit, .exit = lunatik_sessionend, .id = &lunatik_netid, @@ -235,7 +235,7 @@ static int __init modinit(void) lunatik_statesinit(); - if ((ret = register_pernet_subsys(&klua_net_ops))) { + if ((ret = register_pernet_subsys(&lunatik_net_ops))) { pr_err("Failed to register pernet operations\n"); return ret; } @@ -246,7 +246,7 @@ static int __init modinit(void) static void __exit modexit(void) { lunatik_closeall(); - unregister_pernet_subsys(&klua_net_ops); + unregister_pernet_subsys(&lunatik_net_ops); } module_init(modinit); diff --git a/netlink.c b/netlink.c new file mode 100644 index 000000000..6e991dea3 --- /dev/null +++ b/netlink.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2020 Matheus Rodrigues + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "luautil.h" +#include "states.h" +#include "netlink_common.h" + +extern struct lunatik_session *lunatik_pernet(struct net *net); + +static int lunatikN_newstate(struct sk_buff *buff, struct genl_info *info); +static int lunatikN_exec(struct sk_buff *buff, struct genl_info *info); +static int lunatikN_close(struct sk_buff *buff, struct genl_info *info); +static int lunatikN_list(struct sk_buff *buff, struct genl_info *info); + +struct nla_policy lunatik_policy[ATTRS_COUNT] = { + [STATE_NAME] = { .type = NLA_STRING }, + [CODE] = { .type = NLA_STRING }, + [MAX_ALLOC] = { .type = NLA_U32 }, + [SCRIPT_SIZE] = { .type = NLA_U32 }, //TODO See what is the maximum script size accepted by the module + [STATES_COUNT]= { .type = NLA_U32}, + [FLAGS] = { .type = NLA_U8 }, +}; + +static const struct genl_ops l_ops[] = { + { + .cmd = CREATE_STATE, + .doit = lunatikN_newstate, +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) + /*Before kernel 5.2.0, each operation has its own policy*/ + .policy = lunatik_policy +#endif + }, + { + .cmd = EXECUTE_CODE, + .doit = lunatikN_exec, +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) + /*Before kernel 5.2.0, each operation has its own policy*/ + .policy = lunatik_policy +#endif + }, + { + .cmd = DESTROY_STATE, + .doit = lunatikN_close, +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) + /*Before kernel 5.2.0, each operation has its own policy*/ + .policy = lunatik_policy +#endif + }, + { + .cmd = LIST_STATES, + .doit = lunatikN_list, +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) + /*Before kernel 5.2.0, each operation has its own policy*/ + .policy = lunatik_policy +#endif + } +}; + +struct genl_family lunatik_family = { + .name = LUNATIK_FAMILY, + .version = LUNATIK_NLVERSION, + .maxattr = ATTRS_MAX, + .netnsok = true, /*Make this family visible for all namespaces*/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0) + .policy = lunatik_policy, +#endif + .module = THIS_MODULE, + .ops = l_ops, + .n_ops = ARRAY_SIZE(l_ops), +}; + +static int lunatikN_newstate(struct sk_buff *buff, struct genl_info *info) +{ + struct lunatik_session *session; + char *state_name; + u32 *max_alloc; + u32 pid; + + pr_debug("Received a CREATE_STATE message\n"); + + session = lunatik_pernet(genl_info_net(info)); + state_name = (char *)nla_data(info->attrs[STATE_NAME]); + max_alloc = (u32 *)nla_data(info->attrs[MAX_ALLOC]); + pid = info->snd_portid; + + lunatik_newstate(session, *max_alloc, state_name); + + return 0; +} + +static int lunatikN_exec(struct sk_buff *buff, struct genl_info *info) +{ + struct lunatik_state *s; + struct lunatik_session *session; + const char *finalscript; + char *fragment; + char *state_name; + u8 flags; + + pr_debug("Received a EXECUTE_CODE message\n"); + + session = lunatik_pernet(genl_info_net(info)); + state_name = (char *)nla_data(info->attrs[STATE_NAME]); + fragment = (char *)nla_data(info->attrs[CODE]); + flags = *((u8*)nla_data(info->attrs[FLAGS])); + + if ((s = lunatik_netstatelookup(session, state_name)) == NULL) { + pr_err("Error finding klua state\n"); + return 0; + } + + if (flags & LUNATIK_INIT) { + s->curr_script_size = *((u32*)nla_data(info->attrs[SCRIPT_SIZE])); + + if ((s->buffer = kmalloc(sizeof(luaL_Buffer), GFP_KERNEL)) == NULL) { + pr_err("Failed allocating memory to code buffer\n"); + return 0; + } + spin_lock_bh(&s->lock); + luaL_buffinit(s->L, s->buffer); + } // TODO Otherwise, reply with a "busy state" + + if (flags & LUNATIK_MULTI) { + luaL_addlstring(s->buffer, fragment, LUNATIK_FRAGMENT_SIZE); + } + + if (flags & LUNATIK_DONE){ + luaL_addstring(s->buffer, fragment); + luaL_pushresult(s->buffer); + + finalscript = lua_tostring(s->L, -1); + + if (!lunatik_state_get(s)) { + pr_err("Failed to get state\n"); + return 0; + } + + if (luaU_dostring(s->L, finalscript, s->curr_script_size, "Lua in kernel")) { + pr_err("%s\n", lua_tostring(s->L, -1)); + } + + spin_unlock_bh(&s->lock); + lunatik_state_put(s); + } + + return 0; +} + +static int lunatikN_close(struct sk_buff *buff, struct genl_info *info) +{ + struct lunatik_session *session; + char *state_name; + + session = lunatik_pernet(genl_info_net(info)); + state_name = (char *)nla_data(info->attrs[STATE_NAME]); + + pr_debug("Received a DESTROY_STATE command\n"); + + if (lunatik_close(session, state_name)) { + pr_err("Failed to destroy state %s\n", state_name); + return 0; + } + + return 0; +} + +static int lunatikN_list(struct sk_buff *buff, struct genl_info *info) +{ + struct sk_buff *obuff; + struct lunatik_session *session; + struct lunatik_state *state; + void *msg_head; + int bucket; + bool firstmsg = true; + int err = -1; + + pr_debug("Received a LIST_STATES command\n"); + + session = lunatik_pernet(genl_info_net(info)); + + hash_for_each_rcu(session->states_table, bucket, state, node) { + if ((obuff = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL)) == NULL) { + pr_err("Failed allocating message to an reply\n"); + return err; + } + + if ((msg_head = genlmsg_put_reply(obuff, info, &lunatik_family, 0, LIST_STATES)) == NULL) { + pr_err("Failed to put generic netlink header\n"); + return err; + } + + if (nla_put_string(obuff, STATE_NAME, state->name) || + nla_put_u32(obuff, MAX_ALLOC, state->maxalloc) || + nla_put_u32(obuff, CURR_ALLOC, state->curralloc) + ) { + pr_err("Failed to put attributes on socket buffer\n"); + return err; + } + + if (firstmsg) { + if (nla_put_u32(obuff, STATES_COUNT, atomic_read(&session->states_count)) || + nla_put_u8(obuff, FLAGS, LUNATIK_INIT) + ) { + pr_err("Failed to put attributes on socket buffer\n"); + return err; + } + firstmsg = false; + + } else if (nla_put_u8(obuff, FLAGS, 0)) { + pr_err("Failed to put attributes on socket buffer\n"); + return err; + } + + genlmsg_end(obuff, msg_head); + + if (genlmsg_reply(obuff, info) < 0) { + pr_err("Failed to send message to user space\n"); + return err; + } + + pr_debuf("Message sento to kernel\n"); + } + + return 0; +} diff --git a/netlink_common.h b/netlink_common.h new file mode 100644 index 000000000..e38c84b42 --- /dev/null +++ b/netlink_common.h @@ -0,0 +1,38 @@ +#ifndef NETLINK_COMMOM_H +#define NETLINK_COMMOM_H + +#ifdef _KERNEL +extern struct genl_family lunatik_family; +#include +#endif + +#define LUNATIK_FRAGMENT_SIZE (3000) // TODO Find, a size more precise + +/*Lunatik generic netlink protocol flags*/ +#define LUNATIK_INIT 0x01 /* Initializes the needed variables for script execution */ +#define LUNATIK_MULTI 0x02 /* A Fragment of a multipart message */ +#define LUNATIK_DONE 0x04 /* Last message of a multipart message */ + +#define LUNATIK_FAMILY "lunatik_family" +#define LUNATIK_NLVERSION 1 + +enum lunatik_operations { + CREATE_STATE = 1, /* Starts at 1 because 0 is used by generic netlink */ + EXECUTE_CODE, + DESTROY_STATE, + LIST_STATES, +}; + +enum lunatik_attrs { + STATE_NAME = 1, + STATES_COUNT, + MAX_ALLOC, + CURR_ALLOC, + CODE, + FLAGS, + SCRIPT_SIZE, + ATTRS_COUNT +#define ATTRS_MAX (ATTRS_COUNT - 1) +}; + +#endif /* NETLINK_COMMOM_H */ From 38b9a141bf67effeec4893520c5026decc800bce Mon Sep 17 00:00:00 2001 From: NFLua Team <> Date: Tue, 21 Jul 2020 15:52:15 -0300 Subject: [PATCH 06/48] Import user space lib and nfluaconf from NFLua --- lib/Makefile | 43 +++++ lib/lunatik.h | 118 +++++++++++++ lib/lunatik_module.c | 390 +++++++++++++++++++++++++++++++++++++++++++ lunatik_conf.h | 30 ++++ 4 files changed, 581 insertions(+) create mode 100644 lib/Makefile create mode 100644 lib/lunatik.h create mode 100644 lib/lunatik_module.c create mode 100644 lunatik_conf.h diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 000000000..46ebecb91 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,43 @@ +# +# Copyright (C) 2017-2019 CUJO LLC +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +CC = gcc +CFLAGS = -fPIC -Wall -Wextra -O2 -g -I../src +LDFLAGS = -shared +RM = rm -f + +LIBS = libnflua.so +OBJS = $(patsubst %.c,%.o,$(wildcard *.c)) +DEPS = $(OBJS:.o=.d) + +.PHONY: all +all: $(LIBS) + +%.so: + $(CC) -o $@ $^ $(LDFLAGS) + +%.o: %.c + $(CC) $(CFLAGS) -MMD -c -o $@ $< + +-include $(DEPS) + +.PHONY: clean +clean: + $(RM) $(LIBS) $(OBJS) $(DEPS) + +$(LIBS): $(OBJS) diff --git a/lib/lunatik.h b/lib/lunatik.h new file mode 100644 index 000000000..c4e4e2061 --- /dev/null +++ b/lib/lunatik.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2017-2019 CUJO LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef NFLUA_H +#define NFLUA_H + +#include +#include +#include + +enum nflua_control_state { + NFLUA_LINK_READY, + NFLUA_SENDING_REQUEST, + NFLUA_PENDING_REPLY, + NFLUA_RECEIVING_REPLY, + NFLUA_PROTOCOL_OUTOFSYNC, + NFLUA_SOCKET_CLOSED, +}; + +struct nflua_response { + uint32_t type; + uint32_t count; + uint32_t total_size; +}; + +struct nflua_control { + int fd; + uint32_t pid; + uint32_t seqnum; + int currfrag; + enum nflua_control_state state; + uint8_t buffer[NFLUA_PAYLOAD_MAXSIZE]; +}; + +struct nflua_data { + int fd; + uint32_t pid; + uint32_t seqnum; + char state[NFLUA_NAME_MAXSIZE]; + char buffer[NFLUA_PAYLOAD_MAXSIZE]; +}; + +static inline int nflua_control_getsock(const struct nflua_control *ctrl) +{ + return ctrl->fd; +} + +static inline int nflua_control_getstate(const struct nflua_control *ctrl) +{ + return ctrl->state; +} + +static inline int nflua_control_getpid(const struct nflua_control *ctrl) +{ + return ctrl->pid; +} + +static inline int nflua_control_is_open(const struct nflua_control *ctrl) +{ + return ctrl->fd >= 0; +} + +int nflua_control_init(struct nflua_control *ctrl, uint32_t pid); + +void nflua_control_close(struct nflua_control *ctrl); + +int nflua_control_create(struct nflua_control *ctrl, struct nflua_nl_state *); + +int nflua_control_destroy(struct nflua_control *ctrl, const char *name); + +int nflua_control_execute(struct nflua_control *ctrl, const char *name, + const char *scriptname, const char *payload, size_t total); + +int nflua_control_list(struct nflua_control *ctrl); + +int nflua_control_receive(struct nflua_control *ctrl, + struct nflua_response *nr, char *buffer); + +static inline int nflua_data_getsock(const struct nflua_data *dch) +{ + return dch->fd; +} + +static inline int nflua_data_getpid(const struct nflua_data *dch) +{ + return dch->pid; +} + +static inline int nflua_data_is_open(const struct nflua_data *dch) +{ + return dch->fd >= 0; +} + +int nflua_data_init(struct nflua_data *dch, uint32_t pid); + +void nflua_data_close(struct nflua_data *dch); + +int nflua_data_send(struct nflua_data *dch, const char *name, + const char *payload, size_t len); + +int nflua_data_receive(struct nflua_data *dch, char *state, char *buffer); + +#endif /* NFLUA_H */ diff --git a/lib/lunatik_module.c b/lib/lunatik_module.c new file mode 100644 index 000000000..21c50fa1d --- /dev/null +++ b/lib/lunatik_module.c @@ -0,0 +1,390 @@ +/* + * Copyright (C) 2017-2019 CUJO LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +extern int luaopen_memory(lua_State *L); + +#define DEFAULT_MAXALLOC_BYTES (32 * 1024) + +struct control { + struct nflua_control ctrl; + struct nflua_response response; + char buffer[NFLUA_LIST_MAXSIZE]; +}; + +static int pusherrmsg(lua_State *L, const char *msg) +{ + lua_pushnil(L); + lua_pushstring(L, msg); + return 2; +} + +static int pusherrno(lua_State *L, int err) +{ + int r = pusherrmsg(L, strerror(-err)); + lua_pushinteger(L, err); + return r + 1; +} + +static int pushioresult(lua_State *L, int code) +{ + if (code >= 0) { + lua_pushboolean(L, true); + return 1; + } + return pusherrno(L, code); +} + +static void newclass(lua_State *L, const char *name, + const luaL_Reg mt[]) +{ + luaL_newmetatable(L, name); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, mt, 0); + lua_pop(L, 1); +} + +static uint32_t generatepid(lua_State *L, int arg) +{ + const uint32_t mask = 1 << 31; + + switch (lua_type(L, 1)) { + case LUA_TNUMBER: { + uint32_t pid = lua_tointeger(L, arg); + if (pid & mask) + luaL_argerror(L, arg, "must be in range [0, 2^31)"); + return pid; + } + case LUA_TNIL: + case LUA_TNONE: { + static uint16_t globaln = 0; + uint32_t n = __sync_fetch_and_add(&globaln, 1); + return (n << 16) | (getpid() & 0xFFFF) | mask; + } + default: + luaL_argerror(L, arg, "must be integer or nil"); + } + + return 0; +} + +static int lcontrol_open(lua_State *L) +{ + int ret; + uint32_t pid = generatepid(L, 1); + struct control *c = lua_newuserdata(L, sizeof(struct control)); + + luaL_setmetatable(L, "nflua.control"); + ret = nflua_control_init(&c->ctrl, pid); + + return ret < 0 ? pusherrno(L, ret) : 1; +} + +static int lcontrol_gc(lua_State *L) +{ + struct control *c = luaL_checkudata(L, 1, "nflua.control"); + if (nflua_control_is_open(&c->ctrl)) nflua_control_close(&c->ctrl); + return 0; +} + +static struct control *getcontrol(lua_State *L) +{ + struct control *c = luaL_checkudata(L, 1, "nflua.control"); + if (!nflua_control_is_open(&c->ctrl)) + luaL_argerror(L, 1, "socket closed"); + return c; +} + +static int lcontrol_close(lua_State *L) +{ + struct control *c = getcontrol(L); + nflua_control_close(&c->ctrl); + lua_pushboolean(L, true); + return 1; +} + +static int lcontrol_getfd(lua_State *L) +{ + struct control *c = getcontrol(L); + lua_pushinteger(L, nflua_control_getsock(&c->ctrl)); + return 1; +} + +static int lcontrol_getpid(lua_State *L) +{ + struct control *c = getcontrol(L); + lua_pushinteger(L, nflua_control_getpid(&c->ctrl)); + return 1; +} + +static int lcontrol_getstate(lua_State *L) +{ + static const char *tostr[] = { + [NFLUA_LINK_READY] = "ready", + [NFLUA_SENDING_REQUEST] = "sending", + [NFLUA_PENDING_REPLY] = "waiting", + [NFLUA_RECEIVING_REPLY] = "receiving", + [NFLUA_PROTOCOL_OUTOFSYNC] = "failed", + [NFLUA_SOCKET_CLOSED] = "closed" + }; + struct control *c = getcontrol(L); + int state = nflua_control_getstate(&c->ctrl); + + if (state < NFLUA_LINK_READY || state > NFLUA_SOCKET_CLOSED) + return pusherrmsg(L, "unknown state"); + + lua_pushstring(L, tostr[state]); + + return 1; +} + +static int lcontrol_create(lua_State *L) +{ + struct control *c = getcontrol(L); + size_t len; + const char *name = luaL_checklstring(L, 2, &len); + lua_Integer maxalloc = luaL_optinteger(L, 3, DEFAULT_MAXALLOC_BYTES); + struct nflua_nl_state state; + + if (len >= NFLUA_NAME_MAXSIZE) + luaL_argerror(L, 2, "name too long"); + + strcpy(state.name, name); + state.maxalloc = maxalloc; + + return pushioresult(L, nflua_control_create(&c->ctrl, &state)); +} + +static int lcontrol_destroy(lua_State *L) +{ + struct control *c = getcontrol(L); + const char *name = luaL_checkstring(L, 2); + return pushioresult(L, nflua_control_destroy(&c->ctrl, name)); +} + +static int lcontrol_execute(lua_State *L) +{ + struct control *c = getcontrol(L); + const char *name = luaL_checkstring(L, 2); + size_t len; + const char *payload = luaL_checklstring(L, 3, &len); + const char *scriptname = luaL_optstring(L, 4, payload); + int status = nflua_control_execute(&c->ctrl, name, scriptname, + payload, len); + + if (status > 0) return pusherrmsg(L, "pending"); + return pushioresult(L, status); +} + +static int lcontrol_list(lua_State *L) +{ + struct control *c = getcontrol(L); + return pushioresult(L, nflua_control_list(&c->ctrl)); +} + +static void buildlist(lua_State *L, struct nflua_nl_state *states, size_t n) +{ + size_t i; + + lua_newtable(L); + for (i = 0; i < n; i++) { + lua_newtable(L); + lua_pushstring(L, states[i].name); + lua_setfield(L, -2, "name"); + lua_pushinteger(L, states[i].maxalloc); + lua_setfield(L, -2, "maxalloc"); + lua_pushinteger(L, states[i].curralloc); + lua_setfield(L, -2, "curralloc"); + lua_seti(L, -2, i + 1); + } +} + +static int lcontrol_receive(lua_State *L) +{ + struct control *c = getcontrol(L); + int status = nflua_control_receive(&c->ctrl, &c->response, c->buffer); + + if (status < 0) return pusherrno(L, status); + if (status > 0) return pusherrmsg(L, "pending"); + + switch (c->response.type) { + case NLMSG_ERROR: + return pusherrmsg(L, "operation could not be completed"); + case NFLMSG_CREATE: + case NFLMSG_EXECUTE: + case NFLMSG_DESTROY: + lua_pushboolean(L, true); + return 1; + case NFLMSG_LIST: + buildlist(L, (struct nflua_nl_state *)c->buffer, + c->response.count); + return 1; + default: + return pusherrmsg(L, "unknown response"); + } + + return 0; +} + +static int ldata_open(lua_State *L) +{ + int ret; + uint32_t pid = generatepid(L, 1); + struct nflua_data *dch = lua_newuserdata(L, sizeof(struct nflua_data)); + + luaL_setmetatable(L, "nflua.data"); + ret = nflua_data_init(dch, pid); + + return ret < 0 ? pusherrno(L, ret) : 1; +} + +static int ldata_gc(lua_State *L) +{ + struct nflua_data *dch = luaL_checkudata(L, 1, "nflua.data"); + if (nflua_data_is_open(dch)) nflua_data_close(dch); + return 0; +} + +static struct nflua_data *getdata(lua_State *L) +{ + struct nflua_data *dch = luaL_checkudata(L, 1, "nflua.data"); + if (!nflua_data_is_open(dch)) luaL_argerror(L, 1, "socket closed"); + return dch; +} + +static int ldata_close(lua_State *L) +{ + struct nflua_data *dch = getdata(L); + nflua_data_close(dch); + lua_pushboolean(L, true); + return 1; +} + +static int ldata_getfd(lua_State *L) +{ + struct nflua_data *dch = getdata(L); + lua_pushinteger(L, nflua_data_getsock(dch)); + return 1; +} + +static int ldata_getpid(lua_State *L) +{ + struct nflua_data *dch = getdata(L); + lua_pushinteger(L, nflua_data_getpid(dch)); + return 1; +} + +static int ldata_send(lua_State *L) +{ + struct nflua_data *dch = getdata(L); + const char *name = luaL_checkstring(L, 2); + size_t size; + const char *buffer = luamem_checkmemory(L, 3, &size); + + if (buffer == NULL) luaL_argerror(L, 3, "expected non NULL memory object"); + + return pushioresult(L, nflua_data_send(dch, name, buffer, size)); +} + +static int ldata_receive(lua_State *L) +{ + struct nflua_data *dch = getdata(L); + char state[NFLUA_NAME_MAXSIZE] = {0}; + size_t size, offset; + int recv; + char *buffer = luamem_checkmemory(L, 2, &size); + + if (buffer == NULL) luaL_argerror(L, 2, "expected non NULL memory object"); + + offset = luaL_checkinteger(L, 3); + if (offset >= size || size - offset < NFLUA_DATA_MAXSIZE) + luaL_argerror(L, 3, "not enough space in buffer"); + + recv = nflua_data_receive(dch, state, buffer + offset); + if (recv < 0) return pusherrno(L, recv); + + lua_pushinteger(L, recv); + lua_pushstring(L, state); + + return 2; +} + +static const luaL_Reg control_mt[] = { + {"close", lcontrol_close}, + {"getfd", lcontrol_getfd}, + {"getpid", lcontrol_getpid}, + {"getstate", lcontrol_getstate}, + {"create", lcontrol_create}, + {"destroy", lcontrol_destroy}, + {"execute", lcontrol_execute}, + {"list", lcontrol_list}, + {"receive", lcontrol_receive}, + {"__gc", lcontrol_gc}, + {NULL, NULL} +}; + +static const luaL_Reg data_mt[] = { + {"close", ldata_close}, + {"getfd", ldata_getfd}, + {"getpid", ldata_getpid}, + {"send", ldata_send}, + {"receive", ldata_receive}, + {"__gc", ldata_gc}, + {NULL, NULL} +}; + +static const luaL_Reg nflua_lib[] = { + {"control", lcontrol_open}, + {"data", ldata_open}, + {NULL, NULL} +}; + +static void setconst(lua_State *L, const char *name, lua_Integer value) +{ + lua_pushinteger(L, value); + lua_setfield(L, -2, name); +} + +int luaopen_nflua(lua_State *L) +{ + luaL_requiref(L, "memory", luaopen_memory, 1); + lua_pop(L, 1); + + newclass(L, "nflua.control", control_mt); + newclass(L, "nflua.data", data_mt); + + luaL_newlib(L, nflua_lib); + + setconst(L, "datamaxsize", NFLUA_DATA_MAXSIZE); + setconst(L, "defaultmaxallocbytes", DEFAULT_MAXALLOC_BYTES); + setconst(L, "maxstates", NFLUA_MAX_STATES); + setconst(L, "scriptnamemaxsize", NFLUA_SCRIPTNAME_MAXSIZE); + setconst(L, "statenamemaxsize", NFLUA_NAME_MAXSIZE); + + return 1; +} diff --git a/lunatik_conf.h b/lunatik_conf.h new file mode 100644 index 000000000..0a0451892 --- /dev/null +++ b/lunatik_conf.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2017-2019 CUJO LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _NFLUA_CONF_H +#define _NFLUA_CONF_H + +#ifndef NETLINK_NFLUA +#define NETLINK_NFLUA 31 /* NFLua netlink protocol family */ +#endif /* NETLINK_NFLUA */ + +#define NFLUA_NAME_MAXSIZE 64 /* Max length of Lua state name */ + +#define NFLUA_SCRIPTNAME_MAXSIZE 255 /* Max length of Lua state name */ + +#endif /* _NFLUA_CONF_H */ From d1fe1b500f1dded6410762be383425d84d044d3b Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Tue, 21 Jul 2020 15:45:07 -0300 Subject: [PATCH 07/48] Adapt control API from NFLua --- Makefile | 4 +- lib/Makefile | 10 +- lib/lunatik.c | 353 +++++++++++++++++++++++++++++++++++++++++++ lib/lunatik.h | 92 +++++------ lib/lunatik_module.c | 286 +++++++++++++++++------------------ luautil.h | 2 +- lunatik_conf.h | 17 ++- lunatik_core.c | 58 ++++--- netlink.c | 294 +++++++++++++++++++++++++---------- netlink_common.h | 9 ++ states.c | 70 ++++----- states.h | 17 ++- 12 files changed, 868 insertions(+), 344 deletions(-) create mode 100644 lib/lunatik.c diff --git a/Makefile b/Makefile index 0fee9af97..9f0a8df39 100644 --- a/Makefile +++ b/Makefile @@ -33,10 +33,10 @@ lua-objs = lua/lapi.o lua/lcode.o lua/lctype.o lua/ldebug.o lua/ldo.o \ lua/lundump.o lua/lvm.o lua/lzio.o lua/lauxlib.o lua/lbaselib.o \ lua/lbitlib.o lua/lcorolib.o lua/ldblib.o lua/lstrlib.o \ lua/ltablib.o lua/lutf8lib.o lua/loslib.o lua/lmathlib.o lua/linit.o \ - lua/loadlib.o + lua/loadlib.o luautil.o lunatik-objs += $(lua-objs) \ - arch/$(ARCH)/setjmp.o util/modti3.o lunatik_core.o states.o + arch/$(ARCH)/setjmp.o util/modti3.o lunatik_core.o states.o netlink.o ifeq ($(shell [ "${VERSION}" -lt "4" ] && [ "${VERSION}${PATCHLEVEL}" -lt "312" ] && echo y),y) lunatik-objs += util/div64.o diff --git a/lib/Makefile b/lib/Makefile index 46ebecb91..c5dfd4d6a 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,4 +1,4 @@ -# +# Copyright (c) 2020 Matheus Rodrigues # Copyright (C) 2017-2019 CUJO LLC # # This program is free software; you can redistribute it and/or modify @@ -17,11 +17,11 @@ # CC = gcc -CFLAGS = -fPIC -Wall -Wextra -O2 -g -I../src -LDFLAGS = -shared +CFLAGS = -fPIC -Wall -Wextra -O2 -g -I/usr/include/lua5.3/ -I/usr/include/libnl3 -D_UNUSED +LDFLAGS = -shared -lnl-genl-3 -lnl-3 -llua5.3 RM = rm -f -LIBS = libnflua.so +LIBS = lunatik.so OBJS = $(patsubst %.c,%.o,$(wildcard *.c)) DEPS = $(OBJS:.o=.d) @@ -32,7 +32,7 @@ all: $(LIBS) $(CC) -o $@ $^ $(LDFLAGS) %.o: %.c - $(CC) $(CFLAGS) -MMD -c -o $@ $< + $(CC) $(CFLAGS) -c -o $@ $< -include $(DEPS) diff --git a/lib/lunatik.c b/lib/lunatik.c new file mode 100644 index 000000000..503d2068c --- /dev/null +++ b/lib/lunatik.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2020 Matheus Rodrigues + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "lunatik.h" + +#define MIN(x,y) ((x) < (y) ? (x) : (y)) + +static struct nl_msg *prepare_message(struct lunatik_session *session, int command, int flags) +{ + struct nl_msg *msg; + + if ((msg = nlmsg_alloc()) == NULL) { + printf("Failed to allocate a new message\n"); + return NULL; + } + + if ((genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, session->family, + 0, 0, command, LUNATIK_NLVERSION)) == NULL) { + printf("Failed to put generic netlink message header\n"); + return NULL; + } + + NLA_PUT_U8(msg, FLAGS, flags); + + return msg; + +nla_put_failure: + printf("Failed to put attributes preparing the message\n"); + return NULL; +} + +static int send_simple_msg(struct lunatik_session *session, int command, int flags) +{ + struct nl_msg *msg; + int err = -1; + + if ((msg = prepare_message(session, command, flags)) == NULL) { + printf("Error preparing message\n"); + goto error; + } + + if ((err = nl_send_auto(session->sock, msg)) < 0) { + printf("Failed sending message to kernel\n"); + goto error; + } + + nlmsg_free(msg); + return 0; + +error: + nlmsg_free(msg); + return err; +} + +static int send_fragment(struct lunatik_session *session, const char *original_script, int offset, + const char *state_name, const char *script_name, int flags) +{ + struct nl_msg *msg; + char *fragment; + int err = -1; + if ((msg = prepare_message(session, EXECUTE_CODE, 0)) == NULL){ + nlmsg_free(msg); + return err; + } + + if ((fragment = malloc(sizeof(char) * LUNATIK_FRAGMENT_SIZE)) == NULL) { + printf("Failed to allocate memory to code fragment\n"); + return -ENOMEM; + } + strncpy(fragment, original_script + (offset * LUNATIK_FRAGMENT_SIZE), LUNATIK_FRAGMENT_SIZE); + + NLA_PUT_STRING(msg, STATE_NAME, state_name); + NLA_PUT_STRING(msg, CODE, fragment); + + if (offset == 0) + NLA_PUT_U32(msg, SCRIPT_SIZE, strlen(original_script)); + + if (flags & LUNATIK_DONE) + NLA_PUT_STRING(msg, SCRIPT_NAME, script_name); + + NLA_PUT_U8(msg, FLAGS, flags); + + + if ((err = nl_send_auto(session->sock, msg)) < 0) { + printf("Failed to send fragment\n %s\n", nl_geterror(err)); + nlmsg_free(msg); + return err; + } + + nlmsg_free(msg); + + return 0; + +nla_put_failure: + printf("Failed putting attributes on the message\n"); + free(fragment); + return err; +} + +static int receive_op_result(struct lunatik_session *session){ + int ret; + + if ((ret = nl_recvmsgs_default(session->sock))) { + printf("Failed to receive message from kernel: %s\n", nl_geterror(ret)); + return ret; + } + + nl_wait_for_ack(session->sock); + + if (session->cb_result == CB_ERROR) + return -1; + + return 0; +} + +int lunatikS_create(struct lunatik_session *session, struct lunatik_state *cmd) +{ + struct nl_msg *msg; + int ret = -1; + + if ((msg = prepare_message(session, CREATE_STATE, 0)) == NULL) + return ret; + + NLA_PUT_STRING(msg, STATE_NAME, cmd->name); + NLA_PUT_U32(msg, MAX_ALLOC, cmd->maxalloc); + + if ((ret = nl_send_auto(session->sock, msg)) < 0) { + printf("Failed to send message to kernel\n %s\n", nl_geterror(ret)); + return ret; + } + + return receive_op_result(session); + +nla_put_failure: + printf("Failed to put attributes on message\n"); + return ret; +} + +int lunatikS_destroy(struct lunatik_session *session, const char *name) +{ + struct nl_msg *msg; + int ret = -1; + + if ((msg = prepare_message(session, DESTROY_STATE, 0)) == NULL) + return ret; + + NLA_PUT_STRING(msg, STATE_NAME, name); + + if ((ret = nl_send_auto(session->sock, msg)) < 0) { + printf("Failed to send destroy message:\n %s\n", nl_geterror(ret)); + return ret; + } + + return receive_op_result(session); + +nla_put_failure: + printf("Failed to put attributes on netlink message\n"); + return ret; +} + +int lunatikS_dostring(struct lunatik_session *session, const char *state_name, + const char *script, const char *script_name, size_t total_code_size) +{ + int err = -1; + int parts = 0; + + if (total_code_size <= LUNATIK_FRAGMENT_SIZE) { + err = send_fragment(session, script, 0, state_name, script_name, LUNATIK_INIT | LUNATIK_DONE); + if (err) + return err; + } else { + parts = (total_code_size % LUNATIK_FRAGMENT_SIZE == 0) ? + total_code_size / LUNATIK_FRAGMENT_SIZE : + (total_code_size / LUNATIK_FRAGMENT_SIZE) + 1; + + for (int i = 0; i < parts - 1; i++) { + if (i == 0) + err = send_fragment(session, script, i, state_name, script_name, LUNATIK_INIT | LUNATIK_MULTI); + else + err = send_fragment(session, script, i, state_name, script_name, LUNATIK_MULTI); + + nl_wait_for_ack(session->sock); + + if (err) + return err; + } + + err = send_fragment(session, script, parts - 1, state_name, script_name, LUNATIK_DONE); + if (err) + return err; + } + + return receive_op_result(session); +} + +int lunatikS_list(struct lunatik_session *session) +{ + int err = -1; + + if ((err = send_simple_msg(session, LIST_STATES, LUNATIK_INIT))) + return err; + + nl_recvmsgs_default(session->sock); + nl_wait_for_ack(session->sock); + + session->status = SESSION_RECEIVING; + + while (session->status == SESSION_RECEIVING) { + send_simple_msg(session, LIST_STATES, 0); + nl_recvmsgs_default(session->sock); + nl_wait_for_ack(session->sock); + } + + return 0; +} + +static int add_state_on_list(struct lunatik_state state, struct states_list *list) +{ + if (list->tail == list->list_size) { + printf("Trying to add elements to the list out of bounds\n"); + return -1; + } else { + list->states[list->tail++] = state; + } + + return 0; +} + +static int init_list(struct states_list *list, int size) +{ + if ((list->states = malloc(size * sizeof(struct lunatik_state))) == NULL) { + printf("Failed to allocate memory to the list\n"); + return -1; + } + + list->list_size = size; + list->tail = 0; + + return 0; +} + +static int response_handler(struct nl_msg *msg, void *arg) +{ + struct nlmsghdr *nh = nlmsg_hdr(msg); + struct genlmsghdr *gnlh = genlmsg_hdr(nh); + struct lunatik_session *session = (struct lunatik_session *) arg; + struct nlattr * attrs_tb[ATTRS_COUNT + 1]; + struct lunatik_state state; + int list_size; + + if (nla_parse(attrs_tb, ATTRS_COUNT, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL)) + { + printf("Error parsing attributes\n"); + session->cb_result = CB_ERROR; + return NL_OK; + } + switch (gnlh->cmd) + { + case CREATE_STATE: + case DESTROY_STATE: + case EXECUTE_CODE: + if (attrs_tb[OP_SUCESS] && nla_get_u8(attrs_tb[OP_SUCESS])) { + session->cb_result = CB_SUCCESS; + } else if (attrs_tb[OP_ERROR] && nla_get_u8(attrs_tb[OP_ERROR])) { + session->cb_result = CB_ERROR; + } + break; + case LIST_STATES: + if (attrs_tb[FLAGS] && (nla_get_u8(attrs_tb[FLAGS]) & LUNATIK_INIT) && attrs_tb[STATES_COUNT]){ + session->status = SESSION_INIT_LIST; + list_size = nla_get_u32(attrs_tb[STATES_COUNT]); + init_list(&session->states_list, list_size); + } else if (attrs_tb[FLAGS] && (nla_get_u8(attrs_tb[FLAGS]) & LUNATIK_DONE)) { + session->status = SESSION_FREE; + } else { + session->status = SESSION_RECEIVING; + if (!(attrs_tb[STATE_NAME] && attrs_tb[MAX_ALLOC] && attrs_tb[CURR_ALLOC])) + goto nla_get_failure; + + strncpy(state.name, nla_get_string(attrs_tb[STATE_NAME]), LUNATIK_NAME_MAXSIZE); + state.maxalloc = nla_get_u32(attrs_tb[MAX_ALLOC]); + state.curralloc = nla_get_u32(attrs_tb[CURR_ALLOC]); + add_state_on_list(state, &session->states_list); + } + break; + default: + break; + } + + return NL_OK; + +nla_get_failure: + printf("Failed to get attributes\n"); + return NL_OK; +} + +int lunatikS_init(struct lunatik_session *session) +{ + int err = -1; + + if (session == NULL) + return -EINVAL; + + if ((session->sock = nl_socket_alloc()) == NULL) + return err; + + if ((err = genl_connect(session->sock))) + return err; + + if ((session->family = genl_ctrl_resolve(session->sock, LUNATIK_FAMILY)) < 0) + return err; + + nl_socket_modify_cb(session->sock, NL_CB_MSG_IN, NL_CB_CUSTOM, response_handler, session); + session->fd = nl_socket_get_fd(session->sock); + + return 0; +} + +void lunatikS_end(struct lunatik_session *session) +{ + if (session != NULL){ + nl_socket_free(session->sock); + session->fd = -1; + } +} diff --git a/lib/lunatik.h b/lib/lunatik.h index c4e4e2061..3e22be107 100644 --- a/lib/lunatik.h +++ b/lib/lunatik.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 2020 Matheus Rodrigues * Copyright (C) 2017-2019 CUJO LLC * * This program is free software; you can redistribute it and/or modify @@ -16,37 +17,50 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef NFLUA_H -#define NFLUA_H +#ifndef LUNATIK_H +#define LUNATIK_H #include #include -#include - -enum nflua_control_state { - NFLUA_LINK_READY, - NFLUA_SENDING_REQUEST, - NFLUA_PENDING_REPLY, - NFLUA_RECEIVING_REPLY, - NFLUA_PROTOCOL_OUTOFSYNC, - NFLUA_SOCKET_CLOSED, +#include +#include "../netlink_common.h" +#include "../lunatik_conf.h" + +enum callback_result { + CB_SUCCESS, + CB_ERROR, +}; + +enum session_status { + SESSION_FREE, + SESSION_RECEIVING, + SESSION_INIT_LIST, }; -struct nflua_response { - uint32_t type; - uint32_t count; - uint32_t total_size; +struct lunatik_state { + struct lunatik_session *session; + uint32_t maxalloc; + uint32_t curralloc; + char name[LUNATIK_NAME_MAXSIZE]; }; -struct nflua_control { +struct states_list { + struct lunatik_state *states; + size_t list_size; + unsigned int tail; +}; + +struct lunatik_session { + struct nl_sock *sock; + struct states_list states_list; + enum session_status status; + enum callback_result cb_result; + int family; int fd; uint32_t pid; - uint32_t seqnum; - int currfrag; - enum nflua_control_state state; - uint8_t buffer[NFLUA_PAYLOAD_MAXSIZE]; }; +#ifndef _UNUSED struct nflua_data { int fd; uint32_t pid; @@ -54,40 +68,32 @@ struct nflua_data { char state[NFLUA_NAME_MAXSIZE]; char buffer[NFLUA_PAYLOAD_MAXSIZE]; }; +#endif /* _UNUSED */ -static inline int nflua_control_getsock(const struct nflua_control *ctrl) +static inline int lunatikS_getfd(const struct lunatik_session *session) { - return ctrl->fd; + return session->fd; } -static inline int nflua_control_getstate(const struct nflua_control *ctrl) +static inline int lunatikS_isopen(const struct lunatik_session *session) { - return ctrl->state; + return session->fd >= 0; } -static inline int nflua_control_getpid(const struct nflua_control *ctrl) -{ - return ctrl->pid; -} - -static inline int nflua_control_is_open(const struct nflua_control *ctrl) -{ - return ctrl->fd >= 0; -} - -int nflua_control_init(struct nflua_control *ctrl, uint32_t pid); +int lunatikS_init(struct lunatik_session *session); -void nflua_control_close(struct nflua_control *ctrl); +void lunatikS_end(struct lunatik_session *session); -int nflua_control_create(struct nflua_control *ctrl, struct nflua_nl_state *); +int lunatikS_create(struct lunatik_session *session, struct lunatik_state *s); -int nflua_control_destroy(struct nflua_control *ctrl, const char *name); +int lunatikS_destroy(struct lunatik_session *session, const char *name); -int nflua_control_execute(struct nflua_control *ctrl, const char *name, - const char *scriptname, const char *payload, size_t total); +int lunatikS_dostring(struct lunatik_session *session, const char *state_name, + const char *script, const char *script_name, size_t total_code_size); -int nflua_control_list(struct nflua_control *ctrl); +int lunatikS_list(struct lunatik_session *session); +#ifndef _UNUSED int nflua_control_receive(struct nflua_control *ctrl, struct nflua_response *nr, char *buffer); @@ -114,5 +120,5 @@ int nflua_data_send(struct nflua_data *dch, const char *name, const char *payload, size_t len); int nflua_data_receive(struct nflua_data *dch, char *state, char *buffer); - -#endif /* NFLUA_H */ +#endif /* _UNUSED */ +#endif /* LUNATIK_H */ diff --git a/lib/lunatik_module.c b/lib/lunatik_module.c index 21c50fa1d..0c4dfb40d 100644 --- a/lib/lunatik_module.c +++ b/lib/lunatik_module.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2020 Matheus Rodrigues * Copyright (C) 2017-2019 CUJO LLC * * This program is free software; you can redistribute it and/or modify @@ -22,19 +23,15 @@ #include #include -#include #include -#include -extern int luaopen_memory(lua_State *L); +#include "lunatik.h" -#define DEFAULT_MAXALLOC_BYTES (32 * 1024) +#ifndef _UNUSED +extern int luaopen_memory(lua_State *L); +#endif /*_UNUSED*/ -struct control { - struct nflua_control ctrl; - struct nflua_response response; - char buffer[NFLUA_LIST_MAXSIZE]; -}; +#define DEFAULT_MAXALLOC_BYTES (32 * 1024) static int pusherrmsg(lua_State *L, const char *msg) { @@ -50,6 +47,7 @@ static int pusherrno(lua_State *L, int err) return r + 1; } +#ifndef _UNUSED static int pushioresult(lua_State *L, int code) { if (code >= 0) { @@ -58,6 +56,7 @@ static int pushioresult(lua_State *L, int code) } return pusherrno(L, code); } +#endif static void newclass(lua_State *L, const char *name, const luaL_Reg mt[]) @@ -69,145 +68,152 @@ static void newclass(lua_State *L, const char *name, lua_pop(L, 1); } -static uint32_t generatepid(lua_State *L, int arg) -{ - const uint32_t mask = 1 << 31; - - switch (lua_type(L, 1)) { - case LUA_TNUMBER: { - uint32_t pid = lua_tointeger(L, arg); - if (pid & mask) - luaL_argerror(L, arg, "must be in range [0, 2^31)"); - return pid; - } - case LUA_TNIL: - case LUA_TNONE: { - static uint16_t globaln = 0; - uint32_t n = __sync_fetch_and_add(&globaln, 1); - return (n << 16) | (getpid() & 0xFFFF) | mask; - } - default: - luaL_argerror(L, arg, "must be integer or nil"); - } - - return 0; -} - -static int lcontrol_open(lua_State *L) +static int lsession_open(lua_State *L) { int ret; - uint32_t pid = generatepid(L, 1); - struct control *c = lua_newuserdata(L, sizeof(struct control)); + struct lunatik_session *session = lua_newuserdata(L, sizeof(struct lunatik_session)); - luaL_setmetatable(L, "nflua.control"); - ret = nflua_control_init(&c->ctrl, pid); + luaL_setmetatable(L, "lunatik.session"); + ret = lunatikS_init(session); return ret < 0 ? pusherrno(L, ret) : 1; } -static int lcontrol_gc(lua_State *L) +static int lsession_gc(lua_State *L) { - struct control *c = luaL_checkudata(L, 1, "nflua.control"); - if (nflua_control_is_open(&c->ctrl)) nflua_control_close(&c->ctrl); + struct lunatik_session *session = luaL_checkudata(L, 1, "lunatik.session"); + if (lunatikS_isopen(session)) lunatikS_end(session); return 0; } -static struct control *getcontrol(lua_State *L) +static struct lunatik_session *getsession(lua_State *L) { - struct control *c = luaL_checkudata(L, 1, "nflua.control"); - if (!nflua_control_is_open(&c->ctrl)) + struct lunatik_session *c = luaL_checkudata(L, 1, "lunatik.session"); + if (!lunatikS_isopen(c)) luaL_argerror(L, 1, "socket closed"); return c; } -static int lcontrol_close(lua_State *L) -{ - struct control *c = getcontrol(L); - nflua_control_close(&c->ctrl); - lua_pushboolean(L, true); - return 1; -} - -static int lcontrol_getfd(lua_State *L) +static struct lunatik_state *getnlstate(lua_State *L) { - struct control *c = getcontrol(L); - lua_pushinteger(L, nflua_control_getsock(&c->ctrl)); - return 1; + struct lunatik_state *s = luaL_checkudata(L, 1, "states.control"); + if (s == NULL) + luaL_argerror(L, 1, "Failed to get state"); + return s; } -static int lcontrol_getpid(lua_State *L) +static int lsession_end(lua_State *L) { - struct control *c = getcontrol(L); - lua_pushinteger(L, nflua_control_getpid(&c->ctrl)); + struct lunatik_session *session = getsession(L); + lunatikS_end(session); + lua_pushboolean(L, true); return 1; } -static int lcontrol_getstate(lua_State *L) +static int lsession_getfd(lua_State *L) { - static const char *tostr[] = { - [NFLUA_LINK_READY] = "ready", - [NFLUA_SENDING_REQUEST] = "sending", - [NFLUA_PENDING_REPLY] = "waiting", - [NFLUA_RECEIVING_REPLY] = "receiving", - [NFLUA_PROTOCOL_OUTOFSYNC] = "failed", - [NFLUA_SOCKET_CLOSED] = "closed" - }; - struct control *c = getcontrol(L); - int state = nflua_control_getstate(&c->ctrl); - - if (state < NFLUA_LINK_READY || state > NFLUA_SOCKET_CLOSED) - return pusherrmsg(L, "unknown state"); - - lua_pushstring(L, tostr[state]); - + struct lunatik_session *session = getsession(L); + lua_pushinteger(L, lunatikS_getfd(session)); return 1; } -static int lcontrol_create(lua_State *L) +static int lsession_create(lua_State *L) { - struct control *c = getcontrol(L); + struct lunatik_session *session = getsession(L); size_t len; const char *name = luaL_checklstring(L, 2, &len); lua_Integer maxalloc = luaL_optinteger(L, 3, DEFAULT_MAXALLOC_BYTES); - struct nflua_nl_state state; + struct lunatik_state *state = lua_newuserdata(L, sizeof(struct lunatik_state)); - if (len >= NFLUA_NAME_MAXSIZE) + if (len >= LUNATIK_NAME_MAXSIZE) luaL_argerror(L, 2, "name too long"); - strcpy(state.name, name); - state.maxalloc = maxalloc; + strcpy(state->name, name); + state->maxalloc = maxalloc; + state->session = session; - return pushioresult(L, nflua_control_create(&c->ctrl, &state)); + if (lunatikS_create(session, state)) { + pusherrmsg(L, "Failed to create the state\n"); + return 2; + } + + luaL_setmetatable(L, "states.control"); + + return 1; } -static int lcontrol_destroy(lua_State *L) +static int lstate_close(lua_State *L) { - struct control *c = getcontrol(L); - const char *name = luaL_checkstring(L, 2); - return pushioresult(L, nflua_control_destroy(&c->ctrl, name)); + struct lunatik_state *s = getnlstate(L); + if (lunatikS_destroy(s->session, s->name)){ + lua_pushboolean(L, false); + return 1; + } + + lua_pushboolean(L, true); + return 1; } -static int lcontrol_execute(lua_State *L) +static int lstate_dostring(lua_State *L) { - struct control *c = getcontrol(L); - const char *name = luaL_checkstring(L, 2); + struct lunatik_state *s = getnlstate(L); + struct lunatik_session *session = s->session; + const char *name = s->name; size_t len; - const char *payload = luaL_checklstring(L, 3, &len); - const char *scriptname = luaL_optstring(L, 4, payload); - int status = nflua_control_execute(&c->ctrl, name, scriptname, - payload, len); + const char *payload = luaL_checklstring(L, 2, &len); + const char *script_name = luaL_optstring(L, 3, "Lunatik"); + + if (strlen(script_name) > LUNATIK_SCRIPTNAME_MAXSIZE) { + printf("script name too long\n"); + goto error; + } + int status = lunatikS_dostring(session, name, payload, script_name, len); + + if (status) + goto error; + + lua_pushnil(L); + return 1; + +error: + lua_pushboolean(L, true); + return 1; +} + +static int lstate_getname(lua_State *L) { + struct lunatik_state *s = getnlstate(L); + lua_pushstring(L, s->name); + return 1; +} - if (status > 0) return pusherrmsg(L, "pending"); - return pushioresult(L, status); +static int lstate_getmaxalloc(lua_State *L) { + struct lunatik_state *s = getnlstate(L); + lua_pushinteger(L, s->maxalloc); + return 1; } -static int lcontrol_list(lua_State *L) +static void buildlist(lua_State *L, struct lunatik_state *states, size_t n); + +static int lsession_list(lua_State *L) { - struct control *c = getcontrol(L); - return pushioresult(L, nflua_control_list(&c->ctrl)); + struct lunatik_session *session = getsession(L); + struct states_list list; + int status; + + status = lunatikS_list(session); + if (status){ + lua_pushnil(L); + return 1; + } + + list = session->states_list; + buildlist(L, list.states, list.list_size); + free(list.states); + + return 1; } -static void buildlist(lua_State *L, struct nflua_nl_state *states, size_t n) +static void buildlist(lua_State *L, struct lunatik_state *states, size_t n) { size_t i; @@ -223,35 +229,8 @@ static void buildlist(lua_State *L, struct nflua_nl_state *states, size_t n) lua_seti(L, -2, i + 1); } } - -static int lcontrol_receive(lua_State *L) -{ - struct control *c = getcontrol(L); - int status = nflua_control_receive(&c->ctrl, &c->response, c->buffer); - - if (status < 0) return pusherrno(L, status); - if (status > 0) return pusherrmsg(L, "pending"); - - switch (c->response.type) { - case NLMSG_ERROR: - return pusherrmsg(L, "operation could not be completed"); - case NFLMSG_CREATE: - case NFLMSG_EXECUTE: - case NFLMSG_DESTROY: - lua_pushboolean(L, true); - return 1; - case NFLMSG_LIST: - buildlist(L, (struct nflua_nl_state *)c->buffer, - c->response.count); - return 1; - default: - return pusherrmsg(L, "unknown response"); - } - - return 0; -} - -static int ldata_open(lua_State *L) +#ifndef _UNUSED +static int ldata_open(lua_State *L) { int ret; uint32_t pid = generatepid(L, 1); @@ -333,21 +312,26 @@ static int ldata_receive(lua_State *L) return 2; } +#endif /* _UNUSED */ + +static const luaL_Reg session_mt[] = { + {"down", lsession_end}, + {"getfd", lsession_getfd}, + {"new", lsession_create}, + {"list", lsession_list}, + {"__gc", lsession_gc}, + {NULL, NULL} +}; -static const luaL_Reg control_mt[] = { - {"close", lcontrol_close}, - {"getfd", lcontrol_getfd}, - {"getpid", lcontrol_getpid}, - {"getstate", lcontrol_getstate}, - {"create", lcontrol_create}, - {"destroy", lcontrol_destroy}, - {"execute", lcontrol_execute}, - {"list", lcontrol_list}, - {"receive", lcontrol_receive}, - {"__gc", lcontrol_gc}, +static const luaL_Reg state_mt[] = { + {"dostring", lstate_dostring}, + {"getname", lstate_getname}, + {"getmaxalloc", lstate_getmaxalloc}, + {"close", lstate_close}, {NULL, NULL} }; +#ifndef _UNUSED static const luaL_Reg data_mt[] = { {"close", ldata_close}, {"getfd", ldata_getfd}, @@ -357,34 +341,46 @@ static const luaL_Reg data_mt[] = { {"__gc", ldata_gc}, {NULL, NULL} }; +#endif /*_UNUSED*/ -static const luaL_Reg nflua_lib[] = { - {"control", lcontrol_open}, +static const luaL_Reg lunatik_lib[] = { + {"session", lsession_open}, + #ifndef _UNUSED {"data", ldata_open}, + #endif /*_UNUSED*/ {NULL, NULL} }; +#ifndef _UNUSED static void setconst(lua_State *L, const char *name, lua_Integer value) { lua_pushinteger(L, value); lua_setfield(L, -2, name); } +#endif -int luaopen_nflua(lua_State *L) +int luaopen_lunatik(lua_State *L) { + #ifndef _UNUSED luaL_requiref(L, "memory", luaopen_memory, 1); lua_pop(L, 1); + #endif /*_UNUSED*/ - newclass(L, "nflua.control", control_mt); + newclass(L, "lunatik.session", session_mt); + newclass(L, "states.control", state_mt); + #ifndef _UNUSED newclass(L, "nflua.data", data_mt); + #endif /*_UNUSED*/ - luaL_newlib(L, nflua_lib); + luaL_newlib(L, lunatik_lib); + #ifndef _UNUSED setconst(L, "datamaxsize", NFLUA_DATA_MAXSIZE); setconst(L, "defaultmaxallocbytes", DEFAULT_MAXALLOC_BYTES); setconst(L, "maxstates", NFLUA_MAX_STATES); setconst(L, "scriptnamemaxsize", NFLUA_SCRIPTNAME_MAXSIZE); setconst(L, "statenamemaxsize", NFLUA_NAME_MAXSIZE); + #endif /*_UNUSED*/ return 1; } diff --git a/luautil.h b/luautil.h index 476318a6c..5cf4fc008 100644 --- a/luautil.h +++ b/luautil.h @@ -77,11 +77,11 @@ static inline int luaU_pusherr(lua_State *L, const char *err) lua_pushstring(L, err); return 2; } +#endif /* _LUA_UTIL_H */ #define luaU_dostring(L, b, s, n) \ (luaL_loadbufferx(L, b, s, n, "t") || luaU_pcall(L, 0, 0)) int luaU_pcall(lua_State *L, int nargs, int nresults); -#endif /* _LUA_UTIL_H */ #endif /* LUNATIK_UNUSED */ diff --git a/lunatik_conf.h b/lunatik_conf.h index 0a0451892..7d3f18251 100644 --- a/lunatik_conf.h +++ b/lunatik_conf.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 2020 Matheus Rodrigues * Copyright (C) 2017-2019 CUJO LLC * * This program is free software; you can redistribute it and/or modify @@ -16,15 +17,15 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef _NFLUA_CONF_H -#define _NFLUA_CONF_H +#ifndef LUNATIK_CONF_H +#define LUNATIK_CONF_H -#ifndef NETLINK_NFLUA -#define NETLINK_NFLUA 31 /* NFLua netlink protocol family */ -#endif /* NETLINK_NFLUA */ +#define LUNATIK_NAME_MAXSIZE 64 /* Max length of Lua state name */ -#define NFLUA_NAME_MAXSIZE 64 /* Max length of Lua state name */ +#define LUNATIK_SCRIPTNAME_MAXSIZE 255 /* Max length of Lua state name */ -#define NFLUA_SCRIPTNAME_MAXSIZE 255 /* Max length of Lua state name */ +#define LUNATIK_MIN_ALLOC_BYTES (32 * 1024UL) -#endif /* _NFLUA_CONF_H */ +#define LUNATIK_HASH_BUCKETS 32 + +#endif /* LUNATIK_CONF_H */ diff --git a/lunatik_core.c b/lunatik_core.c index e67ed1fe0..daa126bd8 100644 --- a/lunatik_core.c +++ b/lunatik_core.c @@ -32,6 +32,7 @@ #include "lua/lualib.h" #include "states.h" +#include "netlink_common.h" EXPORT_SYMBOL(lua_checkstack); EXPORT_SYMBOL(lua_xmove); @@ -181,63 +182,79 @@ EXPORT_SYMBOL(lunatik_netnewstate); EXPORT_SYMBOL(lunatik_netclose); EXPORT_SYMBOL(lunatik_netstatelookup); +struct send_message; +extern struct genl_family lunatik_family; extern void lunatik_statesinit(void); extern void lunatik_closeall(void); extern void state_destroy(lunatik_State *s); static int lunatik_netid __read_mostly; -struct lunatik_session *lunatik_pernet(struct net *net) +struct lunatik_instance *lunatik_pernet(struct net *net) { - return (struct lunatik_session *)net_generic(net,lunatik_netid); + return (struct lunatik_instance *)net_generic(net,lunatik_netid); } -static int __net_init lunatik_sessioninit(struct net *net) +static int __net_init lunatik_instancenew(struct net *net) { - struct lunatik_session *session = lunatik_pernet(net); + struct lunatik_instance *instance = lunatik_pernet(net); - atomic_set(&(session->states_count), 0); - spin_lock_init(&(session->statestable_lock)); - spin_lock_init(&(session->rfcnt_lock)); - hash_init(session->states_table); + atomic_set(&(instance->states_count), 0); + spin_lock_init(&(instance->statestable_lock)); + spin_lock_init(&(instance->rfcnt_lock)); + spin_lock_init(&(instance->sendmessage_lock)); + hash_init(instance->states_table); + instance->reply_buffer = kmalloc(sizeof(struct reply_buffer), GFP_KERNEL); + + if (instance->reply_buffer == NULL) { + pr_err("Failed to allocate memory to reply buffer\n"); + BUG(); + } return 0; } -static void __net_exit lunatik_sessionend(struct net *net) +static void __net_exit lunatik_instanceclose(struct net *net) { - struct lunatik_session *session; + struct lunatik_instance *instance; lunatik_State *s; struct hlist_node *tmp; int bkt; - session = lunatik_pernet(net); + instance = lunatik_pernet(net); - spin_lock_bh(&(session->statestable_lock)); + spin_lock_bh(&(instance->statestable_lock)); - hash_for_each_safe(session->states_table, bkt, tmp, s, node) { + hash_for_each_safe(instance->states_table, bkt, tmp, s, node) { state_destroy(s); } - spin_unlock_bh(&(session->statestable_lock)); + spin_unlock_bh(&(instance->statestable_lock)); + + kfree(instance->reply_buffer); } static struct pernet_operations lunatik_net_ops = { - .init = lunatik_sessioninit, - .exit = lunatik_sessionend, + .init = lunatik_instancenew, + .exit = lunatik_instanceclose, .id = &lunatik_netid, - .size = sizeof(struct lunatik_session), + .size = sizeof(struct lunatik_instance), }; static int __init modinit(void) { - int ret; + int err; lunatik_statesinit(); - if ((ret = register_pernet_subsys(&lunatik_net_ops))) { + if ((err = register_pernet_subsys(&lunatik_net_ops))) { pr_err("Failed to register pernet operations\n"); - return ret; + return err; + } + + if ((err = genl_register_family(&lunatik_family))) { + pr_err("Failed to register generic netlink family\n"); + return err; } return 0; @@ -247,6 +264,7 @@ static void __exit modexit(void) { lunatik_closeall(); unregister_pernet_subsys(&lunatik_net_ops); + genl_unregister_family(&lunatik_family); } module_init(modinit); diff --git a/netlink.c b/netlink.c index 6e991dea3..e8b792e41 100644 --- a/netlink.c +++ b/netlink.c @@ -31,20 +31,23 @@ #include "states.h" #include "netlink_common.h" -extern struct lunatik_session *lunatik_pernet(struct net *net); +extern struct lunatik_instance *lunatik_pernet(struct net *net); static int lunatikN_newstate(struct sk_buff *buff, struct genl_info *info); -static int lunatikN_exec(struct sk_buff *buff, struct genl_info *info); +static int lunatikN_dostring(struct sk_buff *buff, struct genl_info *info); static int lunatikN_close(struct sk_buff *buff, struct genl_info *info); static int lunatikN_list(struct sk_buff *buff, struct genl_info *info); struct nla_policy lunatik_policy[ATTRS_COUNT] = { [STATE_NAME] = { .type = NLA_STRING }, [CODE] = { .type = NLA_STRING }, + [SCRIPT_NAME] = { .type = NLA_STRING}, [MAX_ALLOC] = { .type = NLA_U32 }, - [SCRIPT_SIZE] = { .type = NLA_U32 }, //TODO See what is the maximum script size accepted by the module + [SCRIPT_SIZE] = { .type = NLA_U32 }, [STATES_COUNT]= { .type = NLA_U32}, [FLAGS] = { .type = NLA_U8 }, + [OP_SUCESS] = { .type = NLA_U8 }, + [OP_ERROR] = { .type = NLA_U8}, }; static const struct genl_ops l_ops[] = { @@ -58,7 +61,7 @@ static const struct genl_ops l_ops[] = { }, { .cmd = EXECUTE_CODE, - .doit = lunatikN_exec, + .doit = lunatikN_dostring, #if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) /*Before kernel 5.2.0, each operation has its own policy*/ .policy = lunatik_policy @@ -86,7 +89,7 @@ struct genl_family lunatik_family = { .name = LUNATIK_FAMILY, .version = LUNATIK_NLVERSION, .maxattr = ATTRS_MAX, - .netnsok = true, /*Make this family visible for all namespaces*/ + .netnsok = true, #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0) .policy = lunatik_policy, #endif @@ -95,56 +98,212 @@ struct genl_family lunatik_family = { .n_ops = ARRAY_SIZE(l_ops), }; +static int fill_reply_buffer(struct reply_buffer *message, struct lunatik_instance *instance) +{ + struct lunatik_state *state; + int bucket; + int states_count = atomic_read(&(instance->states_count)); + int counter = 0; + + message->states_list = kmalloc(states_count * sizeof(lunatik_State), GFP_KERNEL); + + if (message->states_list == NULL) { + pr_err("Failed to allocate memory to hold states list\n"); + return -ENOMEM; + } + + message->list_size = states_count; + message->curr_pos_to_send = 0; + hash_for_each_rcu(instance->states_table, bucket, state, node) { + message->states_list[counter] = *(state); + counter++; + } + + return 0; +} + +static int send_done_msg(int command, struct genl_info *info) +{ + void *msg_head; + struct sk_buff *obuff; + int err = -1; + + if ((obuff = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL)) == NULL) { + pr_err("Failed allocating message to an reply\n"); + return -ENOMEM; + } + + if ((msg_head = genlmsg_put_reply(obuff, info, &lunatik_family, 0, command)) == NULL) { + pr_err("Failed to put generic netlink header\n"); + return err; + } + + nla_put_u8(obuff, FLAGS, LUNATIK_DONE); + + genlmsg_end(obuff, msg_head); + + if (genlmsg_reply(obuff, info) < 0) { + pr_err("Failed to send message to user space\n"); + return err; + } + + return 0; +} + +static int send_states_count(struct lunatik_instance *instance, struct genl_info *info) +{ + void *msg_head; + struct sk_buff *obuff; + int err = -1; + + if ((obuff = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL)) == NULL) { + pr_err("Failed allocating message to an reply\n"); + return -ENOMEM; + } + + if ((msg_head = genlmsg_put_reply(obuff, info, &lunatik_family, 0, LIST_STATES)) == NULL) { + pr_err("Failed to put generic netlink header\n"); + return err; + } + + nla_put_u8(obuff, FLAGS, LUNATIK_INIT); + nla_put_u32(obuff, STATES_COUNT, atomic_read(&instance->states_count)); + + genlmsg_end(obuff, msg_head); + + if (genlmsg_reply(obuff, info) < 0) { + pr_err("Failed to send message to user space\n"); + return err; + } + + return 0; +} + +static int send_state(lunatik_State *state, struct genl_info *info) +{ + struct sk_buff *obuff; + void *msg_head; + int err = -1; + + if ((obuff = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL)) == NULL) { + pr_err("Failed allocating message to an reply\n"); + return err; + } + + if ((msg_head = genlmsg_put_reply(obuff, info, &lunatik_family, 0, LIST_STATES)) == NULL) { + pr_err("Failed to put generic netlink header\n"); + return err; + } + + if (nla_put_string(obuff, STATE_NAME, state->name) || + nla_put_u32(obuff, MAX_ALLOC, state->maxalloc) || + nla_put_u32(obuff, CURR_ALLOC, state->curralloc) + ) { + pr_err("Failed to put attributes on socket buffer\n"); + return err; + } + + genlmsg_end(obuff, msg_head); + + if (genlmsg_reply(obuff, info) < 0) { + pr_err("Failed to send message to user space\n"); + return err; + } + + pr_debug("Message sent to user space\n"); + + return 0; +} + +static void reply_with(int reply, int command, struct genl_info *info) +{ + struct sk_buff *obuff; + void *msg_head; + + if ((obuff = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL)) == NULL) { + pr_err("Failed allocating message to an reply\n"); + return; + } + + if ((msg_head = genlmsg_put_reply(obuff, info, &lunatik_family, 0, command)) == NULL) { + pr_err("Failed to put generic netlink header\n"); + return; + } + + if (nla_put_u8(obuff, reply, 1)) { + pr_err("Failed to put attributes on socket buffer\n"); + return; + } + + genlmsg_end(obuff, msg_head); + + if (genlmsg_reply(obuff, info) < 0) { + pr_err("Failed to send message to user space\n"); + return; + } + + pr_debug("Message sent to user space\n"); +} + static int lunatikN_newstate(struct sk_buff *buff, struct genl_info *info) { - struct lunatik_session *session; + struct lunatik_instance *instance; + struct lunatik_state *s; char *state_name; u32 *max_alloc; u32 pid; pr_debug("Received a CREATE_STATE message\n"); - - session = lunatik_pernet(genl_info_net(info)); + + instance = lunatik_pernet(genl_info_net(info)); state_name = (char *)nla_data(info->attrs[STATE_NAME]); max_alloc = (u32 *)nla_data(info->attrs[MAX_ALLOC]); pid = info->snd_portid; - lunatik_newstate(session, *max_alloc, state_name); + s = lunatik_netnewstate(instance, *max_alloc, state_name); + + s == NULL ? reply_with(OP_ERROR, CREATE_STATE, info) : reply_with(OP_SUCESS, CREATE_STATE, info); return 0; } -static int lunatikN_exec(struct sk_buff *buff, struct genl_info *info) +static int lunatikN_dostring(struct sk_buff *buff, struct genl_info *info) { struct lunatik_state *s; - struct lunatik_session *session; + struct lunatik_instance *instance; const char *finalscript; + const char *script_name; + int err; char *fragment; char *state_name; u8 flags; pr_debug("Received a EXECUTE_CODE message\n"); - session = lunatik_pernet(genl_info_net(info)); + instance = lunatik_pernet(genl_info_net(info)); state_name = (char *)nla_data(info->attrs[STATE_NAME]); fragment = (char *)nla_data(info->attrs[CODE]); flags = *((u8*)nla_data(info->attrs[FLAGS])); - if ((s = lunatik_netstatelookup(session, state_name)) == NULL) { + if ((s = lunatik_netstatelookup(instance, state_name)) == NULL) { pr_err("Error finding klua state\n"); + reply_with(OP_ERROR, EXECUTE_CODE, info); return 0; } if (flags & LUNATIK_INIT) { - s->curr_script_size = *((u32*)nla_data(info->attrs[SCRIPT_SIZE])); - + s->scriptsize = *((u32*)nla_data(info->attrs[SCRIPT_SIZE])); + + /*TODO Discover why this lock when disable bh is causing a kernel panic related to skb release + */ + spin_lock(&s->lock); if ((s->buffer = kmalloc(sizeof(luaL_Buffer), GFP_KERNEL)) == NULL) { pr_err("Failed allocating memory to code buffer\n"); + reply_with(OP_ERROR, EXECUTE_CODE, info); return 0; } - spin_lock_bh(&s->lock); - luaL_buffinit(s->L, s->buffer); - } // TODO Otherwise, reply with a "busy state" + luaL_buffinit(s->L, s->buffer); + } if (flags & LUNATIK_MULTI) { luaL_addlstring(s->buffer, fragment, LUNATIK_FRAGMENT_SIZE); @@ -155,18 +314,22 @@ static int lunatikN_exec(struct sk_buff *buff, struct genl_info *info) luaL_pushresult(s->buffer); finalscript = lua_tostring(s->L, -1); + script_name = nla_data(info->attrs[SCRIPT_NAME]); - if (!lunatik_state_get(s)) { + if (!lunatik_stateget(s)) { pr_err("Failed to get state\n"); + reply_with(OP_ERROR, EXECUTE_CODE, info); return 0; } - if (luaU_dostring(s->L, finalscript, s->curr_script_size, "Lua in kernel")) { + if ((err = luaU_dostring(s->L, finalscript, s->scriptsize, script_name))) { pr_err("%s\n", lua_tostring(s->L, -1)); } - spin_unlock_bh(&s->lock); - lunatik_state_put(s); + spin_unlock(&s->lock); + lunatik_stateput(s); + + err ? reply_with(OP_ERROR, EXECUTE_CODE, info) : reply_with(OP_SUCESS, EXECUTE_CODE, info); } return 0; @@ -174,78 +337,55 @@ static int lunatikN_exec(struct sk_buff *buff, struct genl_info *info) static int lunatikN_close(struct sk_buff *buff, struct genl_info *info) { - struct lunatik_session *session; + struct lunatik_instance *instance; char *state_name; - - session = lunatik_pernet(genl_info_net(info)); + + instance = lunatik_pernet(genl_info_net(info)); state_name = (char *)nla_data(info->attrs[STATE_NAME]); - + pr_debug("Received a DESTROY_STATE command\n"); - if (lunatik_close(session, state_name)) { - pr_err("Failed to destroy state %s\n", state_name); - return 0; - } + if (lunatik_netclose(instance, state_name)) + reply_with(OP_ERROR, DESTROY_STATE, info); + else + reply_with(OP_SUCESS, DESTROY_STATE, info); return 0; } static int lunatikN_list(struct sk_buff *buff, struct genl_info *info) { - struct sk_buff *obuff; - struct lunatik_session *session; - struct lunatik_state *state; - void *msg_head; - int bucket; - bool firstmsg = true; - int err = -1; + struct lunatik_instance *instance; + struct reply_buffer *reply; + lunatik_State currstate; + u8 flags; pr_debug("Received a LIST_STATES command\n"); - session = lunatik_pernet(genl_info_net(info)); + instance = lunatik_pernet(genl_info_net(info)); + flags = *((u8 *)nla_data(info->attrs[FLAGS])); + reply = instance->reply_buffer; - hash_for_each_rcu(session->states_table, bucket, state, node) { - if ((obuff = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL)) == NULL) { - pr_err("Failed allocating message to an reply\n"); - return err; - } - - if ((msg_head = genlmsg_put_reply(obuff, info, &lunatik_family, 0, LIST_STATES)) == NULL) { - pr_err("Failed to put generic netlink header\n"); - return err; - } - - if (nla_put_string(obuff, STATE_NAME, state->name) || - nla_put_u32(obuff, MAX_ALLOC, state->maxalloc) || - nla_put_u32(obuff, CURR_ALLOC, state->curralloc) - ) { - pr_err("Failed to put attributes on socket buffer\n"); - return err; - } - - if (firstmsg) { - if (nla_put_u32(obuff, STATES_COUNT, atomic_read(&session->states_count)) || - nla_put_u8(obuff, FLAGS, LUNATIK_INIT) - ) { - pr_err("Failed to put attributes on socket buffer\n"); - return err; - } - firstmsg = false; - - } else if (nla_put_u8(obuff, FLAGS, 0)) { - pr_err("Failed to put attributes on socket buffer\n"); - return err; - } - - genlmsg_end(obuff, msg_head); + if (flags & LUNATIK_INIT) { + spin_lock(&(instance->sendmessage_lock)); + fill_reply_buffer(reply, instance); // TODO Check error and reply if an error occur + send_states_count(instance, info); + goto out; + } - if (genlmsg_reply(obuff, info) < 0) { - pr_err("Failed to send message to user space\n"); - return err; - } + if (reply->curr_pos_to_send == reply->list_size) { + send_done_msg(LIST_STATES, info); + kfree(reply->states_list); + spin_unlock(&(instance->sendmessage_lock)); + goto out; + } - pr_debuf("Message sento to kernel\n"); + currstate = reply->states_list[reply->curr_pos_to_send++]; + if (send_state(&currstate, info)) { + pr_err("Failed to send state information to user space\n"); + return 0; } +out: return 0; } diff --git a/netlink_common.h b/netlink_common.h index e38c84b42..fe4717916 100644 --- a/netlink_common.h +++ b/netlink_common.h @@ -4,6 +4,12 @@ #ifdef _KERNEL extern struct genl_family lunatik_family; #include + +struct reply_buffer { + lunatik_State *states_list; + int list_size; + int curr_pos_to_send; +}; #endif #define LUNATIK_FRAGMENT_SIZE (3000) // TODO Find, a size more precise @@ -31,6 +37,9 @@ enum lunatik_attrs { CODE, FLAGS, SCRIPT_SIZE, + SCRIPT_NAME, + OP_SUCESS, + OP_ERROR, ATTRS_COUNT #define ATTRS_MAX (ATTRS_COUNT - 1) }; diff --git a/states.c b/states.c index e9cedf071..824aafef7 100644 --- a/states.c +++ b/states.c @@ -34,7 +34,7 @@ #define LUNATIK_SETPAUSE 100 #endif /* LUNATIK_SETPAUSE */ -static struct lunatik_session session; +static struct lunatik_instance instance; static inline int name_hash(void *salt, const char *name) { @@ -45,9 +45,9 @@ static inline int name_hash(void *salt, const char *name) lunatik_State *lunatik_statelookup(const char *name) { lunatik_State *state; - int key = name_hash(&session, name); + int key = name_hash(&instance, name); - hash_for_each_possible_rcu(session.states_table, state, node, key) { + hash_for_each_possible_rcu(instance.states_table, state, node, key) { if (!strncmp(state->name, name, LUNATIK_NAME_MAXSIZE)) return state; } @@ -57,7 +57,7 @@ lunatik_State *lunatik_statelookup(const char *name) void state_destroy(lunatik_State *s) { hash_del_rcu(&s->node); - atomic_dec(&(session.states_count)); + atomic_dec(&(instance.states_count)); spin_lock_bh(&s->lock); if (s->L != NULL) { @@ -131,7 +131,7 @@ lunatik_State *lunatik_newstate(size_t maxalloc, const char *name) return NULL; } - if (atomic_read(&(session.states_count)) >= LUNATIK_HASH_BUCKETS) { + if (atomic_read(&(instance.states_count)) >= LUNATIK_HASH_BUCKETS) { pr_err("could not allocate id for state %.*s\n", namelen, name); pr_err("max states limit reached or out of memory\n"); return NULL; @@ -162,11 +162,11 @@ lunatik_State *lunatik_newstate(size_t maxalloc, const char *name) return NULL; } - spin_lock_bh(&(session.statestable_lock)); - hash_add_rcu(session.states_table, &(s->node), name_hash(&session, name)); + spin_lock_bh(&(instance.statestable_lock)); + hash_add_rcu(instance.states_table, &(s->node), name_hash(&instance, name)); refcount_inc(&s->users); - atomic_inc(&(session.states_count)); - spin_unlock_bh(&(session.statestable_lock)); + atomic_inc(&(instance.states_count)); + spin_unlock_bh(&(instance.statestable_lock)); pr_debug("new state created: %.*s\n", namelen, name); return s; @@ -179,9 +179,9 @@ int lunatik_close(const char *name) if (s == NULL || refcount_read(&s->users) > 1) return -1; - spin_lock_bh(&(session.statestable_lock)); + spin_lock_bh(&(instance.statestable_lock)); state_destroy(s); - spin_unlock_bh(&(session.statestable_lock)); + spin_unlock_bh(&(instance.statestable_lock)); return 0; } @@ -218,11 +218,11 @@ void lunatik_closeall(void) lunatik_State *s; int bkt; - spin_lock_bh(&(session.statestable_lock)); - hash_for_each_safe (session.states_table, bkt, tmp, s, node) { + spin_lock_bh(&(instance.statestable_lock)); + hash_for_each_safe (instance.states_table, bkt, tmp, s, node) { state_destroy(s); } - spin_unlock_bh(&(session.statestable_lock)); + spin_unlock_bh(&(instance.statestable_lock)); } inline bool lunatik_stateget(lunatik_State *s) @@ -233,7 +233,7 @@ inline bool lunatik_stateget(lunatik_State *s) void lunatik_stateput(lunatik_State *s) { refcount_t *users = &s->users; - spinlock_t *refcnt_lock = &(session.rfcnt_lock); + spinlock_t *refcnt_lock = &(instance.rfcnt_lock); if (WARN_ON(s == NULL)) return; @@ -252,33 +252,33 @@ void lunatik_stateput(lunatik_State *s) void lunatik_statesinit(void) { - atomic_set(&(session.states_count), 0); - spin_lock_init(&(session.statestable_lock)); - spin_lock_init(&(session.rfcnt_lock)); - hash_init(session.states_table); + atomic_set(&(instance.states_count), 0); + spin_lock_init(&(instance.statestable_lock)); + spin_lock_init(&(instance.rfcnt_lock)); + hash_init(instance.states_table); } -lunatik_State *lunatik_netstatelookup(struct lunatik_session *session, const char *name) +lunatik_State *lunatik_netstatelookup(struct lunatik_instance *instance, const char *name) { lunatik_State *state; int key; - if (session == NULL) + if (instance == NULL) return NULL; - key = name_hash(session,name); + key = name_hash(instance,name); - hash_for_each_possible_rcu(session->states_table, state, node, key) { + hash_for_each_possible_rcu(instance->states_table, state, node, key) { if (!strncmp(state->name, name, LUNATIK_NAME_MAXSIZE)) return state; } return NULL; } -lunatik_State *lunatik_netnewstate(struct lunatik_session *session, size_t maxalloc, const char *name) +lunatik_State *lunatik_netnewstate(struct lunatik_instance *instance, size_t maxalloc, const char *name) { - lunatik_State *s = lunatik_netstatelookup(session, name); + lunatik_State *s = lunatik_netstatelookup(instance, name); int namelen = strnlen(name, LUNATIK_NAME_MAXSIZE); pr_debug("creating state: %.*s maxalloc: %zd\n", namelen, name, @@ -289,7 +289,7 @@ lunatik_State *lunatik_netnewstate(struct lunatik_session *session, size_t maxal return NULL; } - if (atomic_read(&(session->states_count)) >= LUNATIK_HASH_BUCKETS) { + if (atomic_read(&(instance->states_count)) >= LUNATIK_HASH_BUCKETS) { pr_err("could not allocate id for state %.*s\n", namelen, name); pr_err("max states limit reached or out of memory\n"); return NULL; @@ -317,27 +317,27 @@ lunatik_State *lunatik_netnewstate(struct lunatik_session *session, size_t maxal return NULL; } - spin_lock_bh(&(session->statestable_lock)); - hash_add_rcu(session->states_table, &(s->node), name_hash(session,name)); + spin_lock_bh(&(instance->statestable_lock)); + hash_add_rcu(instance->states_table, &(s->node), name_hash(instance,name)); refcount_inc(&(s->users)); - atomic_inc(&(session->states_count)); - spin_unlock_bh(&(session->statestable_lock)); + atomic_inc(&(instance->states_count)); + spin_unlock_bh(&(instance->statestable_lock)); pr_debug("new state created: %.*s\n", namelen, name); return s; } -int lunatik_netclose(struct lunatik_session *session, const char *name) +int lunatik_netclose(struct lunatik_instance *instance, const char *name) { - lunatik_State *s = lunatik_netstatelookup(session,name); + lunatik_State *s = lunatik_netstatelookup(instance,name); if (s == NULL || refcount_read(&s->users) > 1) return -1; - spin_lock_bh(&(session->statestable_lock)); + spin_lock_bh(&(instance->statestable_lock)); hash_del_rcu(&s->node); - atomic_dec(&(session->states_count)); + atomic_dec(&(instance->states_count)); spin_lock_bh(&s->lock); if (s->L != NULL) { @@ -347,7 +347,7 @@ int lunatik_netclose(struct lunatik_session *session, const char *name) spin_unlock_bh(&s->lock); lunatik_stateput(s); - spin_unlock_bh(&(session->statestable_lock)); + spin_unlock_bh(&(instance->statestable_lock)); return 0; } diff --git a/states.h b/states.h index d552052f6..39cba3a20 100644 --- a/states.h +++ b/states.h @@ -21,25 +21,26 @@ #define LUNATIK_STATES_H #include "lua/lua.h" +#include "lunatik_conf.h" -#define LUNATIK_NAME_MAXSIZE 64 -#define LUNATIK_MIN_ALLOC_BYTES (32 * 1024UL) -#define LUNATIK_HASH_BUCKETS 32 - -struct lunatik_session { +struct lunatik_instance { struct hlist_head states_table[LUNATIK_HASH_BUCKETS]; + struct reply_buffer *reply_buffer; spinlock_t statestable_lock; spinlock_t rfcnt_lock; + spinlock_t sendmessage_lock; atomic_t states_count; }; typedef struct lunatik_state { struct hlist_node node; lua_State *L; + luaL_Buffer *buffer; spinlock_t lock; refcount_t users; size_t maxalloc; size_t curralloc; + size_t scriptsize; unsigned char name[LUNATIK_NAME_MAXSIZE]; } lunatik_State; @@ -59,8 +60,8 @@ int nflua_state_list(struct xt_lua_net *xt_lua, nflua_state_cb cb, bool lunatik_stateget(lunatik_State *s); void lunatik_stateput(lunatik_State *s); -lunatik_State *lunatik_netnewstate(struct lunatik_session *session, size_t maxalloc, const char *name); -int lunatik_netclose(struct lunatik_session *session, const char *name); -lunatik_State *lunatik_netstatelookup(struct lunatik_session *session, const char *name); +lunatik_State *lunatik_netnewstate(struct lunatik_instance *instance, size_t maxalloc, const char *name); +int lunatik_netclose(struct lunatik_instance *instance, const char *name); +lunatik_State *lunatik_netstatelookup(struct lunatik_instance *instance, const char *name); #endif /* LUNATIK_STATES_H */ From 99c40c7036d8495f3522815fa78ac3a4dc03a721 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Sun, 26 Jul 2020 12:19:03 -0300 Subject: [PATCH 08/48] Change list protocol --- lib/lunatik.c | 145 ++++++++++++++++++++++++------- lib/lunatik.h | 14 ++- lib/lunatik_module.c | 29 ++++--- lunatik_core.c | 12 +-- netlink.c | 197 ++++++++++++++++++++++++++----------------- netlink_common.h | 19 ++--- states.h | 3 +- 7 files changed, 270 insertions(+), 149 deletions(-) diff --git a/lib/lunatik.c b/lib/lunatik.c index 503d2068c..bfc6b3c94 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -140,7 +140,7 @@ static int receive_op_result(struct lunatik_session *session){ return 0; } -int lunatikS_create(struct lunatik_session *session, struct lunatik_state *cmd) +int lunatikS_create(struct lunatik_session *session, struct lunatik_nl_state *cmd) { struct nl_msg *msg; int ret = -1; @@ -224,13 +224,14 @@ int lunatikS_list(struct lunatik_session *session) { int err = -1; - if ((err = send_simple_msg(session, LIST_STATES, LUNATIK_INIT))) + if ((err = send_simple_msg(session, LIST_STATES, 0))) return err; nl_recvmsgs_default(session->sock); nl_wait_for_ack(session->sock); - session->status = SESSION_RECEIVING; + if (session->cb_result == CB_ERROR) + return -1; while (session->status == SESSION_RECEIVING) { send_simple_msg(session, LIST_STATES, 0); @@ -241,28 +242,95 @@ int lunatikS_list(struct lunatik_session *session) return 0; } -static int add_state_on_list(struct lunatik_state state, struct states_list *list) +static int parse_states_list(struct lunatik_session *session) +{ + struct lunatik_nl_state *states; + char *ptr; + char *buffer; + int states_cursor = 0; + + buffer = (session->recv_buffer).buffer; + + states = (session->states_list).states; + ptr = strtok(buffer, "#"); + while(ptr != NULL) { + strcpy(states[states_cursor].name, ptr); + ptr = strtok(NULL, "#"); + states[states_cursor].curralloc = atoi(ptr); + ptr = strtok(NULL, "#"); + states[states_cursor].maxalloc = atoi(ptr); + ptr = strtok(NULL, "#"); + states_cursor++; + } + return 0; +} + +static int init_states_list(struct lunatik_session *session, struct nlattr **attrs) { - if (list->tail == list->list_size) { - printf("Trying to add elements to the list out of bounds\n"); + struct states_list *states_list; + int states_count; + + states_list = &session->states_list; + + if (attrs[STATES_COUNT]) { + states_count = nla_get_u32(attrs[STATES_COUNT]); + } else { + printf("Failed to initialize the states list, states count is missing\n"); return -1; + } + + states_list->states = malloc(sizeof(struct lunatik_nl_state) * states_count); + + if (states_list->states == NULL) { + printf("Failed to allocate memory to store states information\n"); + return -ENOMEM; + } + states_list->list_size = states_count; + return 0; +} + +static int init_recv_buffer(struct lunatik_session *session, struct nlattr **attrs) +{ + struct received_buffer *recv_buffer; + int parts; + + recv_buffer = &session->recv_buffer; + + if (attrs[PARTS]) { + parts = nla_get_u32(attrs[PARTS]); } else { - list->states[list->tail++] = state; + printf("Failed to initialize the recv buffer, states count is missing\n"); + return -1; + } + + recv_buffer->buffer = malloc(LUNATIK_FRAGMENT_SIZE * parts); + if (recv_buffer->buffer == NULL) { + printf("Failed to allocate memory to received messages buffer\n"); + return -ENOMEM; } + recv_buffer->cursor = 0; return 0; } -static int init_list(struct states_list *list, int size) +static int append_recv_buffer(struct lunatik_session *session, struct nlattr **attrs) { - if ((list->states = malloc(size * sizeof(struct lunatik_state))) == NULL) { - printf("Failed to allocate memory to the list\n"); + struct received_buffer *recv_buffer; + char *fragment; + + recv_buffer = &session->recv_buffer; + + if (attrs[STATES_LIST]) { + fragment = nla_get_string(attrs[STATES_LIST]); + } else { + printf("Failed to get fragment from states list, attribute is missing\n"); return -1; } - list->list_size = size; - list->tail = 0; + strncpy(recv_buffer->buffer + (LUNATIK_FRAGMENT_SIZE * recv_buffer->cursor), + fragment, LUNATIK_FRAGMENT_SIZE); + recv_buffer->cursor++; return 0; } @@ -272,8 +340,9 @@ static int response_handler(struct nl_msg *msg, void *arg) struct genlmsghdr *gnlh = genlmsg_hdr(nh); struct lunatik_session *session = (struct lunatik_session *) arg; struct nlattr * attrs_tb[ATTRS_COUNT + 1]; - struct lunatik_state state; - int list_size; + uint8_t flags = 0; + int err = 0; + if (nla_parse(attrs_tb, ATTRS_COUNT, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL)) @@ -294,32 +363,44 @@ static int response_handler(struct nl_msg *msg, void *arg) } break; case LIST_STATES: - if (attrs_tb[FLAGS] && (nla_get_u8(attrs_tb[FLAGS]) & LUNATIK_INIT) && attrs_tb[STATES_COUNT]){ - session->status = SESSION_INIT_LIST; - list_size = nla_get_u32(attrs_tb[STATES_COUNT]); - init_list(&session->states_list, list_size); - } else if (attrs_tb[FLAGS] && (nla_get_u8(attrs_tb[FLAGS]) & LUNATIK_DONE)) { - session->status = SESSION_FREE; - } else { + + if (attrs_tb[STATES_LIST_EMPTY]) { + session->states_list.list_size = 0; + session->states_list.states = NULL; + return 0; + } + + if (attrs_tb[FLAGS]) { + flags = nla_get_u8(attrs_tb[FLAGS]); + } + + if (flags & LUNATIK_INIT) { + err = init_states_list(session, attrs_tb); + err = init_recv_buffer(session, attrs_tb); session->status = SESSION_RECEIVING; - if (!(attrs_tb[STATE_NAME] && attrs_tb[MAX_ALLOC] && attrs_tb[CURR_ALLOC])) - goto nla_get_failure; - - strncpy(state.name, nla_get_string(attrs_tb[STATE_NAME]), LUNATIK_NAME_MAXSIZE); - state.maxalloc = nla_get_u32(attrs_tb[MAX_ALLOC]); - state.curralloc = nla_get_u32(attrs_tb[CURR_ALLOC]); - add_state_on_list(state, &session->states_list); } + + if (flags & LUNATIK_DONE) { + err = append_recv_buffer(session, attrs_tb); + err = parse_states_list(session); + session->status = SESSION_FREE; + free(session->recv_buffer.buffer); + session->recv_buffer.cursor = 0; + } + + if (flags & LUNATIK_MULTI) { + err = append_recv_buffer(session, attrs_tb); + } + + if (err) + session->cb_result = OP_ERROR; + break; default: break; } return NL_OK; - -nla_get_failure: - printf("Failed to get attributes\n"); - return NL_OK; } int lunatikS_init(struct lunatik_session *session) diff --git a/lib/lunatik.h b/lib/lunatik.h index 3e22be107..ce0679331 100644 --- a/lib/lunatik.h +++ b/lib/lunatik.h @@ -29,6 +29,7 @@ enum callback_result { CB_SUCCESS, CB_ERROR, + CB_LIST_EMPTY, }; enum session_status { @@ -37,7 +38,7 @@ enum session_status { SESSION_INIT_LIST, }; -struct lunatik_state { +struct lunatik_nl_state { struct lunatik_session *session; uint32_t maxalloc; uint32_t curralloc; @@ -45,14 +46,19 @@ struct lunatik_state { }; struct states_list { - struct lunatik_state *states; + struct lunatik_nl_state *states; size_t list_size; - unsigned int tail; +}; + +struct received_buffer { + char *buffer; + int cursor; }; struct lunatik_session { struct nl_sock *sock; struct states_list states_list; + struct received_buffer recv_buffer; enum session_status status; enum callback_result cb_result; int family; @@ -84,7 +90,7 @@ int lunatikS_init(struct lunatik_session *session); void lunatikS_end(struct lunatik_session *session); -int lunatikS_create(struct lunatik_session *session, struct lunatik_state *s); +int lunatikS_create(struct lunatik_session *session, struct lunatik_nl_state *s); int lunatikS_destroy(struct lunatik_session *session, const char *name); diff --git a/lib/lunatik_module.c b/lib/lunatik_module.c index 0c4dfb40d..b9406200f 100644 --- a/lib/lunatik_module.c +++ b/lib/lunatik_module.c @@ -94,9 +94,9 @@ static struct lunatik_session *getsession(lua_State *L) return c; } -static struct lunatik_state *getnlstate(lua_State *L) +static struct lunatik_nl_state *getnlstate(lua_State *L) { - struct lunatik_state *s = luaL_checkudata(L, 1, "states.control"); + struct lunatik_nl_state *s = luaL_checkudata(L, 1, "states.control"); if (s == NULL) luaL_argerror(L, 1, "Failed to get state"); return s; @@ -123,7 +123,7 @@ static int lsession_create(lua_State *L) size_t len; const char *name = luaL_checklstring(L, 2, &len); lua_Integer maxalloc = luaL_optinteger(L, 3, DEFAULT_MAXALLOC_BYTES); - struct lunatik_state *state = lua_newuserdata(L, sizeof(struct lunatik_state)); + struct lunatik_nl_state *state = lua_newuserdata(L, sizeof(struct lunatik_nl_state)); if (len >= LUNATIK_NAME_MAXSIZE) luaL_argerror(L, 2, "name too long"); @@ -144,7 +144,7 @@ static int lsession_create(lua_State *L) static int lstate_close(lua_State *L) { - struct lunatik_state *s = getnlstate(L); + struct lunatik_nl_state *s = getnlstate(L); if (lunatikS_destroy(s->session, s->name)){ lua_pushboolean(L, false); return 1; @@ -156,7 +156,7 @@ static int lstate_close(lua_State *L) static int lstate_dostring(lua_State *L) { - struct lunatik_state *s = getnlstate(L); + struct lunatik_nl_state *s = getnlstate(L); struct lunatik_session *session = s->session; const char *name = s->name; size_t len; @@ -181,18 +181,18 @@ static int lstate_dostring(lua_State *L) } static int lstate_getname(lua_State *L) { - struct lunatik_state *s = getnlstate(L); + struct lunatik_nl_state *s = getnlstate(L); lua_pushstring(L, s->name); return 1; } static int lstate_getmaxalloc(lua_State *L) { - struct lunatik_state *s = getnlstate(L); + struct lunatik_nl_state *s = getnlstate(L); lua_pushinteger(L, s->maxalloc); return 1; } -static void buildlist(lua_State *L, struct lunatik_state *states, size_t n); +static void buildlist(lua_State *L, struct lunatik_nl_state *states, size_t n); static int lsession_list(lua_State *L) { @@ -206,14 +206,19 @@ static int lsession_list(lua_State *L) return 1; } - list = session->states_list; - buildlist(L, list.states, list.list_size); - free(list.states); + if (session->cb_result == CB_LIST_EMPTY) { + buildlist(L, NULL, 0); + } else { + list = session->states_list; + buildlist(L, list.states, list.list_size); + free(list.states); + list.list_size = 0; + } return 1; } -static void buildlist(lua_State *L, struct lunatik_state *states, size_t n) +static void buildlist(lua_State *L, struct lunatik_nl_state *states, size_t n) { size_t i; diff --git a/lunatik_core.c b/lunatik_core.c index daa126bd8..e3d9c5cb8 100644 --- a/lunatik_core.c +++ b/lunatik_core.c @@ -182,7 +182,6 @@ EXPORT_SYMBOL(lunatik_netnewstate); EXPORT_SYMBOL(lunatik_netclose); EXPORT_SYMBOL(lunatik_netstatelookup); -struct send_message; extern struct genl_family lunatik_family; extern void lunatik_statesinit(void); extern void lunatik_closeall(void); @@ -202,15 +201,8 @@ static int __net_init lunatik_instancenew(struct net *net) atomic_set(&(instance->states_count), 0); spin_lock_init(&(instance->statestable_lock)); spin_lock_init(&(instance->rfcnt_lock)); - spin_lock_init(&(instance->sendmessage_lock)); hash_init(instance->states_table); - instance->reply_buffer = kmalloc(sizeof(struct reply_buffer), GFP_KERNEL); - - if (instance->reply_buffer == NULL) { - pr_err("Failed to allocate memory to reply buffer\n"); - BUG(); - } - + (instance->reply_buffer).status = RB_INIT; return 0; } @@ -230,8 +222,6 @@ static void __net_exit lunatik_instanceclose(struct net *net) } spin_unlock_bh(&(instance->statestable_lock)); - - kfree(instance->reply_buffer); } static struct pernet_operations lunatik_net_ops = { diff --git a/netlink.c b/netlink.c index e8b792e41..8dbc23c8e 100644 --- a/netlink.c +++ b/netlink.c @@ -31,6 +31,14 @@ #include "states.h" #include "netlink_common.h" + + +struct lunatik_nl_state { + char name[LUNATIK_NAME_MAXSIZE]; + size_t maxalloc; + size_t curralloc; +}; + extern struct lunatik_instance *lunatik_pernet(struct net *net); static int lunatikN_newstate(struct sk_buff *buff, struct genl_info *info); @@ -41,13 +49,13 @@ static int lunatikN_list(struct sk_buff *buff, struct genl_info *info); struct nla_policy lunatik_policy[ATTRS_COUNT] = { [STATE_NAME] = { .type = NLA_STRING }, [CODE] = { .type = NLA_STRING }, - [SCRIPT_NAME] = { .type = NLA_STRING}, - [MAX_ALLOC] = { .type = NLA_U32 }, + [SCRIPT_NAME] = { .type = NLA_STRING }, + [STATES_LIST] = { .type = NLA_STRING }, [SCRIPT_SIZE] = { .type = NLA_U32 }, - [STATES_COUNT]= { .type = NLA_U32}, + [MAX_ALLOC] = { .type = NLA_U32 }, [FLAGS] = { .type = NLA_U8 }, [OP_SUCESS] = { .type = NLA_U8 }, - [OP_ERROR] = { .type = NLA_U8}, + [OP_ERROR] = { .type = NLA_U8 }, }; static const struct genl_ops l_ops[] = { @@ -98,28 +106,22 @@ struct genl_family lunatik_family = { .n_ops = ARRAY_SIZE(l_ops), }; -static int fill_reply_buffer(struct reply_buffer *message, struct lunatik_instance *instance) +static void fill_states_list(char *buffer, struct lunatik_instance *instance) { struct lunatik_state *state; int bucket; - int states_count = atomic_read(&(instance->states_count)); int counter = 0; + int states_count = atomic_read(&instance->states_count); - message->states_list = kmalloc(states_count * sizeof(lunatik_State), GFP_KERNEL); - - if (message->states_list == NULL) { - pr_err("Failed to allocate memory to hold states list\n"); - return -ENOMEM; - } - - message->list_size = states_count; - message->curr_pos_to_send = 0; hash_for_each_rcu(instance->states_table, bucket, state, node) { - message->states_list[counter] = *(state); + buffer += sprintf(buffer, "%s#", state->name); + buffer += sprintf(buffer, "%ld#", state->curralloc); + if (counter == states_count - 1) + buffer += sprintf(buffer, "%ld", state->maxalloc); + else + buffer += sprintf(buffer, "%ld#", state->maxalloc); counter++; } - - return 0; } static int send_done_msg(int command, struct genl_info *info) @@ -150,72 +152,37 @@ static int send_done_msg(int command, struct genl_info *info) return 0; } -static int send_states_count(struct lunatik_instance *instance, struct genl_info *info) -{ - void *msg_head; - struct sk_buff *obuff; - int err = -1; - - if ((obuff = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL)) == NULL) { - pr_err("Failed allocating message to an reply\n"); - return -ENOMEM; - } - - if ((msg_head = genlmsg_put_reply(obuff, info, &lunatik_family, 0, LIST_STATES)) == NULL) { - pr_err("Failed to put generic netlink header\n"); - return err; - } - - nla_put_u8(obuff, FLAGS, LUNATIK_INIT); - nla_put_u32(obuff, STATES_COUNT, atomic_read(&instance->states_count)); - - genlmsg_end(obuff, msg_head); - - if (genlmsg_reply(obuff, info) < 0) { - pr_err("Failed to send message to user space\n"); - return err; - } - - return 0; -} - -static int send_state(lunatik_State *state, struct genl_info *info) +static void reply_with(int reply, int command, struct genl_info *info) { struct sk_buff *obuff; void *msg_head; - int err = -1; if ((obuff = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL)) == NULL) { pr_err("Failed allocating message to an reply\n"); - return err; + return; } - if ((msg_head = genlmsg_put_reply(obuff, info, &lunatik_family, 0, LIST_STATES)) == NULL) { + if ((msg_head = genlmsg_put_reply(obuff, info, &lunatik_family, 0, command)) == NULL) { pr_err("Failed to put generic netlink header\n"); - return err; + return; } - if (nla_put_string(obuff, STATE_NAME, state->name) || - nla_put_u32(obuff, MAX_ALLOC, state->maxalloc) || - nla_put_u32(obuff, CURR_ALLOC, state->curralloc) - ) { + if (nla_put_u8(obuff, reply, 1)) { pr_err("Failed to put attributes on socket buffer\n"); - return err; + return; } genlmsg_end(obuff, msg_head); if (genlmsg_reply(obuff, info) < 0) { pr_err("Failed to send message to user space\n"); - return err; + return; } pr_debug("Message sent to user space\n"); - - return 0; } -static void reply_with(int reply, int command, struct genl_info *info) +static void send_states_list(char *buffer, int amount, int flags, struct genl_info *info) { struct sk_buff *obuff; void *msg_head; @@ -225,12 +192,22 @@ static void reply_with(int reply, int command, struct genl_info *info) return; } - if ((msg_head = genlmsg_put_reply(obuff, info, &lunatik_family, 0, command)) == NULL) { + if ((msg_head = genlmsg_put_reply(obuff, info, &lunatik_family, 0, LIST_STATES)) == NULL) { pr_err("Failed to put generic netlink header\n"); return; } - if (nla_put_u8(obuff, reply, 1)) { + if (flags & LUNATIK_INIT) { + if (nla_put_u32(obuff, STATES_COUNT, amount)) { + pr_err("Failed to put attributes on socket buffer\n"); + return; + } + } else if (nla_put_string(obuff, STATES_LIST, buffer)) { + pr_err("Failed to put attributes on socket buffer\n"); + return; + } + + if (nla_put_u8(obuff, FLAGS, flags)) { pr_err("Failed to put attributes on socket buffer\n"); return; } @@ -353,39 +330,103 @@ static int lunatikN_close(struct sk_buff *buff, struct genl_info *info) return 0; } +static void send_init_information(int parts, int states_count, struct genl_info *info) +{ + struct sk_buff *obuff; + void *msg_head; + + if ((obuff = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL)) == NULL) { + pr_err("Failed allocating message to an reply\n"); + return; + } + + if ((msg_head = genlmsg_put_reply(obuff, info, &lunatik_family, 0, LIST_STATES)) == NULL) { + pr_err("Failed to put generic netlink header\n"); + return; + } + + if (nla_put_u32(obuff, STATES_COUNT, states_count) || nla_put_u32(obuff, PARTS, parts)) { + pr_err("Failed to put attributes on socket buffer\n"); + return; + } + + if (nla_put_u8(obuff, FLAGS, LUNATIK_INIT)) { + pr_err("Failed to put attributes on socket buffer\n"); + return; + } + + genlmsg_end(obuff, msg_head); + + if (genlmsg_reply(obuff, info) < 0) { + pr_err("Failed to send message to user space\n"); + return; + } + + pr_debug("Message sent to user space\n"); +} + static int lunatikN_list(struct sk_buff *buff, struct genl_info *info) { struct lunatik_instance *instance; - struct reply_buffer *reply; - lunatik_State currstate; + struct reply_buffer *reply_buffer; + int states_count; + char *fragment; u8 flags; pr_debug("Received a LIST_STATES command\n"); instance = lunatik_pernet(genl_info_net(info)); flags = *((u8 *)nla_data(info->attrs[FLAGS])); - reply = instance->reply_buffer; + states_count = atomic_read(&instance->states_count); + reply_buffer = &instance->reply_buffer; - if (flags & LUNATIK_INIT) { - spin_lock(&(instance->sendmessage_lock)); - fill_reply_buffer(reply, instance); // TODO Check error and reply if an error occur - send_states_count(instance, info); + if ((fragment = kmalloc(LUNATIK_FRAGMENT_SIZE, GFP_KERNEL)) == NULL) { + pr_err("Failed to allocate memory to fragment\n"); + return 0; + } + + if (states_count == 0){ + reply_with(STATES_LIST_EMPTY, LIST_STATES, info); goto out; } - if (reply->curr_pos_to_send == reply->list_size) { - send_done_msg(LIST_STATES, info); - kfree(reply->states_list); - spin_unlock(&(instance->sendmessage_lock)); + if (reply_buffer->status == RB_INIT) { + reply_buffer->buffer = kmalloc(states_count * (sizeof(struct lunatik_nl_state) + DELIMITER), GFP_KERNEL); + + if (reply_buffer->buffer == NULL) { + pr_err("Failed to allocate memory to message buffer\n"); + return 0; + } + + fill_states_list(reply_buffer->buffer, instance); + reply_buffer->curr_pos_to_send = 0; + + reply_buffer->parts = ((strlen(reply_buffer->buffer) % LUNATIK_FRAGMENT_SIZE) == 0) ? + (strlen(reply_buffer->buffer) / LUNATIK_FRAGMENT_SIZE) : + (strlen(reply_buffer->buffer) / LUNATIK_FRAGMENT_SIZE) + 1; + send_init_information(reply_buffer->parts, states_count,info); + reply_buffer->status = RB_SENDING; goto out; } - currstate = reply->states_list[reply->curr_pos_to_send++]; - if (send_state(&currstate, info)) { - pr_err("Failed to send state information to user space\n"); - return 0; + if (reply_buffer->curr_pos_to_send == reply_buffer->parts - 1) { + strncpy(fragment, reply_buffer->buffer + ((reply_buffer->parts - 1) * LUNATIK_FRAGMENT_SIZE), LUNATIK_FRAGMENT_SIZE); + send_states_list(fragment, states_count, LUNATIK_DONE, info); + goto reset_reply_buffer; + } else { + strncpy(fragment, reply_buffer->buffer + (reply_buffer->curr_pos_to_send * LUNATIK_FRAGMENT_SIZE), LUNATIK_FRAGMENT_SIZE); + send_states_list(fragment, states_count, LUNATIK_MULTI, info); + reply_buffer->curr_pos_to_send++; } out: + kfree(fragment); + return 0; + +reset_reply_buffer: + reply_buffer->parts = 0; + reply_buffer->status = RB_INIT; + reply_buffer->curr_pos_to_send = 0; + kfree(fragment); return 0; } diff --git a/netlink_common.h b/netlink_common.h index fe4717916..2c27d183f 100644 --- a/netlink_common.h +++ b/netlink_common.h @@ -4,20 +4,15 @@ #ifdef _KERNEL extern struct genl_family lunatik_family; #include - -struct reply_buffer { - lunatik_State *states_list; - int list_size; - int curr_pos_to_send; -}; #endif -#define LUNATIK_FRAGMENT_SIZE (3000) // TODO Find, a size more precise +#define LUNATIK_FRAGMENT_SIZE (20) // TODO Find, a size more precise +#define DELIMITER 3 //How many delimiters will be necessary in each part of the message /*Lunatik generic netlink protocol flags*/ #define LUNATIK_INIT 0x01 /* Initializes the needed variables for script execution */ -#define LUNATIK_MULTI 0x02 /* A Fragment of a multipart message */ -#define LUNATIK_DONE 0x04 /* Last message of a multipart message */ +#define LUNATIK_MULTI 0x02 /* A Fragment of a multipart message */ +#define LUNATIK_DONE 0x04 /* Last message of a multipart message */ #define LUNATIK_FAMILY "lunatik_family" #define LUNATIK_NLVERSION 1 @@ -31,13 +26,15 @@ enum lunatik_operations { enum lunatik_attrs { STATE_NAME = 1, - STATES_COUNT, MAX_ALLOC, - CURR_ALLOC, + STATES_LIST, + STATES_COUNT, + PARTS, CODE, FLAGS, SCRIPT_SIZE, SCRIPT_NAME, + STATES_LIST_EMPTY, OP_SUCESS, OP_ERROR, ATTRS_COUNT diff --git a/states.h b/states.h index 39cba3a20..1355c2472 100644 --- a/states.h +++ b/states.h @@ -22,10 +22,11 @@ #include "lua/lua.h" #include "lunatik_conf.h" +#include "netlink.h" struct lunatik_instance { struct hlist_head states_table[LUNATIK_HASH_BUCKETS]; - struct reply_buffer *reply_buffer; + struct reply_buffer reply_buffer; spinlock_t statestable_lock; spinlock_t rfcnt_lock; spinlock_t sendmessage_lock; From c74f2469c993ffdfb7843b5265cc6ca7b126a5f1 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Sun, 26 Jul 2020 21:33:02 -0300 Subject: [PATCH 09/48] Change lua_Buffer to a normal buffer --- lib/lunatik.c | 4 +- netlink.c | 115 ++++++++++++++++++++++---------------------------- netlink.h | 24 +++++++++++ states.h | 3 +- 4 files changed, 78 insertions(+), 68 deletions(-) create mode 100644 netlink.h diff --git a/lib/lunatik.c b/lib/lunatik.c index bfc6b3c94..098325815 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -107,7 +107,7 @@ static int send_fragment(struct lunatik_session *session, const char *original_s NLA_PUT_U8(msg, FLAGS, flags); - + if ((err = nl_send_auto(session->sock, msg)) < 0) { printf("Failed to send fragment\n %s\n", nl_geterror(err)); nlmsg_free(msg); @@ -293,7 +293,7 @@ static int init_recv_buffer(struct lunatik_session *session, struct nlattr **att { struct received_buffer *recv_buffer; int parts; - + recv_buffer = &session->recv_buffer; if (attrs[PARTS]) { diff --git a/netlink.c b/netlink.c index 8dbc23c8e..9f0f149f8 100644 --- a/netlink.c +++ b/netlink.c @@ -31,8 +31,6 @@ #include "states.h" #include "netlink_common.h" - - struct lunatik_nl_state { char name[LUNATIK_NAME_MAXSIZE]; size_t maxalloc; @@ -48,12 +46,12 @@ static int lunatikN_list(struct sk_buff *buff, struct genl_info *info); struct nla_policy lunatik_policy[ATTRS_COUNT] = { [STATE_NAME] = { .type = NLA_STRING }, - [CODE] = { .type = NLA_STRING }, + [CODE] = { .type = NLA_STRING }, [SCRIPT_NAME] = { .type = NLA_STRING }, [STATES_LIST] = { .type = NLA_STRING }, [SCRIPT_SIZE] = { .type = NLA_U32 }, - [MAX_ALLOC] = { .type = NLA_U32 }, - [FLAGS] = { .type = NLA_U8 }, + [MAX_ALLOC] = { .type = NLA_U32 }, + [FLAGS] = { .type = NLA_U8 }, [OP_SUCESS] = { .type = NLA_U8 }, [OP_ERROR] = { .type = NLA_U8 }, }; @@ -124,34 +122,6 @@ static void fill_states_list(char *buffer, struct lunatik_instance *instance) } } -static int send_done_msg(int command, struct genl_info *info) -{ - void *msg_head; - struct sk_buff *obuff; - int err = -1; - - if ((obuff = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL)) == NULL) { - pr_err("Failed allocating message to an reply\n"); - return -ENOMEM; - } - - if ((msg_head = genlmsg_put_reply(obuff, info, &lunatik_family, 0, command)) == NULL) { - pr_err("Failed to put generic netlink header\n"); - return err; - } - - nla_put_u8(obuff, FLAGS, LUNATIK_DONE); - - genlmsg_end(obuff, msg_head); - - if (genlmsg_reply(obuff, info) < 0) { - pr_err("Failed to send message to user space\n"); - return err; - } - - return 0; -} - static void reply_with(int reply, int command, struct genl_info *info) { struct sk_buff *obuff; @@ -244,15 +214,56 @@ static int lunatikN_newstate(struct sk_buff *buff, struct genl_info *info) return 0; } +static void init_codebuffer(lunatik_State *s, struct genl_info *info) +{ + s->scriptsize = *((u32*)nla_data(info->attrs[SCRIPT_SIZE])); + + if ((s->code_buffer = kmalloc(s->scriptsize, GFP_KERNEL)) == NULL) { + pr_err("Failed allocating memory to code buffer\n"); + reply_with(OP_ERROR, EXECUTE_CODE, info); + } + + s->buffer_offset = 0; +} + +static void add_fragtostate(char *fragment, lunatik_State *s) +{ + strncpy(s->code_buffer + (s->buffer_offset * LUNATIK_FRAGMENT_SIZE), + fragment, LUNATIK_FRAGMENT_SIZE); + s->buffer_offset++; +} + +static int dostring(char *code, lunatik_State *s, const char *script_name) +{ + int err = 0; + spin_lock_bh(&s->lock); + + if (!lunatik_stateget(s)) { + pr_err("Failed to get state\n"); + err = -1; + goto out; + } + + if ((err = luaU_dostring(s->L, code, s->scriptsize, script_name))) { + pr_err("%s\n", lua_tostring(s->L, -1)); + } + + lunatik_stateput(s); + +out: + kfree(s->code_buffer); + spin_unlock_bh(&s->lock); + return err; +} + static int lunatikN_dostring(struct sk_buff *buff, struct genl_info *info) { struct lunatik_state *s; struct lunatik_instance *instance; - const char *finalscript; const char *script_name; - int err; char *fragment; char *state_name; + int err; u8 flags; pr_debug("Received a EXECUTE_CODE message\n"); @@ -269,43 +280,17 @@ static int lunatikN_dostring(struct sk_buff *buff, struct genl_info *info) } if (flags & LUNATIK_INIT) { - s->scriptsize = *((u32*)nla_data(info->attrs[SCRIPT_SIZE])); - - /*TODO Discover why this lock when disable bh is causing a kernel panic related to skb release - */ - spin_lock(&s->lock); - if ((s->buffer = kmalloc(sizeof(luaL_Buffer), GFP_KERNEL)) == NULL) { - pr_err("Failed allocating memory to code buffer\n"); - reply_with(OP_ERROR, EXECUTE_CODE, info); - return 0; - } - luaL_buffinit(s->L, s->buffer); + init_codebuffer(s, info); } if (flags & LUNATIK_MULTI) { - luaL_addlstring(s->buffer, fragment, LUNATIK_FRAGMENT_SIZE); + add_fragtostate(fragment, s); } if (flags & LUNATIK_DONE){ - luaL_addstring(s->buffer, fragment); - luaL_pushresult(s->buffer); - - finalscript = lua_tostring(s->L, -1); + add_fragtostate(fragment, s); script_name = nla_data(info->attrs[SCRIPT_NAME]); - - if (!lunatik_stateget(s)) { - pr_err("Failed to get state\n"); - reply_with(OP_ERROR, EXECUTE_CODE, info); - return 0; - } - - if ((err = luaU_dostring(s->L, finalscript, s->scriptsize, script_name))) { - pr_err("%s\n", lua_tostring(s->L, -1)); - } - - spin_unlock(&s->lock); - lunatik_stateput(s); - + err = dostring(s->code_buffer, s, script_name); err ? reply_with(OP_ERROR, EXECUTE_CODE, info) : reply_with(OP_SUCESS, EXECUTE_CODE, info); } diff --git a/netlink.h b/netlink.h new file mode 100644 index 000000000..4d27dbf73 --- /dev/null +++ b/netlink.h @@ -0,0 +1,24 @@ +#ifndef NETLINK_H +#include + +extern struct genl_family lunatik_family; + +enum reply_buffer_status { + RB_INIT, + RB_SENDING, +}; + +struct reply_buffer { + char *buffer; + int parts; + int curr_pos_to_send; + enum reply_buffer_status status; +}; + +struct lunatik_data { + char *buffer; + size_t size; +}; + +#endif + diff --git a/states.h b/states.h index 1355c2472..89644a9ab 100644 --- a/states.h +++ b/states.h @@ -36,7 +36,8 @@ struct lunatik_instance { typedef struct lunatik_state { struct hlist_node node; lua_State *L; - luaL_Buffer *buffer; + char *code_buffer; + int buffer_offset; spinlock_t lock; refcount_t users; size_t maxalloc; From cc4e3b66aa728d0f5b4362892531bc0f0795bf88 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Mon, 27 Jul 2020 11:08:26 -0300 Subject: [PATCH 10/48] Remove unnucessary functions --- states.c | 31 +++---------------------------- states.h | 10 +--------- 2 files changed, 4 insertions(+), 37 deletions(-) diff --git a/states.c b/states.c index 824aafef7..beecad9f7 100644 --- a/states.c +++ b/states.c @@ -186,32 +186,6 @@ int lunatik_close(const char *name) return 0; } -#ifndef LUNATIK_UNUSED -int lunatik_state_list(struct xt_lua_net *xt_lua, nflua_state_cb cb, - unsigned short *total) -{ - struct hlist_head *head; - struct nflua_state *s; - int i, ret = 0; - - spin_lock_bh(&xt_lua->state_lock); - - *total = atomic_read(&xt_lua->state_count); - - for (i = 0; i < XT_LUA_HASH_BUCKETS; i++) { - head = &xt_lua->state_table[i]; - kpi_hlist_for_each_entry_rcu(s, head, node) { - if ((ret = cb(s, total)) != 0) - goto out; - } - } - -out: - spin_unlock_bh(&xt_lua->state_lock); - return ret; -} -#endif - void lunatik_closeall(void) { struct hlist_node *tmp; @@ -237,14 +211,14 @@ void lunatik_stateput(lunatik_State *s) if (WARN_ON(s == NULL)) return; - + if (refcount_dec_not_one(users)) return; spin_lock_bh(refcnt_lock); if (!refcount_dec_and_test(users)) goto out; - + kfree(s); out: spin_unlock_bh(refcnt_lock); @@ -351,3 +325,4 @@ int lunatik_netclose(struct lunatik_instance *instance, const char *name) return 0; } + diff --git a/states.h b/states.h index 89644a9ab..028252251 100644 --- a/states.h +++ b/states.h @@ -46,19 +46,10 @@ typedef struct lunatik_state { unsigned char name[LUNATIK_NAME_MAXSIZE]; } lunatik_State; -#ifndef LUNATIK_UNUSED -typedef int (*nflua_state_cb)(struct nflua_state *s, unsigned short *total); -#endif /*LUNATIK_UNUSED*/ - lunatik_State *lunatik_newstate(size_t maxalloc, const char *name); int lunatik_close(const char *name); lunatik_State *lunatik_statelookup(const char *name); -#ifndef LUNATIK_UNUSED -int nflua_state_list(struct xt_lua_net *xt_lua, nflua_state_cb cb, - unsigned short *total); -#endif /*LUNATIK_UNUSED*/ - bool lunatik_stateget(lunatik_State *s); void lunatik_stateput(lunatik_State *s); @@ -67,3 +58,4 @@ int lunatik_netclose(struct lunatik_instance *instance, const char *name); lunatik_State *lunatik_netstatelookup(struct lunatik_instance *instance, const char *name); #endif /* LUNATIK_STATES_H */ + From 54ec7f4beedc70bea69290cbd570e3840c39907f Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Mon, 27 Jul 2020 11:46:58 -0300 Subject: [PATCH 11/48] Name changes to fit with lua API's --- lib/lunatik.c | 6 +++--- lib/lunatik.h | 6 +++--- lib/lunatik_module.c | 20 ++++++++++---------- lunatik_conf.h | 2 +- states.c | 1 - states.h | 1 - 6 files changed, 17 insertions(+), 19 deletions(-) diff --git a/lib/lunatik.c b/lib/lunatik.c index 098325815..3df6d3015 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -140,7 +140,7 @@ static int receive_op_result(struct lunatik_session *session){ return 0; } -int lunatikS_create(struct lunatik_session *session, struct lunatik_nl_state *cmd) +int lunatikS_newstate(struct lunatik_session *session, struct lunatik_nl_state *cmd) { struct nl_msg *msg; int ret = -1; @@ -163,7 +163,7 @@ int lunatikS_create(struct lunatik_session *session, struct lunatik_nl_state *cm return ret; } -int lunatikS_destroy(struct lunatik_session *session, const char *name) +int lunatikS_closestate(struct lunatik_session *session, const char *name) { struct nl_msg *msg; int ret = -1; @@ -425,7 +425,7 @@ int lunatikS_init(struct lunatik_session *session) return 0; } -void lunatikS_end(struct lunatik_session *session) +void lunatikS_close(struct lunatik_session *session) { if (session != NULL){ nl_socket_free(session->sock); diff --git a/lib/lunatik.h b/lib/lunatik.h index ce0679331..39f676f4b 100644 --- a/lib/lunatik.h +++ b/lib/lunatik.h @@ -88,11 +88,11 @@ static inline int lunatikS_isopen(const struct lunatik_session *session) int lunatikS_init(struct lunatik_session *session); -void lunatikS_end(struct lunatik_session *session); +void lunatikS_close(struct lunatik_session *session); -int lunatikS_create(struct lunatik_session *session, struct lunatik_nl_state *s); +int lunatikS_newstate(struct lunatik_session *session, struct lunatik_nl_state *s); -int lunatikS_destroy(struct lunatik_session *session, const char *name); +int lunatikS_closestate(struct lunatik_session *session, const char *name); int lunatikS_dostring(struct lunatik_session *session, const char *state_name, const char *script, const char *script_name, size_t total_code_size); diff --git a/lib/lunatik_module.c b/lib/lunatik_module.c index b9406200f..dd098fff7 100644 --- a/lib/lunatik_module.c +++ b/lib/lunatik_module.c @@ -31,7 +31,7 @@ extern int luaopen_memory(lua_State *L); #endif /*_UNUSED*/ -#define DEFAULT_MAXALLOC_BYTES (32 * 1024) +#define DEFAULT_MAXALLOC_BYTES (32 * 1024) static int pusherrmsg(lua_State *L, const char *msg) { @@ -82,7 +82,7 @@ static int lsession_open(lua_State *L) static int lsession_gc(lua_State *L) { struct lunatik_session *session = luaL_checkudata(L, 1, "lunatik.session"); - if (lunatikS_isopen(session)) lunatikS_end(session); + if (lunatikS_isopen(session)) lunatikS_close(session); return 0; } @@ -102,10 +102,10 @@ static struct lunatik_nl_state *getnlstate(lua_State *L) return s; } -static int lsession_end(lua_State *L) +static int lsession_close(lua_State *L) { struct lunatik_session *session = getsession(L); - lunatikS_end(session); + lunatikS_close(session); lua_pushboolean(L, true); return 1; } @@ -117,7 +117,7 @@ static int lsession_getfd(lua_State *L) return 1; } -static int lsession_create(lua_State *L) +static int lsession_newstate(lua_State *L) { struct lunatik_session *session = getsession(L); size_t len; @@ -132,7 +132,7 @@ static int lsession_create(lua_State *L) state->maxalloc = maxalloc; state->session = session; - if (lunatikS_create(session, state)) { + if (lunatikS_newstate(session, state)) { pusherrmsg(L, "Failed to create the state\n"); return 2; } @@ -145,7 +145,7 @@ static int lsession_create(lua_State *L) static int lstate_close(lua_State *L) { struct lunatik_nl_state *s = getnlstate(L); - if (lunatikS_destroy(s->session, s->name)){ + if (lunatikS_closestate(s->session, s->name)){ lua_pushboolean(L, false); return 1; } @@ -235,7 +235,7 @@ static void buildlist(lua_State *L, struct lunatik_nl_state *states, size_t n) } } #ifndef _UNUSED -static int ldata_open(lua_State *L) +static int ldata_open(lua_State *L) { int ret; uint32_t pid = generatepid(L, 1); @@ -320,9 +320,9 @@ static int ldata_receive(lua_State *L) #endif /* _UNUSED */ static const luaL_Reg session_mt[] = { - {"down", lsession_end}, + {"close", lsession_close}, {"getfd", lsession_getfd}, - {"new", lsession_create}, + {"new", lsession_newstate}, {"list", lsession_list}, {"__gc", lsession_gc}, {NULL, NULL} diff --git a/lunatik_conf.h b/lunatik_conf.h index 7d3f18251..e44c81f44 100644 --- a/lunatik_conf.h +++ b/lunatik_conf.h @@ -22,7 +22,7 @@ #define LUNATIK_NAME_MAXSIZE 64 /* Max length of Lua state name */ -#define LUNATIK_SCRIPTNAME_MAXSIZE 255 /* Max length of Lua state name */ +#define LUNATIK_SCRIPTNAME_MAXSIZE 255 /* Max length of script name */ #define LUNATIK_MIN_ALLOC_BYTES (32 * 1024UL) diff --git a/states.c b/states.c index beecad9f7..6b3e66ff6 100644 --- a/states.c +++ b/states.c @@ -325,4 +325,3 @@ int lunatik_netclose(struct lunatik_instance *instance, const char *name) return 0; } - diff --git a/states.h b/states.h index 028252251..90b267718 100644 --- a/states.h +++ b/states.h @@ -58,4 +58,3 @@ int lunatik_netclose(struct lunatik_instance *instance, const char *name); lunatik_State *lunatik_netstatelookup(struct lunatik_instance *instance, const char *name); #endif /* LUNATIK_STATES_H */ - From 5ea4da346dd957b5ed25f5e38c1e49abe5c6ad4c Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Mon, 27 Jul 2020 17:41:15 -0300 Subject: [PATCH 12/48] Refatoration of functions --- lib/lunatik.c | 5 ++-- netlink.c | 70 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 46 insertions(+), 29 deletions(-) diff --git a/lib/lunatik.c b/lib/lunatik.c index 3df6d3015..1246a26fe 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -367,7 +367,8 @@ static int response_handler(struct nl_msg *msg, void *arg) if (attrs_tb[STATES_LIST_EMPTY]) { session->states_list.list_size = 0; session->states_list.states = NULL; - return 0; + session->cb_result = CB_LIST_EMPTY; + return NL_OK; } if (attrs_tb[FLAGS]) { @@ -393,7 +394,7 @@ static int response_handler(struct nl_msg *msg, void *arg) } if (err) - session->cb_result = OP_ERROR; + session->cb_result = CB_ERROR; break; default: diff --git a/netlink.c b/netlink.c index 9f0f149f8..f8b3ebd17 100644 --- a/netlink.c +++ b/netlink.c @@ -152,7 +152,7 @@ static void reply_with(int reply, int command, struct genl_info *info) pr_debug("Message sent to user space\n"); } -static void send_states_list(char *buffer, int amount, int flags, struct genl_info *info) +static void send_states_list(char *buffer, int flags, struct genl_info *info) { struct sk_buff *obuff; void *msg_head; @@ -167,12 +167,7 @@ static void send_states_list(char *buffer, int amount, int flags, struct genl_in return; } - if (flags & LUNATIK_INIT) { - if (nla_put_u32(obuff, STATES_COUNT, amount)) { - pr_err("Failed to put attributes on socket buffer\n"); - return; - } - } else if (nla_put_string(obuff, STATES_LIST, buffer)) { + if (nla_put_string(obuff, STATES_LIST, buffer)) { pr_err("Failed to put attributes on socket buffer\n"); return; } @@ -350,12 +345,46 @@ static void send_init_information(int parts, int states_count, struct genl_info pr_debug("Message sent to user space\n"); } +static int init_replybuffer(struct lunatik_instance *instance, size_t size) +{ + struct reply_buffer *reply_buffer = &instance->reply_buffer; + reply_buffer->buffer = kmalloc(size * (sizeof(struct lunatik_nl_state) + DELIMITER), GFP_KERNEL); + + if (reply_buffer->buffer == NULL) { + pr_err("Failed to allocate memory to message buffer\n"); + return -1; + } + + fill_states_list(reply_buffer->buffer, instance); + reply_buffer->curr_pos_to_send = 0; + + reply_buffer->parts = ((strlen(reply_buffer->buffer) % LUNATIK_FRAGMENT_SIZE) == 0) ? + (strlen(reply_buffer->buffer) / LUNATIK_FRAGMENT_SIZE) : + (strlen(reply_buffer->buffer) / LUNATIK_FRAGMENT_SIZE) + 1; + reply_buffer->status = RB_SENDING; + return 0; +} + +static void send_lastfragment(char *fragment, struct reply_buffer *reply_buffer, struct genl_info *info) +{ + strncpy(fragment, reply_buffer->buffer + ((reply_buffer->parts - 1) * LUNATIK_FRAGMENT_SIZE), LUNATIK_FRAGMENT_SIZE); + send_states_list(fragment, LUNATIK_DONE, info); +} + +static void send_fragment(char *fragment, struct reply_buffer *reply_buffer, struct genl_info *info) +{ + strncpy(fragment, reply_buffer->buffer + (reply_buffer->curr_pos_to_send * LUNATIK_FRAGMENT_SIZE), LUNATIK_FRAGMENT_SIZE); + send_states_list(fragment, LUNATIK_MULTI, info); + reply_buffer->curr_pos_to_send++; +} + static int lunatikN_list(struct sk_buff *buff, struct genl_info *info) { struct lunatik_instance *instance; struct reply_buffer *reply_buffer; int states_count; char *fragment; + int err = 0; u8 flags; pr_debug("Received a LIST_STATES command\n"); @@ -376,32 +405,19 @@ static int lunatikN_list(struct sk_buff *buff, struct genl_info *info) } if (reply_buffer->status == RB_INIT) { - reply_buffer->buffer = kmalloc(states_count * (sizeof(struct lunatik_nl_state) + DELIMITER), GFP_KERNEL); - - if (reply_buffer->buffer == NULL) { - pr_err("Failed to allocate memory to message buffer\n"); - return 0; - } - - fill_states_list(reply_buffer->buffer, instance); - reply_buffer->curr_pos_to_send = 0; - - reply_buffer->parts = ((strlen(reply_buffer->buffer) % LUNATIK_FRAGMENT_SIZE) == 0) ? - (strlen(reply_buffer->buffer) / LUNATIK_FRAGMENT_SIZE) : - (strlen(reply_buffer->buffer) / LUNATIK_FRAGMENT_SIZE) + 1; - send_init_information(reply_buffer->parts, states_count,info); - reply_buffer->status = RB_SENDING; + err = init_replybuffer(instance, states_count); + if (err) + reply_with(OP_ERROR, LIST_STATES, info); + else + send_init_information(reply_buffer->parts, states_count, info); goto out; } if (reply_buffer->curr_pos_to_send == reply_buffer->parts - 1) { - strncpy(fragment, reply_buffer->buffer + ((reply_buffer->parts - 1) * LUNATIK_FRAGMENT_SIZE), LUNATIK_FRAGMENT_SIZE); - send_states_list(fragment, states_count, LUNATIK_DONE, info); + send_lastfragment(fragment, reply_buffer, info); goto reset_reply_buffer; } else { - strncpy(fragment, reply_buffer->buffer + (reply_buffer->curr_pos_to_send * LUNATIK_FRAGMENT_SIZE), LUNATIK_FRAGMENT_SIZE); - send_states_list(fragment, states_count, LUNATIK_MULTI, info); - reply_buffer->curr_pos_to_send++; + send_fragment(fragment, reply_buffer, info); } out: From 2092d56ee4db8cce88b7f116667a04d98f7472d2 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Thu, 30 Jul 2020 13:25:41 -0300 Subject: [PATCH 13/48] Add lua-memory as dependecy --- .gitmodules | 3 +++ Makefile | 7 +++++-- deps/lua-memory | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 .gitmodules create mode 160000 deps/lua-memory diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..d9b94c1bc --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "deps/lua-memory"] + path = deps/lua-memory + url = https://github.com/MatheusNtg/lua-memory diff --git a/Makefile b/Makefile index 9f0a8df39..5251a6e0d 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ -ccflags-y += -D_LUNATIK -D_KERNEL -I$(src) -D_CONFIG_FULL_PANIC -DLUNATIK_UNUSED +ccflags-y += -D_LUNATIK -D_KERNEL -I$(src) -D_CONFIG_FULL_PANIC -DLUNATIK_UNUSED \ + -I$(src)/lua asflags-y += -D_LUNATIK -D_KERNEL ifeq ($(ARCH), $(filter $(ARCH),i386 x86)) @@ -35,8 +36,10 @@ lua-objs = lua/lapi.o lua/lcode.o lua/lctype.o lua/ldebug.o lua/ldo.o \ lua/ltablib.o lua/lutf8lib.o lua/loslib.o lua/lmathlib.o lua/linit.o \ lua/loadlib.o luautil.o +lua_memory-objs = deps/lua-memory/src/lmemlib.o deps/lua-memory/src/lmemmod.o + lunatik-objs += $(lua-objs) \ - arch/$(ARCH)/setjmp.o util/modti3.o lunatik_core.o states.o netlink.o + arch/$(ARCH)/setjmp.o util/modti3.o lunatik_core.o states.o netlink.o $(lua_memory-objs) ifeq ($(shell [ "${VERSION}" -lt "4" ] && [ "${VERSION}${PATCHLEVEL}" -lt "312" ] && echo y),y) lunatik-objs += util/div64.o diff --git a/deps/lua-memory b/deps/lua-memory new file mode 160000 index 000000000..6909c01bf --- /dev/null +++ b/deps/lua-memory @@ -0,0 +1 @@ +Subproject commit 6909c01bf3b333f23fa1466dd60208f35ffc5aca From 8c3240a58664a06e02e759c890b2d5a32f949db2 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Thu, 6 Aug 2020 22:47:00 -0300 Subject: [PATCH 14/48] Send data to kernel --- Makefile | 2 +- lib/Makefile | 5 +- lib/lunatik.c | 133 ++++++++++++++++++++++++++++++++------ lib/lunatik.h | 15 +++-- lib/lunatik_module.c | 21 +++--- netlink.c | 150 ++++++++++++++++++++++++++++++++++++++++++- netlink_common.h | 6 +- states.c | 11 ++-- states.h | 1 + 9 files changed, 300 insertions(+), 44 deletions(-) diff --git a/Makefile b/Makefile index 5251a6e0d..5c6bf329a 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ ccflags-y += -D_LUNATIK -D_KERNEL -I$(src) -D_CONFIG_FULL_PANIC -DLUNATIK_UNUSED \ - -I$(src)/lua + -I$(src)/lua -I$(src)/deps/lua-memory/src asflags-y += -D_LUNATIK -D_KERNEL ifeq ($(ARCH), $(filter $(ARCH),i386 x86)) diff --git a/lib/Makefile b/lib/Makefile index c5dfd4d6a..01583648b 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -17,8 +17,9 @@ # CC = gcc -CFLAGS = -fPIC -Wall -Wextra -O2 -g -I/usr/include/lua5.3/ -I/usr/include/libnl3 -D_UNUSED -LDFLAGS = -shared -lnl-genl-3 -lnl-3 -llua5.3 +CFLAGS = -fPIC -Wall -Wextra -O2 -g -I/usr/include/lua5.3/ -I/usr/include/libnl3 -D_UNUSED \ + -I$(src)../deps/lua-memory/src +LDFLAGS = -shared -lnl-genl-3 -lnl-3 -llua5.3 -L../deps/lua-memory/src -l:memory.so RM = rm -f LIBS = lunatik.so diff --git a/lib/lunatik.c b/lib/lunatik.c index 1246a26fe..009314b7b 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -66,7 +66,7 @@ static int send_simple_msg(struct lunatik_session *session, int command, int fla goto error; } - if ((err = nl_send_auto(session->sock, msg)) < 0) { + if ((err = nl_send_auto(session->control_sock, msg)) < 0) { printf("Failed sending message to kernel\n"); goto error; } @@ -108,7 +108,7 @@ static int send_fragment(struct lunatik_session *session, const char *original_s NLA_PUT_U8(msg, FLAGS, flags); - if ((err = nl_send_auto(session->sock, msg)) < 0) { + if ((err = nl_send_auto(session->control_sock, msg)) < 0) { printf("Failed to send fragment\n %s\n", nl_geterror(err)); nlmsg_free(msg); return err; @@ -127,12 +127,12 @@ static int send_fragment(struct lunatik_session *session, const char *original_s static int receive_op_result(struct lunatik_session *session){ int ret; - if ((ret = nl_recvmsgs_default(session->sock))) { + if ((ret = nl_recvmsgs_default(session->control_sock))) { printf("Failed to receive message from kernel: %s\n", nl_geterror(ret)); return ret; } - nl_wait_for_ack(session->sock); + nl_wait_for_ack(session->control_sock); if (session->cb_result == CB_ERROR) return -1; @@ -140,6 +140,35 @@ static int receive_op_result(struct lunatik_session *session){ return 0; } +static int init_data_socket(struct lunatik_session *session, char *name) +{ + struct nl_msg *msg; + int err = -1; + + if ((msg = prepare_message(session, DATA_INIT, 0)) == NULL) { + printf("Error preparing message\n"); + goto error; + } + + NLA_PUT_STRING(msg, STATE_NAME, name); + + if ((err = nl_send_auto(session->data_sock, msg)) < 0) { + printf("Failed sending message to kernel\n"); + goto error; + } + + nl_wait_for_ack(session->data_sock); + + nlmsg_free(msg); + return 0; + +nla_put_failure: + printf("Failed to put attributes on DATA_INIT message\n"); +error: + nlmsg_free(msg); + return err; +} + int lunatikS_newstate(struct lunatik_session *session, struct lunatik_nl_state *cmd) { struct nl_msg *msg; @@ -151,12 +180,15 @@ int lunatikS_newstate(struct lunatik_session *session, struct lunatik_nl_state * NLA_PUT_STRING(msg, STATE_NAME, cmd->name); NLA_PUT_U32(msg, MAX_ALLOC, cmd->maxalloc); - if ((ret = nl_send_auto(session->sock, msg)) < 0) { + if ((ret = nl_send_auto(session->control_sock, msg)) < 0) { printf("Failed to send message to kernel\n %s\n", nl_geterror(ret)); return ret; } - return receive_op_result(session); + if (init_data_socket(session, cmd->name) || receive_op_result(session)) + return -1; + + return 0; nla_put_failure: printf("Failed to put attributes on message\n"); @@ -173,7 +205,7 @@ int lunatikS_closestate(struct lunatik_session *session, const char *name) NLA_PUT_STRING(msg, STATE_NAME, name); - if ((ret = nl_send_auto(session->sock, msg)) < 0) { + if ((ret = nl_send_auto(session->control_sock, msg)) < 0) { printf("Failed to send destroy message:\n %s\n", nl_geterror(ret)); return ret; } @@ -206,7 +238,7 @@ int lunatikS_dostring(struct lunatik_session *session, const char *state_name, else err = send_fragment(session, script, i, state_name, script_name, LUNATIK_MULTI); - nl_wait_for_ack(session->sock); + nl_wait_for_ack(session->control_sock); if (err) return err; @@ -227,16 +259,16 @@ int lunatikS_list(struct lunatik_session *session) if ((err = send_simple_msg(session, LIST_STATES, 0))) return err; - nl_recvmsgs_default(session->sock); - nl_wait_for_ack(session->sock); + nl_recvmsgs_default(session->control_sock); + nl_wait_for_ack(session->control_sock); if (session->cb_result == CB_ERROR) return -1; while (session->status == SESSION_RECEIVING) { send_simple_msg(session, LIST_STATES, 0); - nl_recvmsgs_default(session->sock); - nl_wait_for_ack(session->sock); + nl_recvmsgs_default(session->control_sock); + nl_wait_for_ack(session->control_sock); } return 0; @@ -404,6 +436,26 @@ static int response_handler(struct nl_msg *msg, void *arg) return NL_OK; } +static int data_handler(struct nl_msg *msg, void *arg) +{ + return NL_OK; +} + +int init_socket(struct nl_sock **socket, struct lunatik_session *session) +{ + int err = -1; + if ((*socket = nl_socket_alloc()) == NULL) + return err; + + if ((err = genl_connect(*socket))) + return err; + + if ((session->family = genl_ctrl_resolve(*socket, LUNATIK_FAMILY)) < 0) + return session->family; + + return 0; +} + int lunatikS_init(struct lunatik_session *session) { int err = -1; @@ -411,17 +463,22 @@ int lunatikS_init(struct lunatik_session *session) if (session == NULL) return -EINVAL; - if ((session->sock = nl_socket_alloc()) == NULL) - return err; - - if ((err = genl_connect(session->sock))) + if ((err = init_socket(&session->control_sock, session))) { + printf("Failed to initialize control socket\n"); + nl_socket_free(session->control_sock); return err; + } - if ((session->family = genl_ctrl_resolve(session->sock, LUNATIK_FAMILY)) < 0) + if ((err = init_socket(&session->data_sock, session))) { + printf("Failed to initialize data socket\n"); + nl_socket_free(session->data_sock); return err; + } - nl_socket_modify_cb(session->sock, NL_CB_MSG_IN, NL_CB_CUSTOM, response_handler, session); - session->fd = nl_socket_get_fd(session->sock); + nl_socket_modify_cb(session->control_sock, NL_CB_MSG_IN, NL_CB_CUSTOM, response_handler, session); + nl_socket_modify_cb(session->data_sock, NL_CB_MSG_IN, NL_CB_CUSTOM, data_handler, session); + session->control_fd = nl_socket_get_fd(session->control_sock); + session->data_fd = nl_socket_get_fd(session->data_sock); return 0; } @@ -429,7 +486,41 @@ int lunatikS_init(struct lunatik_session *session) void lunatikS_close(struct lunatik_session *session) { if (session != NULL){ - nl_socket_free(session->sock); - session->fd = -1; + nl_socket_free(session->control_sock); + nl_socket_free(session->data_sock); + session->control_fd = -1; + session->data_fd = -1; } } + +int lunatik_datasend(struct lunatik_nl_state *state, const char *payload, size_t len) +{ + struct nl_msg *msg = prepare_message(state->session, DATA, 0); + struct lunatik_session *session = state->session; + int err = 0; + + if (msg == NULL) + return -1; + + NLA_PUT_STRING(msg, LUNATIK_DATA, payload); + NLA_PUT_STRING(msg, STATE_NAME, state->name); + NLA_PUT_U32(msg, LUNATIK_DATA_LEN, len); + + if ((err = nl_send_auto(session->data_sock, msg)) < 0) { + printf("Failed sending message to kernel\n"); + nlmsg_free(msg); + return err; + } + + nl_recvmsgs_default(session->data_sock); + nl_wait_for_ack(session->data_sock); + nlmsg_free(msg); + + return 0; + +nla_put_failure: + printf("Failure to put attributes to data send operation\n"); + nlmsg_free(msg); + return -1; +} + diff --git a/lib/lunatik.h b/lib/lunatik.h index 39f676f4b..6b921a289 100644 --- a/lib/lunatik.h +++ b/lib/lunatik.h @@ -35,7 +35,6 @@ enum callback_result { enum session_status { SESSION_FREE, SESSION_RECEIVING, - SESSION_INIT_LIST, }; struct lunatik_nl_state { @@ -56,13 +55,15 @@ struct received_buffer { }; struct lunatik_session { - struct nl_sock *sock; + struct nl_sock *control_sock; + struct nl_sock *data_sock; struct states_list states_list; struct received_buffer recv_buffer; enum session_status status; enum callback_result cb_result; int family; - int fd; + int control_fd; + int data_fd; uint32_t pid; }; @@ -78,12 +79,12 @@ struct nflua_data { static inline int lunatikS_getfd(const struct lunatik_session *session) { - return session->fd; + return session->control_fd; } static inline int lunatikS_isopen(const struct lunatik_session *session) { - return session->fd >= 0; + return session->control_fd >= 0; } int lunatikS_init(struct lunatik_session *session); @@ -121,10 +122,12 @@ static inline int nflua_data_is_open(const struct nflua_data *dch) int nflua_data_init(struct nflua_data *dch, uint32_t pid); void nflua_data_close(struct nflua_data *dch); +#endif /* _UNUSED */ -int nflua_data_send(struct nflua_data *dch, const char *name, +int lunatik_datasend(struct lunatik_nl_state *state, const char *payload, size_t len); +#ifndef _UNUSED int nflua_data_receive(struct nflua_data *dch, char *state, char *buffer); #endif /* _UNUSED */ #endif /* LUNATIK_H */ diff --git a/lib/lunatik_module.c b/lib/lunatik_module.c index dd098fff7..8a14fb973 100644 --- a/lib/lunatik_module.c +++ b/lib/lunatik_module.c @@ -24,6 +24,7 @@ #include #include +#include #include "lunatik.h" @@ -282,19 +283,24 @@ static int ldata_getpid(lua_State *L) lua_pushinteger(L, nflua_data_getpid(dch)); return 1; } +#endif /* _UNUSED */ -static int ldata_send(lua_State *L) +static int lstate_datasend(lua_State *L) { - struct nflua_data *dch = getdata(L); - const char *name = luaL_checkstring(L, 2); + struct lunatik_nl_state *state = getnlstate(L); size_t size; - const char *buffer = luamem_checkmemory(L, 3, &size); + int err; + const char *buffer = luamem_checkmemory(L, 2, &size); + + if (buffer == NULL) luaL_argerror(L, 2, "expected non NULL memory object"); - if (buffer == NULL) luaL_argerror(L, 3, "expected non NULL memory object"); + err = lunatik_datasend(state, buffer, size); + err ? lua_pushnil(L) : lua_pushboolean(L, true); - return pushioresult(L, nflua_data_send(dch, name, buffer, size)); + return 1; } +#ifndef _UNUSED static int ldata_receive(lua_State *L) { struct nflua_data *dch = getdata(L); @@ -333,6 +339,7 @@ static const luaL_Reg state_mt[] = { {"getname", lstate_getname}, {"getmaxalloc", lstate_getmaxalloc}, {"close", lstate_close}, + {"send", lstate_datasend}, {NULL, NULL} }; @@ -341,8 +348,6 @@ static const luaL_Reg data_mt[] = { {"close", ldata_close}, {"getfd", ldata_getfd}, {"getpid", ldata_getpid}, - {"send", ldata_send}, - {"receive", ldata_receive}, {"__gc", ldata_gc}, {NULL, NULL} }; diff --git a/netlink.c b/netlink.c index f8b3ebd17..7c8dd38ef 100644 --- a/netlink.c +++ b/netlink.c @@ -27,10 +27,14 @@ #include #include +#include + #include "luautil.h" #include "states.h" #include "netlink_common.h" +#define DATA_RECV_FUNC "receive_callback" + struct lunatik_nl_state { char name[LUNATIK_NAME_MAXSIZE]; size_t maxalloc; @@ -43,12 +47,16 @@ static int lunatikN_newstate(struct sk_buff *buff, struct genl_info *info); static int lunatikN_dostring(struct sk_buff *buff, struct genl_info *info); static int lunatikN_close(struct sk_buff *buff, struct genl_info *info); static int lunatikN_list(struct sk_buff *buff, struct genl_info *info); +static int lunatikN_data(struct sk_buff *buff, struct genl_info *info); +static int lunatikN_datainit(struct sk_buff *buff, struct genl_info *info); struct nla_policy lunatik_policy[ATTRS_COUNT] = { [STATE_NAME] = { .type = NLA_STRING }, [CODE] = { .type = NLA_STRING }, [SCRIPT_NAME] = { .type = NLA_STRING }, [STATES_LIST] = { .type = NLA_STRING }, + [LUNATIK_DATA]= { .type = NLA_STRING }, + [LUNATIK_DATA_LEN] = { .type = NLA_U32}, [SCRIPT_SIZE] = { .type = NLA_U32 }, [MAX_ALLOC] = { .type = NLA_U32 }, [FLAGS] = { .type = NLA_U8 }, @@ -87,6 +95,22 @@ static const struct genl_ops l_ops[] = { #if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) /*Before kernel 5.2.0, each operation has its own policy*/ .policy = lunatik_policy +#endif + }, + { + .cmd = DATA, + .doit = lunatikN_data, +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) + /*Before kernel 5.2.0, each operation has its own policy*/ + .policy = lunatik_policy +#endif + }, + { + .cmd = DATA_INIT, + .doit = lunatikN_datainit, +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) + /*Before kernel 5.2.0, each operation has its own policy*/ + .policy = lunatik_policy #endif } }; @@ -283,7 +307,7 @@ static int lunatikN_dostring(struct sk_buff *buff, struct genl_info *info) } if (flags & LUNATIK_DONE){ - add_fragtostate(fragment, s); + strcpy(s->code_buffer, fragment); script_name = nla_data(info->attrs[SCRIPT_NAME]); err = dostring(s->code_buffer, s, script_name); err ? reply_with(OP_ERROR, EXECUTE_CODE, info) : reply_with(OP_SUCESS, EXECUTE_CODE, info); @@ -431,3 +455,127 @@ static int lunatikN_list(struct sk_buff *buff, struct genl_info *info) kfree(fragment); return 0; } + +static int init_data(struct lunatik_data *data, char *buffer, size_t size) +{ + if ((data->buffer = kmalloc(sizeof(size), GFP_KERNEL)) == NULL) { + pr_err("Failed to allocate memory to data buffer\n"); + return -1; + } + memcpy(data->buffer, buffer, size); + data->size = size; + return 0; +} + +static int handle_data(lua_State *L); + +static int lunatikN_data(struct sk_buff *buff, struct genl_info *info) +{ + struct lunatik_instance *instance; + struct lunatik_data data; + lunatik_State *state; + char *payload; + char *state_name; + u32 payload_len; + int err = 0; + + instance = lunatik_pernet(genl_info_net(info)); + state_name = nla_data(info->attrs[STATE_NAME]); + + if ((state = lunatik_netstatelookup(instance, state_name)) == NULL) { + pr_err("State %s not found\n", state_name); + goto error; + } + + payload = nla_data(info->attrs[LUNATIK_DATA]); + payload_len = *((u32 *)nla_data(info->attrs[LUNATIK_DATA_LEN])); + + err = init_data(&data, payload, payload_len); + if (err) + goto error; + + if (!lunatik_stateget(state)) { + pr_err("Failed to get state %s\n", state_name); + goto error; + } + + spin_lock_bh(&state->lock); + + lua_pushcfunction(state->L, handle_data); + lua_pushlightuserdata(state->L, &data); + if (luaU_pcall(state->L, 1, 0)) { + pr_err("%s\n", lua_tostring(state->L, -1)); + err = -1; + goto unlock; + } + +unlock: + spin_unlock_bh(&state->lock); + lunatik_stateput(state); + + err ? reply_with(OP_ERROR, DATA, info) : reply_with(OP_SUCESS, DATA, info); + + return 0; + +error: + reply_with(OP_ERROR, DATA, info); + return 0; +} + +static int lunatikN_datainit(struct sk_buff *buff, struct genl_info *info) +{ + struct lunatik_instance *instance; + char *name; + lunatik_State *state; + + instance = lunatik_pernet(genl_info_net(info)); + name = nla_data(info->attrs[STATE_NAME]); + state = lunatik_netstatelookup(instance, name); + state->genl_info = *info; + + return 0; +} + +/* Note: Most of the functions below are copied from NFLua: https://github.com/cujoai/nflua + * Copyright (C) 2017-2019 CUJO LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +static int handle_data(lua_State *L) +{ + int error; + struct lunatik_data *req = lua_touserdata(L, 1); + + lua_pop(L, 1); + + luamem_newref(L); + luamem_setref(L, -1, req->buffer, req->size, NULL); + + if (lua_getglobal(L, DATA_RECV_FUNC) != LUA_TFUNCTION) + return luaL_error(L, "couldn't find receive function: %s\n", + DATA_RECV_FUNC); + + lua_pushvalue(L, 1); /* memory */ + + error = lua_pcall(L, 1, 0, 0); + + luamem_setref(L, 1, NULL, 0, NULL); + + if (error) + lua_error(L); + + return 0; +} diff --git a/netlink_common.h b/netlink_common.h index 2c27d183f..16a1af46a 100644 --- a/netlink_common.h +++ b/netlink_common.h @@ -6,7 +6,7 @@ extern struct genl_family lunatik_family; #include #endif -#define LUNATIK_FRAGMENT_SIZE (20) // TODO Find, a size more precise +#define LUNATIK_FRAGMENT_SIZE (3000) // TODO Find, a size more precise #define DELIMITER 3 //How many delimiters will be necessary in each part of the message /*Lunatik generic netlink protocol flags*/ @@ -22,6 +22,8 @@ enum lunatik_operations { EXECUTE_CODE, DESTROY_STATE, LIST_STATES, + DATA, + DATA_INIT }; enum lunatik_attrs { @@ -37,6 +39,8 @@ enum lunatik_attrs { STATES_LIST_EMPTY, OP_SUCESS, OP_ERROR, + LUNATIK_DATA, + LUNATIK_DATA_LEN, ATTRS_COUNT #define ATTRS_MAX (ATTRS_COUNT - 1) }; diff --git a/states.c b/states.c index 6b3e66ff6..3404e4838 100644 --- a/states.c +++ b/states.c @@ -34,8 +34,15 @@ #define LUNATIK_SETPAUSE 100 #endif /* LUNATIK_SETPAUSE */ +extern int luaopen_memory(lua_State *); + static struct lunatik_instance instance; +static const luaL_Reg libs[] = { + {"memory", luaopen_memory}, + {NULL, NULL} +}; + static inline int name_hash(void *salt, const char *name) { int len = strnlen(name, LUNATIK_NAME_MAXSIZE); @@ -92,9 +99,7 @@ static void *lua_alloc(void *ud, void *ptr, size_t osize, size_t nsize) static int state_init(lunatik_State *s) { - #ifndef LUNATIK_UNUSED const luaL_Reg *lib; - #endif /*LUNATIK_UNUSED*/ s->L = lua_newstate(lua_alloc, s); if (s->L == NULL) @@ -103,12 +108,10 @@ static int state_init(lunatik_State *s) luaU_setenv(s->L, s, lunatik_State); luaL_openlibs(s->L); - #ifndef LUNATIK_UNUSED for (lib = libs; lib->name != NULL; lib++) { luaL_requiref(s->L, lib->name, lib->func, 1); lua_pop(s->L, 1); } - #endif /* fixes an issue where the Lua's GC enters a vicious cycle. * more info here: https://marc.info/?l=lua-l&m=155024035605499&w=2 diff --git a/states.h b/states.h index 90b267718..d0e0cabbd 100644 --- a/states.h +++ b/states.h @@ -35,6 +35,7 @@ struct lunatik_instance { typedef struct lunatik_state { struct hlist_node node; + struct genl_info genl_info; lua_State *L; char *code_buffer; int buffer_offset; From 764f083d614a987ba9c0452ae99484ea83cc3c0f Mon Sep 17 00:00:00 2001 From: NFLua Team <> Date: Thu, 30 Jul 2020 19:51:58 -0300 Subject: [PATCH 15/48] Import luanetlink from NFLua --- luanetlink.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 luanetlink.c diff --git a/luanetlink.c b/luanetlink.c new file mode 100644 index 000000000..bab1c4a84 --- /dev/null +++ b/luanetlink.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2017-2019 CUJO LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +#include + +#include "luautil.h" +#include "netlink.h" +#include "states.h" + +static int luanetlink_send(lua_State *L) +{ + struct nflua_state *s = luaU_getenv(L, struct nflua_state); + int pid = luaL_checkinteger(L, 1); + int group = luaL_optinteger(L, 2, 0); + const char *payload; + size_t size; + int err; + + if (s == NULL) + return luaL_error(L, "invalid nflua_state"); + + payload = luamem_checkstring(L, 3, &size); + + if ((err = nflua_nl_send_data(s, pid, group, payload, size)) < 0) + return luaL_error(L, "failed to send message. Return code %d", err); + + lua_pushinteger(L, (lua_Integer)size); + + return 1; +} + +static const luaL_Reg luanetlink_lib[] = { + {"send", luanetlink_send}, + {NULL, NULL} +}; + +int luaopen_netlink(lua_State *L) +{ + luaL_newlib(L, luanetlink_lib); + return 1; +} +EXPORT_SYMBOL(luaopen_netlink); From 650f7de6eccf3b73a1344e6361de0b2830f598f4 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Thu, 6 Aug 2020 23:31:01 -0300 Subject: [PATCH 16/48] Receiving data from kernel --- Makefile | 3 +- lib/Makefile | 2 +- lib/lunatik.c | 103 +++++++++++++++++++++++++++++++++---------- lib/lunatik.h | 15 +++++-- lib/lunatik_module.c | 15 +++---- luanetlink.c | 13 +++--- luautil.h | 3 +- netlink.c | 69 +++++++++++++++++++++++------ netlink.h | 3 ++ states.c | 2 + states.h | 3 +- 11 files changed, 171 insertions(+), 60 deletions(-) diff --git a/Makefile b/Makefile index 5c6bf329a..5ea5da821 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,8 @@ lua-objs = lua/lapi.o lua/lcode.o lua/lctype.o lua/ldebug.o lua/ldo.o \ lua_memory-objs = deps/lua-memory/src/lmemlib.o deps/lua-memory/src/lmemmod.o lunatik-objs += $(lua-objs) \ - arch/$(ARCH)/setjmp.o util/modti3.o lunatik_core.o states.o netlink.o $(lua_memory-objs) + arch/$(ARCH)/setjmp.o util/modti3.o lunatik_core.o states.o netlink.o $(lua_memory-objs) \ + luanetlink.o ifeq ($(shell [ "${VERSION}" -lt "4" ] && [ "${VERSION}${PATCHLEVEL}" -lt "312" ] && echo y),y) lunatik-objs += util/div64.o diff --git a/lib/Makefile b/lib/Makefile index 01583648b..e7e182dc3 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -19,7 +19,7 @@ CC = gcc CFLAGS = -fPIC -Wall -Wextra -O2 -g -I/usr/include/lua5.3/ -I/usr/include/libnl3 -D_UNUSED \ -I$(src)../deps/lua-memory/src -LDFLAGS = -shared -lnl-genl-3 -lnl-3 -llua5.3 -L../deps/lua-memory/src -l:memory.so +LDFLAGS = -shared -lnl-genl-3 -lnl-3 -llua5.3 -L../deps/lua-memory/src -lluamemlib RM = rm -f LIBS = lunatik.so diff --git a/lib/lunatik.c b/lib/lunatik.c index 009314b7b..a075bfd35 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -107,7 +107,6 @@ static int send_fragment(struct lunatik_session *session, const char *original_s NLA_PUT_U8(msg, FLAGS, flags); - if ((err = nl_send_auto(session->control_sock, msg)) < 0) { printf("Failed to send fragment\n %s\n", nl_geterror(err)); nlmsg_free(msg); @@ -140,7 +139,7 @@ static int receive_op_result(struct lunatik_session *session){ return 0; } -static int init_data_socket(struct lunatik_session *session, char *name) +static int init_recv_datasocket(struct lunatik_session *session) { struct nl_msg *msg; int err = -1; @@ -150,20 +149,14 @@ static int init_data_socket(struct lunatik_session *session, char *name) goto error; } - NLA_PUT_STRING(msg, STATE_NAME, name); - - if ((err = nl_send_auto(session->data_sock, msg)) < 0) { + if ((err = nl_send_auto(session->recv_datasock, msg)) < 0) { printf("Failed sending message to kernel\n"); goto error; } - nl_wait_for_ack(session->data_sock); - nlmsg_free(msg); return 0; -nla_put_failure: - printf("Failed to put attributes on DATA_INIT message\n"); error: nlmsg_free(msg); return err; @@ -185,10 +178,7 @@ int lunatikS_newstate(struct lunatik_session *session, struct lunatik_nl_state * return ret; } - if (init_data_socket(session, cmd->name) || receive_op_result(session)) - return -1; - - return 0; + return receive_op_result(session); nla_put_failure: printf("Failed to put attributes on message\n"); @@ -375,7 +365,6 @@ static int response_handler(struct nl_msg *msg, void *arg) uint8_t flags = 0; int err = 0; - if (nla_parse(attrs_tb, ATTRS_COUNT, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL)) { @@ -387,6 +376,7 @@ static int response_handler(struct nl_msg *msg, void *arg) { case CREATE_STATE: case DESTROY_STATE: + case DATA: case EXECUTE_CODE: if (attrs_tb[OP_SUCESS] && nla_get_u8(attrs_tb[OP_SUCESS])) { session->cb_result = CB_SUCCESS; @@ -438,6 +428,27 @@ static int response_handler(struct nl_msg *msg, void *arg) static int data_handler(struct nl_msg *msg, void *arg) { + struct nlmsghdr *nh = nlmsg_hdr(msg); + struct genlmsghdr *gnlh = genlmsg_hdr(nh); + struct lunatik_session *session = (struct lunatik_session *) arg; + struct data_buffer *data_buffer = &session->data_buffer; + struct nlattr *attrs_tb[ATTRS_COUNT + 1]; + + if (nla_parse(attrs_tb, ATTRS_COUNT, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL)) + { + printf("Error parsing attributes\n"); + session->cb_result = CB_ERROR; + return NL_OK; + } + + if (attrs_tb[LUNATIK_DATA] && attrs_tb[LUNATIK_DATA_LEN] && attrs_tb[STATE_NAME]) { + strcpy(data_buffer->buffer, nla_get_string(attrs_tb[LUNATIK_DATA])); + strcpy(data_buffer->state_name, nla_get_string(attrs_tb[STATE_NAME])); + data_buffer->size = nla_get_u32(attrs_tb[LUNATIK_DATA_LEN]); + } else { + printf("Some attributes are missing\n"); + } return NL_OK; } @@ -469,16 +480,27 @@ int lunatikS_init(struct lunatik_session *session) return err; } - if ((err = init_socket(&session->data_sock, session))) { - printf("Failed to initialize data socket\n"); - nl_socket_free(session->data_sock); + if ((err = init_socket(&session->send_datasock, session))) { + printf("Failed to initialize send data socket\n"); + nl_socket_free(session->send_datasock); + return err; + } + + if ((err = init_socket(&session->recv_datasock, session))) { + printf("Failed to initialize recv data socket\n"); + nl_socket_free(session->recv_datasock); return err; } nl_socket_modify_cb(session->control_sock, NL_CB_MSG_IN, NL_CB_CUSTOM, response_handler, session); - nl_socket_modify_cb(session->data_sock, NL_CB_MSG_IN, NL_CB_CUSTOM, data_handler, session); + nl_socket_modify_cb(session->send_datasock, NL_CB_MSG_IN, NL_CB_CUSTOM, response_handler, session); + nl_socket_modify_cb(session->recv_datasock, NL_CB_MSG_IN, NL_CB_CUSTOM, data_handler, session); + nl_socket_disable_seq_check(session->recv_datasock); + nl_socket_disable_auto_ack(session->recv_datasock); session->control_fd = nl_socket_get_fd(session->control_sock); - session->data_fd = nl_socket_get_fd(session->data_sock); + session->data_fd = nl_socket_get_fd(session->recv_datasock); + + init_recv_datasocket(session); return 0; } @@ -487,7 +509,8 @@ void lunatikS_close(struct lunatik_session *session) { if (session != NULL){ nl_socket_free(session->control_sock); - nl_socket_free(session->data_sock); + nl_socket_free(session->send_datasock); + nl_socket_free(session->recv_datasock); session->control_fd = -1; session->data_fd = -1; } @@ -506,14 +529,14 @@ int lunatik_datasend(struct lunatik_nl_state *state, const char *payload, size_t NLA_PUT_STRING(msg, STATE_NAME, state->name); NLA_PUT_U32(msg, LUNATIK_DATA_LEN, len); - if ((err = nl_send_auto(session->data_sock, msg)) < 0) { + if ((err = nl_send_auto(session->send_datasock, msg)) < 0) { printf("Failed sending message to kernel\n"); nlmsg_free(msg); return err; } - nl_recvmsgs_default(session->data_sock); - nl_wait_for_ack(session->data_sock); + nl_recvmsgs_default(session->send_datasock); + nl_wait_for_ack(session->send_datasock); nlmsg_free(msg); return 0; @@ -524,3 +547,37 @@ int lunatik_datasend(struct lunatik_nl_state *state, const char *payload, size_t return -1; } +int init_data_buffer(struct data_buffer *data_buffer, size_t size) +{ + if ((data_buffer->buffer = malloc(size)) == NULL) { + printf("Failed to allocate memory to data buffer\n"); + return -1; + } + memset(data_buffer->buffer, 0, size); + data_buffer->size = size; + return 0; +} + +int release_data_buffer(struct data_buffer *data_buffer) +{ + free(data_buffer->buffer); + data_buffer->size = 0; + memset(data_buffer->state_name, 0, LUNATIK_NAME_MAXSIZE); + return 0; +} + +int lunatikS_receive(struct lunatik_session *session, char *state, char *buffer) +{ + struct data_buffer *data_buffer = &session->data_buffer; + int received_data; + + init_data_buffer(data_buffer, LUNATIK_FRAGMENT_SIZE); + nl_recvmsgs_default(session->recv_datasock); + + memcpy(buffer, data_buffer->buffer, data_buffer->size); + strcpy(state, data_buffer->state_name); + received_data = data_buffer->size; + + release_data_buffer(data_buffer); + return received_data; +} diff --git a/lib/lunatik.h b/lib/lunatik.h index 6b921a289..b6a59118d 100644 --- a/lib/lunatik.h +++ b/lib/lunatik.h @@ -54,11 +54,19 @@ struct received_buffer { int cursor; }; +struct data_buffer { + char *buffer; + char state_name[LUNATIK_NAME_MAXSIZE]; + int size; +}; + struct lunatik_session { struct nl_sock *control_sock; - struct nl_sock *data_sock; + struct nl_sock *send_datasock; + struct nl_sock *recv_datasock; struct states_list states_list; struct received_buffer recv_buffer; + struct data_buffer data_buffer; enum session_status status; enum callback_result cb_result; int family; @@ -100,10 +108,9 @@ int lunatikS_dostring(struct lunatik_session *session, const char *state_name, int lunatikS_list(struct lunatik_session *session); -#ifndef _UNUSED -int nflua_control_receive(struct nflua_control *ctrl, - struct nflua_response *nr, char *buffer); +int lunatikS_receive(struct lunatik_session *session, char *state, char *buffer); +#ifndef _UNUSED static inline int nflua_data_getsock(const struct nflua_data *dch) { return dch->fd; diff --git a/lib/lunatik_module.c b/lib/lunatik_module.c index 8a14fb973..4aae122db 100644 --- a/lib/lunatik_module.c +++ b/lib/lunatik_module.c @@ -300,11 +300,10 @@ static int lstate_datasend(lua_State *L) return 1; } -#ifndef _UNUSED -static int ldata_receive(lua_State *L) +static int lsession_datareceive(lua_State *L) { - struct nflua_data *dch = getdata(L); - char state[NFLUA_NAME_MAXSIZE] = {0}; + struct lunatik_session *session = getsession(L); + char state[LUNATIK_NAME_MAXSIZE] = {0}; size_t size, offset; int recv; char *buffer = luamem_checkmemory(L, 2, &size); @@ -312,10 +311,10 @@ static int ldata_receive(lua_State *L) if (buffer == NULL) luaL_argerror(L, 2, "expected non NULL memory object"); offset = luaL_checkinteger(L, 3); - if (offset >= size || size - offset < NFLUA_DATA_MAXSIZE) - luaL_argerror(L, 3, "not enough space in buffer"); + if (offset >= size || size - offset < LUNATIK_FRAGMENT_SIZE) + luaL_argerror(L, 2, "not enough space in buffer"); - recv = nflua_data_receive(dch, state, buffer + offset); + recv = lunatikS_receive(session, state, buffer); if (recv < 0) return pusherrno(L, recv); lua_pushinteger(L, recv); @@ -323,13 +322,13 @@ static int ldata_receive(lua_State *L) return 2; } -#endif /* _UNUSED */ static const luaL_Reg session_mt[] = { {"close", lsession_close}, {"getfd", lsession_getfd}, {"new", lsession_newstate}, {"list", lsession_list}, + {"receive", lsession_datareceive}, {"__gc", lsession_gc}, {NULL, NULL} }; diff --git a/luanetlink.c b/luanetlink.c index bab1c4a84..9a73ae923 100644 --- a/luanetlink.c +++ b/luanetlink.c @@ -22,24 +22,23 @@ #include #include "luautil.h" -#include "netlink.h" #include "states.h" +extern int lunatikN_send_data(lunatik_State *state, const char *payload, size_t size); + static int luanetlink_send(lua_State *L) { - struct nflua_state *s = luaU_getenv(L, struct nflua_state); - int pid = luaL_checkinteger(L, 1); - int group = luaL_optinteger(L, 2, 0); + lunatik_State *s = luaU_getenv(L, lunatik_State); const char *payload; size_t size; int err; if (s == NULL) - return luaL_error(L, "invalid nflua_state"); + return luaL_error(L, "invalid lunatik_State"); - payload = luamem_checkstring(L, 3, &size); + payload = luamem_checkstring(L, 1, &size); - if ((err = nflua_nl_send_data(s, pid, group, payload, size)) < 0) + if ((err = lunatikN_send_data(s, payload, size)) < 0) return luaL_error(L, "failed to send message. Return code %d", err); lua_pushinteger(L, (lua_Integer)size); diff --git a/luautil.h b/luautil.h index 5cf4fc008..a44abf95a 100644 --- a/luautil.h +++ b/luautil.h @@ -68,9 +68,10 @@ static inline void *luaU_getregval(lua_State *L, luaU_id id) st **penv = (st **)lua_getextraspace(L); \ *penv = env; } -#ifndef LUNATIK_UNUSED + #define luaU_getenv(L, st) (*((st **)lua_getextraspace(L))) +#ifndef LUNATIK_UNUSED static inline int luaU_pusherr(lua_State *L, const char *err) { lua_pushnil(L); diff --git a/netlink.c b/netlink.c index 7c8dd38ef..ec3c7ec43 100644 --- a/netlink.c +++ b/netlink.c @@ -52,16 +52,16 @@ static int lunatikN_datainit(struct sk_buff *buff, struct genl_info *info); struct nla_policy lunatik_policy[ATTRS_COUNT] = { [STATE_NAME] = { .type = NLA_STRING }, - [CODE] = { .type = NLA_STRING }, + [CODE] = { .type = NLA_STRING }, [SCRIPT_NAME] = { .type = NLA_STRING }, [STATES_LIST] = { .type = NLA_STRING }, [LUNATIK_DATA]= { .type = NLA_STRING }, [LUNATIK_DATA_LEN] = { .type = NLA_U32}, [SCRIPT_SIZE] = { .type = NLA_U32 }, - [MAX_ALLOC] = { .type = NLA_U32 }, - [FLAGS] = { .type = NLA_U8 }, + [MAX_ALLOC] = { .type = NLA_U32 }, + [FLAGS] = { .type = NLA_U8 }, [OP_SUCESS] = { .type = NLA_U8 }, - [OP_ERROR] = { .type = NLA_U8 }, + [OP_ERROR] = { .type = NLA_U8 }, }; static const struct genl_ops l_ops[] = { @@ -217,18 +217,21 @@ static int lunatikN_newstate(struct sk_buff *buff, struct genl_info *info) struct lunatik_state *s; char *state_name; u32 *max_alloc; - u32 pid; pr_debug("Received a CREATE_STATE message\n"); instance = lunatik_pernet(genl_info_net(info)); state_name = (char *)nla_data(info->attrs[STATE_NAME]); max_alloc = (u32 *)nla_data(info->attrs[MAX_ALLOC]); - pid = info->snd_portid; s = lunatik_netnewstate(instance, *max_alloc, state_name); - s == NULL ? reply_with(OP_ERROR, CREATE_STATE, info) : reply_with(OP_SUCESS, CREATE_STATE, info); + if (s == NULL) { + reply_with(OP_ERROR, CREATE_STATE, info); + } else { + s->instance = *instance; + reply_with(OP_SUCESS, CREATE_STATE, info); + } return 0; } @@ -255,6 +258,7 @@ static void add_fragtostate(char *fragment, lunatik_State *s) static int dostring(char *code, lunatik_State *s, const char *script_name) { int err = 0; + int base; spin_lock_bh(&s->lock); if (!lunatik_stateget(s)) { @@ -263,11 +267,13 @@ static int dostring(char *code, lunatik_State *s, const char *script_name) goto out; } + base = lua_gettop(s->L); if ((err = luaU_dostring(s->L, code, s->scriptsize, script_name))) { pr_err("%s\n", lua_tostring(s->L, -1)); } lunatik_stateput(s); + lua_settop(s->L, base); out: kfree(s->code_buffer); @@ -299,7 +305,7 @@ static int lunatikN_dostring(struct sk_buff *buff, struct genl_info *info) } if (flags & LUNATIK_INIT) { - init_codebuffer(s, info); + init_codebuffer(s, info); } if (flags & LUNATIK_MULTI) { @@ -478,6 +484,7 @@ static int lunatikN_data(struct sk_buff *buff, struct genl_info *info) char *state_name; u32 payload_len; int err = 0; + int base; instance = lunatik_pernet(genl_info_net(info)); state_name = nla_data(info->attrs[STATE_NAME]); @@ -501,6 +508,7 @@ static int lunatikN_data(struct sk_buff *buff, struct genl_info *info) spin_lock_bh(&state->lock); + base = lua_gettop(state->L); lua_pushcfunction(state->L, handle_data); lua_pushlightuserdata(state->L, &data); if (luaU_pcall(state->L, 1, 0)) { @@ -511,6 +519,7 @@ static int lunatikN_data(struct sk_buff *buff, struct genl_info *info) unlock: spin_unlock_bh(&state->lock); + lua_settop(state->L, base); lunatik_stateput(state); err ? reply_with(OP_ERROR, DATA, info) : reply_with(OP_SUCESS, DATA, info); @@ -525,18 +534,50 @@ static int lunatikN_data(struct sk_buff *buff, struct genl_info *info) static int lunatikN_datainit(struct sk_buff *buff, struct genl_info *info) { struct lunatik_instance *instance; - char *name; - lunatik_State *state; instance = lunatik_pernet(genl_info_net(info)); - name = nla_data(info->attrs[STATE_NAME]); - state = lunatik_netstatelookup(instance, name); - state->genl_info = *info; + instance->usr_info = *info; + + return 0; +} + +int lunatikN_send_data(lunatik_State *s, const char *payload, size_t size) +{ + struct lunatik_instance instance; + struct sk_buff *obuff; + void *msg_head; + + if ((obuff = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL)) == NULL) { + pr_err("Failed allocating message to an reply\n"); + return 0; + } + + instance = s->instance; + if ((msg_head = genlmsg_put_reply(obuff, &(instance.usr_info), &lunatik_family, 0, DATA)) == NULL) { + pr_err("Failed to put generic netlink header\n"); + return 0; + } + + if (nla_put_string(obuff, LUNATIK_DATA, payload) || + nla_put_string(obuff, STATE_NAME, s->name) || + nla_put_u32(obuff, LUNATIK_DATA_LEN, size)) { + pr_err("Failed to put attributes on socket buffer\n"); + return 0; + } + + genlmsg_end(obuff, msg_head); + + if (genlmsg_reply(obuff, &(instance.usr_info)) < 0) { + pr_err("Failed to send message to user space\n"); + return 0; + } + + pr_debug("Message sent to user space\n"); return 0; } -/* Note: Most of the functions below are copied from NFLua: https://github.com/cujoai/nflua +/* Note: Most of the function below is copied from NFLua: https://github.com/cujoai/nflua * Copyright (C) 2017-2019 CUJO LLC * * This program is free software; you can redistribute it and/or modify diff --git a/netlink.h b/netlink.h index 4d27dbf73..71e413504 100644 --- a/netlink.h +++ b/netlink.h @@ -1,6 +1,9 @@ #ifndef NETLINK_H +#define NETLINK_H #include +#include "states.h" + extern struct genl_family lunatik_family; enum reply_buffer_status { diff --git a/states.c b/states.c index 3404e4838..caabe9b65 100644 --- a/states.c +++ b/states.c @@ -35,11 +35,13 @@ #endif /* LUNATIK_SETPAUSE */ extern int luaopen_memory(lua_State *); +extern int luaopen_netlink(lua_State *L); static struct lunatik_instance instance; static const luaL_Reg libs[] = { {"memory", luaopen_memory}, + {"netlink", luaopen_netlink}, {NULL, NULL} }; diff --git a/states.h b/states.h index d0e0cabbd..c0c2e590a 100644 --- a/states.h +++ b/states.h @@ -27,6 +27,7 @@ struct lunatik_instance { struct hlist_head states_table[LUNATIK_HASH_BUCKETS]; struct reply_buffer reply_buffer; + struct genl_info usr_info; spinlock_t statestable_lock; spinlock_t rfcnt_lock; spinlock_t sendmessage_lock; @@ -35,7 +36,7 @@ struct lunatik_instance { typedef struct lunatik_state { struct hlist_node node; - struct genl_info genl_info; + struct lunatik_instance instance; lua_State *L; char *code_buffer; int buffer_offset; From 9948f46ca3bac40712cce3b4e91a068432bb69ea Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Tue, 4 Aug 2020 16:42:24 -0300 Subject: [PATCH 17/48] Solve send to kernel bug --- netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netlink.c b/netlink.c index ec3c7ec43..42e055099 100644 --- a/netlink.c +++ b/netlink.c @@ -464,7 +464,7 @@ static int lunatikN_list(struct sk_buff *buff, struct genl_info *info) static int init_data(struct lunatik_data *data, char *buffer, size_t size) { - if ((data->buffer = kmalloc(sizeof(size), GFP_KERNEL)) == NULL) { + if ((data->buffer = kmalloc(size, GFP_KERNEL)) == NULL) { pr_err("Failed to allocate memory to data buffer\n"); return -1; } From ca465c127677cecf0e43bbe64ab9ce1fe02b8205 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Thu, 6 Aug 2020 18:32:47 -0300 Subject: [PATCH 18/48] Add user space API documentation --- doc/lib.md | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 doc/lib.md diff --git a/doc/lib.md b/doc/lib.md new file mode 100644 index 000000000..ac5e5a9e5 --- /dev/null +++ b/doc/lib.md @@ -0,0 +1,80 @@ +# User Space API documentation + +## Introduction + +This document provides the documentation of the user space API of Lunatik. This API is divided in two main features, being the control API and the data API, the first one is responsible to send messages to Lunatik kernel module to perform some operations, whereas the data API is responsible to exchange data between the kernel module and this user space API. + +## Control API + +Responsable to send messages to Lunatik kernel module perform some operations, these are: + * States creations + * States deletion + * States listing + * Code execution + +To use this API, first you must to include the lunatik module on your lua code, you can do this as follow: + +```lua +local lunatik = require'lunatik' +``` + +After that, you have to create a lunatik session. This session represents a connection between kernel and user space API. To do it, simple store the return of the function `lunatik.session()` for example: + +```lua +local lunatik = require'lunatik' +local session = lunatik.session() +``` + +Now you can use the variable session to do all operations related to control API. These operations you be showed next. + +#### `session:new(name [, maxalloc])` + +Tells the lunatik kernel module to create a state with the name `name`. If some value is passed to `maxalloc` that you be the maximum amount of memory that the state `name` can use during it execution, if no value is passed, a state with a default `maxalloc` will be created. If the state is succesfully created, the function returns a userdata, such userdata is used to perform all needed operations on that state. You can imagine this userdata as your user space representation of the state created on the kernel side. If the state creation fails, this function returns a `nil` value alongside with a error message. + +#### `session:list()` + +Returns a table with all states present on kernel. Each entry of that table is another table containing the following informations about the state: `name`, `curralloc` and `maxalloc`. `name` represents the state name, `curralloc` the amount of memory that the state `name` is using in that given moment (when the function `session:list()` was called) and `maxalloc` has the same meaning showed at [`session:new`](#sessionnewname--maxalloc). + +#### `session:close()` + +Closes the connection with the kernel, after that, all references for the states will be lost, so it's important to check if you don't have any states in use before close the connection with the kernel to avoid memory leaks. + +### State related operations + +As mentioned at [`session:new`](#sessionnewname--maxalloc) function, when you call that function, if the state is succesfully created, it will be returned a userdata. That userdata is used to perform all operations related to that state, for example: + +```lua +local mystate = session:new'somename' +``` + +This code will create a state named `somename` on kernel and store the userdata to perform all operations related to the state `somename` on the variable `mystate`. From now on, it will be used `mystate` to explain all operations that can be done at some state. + +#### `mystate:dostring(code [, codename])` + +Runs on the kernel, the code given by `code`, you can give a name for that code, this can be used for debug purposes, if something get wrong on the execution of the code, then the name present on `codename` will be showed at the stack trace. If no value is passed, the default value `'lua in kernel'` will be showed for all states that loaded code without a `codename`. + +#### `mystate:close()` + +Closes on the kernel the state that `mystate` represents. + +## Data API + +To transmit data from kernel to user space (and vice versa), we use lua memory (see [lua memory](https://github.com/luainkernel/lua-memory)). + +#### `mystate:send(memory)` + +Sends a [memory](https://github.com/luainkernel/lua-memory/blob/master/doc/manual.md#writable-byte-sequences) `memory` to the kernel state represented by `mystate`. + +In order to receive this memory on the kernel side you must to define a global function called `receive_callback` with one parameter which represents the memory which was sent from the user space. For example: + +```lua +function receive_callbakc(mem) + -- Here I can do whatever I want with mem +end +``` + +This callback will be called every time that a memory is received by the kernel. It's important to say that the module `memory` from lua memory is loaded by default in this version of Lunatik, thus you can do all supported operations with memory that Lua Memory offers. + +#### `session:receive(buffer)` + +Receives from some state the memory sent by it and stores this memory at memory buffer `buffer`. This function returns two values `recv` and `state`, representing the amount of bytes received and the state which sent the data respectively. From 723619b0e28b594c0bd13230cad715f11b8367f9 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Sat, 8 Aug 2020 21:50:55 +0000 Subject: [PATCH 19/48] Chage receive and send socket to state --- lib/lunatik.c | 117 +++++++++++++++++++++++++------------------ lib/lunatik.h | 25 +++++---- lib/lunatik_module.c | 30 ++++++++--- 3 files changed, 105 insertions(+), 67 deletions(-) diff --git a/lib/lunatik.c b/lib/lunatik.c index a075bfd35..599276448 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -32,7 +32,9 @@ #define MIN(x,y) ((x) < (y) ? (x) : (y)) -static struct nl_msg *prepare_message(struct lunatik_session *session, int command, int flags) +static int lunatik_family; + +static struct nl_msg *prepare_message(int command, int flags) { struct nl_msg *msg; @@ -41,7 +43,7 @@ static struct nl_msg *prepare_message(struct lunatik_session *session, int comma return NULL; } - if ((genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, session->family, + if ((genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, lunatik_family, 0, 0, command, LUNATIK_NLVERSION)) == NULL) { printf("Failed to put generic netlink message header\n"); return NULL; @@ -56,12 +58,12 @@ static struct nl_msg *prepare_message(struct lunatik_session *session, int comma return NULL; } -static int send_simple_msg(struct lunatik_session *session, int command, int flags) +static int send_simple_control_msg(struct lunatik_session *session, int command, int flags) { struct nl_msg *msg; int err = -1; - if ((msg = prepare_message(session, command, flags)) == NULL) { + if ((msg = prepare_message(command, flags)) == NULL) { printf("Error preparing message\n"); goto error; } @@ -85,7 +87,7 @@ static int send_fragment(struct lunatik_session *session, const char *original_s struct nl_msg *msg; char *fragment; int err = -1; - if ((msg = prepare_message(session, EXECUTE_CODE, 0)) == NULL){ + if ((msg = prepare_message(EXECUTE_CODE, 0)) == NULL){ nlmsg_free(msg); return err; } @@ -133,27 +135,31 @@ static int receive_op_result(struct lunatik_session *session){ nl_wait_for_ack(session->control_sock); - if (session->cb_result == CB_ERROR) + if (session->cb_result == CB_ERROR){ + session->cb_result = CB_EMPTY_RESULT; return -1; + } return 0; } -static int init_recv_datasocket(struct lunatik_session *session) +int init_recv_datasocket_on_kernel(struct lunatik_nl_state *state) { struct nl_msg *msg; int err = -1; - if ((msg = prepare_message(session, DATA_INIT, 0)) == NULL) { + if ((msg = prepare_message(DATA_INIT, 0)) == NULL) { printf("Error preparing message\n"); goto error; } - if ((err = nl_send_auto(session->recv_datasock, msg)) < 0) { + if ((err = nl_send_auto(state->recv_datasock, msg)) < 0) { printf("Failed sending message to kernel\n"); goto error; } + //TODO Receive a response from kernel + nlmsg_free(msg); return 0; @@ -167,7 +173,7 @@ int lunatikS_newstate(struct lunatik_session *session, struct lunatik_nl_state * struct nl_msg *msg; int ret = -1; - if ((msg = prepare_message(session, CREATE_STATE, 0)) == NULL) + if ((msg = prepare_message(CREATE_STATE, 0)) == NULL) return ret; NLA_PUT_STRING(msg, STATE_NAME, cmd->name); @@ -185,21 +191,27 @@ int lunatikS_newstate(struct lunatik_session *session, struct lunatik_nl_state * return ret; } -int lunatikS_closestate(struct lunatik_session *session, const char *name) +int lunatikS_closestate(struct lunatik_nl_state *state) { + struct lunatik_session *session; struct nl_msg *msg; int ret = -1; - if ((msg = prepare_message(session, DESTROY_STATE, 0)) == NULL) + session = state->session; + + if ((msg = prepare_message(DESTROY_STATE, 0)) == NULL) return ret; - NLA_PUT_STRING(msg, STATE_NAME, name); + NLA_PUT_STRING(msg, STATE_NAME, state->name); if ((ret = nl_send_auto(session->control_sock, msg)) < 0) { printf("Failed to send destroy message:\n %s\n", nl_geterror(ret)); return ret; } + nl_socket_free(state->send_datasock); + nl_socket_free(state->recv_datasock); + return receive_op_result(session); nla_put_failure: @@ -246,7 +258,7 @@ int lunatikS_list(struct lunatik_session *session) { int err = -1; - if ((err = send_simple_msg(session, LIST_STATES, 0))) + if ((err = send_simple_control_msg(session, LIST_STATES, 0))) return err; nl_recvmsgs_default(session->control_sock); @@ -256,7 +268,7 @@ int lunatikS_list(struct lunatik_session *session) return -1; while (session->status == SESSION_RECEIVING) { - send_simple_msg(session, LIST_STATES, 0); + send_simple_control_msg(session, LIST_STATES, 0); nl_recvmsgs_default(session->control_sock); nl_wait_for_ack(session->control_sock); } @@ -428,6 +440,7 @@ static int response_handler(struct nl_msg *msg, void *arg) static int data_handler(struct nl_msg *msg, void *arg) { +#ifndef _UNUSED // TODO Handle with messages received struct nlmsghdr *nh = nlmsg_hdr(msg); struct genlmsghdr *gnlh = genlmsg_hdr(nh); struct lunatik_session *session = (struct lunatik_session *) arg; @@ -449,10 +462,11 @@ static int data_handler(struct nl_msg *msg, void *arg) } else { printf("Some attributes are missing\n"); } +#endif return NL_OK; } -int init_socket(struct nl_sock **socket, struct lunatik_session *session) +int init_socket(struct nl_sock **socket) { int err = -1; if ((*socket = nl_socket_alloc()) == NULL) @@ -461,8 +475,8 @@ int init_socket(struct nl_sock **socket, struct lunatik_session *session) if ((err = genl_connect(*socket))) return err; - if ((session->family = genl_ctrl_resolve(*socket, LUNATIK_FAMILY)) < 0) - return session->family; + if ((lunatik_family = genl_ctrl_resolve(*socket, LUNATIK_FAMILY)) < 0) + return lunatik_family; return 0; } @@ -474,33 +488,14 @@ int lunatikS_init(struct lunatik_session *session) if (session == NULL) return -EINVAL; - if ((err = init_socket(&session->control_sock, session))) { + if ((err = init_socket(&session->control_sock))) { printf("Failed to initialize control socket\n"); nl_socket_free(session->control_sock); return err; } - if ((err = init_socket(&session->send_datasock, session))) { - printf("Failed to initialize send data socket\n"); - nl_socket_free(session->send_datasock); - return err; - } - - if ((err = init_socket(&session->recv_datasock, session))) { - printf("Failed to initialize recv data socket\n"); - nl_socket_free(session->recv_datasock); - return err; - } - nl_socket_modify_cb(session->control_sock, NL_CB_MSG_IN, NL_CB_CUSTOM, response_handler, session); - nl_socket_modify_cb(session->send_datasock, NL_CB_MSG_IN, NL_CB_CUSTOM, response_handler, session); - nl_socket_modify_cb(session->recv_datasock, NL_CB_MSG_IN, NL_CB_CUSTOM, data_handler, session); - nl_socket_disable_seq_check(session->recv_datasock); - nl_socket_disable_auto_ack(session->recv_datasock); session->control_fd = nl_socket_get_fd(session->control_sock); - session->data_fd = nl_socket_get_fd(session->recv_datasock); - - init_recv_datasocket(session); return 0; } @@ -509,17 +504,13 @@ void lunatikS_close(struct lunatik_session *session) { if (session != NULL){ nl_socket_free(session->control_sock); - nl_socket_free(session->send_datasock); - nl_socket_free(session->recv_datasock); session->control_fd = -1; - session->data_fd = -1; } } int lunatik_datasend(struct lunatik_nl_state *state, const char *payload, size_t len) { - struct nl_msg *msg = prepare_message(state->session, DATA, 0); - struct lunatik_session *session = state->session; + struct nl_msg *msg = prepare_message(DATA, 0); int err = 0; if (msg == NULL) @@ -529,14 +520,14 @@ int lunatik_datasend(struct lunatik_nl_state *state, const char *payload, size_t NLA_PUT_STRING(msg, STATE_NAME, state->name); NLA_PUT_U32(msg, LUNATIK_DATA_LEN, len); - if ((err = nl_send_auto(session->send_datasock, msg)) < 0) { + if ((err = nl_send_auto(state->send_datasock, msg)) < 0) { printf("Failed sending message to kernel\n"); nlmsg_free(msg); return err; } - nl_recvmsgs_default(session->send_datasock); - nl_wait_for_ack(session->send_datasock); + nl_recvmsgs_default(state->send_datasock); + nl_wait_for_ack(state->send_datasock); nlmsg_free(msg); return 0; @@ -566,13 +557,13 @@ int release_data_buffer(struct data_buffer *data_buffer) return 0; } -int lunatikS_receive(struct lunatik_session *session, char *state, char *buffer) +int lunatikS_receive(struct lunatik_nl_state *state, char *buffer) { - struct data_buffer *data_buffer = &session->data_buffer; + struct data_buffer *data_buffer = &state->data_buffer; int received_data; init_data_buffer(data_buffer, LUNATIK_FRAGMENT_SIZE); - nl_recvmsgs_default(session->recv_datasock); + nl_recvmsgs_default(state->recv_datasock); memcpy(buffer, data_buffer->buffer, data_buffer->size); strcpy(state, data_buffer->state_name); @@ -581,3 +572,31 @@ int lunatikS_receive(struct lunatik_session *session, char *state, char *buffer) release_data_buffer(data_buffer); return received_data; } + +int lunatikS_initdata(struct lunatik_nl_state *state) +{ + int ret = 0; + + if ((ret = init_socket(&state->send_datasock))) { + printf("Failed to initialize the send socket\n"); + nl_socket_free(state->send_datasock); + return ret; + } + + if ((ret = init_socket(&state->recv_datasock))) { + printf("Failed to initialize the recv socket\n"); + nl_socket_free(state->recv_datasock); + return ret; + } + + if ((ret = init_recv_datasocket_on_kernel(state))) { + printf("Failed to initialize receive socket on kernel\n"); + nl_socket_free(state->recv_datasock); + return ret; + } + + nl_socket_modify_cb(state->send_datasock, NL_CB_MSG_IN, NL_CB_CUSTOM, response_handler, NULL); + nl_socket_modify_cb(state->recv_datasock, NL_CB_MSG_IN, NL_CB_CUSTOM, data_handler, state); + + return 0; +} diff --git a/lib/lunatik.h b/lib/lunatik.h index b6a59118d..5a89b79f5 100644 --- a/lib/lunatik.h +++ b/lib/lunatik.h @@ -29,6 +29,7 @@ enum callback_result { CB_SUCCESS, CB_ERROR, + CB_EMPTY_RESULT, CB_LIST_EMPTY, }; @@ -37,8 +38,17 @@ enum session_status { SESSION_RECEIVING, }; +struct data_buffer { + char *buffer; + char state_name[LUNATIK_NAME_MAXSIZE]; + int size; +}; + struct lunatik_nl_state { struct lunatik_session *session; + struct nl_sock *send_datasock; + struct nl_sock *recv_datasock; + struct data_buffer data_buffer; uint32_t maxalloc; uint32_t curralloc; char name[LUNATIK_NAME_MAXSIZE]; @@ -54,19 +64,10 @@ struct received_buffer { int cursor; }; -struct data_buffer { - char *buffer; - char state_name[LUNATIK_NAME_MAXSIZE]; - int size; -}; - struct lunatik_session { struct nl_sock *control_sock; - struct nl_sock *send_datasock; - struct nl_sock *recv_datasock; struct states_list states_list; struct received_buffer recv_buffer; - struct data_buffer data_buffer; enum session_status status; enum callback_result cb_result; int family; @@ -101,14 +102,16 @@ void lunatikS_close(struct lunatik_session *session); int lunatikS_newstate(struct lunatik_session *session, struct lunatik_nl_state *s); -int lunatikS_closestate(struct lunatik_session *session, const char *name); +int lunatikS_closestate(struct lunatik_nl_state *state); int lunatikS_dostring(struct lunatik_session *session, const char *state_name, const char *script, const char *script_name, size_t total_code_size); int lunatikS_list(struct lunatik_session *session); -int lunatikS_receive(struct lunatik_session *session, char *state, char *buffer); +int lunatikS_receive(struct lunatik_nl_state *state, char *buffer); + +int lunatikS_initdata(struct lunatik_nl_state *state); #ifndef _UNUSED static inline int nflua_data_getsock(const struct nflua_data *dch) diff --git a/lib/lunatik_module.c b/lib/lunatik_module.c index 4aae122db..b359ba780 100644 --- a/lib/lunatik_module.c +++ b/lib/lunatik_module.c @@ -34,6 +34,9 @@ extern int luaopen_memory(lua_State *L); #define DEFAULT_MAXALLOC_BYTES (32 * 1024) +extern int init_socket(struct nl_sock **socket); +extern int init_recv_datasocket_on_kernel(struct lunatik_nl_state *state); + static int pusherrmsg(lua_State *L, const char *msg) { lua_pushnil(L); @@ -145,9 +148,9 @@ static int lsession_newstate(lua_State *L) static int lstate_close(lua_State *L) { - struct lunatik_nl_state *s = getnlstate(L); - if (lunatikS_closestate(s->session, s->name)){ - lua_pushboolean(L, false); + struct lunatik_nl_state *state = getnlstate(L); + if (lunatikS_closestate(state)){ + lua_pushnil(L); return 1; } @@ -285,6 +288,19 @@ static int ldata_getpid(lua_State *L) } #endif /* _UNUSED */ +static int lstate_initdata(lua_State *L) +{ + struct lunatik_nl_state *state = getnlstate(L); + + if (lunatikS_initdata(state)) { + lua_pushnil(L); + return 1; + } + + lua_pushboolean(L, true); + return 1; +} + static int lstate_datasend(lua_State *L) { struct lunatik_nl_state *state = getnlstate(L); @@ -302,8 +318,7 @@ static int lstate_datasend(lua_State *L) static int lsession_datareceive(lua_State *L) { - struct lunatik_session *session = getsession(L); - char state[LUNATIK_NAME_MAXSIZE] = {0}; + struct lunatik_nl_state *state = getnlstate(L); size_t size, offset; int recv; char *buffer = luamem_checkmemory(L, 2, &size); @@ -314,11 +329,11 @@ static int lsession_datareceive(lua_State *L) if (offset >= size || size - offset < LUNATIK_FRAGMENT_SIZE) luaL_argerror(L, 2, "not enough space in buffer"); - recv = lunatikS_receive(session, state, buffer); + recv = lunatikS_receive(state, buffer); if (recv < 0) return pusherrno(L, recv); lua_pushinteger(L, recv); - lua_pushstring(L, state); + lua_pushstring(L, state->name); return 2; } @@ -339,6 +354,7 @@ static const luaL_Reg state_mt[] = { {"getmaxalloc", lstate_getmaxalloc}, {"close", lstate_close}, {"send", lstate_datasend}, + {"initdata", lstate_initdata}, {NULL, NULL} }; From 7c2bfaa493c321f40a3896bb36e5d302b4457b88 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Sat, 8 Aug 2020 23:34:47 +0000 Subject: [PATCH 20/48] Adapt messages sent to kernel --- lib/lunatik.c | 37 +++++++++++++++++++++++++++++++++++-- lib/lunatik.h | 1 + lib/lunatik_module.c | 4 ++-- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/lib/lunatik.c b/lib/lunatik.c index 599276448..469a3ff7d 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -368,6 +368,30 @@ static int append_recv_buffer(struct lunatik_session *session, struct nlattr **a return 0; } +static int send_data_cb_handler(struct nl_msg *msg, void *arg) +{ + struct nlmsghdr *nh = nlmsg_hdr(msg); + struct genlmsghdr *gnlh = genlmsg_hdr(nh); + struct nlattr * attrs_tb[ATTRS_COUNT + 1]; + struct lunatik_nl_state *state = (struct lunatik_nl_state *)arg; + + if (nla_parse(attrs_tb, ATTRS_COUNT, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL)) + { + printf("Error parsing attributes\n"); + state->cb_result = CB_ERROR; + return NL_OK; + } + + if (attrs_tb[OP_SUCESS] && nla_get_u8(attrs_tb[OP_SUCESS])) { + state->cb_result = CB_SUCCESS; + } else if (attrs_tb[OP_ERROR] && nla_get_u8(attrs_tb[OP_ERROR])) { + state->cb_result = CB_ERROR; + } + + return NL_OK; +} + static int response_handler(struct nl_msg *msg, void *arg) { struct nlmsghdr *nh = nlmsg_hdr(msg); @@ -388,7 +412,6 @@ static int response_handler(struct nl_msg *msg, void *arg) { case CREATE_STATE: case DESTROY_STATE: - case DATA: case EXECUTE_CODE: if (attrs_tb[OP_SUCESS] && nla_get_u8(attrs_tb[OP_SUCESS])) { session->cb_result = CB_SUCCESS; @@ -516,6 +539,11 @@ int lunatik_datasend(struct lunatik_nl_state *state, const char *payload, size_t if (msg == NULL) return -1; + if (state->send_datasock == NULL) { + printf("There is no socket available to send a message from this state, did you initialize the data for this state?\n"); + return -1; + } + NLA_PUT_STRING(msg, LUNATIK_DATA, payload); NLA_PUT_STRING(msg, STATE_NAME, state->name); NLA_PUT_U32(msg, LUNATIK_DATA_LEN, len); @@ -530,6 +558,11 @@ int lunatik_datasend(struct lunatik_nl_state *state, const char *payload, size_t nl_wait_for_ack(state->send_datasock); nlmsg_free(msg); + if (state->cb_result == CB_ERROR) { + state->cb_result = CB_EMPTY_RESULT; + return -1; + } + return 0; nla_put_failure: @@ -595,7 +628,7 @@ int lunatikS_initdata(struct lunatik_nl_state *state) return ret; } - nl_socket_modify_cb(state->send_datasock, NL_CB_MSG_IN, NL_CB_CUSTOM, response_handler, NULL); + nl_socket_modify_cb(state->send_datasock, NL_CB_MSG_IN, NL_CB_CUSTOM, send_data_cb_handler, state); nl_socket_modify_cb(state->recv_datasock, NL_CB_MSG_IN, NL_CB_CUSTOM, data_handler, state); return 0; diff --git a/lib/lunatik.h b/lib/lunatik.h index 5a89b79f5..02b75d9d2 100644 --- a/lib/lunatik.h +++ b/lib/lunatik.h @@ -49,6 +49,7 @@ struct lunatik_nl_state { struct nl_sock *send_datasock; struct nl_sock *recv_datasock; struct data_buffer data_buffer; + enum callback_result cb_result; uint32_t maxalloc; uint32_t curralloc; char name[LUNATIK_NAME_MAXSIZE]; diff --git a/lib/lunatik_module.c b/lib/lunatik_module.c index b359ba780..52d6f2262 100644 --- a/lib/lunatik_module.c +++ b/lib/lunatik_module.c @@ -176,11 +176,11 @@ static int lstate_dostring(lua_State *L) if (status) goto error; - lua_pushnil(L); + lua_pushboolean(L, true); return 1; error: - lua_pushboolean(L, true); + lua_pushnil(L); return 1; } From 9ef722254639885a70fbc69e093fd98873cc63ce Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Sun, 9 Aug 2020 19:17:48 +0000 Subject: [PATCH 21/48] Adapt received data from kernel --- lib/lunatik.c | 81 ++++++++++++++++++++++++++++++-------------- lib/lunatik.h | 3 +- lib/lunatik_module.c | 47 +++++++++++-------------- netlink.c | 24 ++++++++----- states.h | 2 +- 5 files changed, 93 insertions(+), 64 deletions(-) diff --git a/lib/lunatik.c b/lib/lunatik.c index 469a3ff7d..0cd4fefbb 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -153,19 +153,32 @@ int init_recv_datasocket_on_kernel(struct lunatik_nl_state *state) goto error; } + NLA_PUT_STRING(msg, STATE_NAME, state->name); + if ((err = nl_send_auto(state->recv_datasock, msg)) < 0) { printf("Failed sending message to kernel\n"); goto error; } - //TODO Receive a response from kernel + nl_recvmsgs_default(state->recv_datasock); + nl_wait_for_ack(state->recv_datasock); + + if (state->cb_result == CB_ERROR) { + state->cb_result = CB_EMPTY_RESULT; + goto error; + } nlmsg_free(msg); + return 0; error: nlmsg_free(msg); return err; + +nla_put_failure: + printf("Failed to put attributes on to initialize data socket on kernel side\n"); + return err; } int lunatikS_newstate(struct lunatik_session *session, struct lunatik_nl_state *cmd) @@ -461,31 +474,51 @@ static int response_handler(struct nl_msg *msg, void *arg) return NL_OK; } +static int init_data_buffer(struct data_buffer *data_buffer, size_t size); + static int data_handler(struct nl_msg *msg, void *arg) { -#ifndef _UNUSED // TODO Handle with messages received struct nlmsghdr *nh = nlmsg_hdr(msg); struct genlmsghdr *gnlh = genlmsg_hdr(nh); - struct lunatik_session *session = (struct lunatik_session *) arg; - struct data_buffer *data_buffer = &session->data_buffer; + struct lunatik_nl_state *state = (struct lunatik_nl_state *) arg; + struct data_buffer *data_buffer = &state->data_buffer; struct nlattr *attrs_tb[ATTRS_COUNT + 1]; + char *payload; + size_t payload_size; + int err; if (nla_parse(attrs_tb, ATTRS_COUNT, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL)) { printf("Error parsing attributes\n"); - session->cb_result = CB_ERROR; + state->cb_result = CB_ERROR; return NL_OK; } - if (attrs_tb[LUNATIK_DATA] && attrs_tb[LUNATIK_DATA_LEN] && attrs_tb[STATE_NAME]) { - strcpy(data_buffer->buffer, nla_get_string(attrs_tb[LUNATIK_DATA])); - strcpy(data_buffer->state_name, nla_get_string(attrs_tb[STATE_NAME])); - data_buffer->size = nla_get_u32(attrs_tb[LUNATIK_DATA_LEN]); - } else { - printf("Some attributes are missing\n"); + if (attrs_tb[OP_SUCESS]) { + state->cb_result = CB_SUCCESS; + return NL_OK; + } + + if (attrs_tb[OP_ERROR]) { + state->cb_result = CB_ERROR; + return NL_OK; } -#endif + + if (attrs_tb[LUNATIK_DATA] && attrs_tb[LUNATIK_DATA_LEN]) { + payload = nla_get_string(attrs_tb[LUNATIK_DATA]); + payload_size = nla_get_u32(attrs_tb[LUNATIK_DATA_LEN]); + + err = init_data_buffer(&state->data_buffer, payload_size); + if (err) { + state->cb_result = CB_ERROR; + return NL_OK; + } + + memcpy(data_buffer->buffer, payload, payload_size); + data_buffer->size = payload_size; + } + return NL_OK; } @@ -571,7 +604,7 @@ int lunatik_datasend(struct lunatik_nl_state *state, const char *payload, size_t return -1; } -int init_data_buffer(struct data_buffer *data_buffer, size_t size) +static int init_data_buffer(struct data_buffer *data_buffer, size_t size) { if ((data_buffer->buffer = malloc(size)) == NULL) { printf("Failed to allocate memory to data buffer\n"); @@ -582,28 +615,24 @@ int init_data_buffer(struct data_buffer *data_buffer, size_t size) return 0; } -int release_data_buffer(struct data_buffer *data_buffer) +void release_data_buffer(struct data_buffer *data_buffer) { free(data_buffer->buffer); data_buffer->size = 0; - memset(data_buffer->state_name, 0, LUNATIK_NAME_MAXSIZE); - return 0; } -int lunatikS_receive(struct lunatik_nl_state *state, char *buffer) +int lunatikS_receive(struct lunatik_nl_state *state) { - struct data_buffer *data_buffer = &state->data_buffer; - int received_data; + int err = 0; - init_data_buffer(data_buffer, LUNATIK_FRAGMENT_SIZE); nl_recvmsgs_default(state->recv_datasock); - memcpy(buffer, data_buffer->buffer, data_buffer->size); - strcpy(state, data_buffer->state_name); - received_data = data_buffer->size; + if (state->cb_result == CB_ERROR) { + state->cb_result = CB_EMPTY_RESULT; + err = -1; + } - release_data_buffer(data_buffer); - return received_data; + return err; } int lunatikS_initdata(struct lunatik_nl_state *state) @@ -630,6 +659,8 @@ int lunatikS_initdata(struct lunatik_nl_state *state) nl_socket_modify_cb(state->send_datasock, NL_CB_MSG_IN, NL_CB_CUSTOM, send_data_cb_handler, state); nl_socket_modify_cb(state->recv_datasock, NL_CB_MSG_IN, NL_CB_CUSTOM, data_handler, state); + nl_socket_disable_seq_check(state->recv_datasock); + nl_socket_disable_auto_ack(state->recv_datasock); return 0; } diff --git a/lib/lunatik.h b/lib/lunatik.h index 02b75d9d2..353f7176b 100644 --- a/lib/lunatik.h +++ b/lib/lunatik.h @@ -40,7 +40,6 @@ enum session_status { struct data_buffer { char *buffer; - char state_name[LUNATIK_NAME_MAXSIZE]; int size; }; @@ -110,7 +109,7 @@ int lunatikS_dostring(struct lunatik_session *session, const char *state_name, int lunatikS_list(struct lunatik_session *session); -int lunatikS_receive(struct lunatik_nl_state *state, char *buffer); +int lunatikS_receive(struct lunatik_nl_state *state); int lunatikS_initdata(struct lunatik_nl_state *state); diff --git a/lib/lunatik_module.c b/lib/lunatik_module.c index 52d6f2262..a87956216 100644 --- a/lib/lunatik_module.c +++ b/lib/lunatik_module.c @@ -141,6 +141,11 @@ static int lsession_newstate(lua_State *L) return 2; } + if (lunatikS_initdata(state)) { + lua_pushnil(L); + return 1; + } + luaL_setmetatable(L, "states.control"); return 1; @@ -288,19 +293,6 @@ static int ldata_getpid(lua_State *L) } #endif /* _UNUSED */ -static int lstate_initdata(lua_State *L) -{ - struct lunatik_nl_state *state = getnlstate(L); - - if (lunatikS_initdata(state)) { - lua_pushnil(L); - return 1; - } - - lua_pushboolean(L, true); - return 1; -} - static int lstate_datasend(lua_State *L) { struct lunatik_nl_state *state = getnlstate(L); @@ -316,26 +308,26 @@ static int lstate_datasend(lua_State *L) return 1; } -static int lsession_datareceive(lua_State *L) +extern void release_data_buffer(struct data_buffer *data_buffer); + +static int lstate_datareceive(lua_State *L) { struct lunatik_nl_state *state = getnlstate(L); - size_t size, offset; - int recv; - char *buffer = luamem_checkmemory(L, 2, &size); + char *memory; - if (buffer == NULL) luaL_argerror(L, 2, "expected non NULL memory object"); + if (lunatikS_receive(state)) + goto error; - offset = luaL_checkinteger(L, 3); - if (offset >= size || size - offset < LUNATIK_FRAGMENT_SIZE) - luaL_argerror(L, 2, "not enough space in buffer"); + memory = luamem_newalloc(L, state->data_buffer.size); + memcpy(memory, state->data_buffer.buffer, state->data_buffer.size); - recv = lunatikS_receive(state, buffer); - if (recv < 0) return pusherrno(L, recv); + release_data_buffer(&state->data_buffer); - lua_pushinteger(L, recv); - lua_pushstring(L, state->name); + return 1; - return 2; +error: + lua_pushnil(L); + return 1; } static const luaL_Reg session_mt[] = { @@ -343,7 +335,6 @@ static const luaL_Reg session_mt[] = { {"getfd", lsession_getfd}, {"new", lsession_newstate}, {"list", lsession_list}, - {"receive", lsession_datareceive}, {"__gc", lsession_gc}, {NULL, NULL} }; @@ -354,7 +345,7 @@ static const luaL_Reg state_mt[] = { {"getmaxalloc", lstate_getmaxalloc}, {"close", lstate_close}, {"send", lstate_datasend}, - {"initdata", lstate_initdata}, + {"receive", lstate_datareceive}, {NULL, NULL} }; diff --git a/netlink.c b/netlink.c index 42e055099..379d23cbb 100644 --- a/netlink.c +++ b/netlink.c @@ -534,16 +534,27 @@ static int lunatikN_data(struct sk_buff *buff, struct genl_info *info) static int lunatikN_datainit(struct sk_buff *buff, struct genl_info *info) { struct lunatik_instance *instance; + lunatik_State *state; + char *name; instance = lunatik_pernet(genl_info_net(info)); - instance->usr_info = *info; + name = nla_data(info->attrs[STATE_NAME]); + + if ((state = lunatik_netstatelookup(instance, name)) == NULL) { + pr_err("Failed to find the state %s\n", name); + reply_with(OP_ERROR, DATA_INIT, info); + return 0; + } + + state->usr_state_info = *info; + + reply_with(OP_SUCESS, DATA_INIT, info); return 0; } -int lunatikN_send_data(lunatik_State *s, const char *payload, size_t size) +int lunatikN_send_data(lunatik_State *state, const char *payload, size_t size) { - struct lunatik_instance instance; struct sk_buff *obuff; void *msg_head; @@ -552,15 +563,12 @@ int lunatikN_send_data(lunatik_State *s, const char *payload, size_t size) return 0; } - instance = s->instance; - - if ((msg_head = genlmsg_put_reply(obuff, &(instance.usr_info), &lunatik_family, 0, DATA)) == NULL) { + if ((msg_head = genlmsg_put_reply(obuff, &state->usr_state_info, &lunatik_family, 0, DATA)) == NULL) { pr_err("Failed to put generic netlink header\n"); return 0; } if (nla_put_string(obuff, LUNATIK_DATA, payload) || - nla_put_string(obuff, STATE_NAME, s->name) || nla_put_u32(obuff, LUNATIK_DATA_LEN, size)) { pr_err("Failed to put attributes on socket buffer\n"); return 0; @@ -568,7 +576,7 @@ int lunatikN_send_data(lunatik_State *s, const char *payload, size_t size) genlmsg_end(obuff, msg_head); - if (genlmsg_reply(obuff, &(instance.usr_info)) < 0) { + if (genlmsg_reply(obuff, &state->usr_state_info) < 0) { pr_err("Failed to send message to user space\n"); return 0; } diff --git a/states.h b/states.h index c0c2e590a..e3c9d2039 100644 --- a/states.h +++ b/states.h @@ -27,7 +27,6 @@ struct lunatik_instance { struct hlist_head states_table[LUNATIK_HASH_BUCKETS]; struct reply_buffer reply_buffer; - struct genl_info usr_info; spinlock_t statestable_lock; spinlock_t rfcnt_lock; spinlock_t sendmessage_lock; @@ -37,6 +36,7 @@ struct lunatik_instance { typedef struct lunatik_state { struct hlist_node node; struct lunatik_instance instance; + struct genl_info usr_state_info; lua_State *L; char *code_buffer; int buffer_offset; From 20eecdb850ac80e644eec1f7d2311e3e669bc46b Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Mon, 10 Aug 2020 19:16:16 +0000 Subject: [PATCH 22/48] Update documentation --- doc/lib.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/lib.md b/doc/lib.md index ac5e5a9e5..c5d50226c 100644 --- a/doc/lib.md +++ b/doc/lib.md @@ -25,7 +25,7 @@ local lunatik = require'lunatik' local session = lunatik.session() ``` -Now you can use the variable session to do all operations related to control API. These operations you be showed next. +Now you can use the variable `session` to do all operations related to control API. These operations will be showed next. #### `session:new(name [, maxalloc])` @@ -47,7 +47,7 @@ As mentioned at [`session:new`](#sessionnewname--maxalloc) function, when you ca local mystate = session:new'somename' ``` -This code will create a state named `somename` on kernel and store the userdata to perform all operations related to the state `somename` on the variable `mystate`. From now on, it will be used `mystate` to explain all operations that can be done at some state. +This code will create a state named `somename` on kernel and store the userdata to perform all operations related to the state `somename` on the variable `mystate`. From now on, it will be used `mystate` to explain all operations that can be done at that state. #### `mystate:dostring(code [, codename])` @@ -68,13 +68,13 @@ Sends a [memory](https://github.com/luainkernel/lua-memory/blob/master/doc/manua In order to receive this memory on the kernel side you must to define a global function called `receive_callback` with one parameter which represents the memory which was sent from the user space. For example: ```lua -function receive_callbakc(mem) +function receive_callback(mem) -- Here I can do whatever I want with mem end ``` This callback will be called every time that a memory is received by the kernel. It's important to say that the module `memory` from lua memory is loaded by default in this version of Lunatik, thus you can do all supported operations with memory that Lua Memory offers. -#### `session:receive(buffer)` +#### `mystate:receive()` -Receives from some state the memory sent by it and stores this memory at memory buffer `buffer`. This function returns two values `recv` and `state`, representing the amount of bytes received and the state which sent the data respectively. +Receives from the state represented by `mystate` the data sent from kernel and return a [memory](https://github.com/luainkernel/lua-memory/blob/master/doc/manual.md#writable-byte-sequences) to manipulate the data sent by kernel. If no data is available to be received, this function blocks until receive some data. From 0027028b9d4f4f425beb674ac799b2d31273665e Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Tue, 11 Aug 2020 14:00:56 +0000 Subject: [PATCH 23/48] Add get state functionality --- lib/lunatik.c | 59 +++++++++++++++++++++++++++++++++++ lib/lunatik.h | 3 ++ lib/lunatik_module.c | 21 +++++++++++++ netlink.c | 74 ++++++++++++++++++++++++++++++++++++++++++-- netlink_common.h | 4 ++- 5 files changed, 157 insertions(+), 4 deletions(-) diff --git a/lib/lunatik.c b/lib/lunatik.c index 0cd4fefbb..87e87112c 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -405,6 +405,41 @@ static int send_data_cb_handler(struct nl_msg *msg, void *arg) return NL_OK; } +int init_socket(struct nl_sock**); + +static int get_state_handler(struct lunatik_session *session, struct nlattr **attrs_tb) +{ + char *name; + + if (!(attrs_tb[STATE_NAME] || attrs_tb[CURR_ALLOC] || attrs_tb[MAX_ALLOC])) { + printf("Some attributes are missing\n"); + return -1; + } + + name = nla_get_string(attrs_tb[STATE_NAME]); + + strcpy(session->state_holder.name, name); + session->state_holder.curralloc = nla_get_u32(attrs_tb[CURR_ALLOC]); + session->state_holder.maxalloc = nla_get_u32(attrs_tb[MAX_ALLOC]); + session->state_holder.session = session; + + if (init_socket(&(session->state_holder.recv_datasock))) { + printf("Failed to initialize recv data socket\n"); + nl_socket_free(session->state_holder.recv_datasock); + return -1; + } + + if (init_socket(&(session->state_holder.send_datasock))) { + printf("Failed to initialize send data socket\n"); + nl_socket_free(session->state_holder.send_datasock); + return -1; + } + + init_recv_datasocket_on_kernel(&session->state_holder); + + return 0; +} + static int response_handler(struct nl_msg *msg, void *arg) { struct nlmsghdr *nh = nlmsg_hdr(msg); @@ -467,6 +502,9 @@ static int response_handler(struct nl_msg *msg, void *arg) session->cb_result = CB_ERROR; break; + case GET_STATE: + if (get_state_handler(session, attrs_tb)) + session->cb_result = CB_ERROR; default: break; } @@ -664,3 +702,24 @@ int lunatikS_initdata(struct lunatik_nl_state *state) return 0; } + +struct lunatik_nl_state *lunatikS_getstate(struct lunatik_session *session, const char *name) +{ + struct nl_msg *msg = prepare_message(GET_STATE, 0); + + NLA_PUT_STRING(msg, STATE_NAME, name); + + if (nl_send_auto(session->control_sock, msg) < 0) { + printf("Failed to send message to kernel\n"); + return NULL; + } + + if (receive_op_result(session)) + return NULL; + + return &session->state_holder; + +nla_put_failure: + printf("Failed to put attributes on netlink message\n"); + return NULL; +} diff --git a/lib/lunatik.h b/lib/lunatik.h index 353f7176b..3255861ee 100644 --- a/lib/lunatik.h +++ b/lib/lunatik.h @@ -68,6 +68,7 @@ struct lunatik_session { struct nl_sock *control_sock; struct states_list states_list; struct received_buffer recv_buffer; + struct lunatik_nl_state state_holder; enum session_status status; enum callback_result cb_result; int family; @@ -113,6 +114,8 @@ int lunatikS_receive(struct lunatik_nl_state *state); int lunatikS_initdata(struct lunatik_nl_state *state); +struct lunatik_nl_state *lunatikS_getstate(struct lunatik_session *session, const char *name); + #ifndef _UNUSED static inline int nflua_data_getsock(const struct nflua_data *dch) { diff --git a/lib/lunatik_module.c b/lib/lunatik_module.c index a87956216..228608a77 100644 --- a/lib/lunatik_module.c +++ b/lib/lunatik_module.c @@ -227,6 +227,26 @@ static int lsession_list(lua_State *L) return 1; } +static int lsession_getstate(lua_State *L) +{ + struct lunatik_session *session = getsession(L); + struct lunatik_nl_state *state = lua_newuserdata(L, sizeof(struct lunatik_nl_state)); + struct lunatik_nl_state *received_state; + const char *name; + + name = luaL_checkstring(L, 2); + + if ((received_state = lunatikS_getstate(session, name)) == NULL) { + lua_pushnil(L); + return 1; + } + + *state = *received_state; + luaL_setmetatable(L, "states.control"); + + return 1; +} + static void buildlist(lua_State *L, struct lunatik_nl_state *states, size_t n) { size_t i; @@ -335,6 +355,7 @@ static const luaL_Reg session_mt[] = { {"getfd", lsession_getfd}, {"new", lsession_newstate}, {"list", lsession_list}, + {"getstate", lsession_getstate}, {"__gc", lsession_gc}, {NULL, NULL} }; diff --git a/netlink.c b/netlink.c index 379d23cbb..1f755add3 100644 --- a/netlink.c +++ b/netlink.c @@ -49,19 +49,21 @@ static int lunatikN_close(struct sk_buff *buff, struct genl_info *info); static int lunatikN_list(struct sk_buff *buff, struct genl_info *info); static int lunatikN_data(struct sk_buff *buff, struct genl_info *info); static int lunatikN_datainit(struct sk_buff *buff, struct genl_info *info); +static int lunatikN_sendstate(struct sk_buff *buff, struct genl_info *info); struct nla_policy lunatik_policy[ATTRS_COUNT] = { [STATE_NAME] = { .type = NLA_STRING }, - [CODE] = { .type = NLA_STRING }, + [CODE] = { .type = NLA_STRING }, [SCRIPT_NAME] = { .type = NLA_STRING }, [STATES_LIST] = { .type = NLA_STRING }, [LUNATIK_DATA]= { .type = NLA_STRING }, [LUNATIK_DATA_LEN] = { .type = NLA_U32}, [SCRIPT_SIZE] = { .type = NLA_U32 }, [MAX_ALLOC] = { .type = NLA_U32 }, - [FLAGS] = { .type = NLA_U8 }, + [CURR_ALLOC] = { .type = NLA_U32}, + [FLAGS] = { .type = NLA_U8 }, [OP_SUCESS] = { .type = NLA_U8 }, - [OP_ERROR] = { .type = NLA_U8 }, + [OP_ERROR] = { .type = NLA_U8 }, }; static const struct genl_ops l_ops[] = { @@ -111,6 +113,14 @@ static const struct genl_ops l_ops[] = { #if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) /*Before kernel 5.2.0, each operation has its own policy*/ .policy = lunatik_policy +#endif + }, + { + .cmd = GET_STATE, + .doit = lunatikN_sendstate, +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) + /*Before kernel 5.2.0, each operation has its own policy*/ + .policy = lunatik_policy #endif } }; @@ -585,6 +595,64 @@ int lunatikN_send_data(lunatik_State *state, const char *payload, size_t size) return 0; } +static int sendstate_msg(lunatik_State *state, struct genl_info *info) +{ + struct sk_buff *obuff; + void *msg_head; + + if ((obuff = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL)) == NULL) { + pr_err("Failed allocating message to an reply\n"); + return -1; + } + + if ((msg_head = genlmsg_put_reply(obuff, info, &lunatik_family, 0, GET_STATE)) == NULL) { + pr_err("Failed to put generic netlink header\n"); + return -1; + } + + if (nla_put_string(obuff, STATE_NAME, state->name) || + nla_put_u32(obuff, MAX_ALLOC, state->maxalloc) || + nla_put_u32(obuff, CURR_ALLOC, state->curralloc)) { + pr_err("Failed to put attributes on socket buffer\n"); + return -1; + } + + genlmsg_end(obuff, msg_head); + + if (genlmsg_reply(obuff, info) < 0) { + pr_err("Failed to send message to user space\n"); + return -1; + } + + pr_debug("Message sent to user space\n"); + return 0; +} + +static int lunatikN_sendstate(struct sk_buff *buff, struct genl_info *info) +{ + struct lunatik_instance *instance; + lunatik_State *state; + char *state_name; + + instance = lunatik_pernet(genl_info_net(info)); + + state_name = nla_data(info->attrs[STATE_NAME]); + + if(((state = lunatik_netstatelookup(instance, state_name)) == NULL) && + ((state = lunatik_statelookup(state_name)) == NULL)) { + pr_err("State not found\n"); + //TODO reply with state not found + } + + if (sendstate_msg(state, info)) { + pr_err("Failed to send message to user space\n"); + // Reply with error + } + + return 0; + +} + /* Note: Most of the function below is copied from NFLua: https://github.com/cujoai/nflua * Copyright (C) 2017-2019 CUJO LLC * diff --git a/netlink_common.h b/netlink_common.h index 16a1af46a..4c480d616 100644 --- a/netlink_common.h +++ b/netlink_common.h @@ -23,7 +23,8 @@ enum lunatik_operations { DESTROY_STATE, LIST_STATES, DATA, - DATA_INIT + DATA_INIT, + GET_STATE, }; enum lunatik_attrs { @@ -41,6 +42,7 @@ enum lunatik_attrs { OP_ERROR, LUNATIK_DATA, LUNATIK_DATA_LEN, + CURR_ALLOC, ATTRS_COUNT #define ATTRS_MAX (ATTRS_COUNT - 1) }; From 8f4e5953f54253a31138534780e5a2cfb2b5f224 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Tue, 11 Aug 2020 17:04:51 +0000 Subject: [PATCH 24/48] Make the global network namespace as default space to store states --- lib/lunatik.c | 31 +++++----- lib/lunatik.h | 1 + lib/lunatik_module.c | 8 ++- lunatik_core.c | 8 +-- netlink.c | 31 ++++------ netlink_common.h | 1 + states.c | 139 +++++++++++++------------------------------ states.h | 6 +- 8 files changed, 85 insertions(+), 140 deletions(-) diff --git a/lib/lunatik.c b/lib/lunatik.c index 87e87112c..867f6da16 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -422,20 +422,6 @@ static int get_state_handler(struct lunatik_session *session, struct nlattr **at session->state_holder.curralloc = nla_get_u32(attrs_tb[CURR_ALLOC]); session->state_holder.maxalloc = nla_get_u32(attrs_tb[MAX_ALLOC]); session->state_holder.session = session; - - if (init_socket(&(session->state_holder.recv_datasock))) { - printf("Failed to initialize recv data socket\n"); - nl_socket_free(session->state_holder.recv_datasock); - return -1; - } - - if (init_socket(&(session->state_holder.send_datasock))) { - printf("Failed to initialize send data socket\n"); - nl_socket_free(session->state_holder.send_datasock); - return -1; - } - - init_recv_datasocket_on_kernel(&session->state_holder); return 0; } @@ -503,8 +489,20 @@ static int response_handler(struct nl_msg *msg, void *arg) break; case GET_STATE: + if (attrs_tb[STATE_NOT_FOUND]) { + session->cb_result = CB_STATE_NOT_FOUND; + return NL_OK; + } + + if (attrs_tb[OP_ERROR]) { + session->cb_result = CB_ERROR; + return NL_OK; + } + if (get_state_handler(session, attrs_tb)) session->cb_result = CB_ERROR; + + break; default: break; } @@ -717,6 +715,11 @@ struct lunatik_nl_state *lunatikS_getstate(struct lunatik_session *session, cons if (receive_op_result(session)) return NULL; + if ((session->cb_result == CB_STATE_NOT_FOUND) || (session->cb_result == CB_ERROR)) { + session->cb_result = CB_EMPTY_RESULT; + return NULL; + } + return &session->state_holder; nla_put_failure: diff --git a/lib/lunatik.h b/lib/lunatik.h index 3255861ee..de26134f9 100644 --- a/lib/lunatik.h +++ b/lib/lunatik.h @@ -31,6 +31,7 @@ enum callback_result { CB_ERROR, CB_EMPTY_RESULT, CB_LIST_EMPTY, + CB_STATE_NOT_FOUND, }; enum session_status { diff --git a/lib/lunatik_module.c b/lib/lunatik_module.c index 228608a77..af1693a67 100644 --- a/lib/lunatik_module.c +++ b/lib/lunatik_module.c @@ -242,8 +242,14 @@ static int lsession_getstate(lua_State *L) } *state = *received_state; + + if (lunatikS_initdata(state)) { + lua_pushnil(L); + return 1; + } + luaL_setmetatable(L, "states.control"); - + return 1; } diff --git a/lunatik_core.c b/lunatik_core.c index e3d9c5cb8..318a67380 100644 --- a/lunatik_core.c +++ b/lunatik_core.c @@ -179,12 +179,12 @@ EXPORT_SYMBOL(lunatik_stateget); EXPORT_SYMBOL(lunatik_stateput); EXPORT_SYMBOL(lunatik_netnewstate); -EXPORT_SYMBOL(lunatik_netclose); +EXPORT_SYMBOL(lunatik_netclosestate); EXPORT_SYMBOL(lunatik_netstatelookup); extern struct genl_family lunatik_family; extern void lunatik_statesinit(void); -extern void lunatik_closeall(void); +extern void lunatik_closeall_from_default_ns(void); extern void state_destroy(lunatik_State *s); static int lunatik_netid __read_mostly; @@ -235,8 +235,6 @@ static int __init modinit(void) { int err; - lunatik_statesinit(); - if ((err = register_pernet_subsys(&lunatik_net_ops))) { pr_err("Failed to register pernet operations\n"); return err; @@ -252,7 +250,7 @@ static int __init modinit(void) static void __exit modexit(void) { - lunatik_closeall(); + lunatik_closeall_from_default_ns(); unregister_pernet_subsys(&lunatik_net_ops); genl_unregister_family(&lunatik_family); } diff --git a/netlink.c b/netlink.c index 1f755add3..916a6f1c7 100644 --- a/netlink.c +++ b/netlink.c @@ -234,7 +234,7 @@ static int lunatikN_newstate(struct sk_buff *buff, struct genl_info *info) state_name = (char *)nla_data(info->attrs[STATE_NAME]); max_alloc = (u32 *)nla_data(info->attrs[MAX_ALLOC]); - s = lunatik_netnewstate(instance, *max_alloc, state_name); + s = lunatik_netnewstate(genl_info_net(info), *max_alloc, state_name); if (s == NULL) { reply_with(OP_ERROR, CREATE_STATE, info); @@ -294,7 +294,6 @@ static int dostring(char *code, lunatik_State *s, const char *script_name) static int lunatikN_dostring(struct sk_buff *buff, struct genl_info *info) { struct lunatik_state *s; - struct lunatik_instance *instance; const char *script_name; char *fragment; char *state_name; @@ -303,12 +302,11 @@ static int lunatikN_dostring(struct sk_buff *buff, struct genl_info *info) pr_debug("Received a EXECUTE_CODE message\n"); - instance = lunatik_pernet(genl_info_net(info)); state_name = (char *)nla_data(info->attrs[STATE_NAME]); fragment = (char *)nla_data(info->attrs[CODE]); flags = *((u8*)nla_data(info->attrs[FLAGS])); - if ((s = lunatik_netstatelookup(instance, state_name)) == NULL) { + if ((s = lunatik_netstatelookup(genl_info_net(info), state_name)) == NULL) { pr_err("Error finding klua state\n"); reply_with(OP_ERROR, EXECUTE_CODE, info); return 0; @@ -334,15 +332,13 @@ static int lunatikN_dostring(struct sk_buff *buff, struct genl_info *info) static int lunatikN_close(struct sk_buff *buff, struct genl_info *info) { - struct lunatik_instance *instance; char *state_name; - instance = lunatik_pernet(genl_info_net(info)); state_name = (char *)nla_data(info->attrs[STATE_NAME]); pr_debug("Received a DESTROY_STATE command\n"); - if (lunatik_netclose(instance, state_name)) + if (lunatik_netclosestate(genl_info_net(info), state_name)) reply_with(OP_ERROR, DESTROY_STATE, info); else reply_with(OP_SUCESS, DESTROY_STATE, info); @@ -487,7 +483,6 @@ static int handle_data(lua_State *L); static int lunatikN_data(struct sk_buff *buff, struct genl_info *info) { - struct lunatik_instance *instance; struct lunatik_data data; lunatik_State *state; char *payload; @@ -496,10 +491,9 @@ static int lunatikN_data(struct sk_buff *buff, struct genl_info *info) int err = 0; int base; - instance = lunatik_pernet(genl_info_net(info)); state_name = nla_data(info->attrs[STATE_NAME]); - if ((state = lunatik_netstatelookup(instance, state_name)) == NULL) { + if ((state = lunatik_netstatelookup(genl_info_net(info), state_name)) == NULL) { pr_err("State %s not found\n", state_name); goto error; } @@ -543,14 +537,12 @@ static int lunatikN_data(struct sk_buff *buff, struct genl_info *info) static int lunatikN_datainit(struct sk_buff *buff, struct genl_info *info) { - struct lunatik_instance *instance; lunatik_State *state; char *name; - instance = lunatik_pernet(genl_info_net(info)); name = nla_data(info->attrs[STATE_NAME]); - if ((state = lunatik_netstatelookup(instance, name)) == NULL) { + if ((state = lunatik_netstatelookup(genl_info_net(info), name)) == NULL) { pr_err("Failed to find the state %s\n", name); reply_with(OP_ERROR, DATA_INIT, info); return 0; @@ -630,23 +622,20 @@ static int sendstate_msg(lunatik_State *state, struct genl_info *info) static int lunatikN_sendstate(struct sk_buff *buff, struct genl_info *info) { - struct lunatik_instance *instance; lunatik_State *state; char *state_name; - instance = lunatik_pernet(genl_info_net(info)); - state_name = nla_data(info->attrs[STATE_NAME]); - if(((state = lunatik_netstatelookup(instance, state_name)) == NULL) && - ((state = lunatik_statelookup(state_name)) == NULL)) { - pr_err("State not found\n"); - //TODO reply with state not found + if(((state = lunatik_netstatelookup(genl_info_net(info), state_name)) == NULL)) { + pr_err("State %s not found\n", state_name); + reply_with(STATE_NOT_FOUND, GET_STATE, info); + return 0; } if (sendstate_msg(state, info)) { pr_err("Failed to send message to user space\n"); - // Reply with error + reply_with(OP_ERROR, GET_STATE, info); } return 0; diff --git a/netlink_common.h b/netlink_common.h index 4c480d616..359b53436 100644 --- a/netlink_common.h +++ b/netlink_common.h @@ -43,6 +43,7 @@ enum lunatik_attrs { LUNATIK_DATA, LUNATIK_DATA_LEN, CURR_ALLOC, + STATE_NOT_FOUND, ATTRS_COUNT #define ATTRS_MAX (ATTRS_COUNT - 1) }; diff --git a/states.c b/states.c index caabe9b65..3dc8e6d6d 100644 --- a/states.c +++ b/states.c @@ -36,8 +36,7 @@ extern int luaopen_memory(lua_State *); extern int luaopen_netlink(lua_State *L); - -static struct lunatik_instance instance; +extern struct lunatik_instance *lunatik_pernet(struct net *net); static const luaL_Reg libs[] = { {"memory", luaopen_memory}, @@ -51,22 +50,15 @@ static inline int name_hash(void *salt, const char *name) return full_name_hash(salt, name, len) & (LUNATIK_HASH_BUCKETS - 1); } -lunatik_State *lunatik_statelookup(const char *name) +inline lunatik_State *lunatik_statelookup(const char *name) { - lunatik_State *state; - int key = name_hash(&instance, name); - - hash_for_each_possible_rcu(instance.states_table, state, node, key) { - if (!strncmp(state->name, name, LUNATIK_NAME_MAXSIZE)) - return state; - } - return NULL; + return lunatik_netstatelookup(NULL, name); } void state_destroy(lunatik_State *s) { hash_del_rcu(&s->node); - atomic_dec(&(instance.states_count)); + atomic_dec(&(s->instance.states_count)); spin_lock_bh(&s->lock); if (s->L != NULL) { @@ -123,85 +115,32 @@ static int state_init(lunatik_State *s) return 0; } -lunatik_State *lunatik_newstate(size_t maxalloc, const char *name) +inline lunatik_State *lunatik_newstate(size_t maxalloc, const char *name) { - lunatik_State *s = lunatik_statelookup(name); - int namelen = strnlen(name, LUNATIK_NAME_MAXSIZE); - - pr_debug("creating state: %.*s maxalloc: %zd\n", namelen, name, - maxalloc); - - if (s != NULL) { - pr_err("state already exists: %.*s\n", namelen, name); - return NULL; - } - - if (atomic_read(&(instance.states_count)) >= LUNATIK_HASH_BUCKETS) { - pr_err("could not allocate id for state %.*s\n", namelen, name); - pr_err("max states limit reached or out of memory\n"); - return NULL; - } - - if (maxalloc < LUNATIK_MIN_ALLOC_BYTES) { - pr_err("maxalloc %zu should be greater then MIN_ALLOC %zu\n", - maxalloc, LUNATIK_MIN_ALLOC_BYTES); - return NULL; - } - - if ((s = kzalloc(sizeof(lunatik_State), GFP_ATOMIC)) == NULL) { - pr_err("could not allocate nflua state\n"); - return NULL; - } - - spin_lock_init(&s->lock); - #ifndef LUNATIK_UNUSED - s->dseqnum = 0; - #endif - s->maxalloc = maxalloc; - s->curralloc = 0; - memcpy(&(s->name), name, namelen); - - if (state_init(s)) { - pr_err("could not allocate a new lua state\n"); - kfree(s); - return NULL; - } - - spin_lock_bh(&(instance.statestable_lock)); - hash_add_rcu(instance.states_table, &(s->node), name_hash(&instance, name)); - refcount_inc(&s->users); - atomic_inc(&(instance.states_count)); - spin_unlock_bh(&(instance.statestable_lock)); - - pr_debug("new state created: %.*s\n", namelen, name); - return s; + return lunatik_netnewstate(NULL, maxalloc, name); } -int lunatik_close(const char *name) +inline int lunatik_close(const char *name) { - lunatik_State *s = lunatik_statelookup(name); - - if (s == NULL || refcount_read(&s->users) > 1) - return -1; - - spin_lock_bh(&(instance.statestable_lock)); - state_destroy(s); - spin_unlock_bh(&(instance.statestable_lock)); - - return 0; + return lunatik_netclosestate(NULL, name); } -void lunatik_closeall(void) +void lunatik_closeall_from_default_ns(void) { + struct lunatik_instance *instance; + struct net *net; struct hlist_node *tmp; lunatik_State *s; int bkt; - spin_lock_bh(&(instance.statestable_lock)); - hash_for_each_safe (instance.states_table, bkt, tmp, s, node) { + net = get_net_ns_by_pid(1); + instance = lunatik_pernet(net); + + spin_lock_bh(&(instance->statestable_lock)); + hash_for_each_safe (instance->states_table, bkt, tmp, s, node) { state_destroy(s); } - spin_unlock_bh(&(instance.statestable_lock)); + spin_unlock_bh(&(instance->statestable_lock)); } inline bool lunatik_stateget(lunatik_State *s) @@ -212,7 +151,7 @@ inline bool lunatik_stateget(lunatik_State *s) void lunatik_stateput(lunatik_State *s) { refcount_t *users = &s->users; - spinlock_t *refcnt_lock = &(instance.rfcnt_lock); + spinlock_t *refcnt_lock = &(s->instance.rfcnt_lock); if (WARN_ON(s == NULL)) return; @@ -229,23 +168,19 @@ void lunatik_stateput(lunatik_State *s) spin_unlock_bh(refcnt_lock); } -void lunatik_statesinit(void) +lunatik_State *lunatik_netstatelookup(struct net *net, const char *name) { - atomic_set(&(instance.states_count), 0); - spin_lock_init(&(instance.statestable_lock)); - spin_lock_init(&(instance.rfcnt_lock)); - hash_init(instance.states_table); -} - -lunatik_State *lunatik_netstatelookup(struct lunatik_instance *instance, const char *name) -{ - lunatik_State *state; + struct lunatik_instance *instance; int key; - if (instance == NULL) - return NULL; - key = name_hash(instance,name); + if (net == NULL) { + net = get_net_ns_by_pid(1); + } + + instance = lunatik_pernet(net); + + key = name_hash(instance, name); hash_for_each_possible_rcu(instance->states_table, state, node, key) { if (!strncmp(state->name, name, LUNATIK_NAME_MAXSIZE)) @@ -254,10 +189,16 @@ lunatik_State *lunatik_netstatelookup(struct lunatik_instance *instance, const c return NULL; } -lunatik_State *lunatik_netnewstate(struct lunatik_instance *instance, size_t maxalloc, const char *name) +lunatik_State *lunatik_netnewstate(struct net *net, size_t maxalloc, const char *name) { + lunatik_State *s = lunatik_netstatelookup(net, name); + struct lunatik_instance *instance; + + if (net == NULL) + net = get_net_ns_by_pid(1); + + instance = lunatik_pernet(net); - lunatik_State *s = lunatik_netstatelookup(instance, name); int namelen = strnlen(name, LUNATIK_NAME_MAXSIZE); pr_debug("creating state: %.*s maxalloc: %zd\n", namelen, name, @@ -306,9 +247,15 @@ lunatik_State *lunatik_netnewstate(struct lunatik_instance *instance, size_t max return s; } -int lunatik_netclose(struct lunatik_instance *instance, const char *name) +int lunatik_netclosestate(struct net *net, const char *name) { - lunatik_State *s = lunatik_netstatelookup(instance,name); + lunatik_State *s = lunatik_netstatelookup(net, name); + struct lunatik_instance *instance; + + if (net == NULL) + net = get_net_ns_by_pid(1); + + instance = lunatik_pernet(net); if (s == NULL || refcount_read(&s->users) > 1) return -1; diff --git a/states.h b/states.h index e3c9d2039..0f55e2f6d 100644 --- a/states.h +++ b/states.h @@ -55,8 +55,8 @@ lunatik_State *lunatik_statelookup(const char *name); bool lunatik_stateget(lunatik_State *s); void lunatik_stateput(lunatik_State *s); -lunatik_State *lunatik_netnewstate(struct lunatik_instance *instance, size_t maxalloc, const char *name); -int lunatik_netclose(struct lunatik_instance *instance, const char *name); -lunatik_State *lunatik_netstatelookup(struct lunatik_instance *instance, const char *name); +lunatik_State *lunatik_netnewstate(struct net *net, size_t maxalloc, const char *name); +int lunatik_netclosestate(struct net *net, const char *name); +lunatik_State *lunatik_netstatelookup(struct net *net, const char *name); #endif /* LUNATIK_STATES_H */ From 7303d68604d78a0e097e19ba605f9b231878a3b0 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Tue, 11 Aug 2020 21:07:30 +0000 Subject: [PATCH 25/48] Unnecessary functions remotion, and documentation update --- doc/lib.md | 26 ++++++++++++++ lib/lunatik.h | 34 ------------------ lib/lunatik_module.c | 82 +++----------------------------------------- 3 files changed, 30 insertions(+), 112 deletions(-) diff --git a/doc/lib.md b/doc/lib.md index c5d50226c..2477a6ead 100644 --- a/doc/lib.md +++ b/doc/lib.md @@ -4,6 +4,28 @@ This document provides the documentation of the user space API of Lunatik. This API is divided in two main features, being the control API and the data API, the first one is responsible to send messages to Lunatik kernel module to perform some operations, whereas the data API is responsible to exchange data between the kernel module and this user space API. +## Constants + +#### `lunatik.datamaxsize` + +Integer that represents the maximum amount of data that a state can receive or send each time. + +#### `lunatik.defaultmaxallocbytes` + +The default amount of memory that a state will be able to use if no value is passed on creation. + +#### `lunatik.maxstates` + +The maximum number of states that the lunatik module is able to store. + +#### `lunatik.scriptnamemaxsize` + +The maximum length of a script name, this name is used on debug porpuses, for example, show a name for the script on the callback stack trace. + +#### `lunatik.statenamemaxsize` + +The maximum length of a state name. + ## Control API Responsable to send messages to Lunatik kernel module perform some operations, these are: @@ -39,6 +61,10 @@ Returns a table with all states present on kernel. Each entry of that table is a Closes the connection with the kernel, after that, all references for the states will be lost, so it's important to check if you don't have any states in use before close the connection with the kernel to avoid memory leaks. +#### `session:getstate(name)` + +Gets a user representation of the state with the name `name` which was created on kernel. Returns a userdata as described on [`session:new`](#sessionnewname--maxalloc) if such state is found and `nil` otherwise. + ### State related operations As mentioned at [`session:new`](#sessionnewname--maxalloc) function, when you call that function, if the state is succesfully created, it will be returned a userdata. That userdata is used to perform all operations related to that state, for example: diff --git a/lib/lunatik.h b/lib/lunatik.h index de26134f9..733f3dfb3 100644 --- a/lib/lunatik.h +++ b/lib/lunatik.h @@ -78,16 +78,6 @@ struct lunatik_session { uint32_t pid; }; -#ifndef _UNUSED -struct nflua_data { - int fd; - uint32_t pid; - uint32_t seqnum; - char state[NFLUA_NAME_MAXSIZE]; - char buffer[NFLUA_PAYLOAD_MAXSIZE]; -}; -#endif /* _UNUSED */ - static inline int lunatikS_getfd(const struct lunatik_session *session) { return session->control_fd; @@ -117,31 +107,7 @@ int lunatikS_initdata(struct lunatik_nl_state *state); struct lunatik_nl_state *lunatikS_getstate(struct lunatik_session *session, const char *name); -#ifndef _UNUSED -static inline int nflua_data_getsock(const struct nflua_data *dch) -{ - return dch->fd; -} - -static inline int nflua_data_getpid(const struct nflua_data *dch) -{ - return dch->pid; -} - -static inline int nflua_data_is_open(const struct nflua_data *dch) -{ - return dch->fd >= 0; -} - -int nflua_data_init(struct nflua_data *dch, uint32_t pid); - -void nflua_data_close(struct nflua_data *dch); -#endif /* _UNUSED */ - int lunatik_datasend(struct lunatik_nl_state *state, const char *payload, size_t len); -#ifndef _UNUSED -int nflua_data_receive(struct nflua_data *dch, char *state, char *buffer); -#endif /* _UNUSED */ #endif /* LUNATIK_H */ diff --git a/lib/lunatik_module.c b/lib/lunatik_module.c index af1693a67..b4409e02f 100644 --- a/lib/lunatik_module.c +++ b/lib/lunatik_module.c @@ -269,55 +269,6 @@ static void buildlist(lua_State *L, struct lunatik_nl_state *states, size_t n) lua_seti(L, -2, i + 1); } } -#ifndef _UNUSED -static int ldata_open(lua_State *L) -{ - int ret; - uint32_t pid = generatepid(L, 1); - struct nflua_data *dch = lua_newuserdata(L, sizeof(struct nflua_data)); - - luaL_setmetatable(L, "nflua.data"); - ret = nflua_data_init(dch, pid); - - return ret < 0 ? pusherrno(L, ret) : 1; -} - -static int ldata_gc(lua_State *L) -{ - struct nflua_data *dch = luaL_checkudata(L, 1, "nflua.data"); - if (nflua_data_is_open(dch)) nflua_data_close(dch); - return 0; -} - -static struct nflua_data *getdata(lua_State *L) -{ - struct nflua_data *dch = luaL_checkudata(L, 1, "nflua.data"); - if (!nflua_data_is_open(dch)) luaL_argerror(L, 1, "socket closed"); - return dch; -} - -static int ldata_close(lua_State *L) -{ - struct nflua_data *dch = getdata(L); - nflua_data_close(dch); - lua_pushboolean(L, true); - return 1; -} - -static int ldata_getfd(lua_State *L) -{ - struct nflua_data *dch = getdata(L); - lua_pushinteger(L, nflua_data_getsock(dch)); - return 1; -} - -static int ldata_getpid(lua_State *L) -{ - struct nflua_data *dch = getdata(L); - lua_pushinteger(L, nflua_data_getpid(dch)); - return 1; -} -#endif /* _UNUSED */ static int lstate_datasend(lua_State *L) { @@ -376,54 +327,29 @@ static const luaL_Reg state_mt[] = { {NULL, NULL} }; -#ifndef _UNUSED -static const luaL_Reg data_mt[] = { - {"close", ldata_close}, - {"getfd", ldata_getfd}, - {"getpid", ldata_getpid}, - {"__gc", ldata_gc}, - {NULL, NULL} -}; -#endif /*_UNUSED*/ - static const luaL_Reg lunatik_lib[] = { {"session", lsession_open}, - #ifndef _UNUSED - {"data", ldata_open}, - #endif /*_UNUSED*/ {NULL, NULL} }; -#ifndef _UNUSED static void setconst(lua_State *L, const char *name, lua_Integer value) { lua_pushinteger(L, value); lua_setfield(L, -2, name); } -#endif int luaopen_lunatik(lua_State *L) { - #ifndef _UNUSED - luaL_requiref(L, "memory", luaopen_memory, 1); - lua_pop(L, 1); - #endif /*_UNUSED*/ - newclass(L, "lunatik.session", session_mt); newclass(L, "states.control", state_mt); - #ifndef _UNUSED - newclass(L, "nflua.data", data_mt); - #endif /*_UNUSED*/ luaL_newlib(L, lunatik_lib); - #ifndef _UNUSED - setconst(L, "datamaxsize", NFLUA_DATA_MAXSIZE); + setconst(L, "datamaxsize", LUNATIK_FRAGMENT_SIZE); setconst(L, "defaultmaxallocbytes", DEFAULT_MAXALLOC_BYTES); - setconst(L, "maxstates", NFLUA_MAX_STATES); - setconst(L, "scriptnamemaxsize", NFLUA_SCRIPTNAME_MAXSIZE); - setconst(L, "statenamemaxsize", NFLUA_NAME_MAXSIZE); - #endif /*_UNUSED*/ + setconst(L, "maxstates", LUNATIK_HASH_BUCKETS); + setconst(L, "scriptnamemaxsize", LUNATIK_SCRIPTNAME_MAXSIZE); + setconst(L, "statenamemaxsize", LUNATIK_NAME_MAXSIZE); return 1; } From 9b86a2ec62423e65ade34e5579a0c6cf51f2fa11 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Tue, 11 Aug 2020 21:54:37 +0000 Subject: [PATCH 26/48] Add tests --- lib/runtests.sh | 9 +++++++++ lib/tests/close.lua | 9 +++++++++ lib/tests/create.lua | 37 +++++++++++++++++++++++++++++++++++++ lib/tests/getstate.lua | 26 ++++++++++++++++++++++++++ lib/tests/list.lua | 39 +++++++++++++++++++++++++++++++++++++++ lib/tests/receive.lua | 25 +++++++++++++++++++++++++ lib/tests/send.lua | 31 +++++++++++++++++++++++++++++++ lib/tests/session.lua | 7 +++++++ 8 files changed, 183 insertions(+) create mode 100755 lib/runtests.sh create mode 100644 lib/tests/close.lua create mode 100644 lib/tests/create.lua create mode 100644 lib/tests/getstate.lua create mode 100644 lib/tests/list.lua create mode 100644 lib/tests/receive.lua create mode 100644 lib/tests/send.lua create mode 100644 lib/tests/session.lua diff --git a/lib/runtests.sh b/lib/runtests.sh new file mode 100755 index 000000000..1d8554cea --- /dev/null +++ b/lib/runtests.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -e + +for file in tests/*; do + echo "Running $file" + LD_LIBRARY_PATH=../deps/lua-memory/src LUA_CPATH='../deps/lua-memory/src/?.so;;' lua $file + echo "$file executed with no errors!" +done diff --git a/lib/tests/close.lua b/lib/tests/close.lua new file mode 100644 index 000000000..38fa69c85 --- /dev/null +++ b/lib/tests/close.lua @@ -0,0 +1,9 @@ +local lunatik = require'lunatik' +local session = lunatik.session() + +-- Normal close +local s1 = session:new's1' +assert(s1 ~= nil) + +local err = s1:close() +assert(err ~= nil) diff --git a/lib/tests/create.lua b/lib/tests/create.lua new file mode 100644 index 000000000..1b3183cb1 --- /dev/null +++ b/lib/tests/create.lua @@ -0,0 +1,37 @@ +local lunatik = require'lunatik' + +local session = lunatik.session() + +-- Normal creation +local s1 = session:new's1' +assert(s1 ~= nil) + +-- Max alloc greater than MIN_ALLOC +local s2 = session:new('s2', 100000) +assert(s2 ~= nil) + +-- Max alloc less than MIN_ALLOC +local s3 = session:new('s3', 1) +assert(s3 == nil) + +-- State already exists +local s4 = session:new's1' +assert(s4 == nil) + +-- State creation from another session +local session2 = lunatik.session() + +-- Normal creation +ss1 = session2:new'ss1' +assert(ss1 ~= nil) + +-- State created from another session +ss2 = session2:new's1' +assert(ss2 == nil) + + +s1:close() +s2:close() +ss1:close() +session:close() +session2:close() diff --git a/lib/tests/getstate.lua b/lib/tests/getstate.lua new file mode 100644 index 000000000..eadf62d1a --- /dev/null +++ b/lib/tests/getstate.lua @@ -0,0 +1,26 @@ +local lunatik = require'lunatik' +local memory = require'memory' +local buffer = memory.create(3) +local session = lunatik.session() + +local kscript = [[ + print'olá mundo!' +]] + +local s1 = session:new's1' +assert(s1 ~= nil) +local err = s1:dostring(kscript) +assert(err ~= nil) + +local state = session:getstate's1' +assert(state ~= nil) +err = state:dostring(kscript) +assert(err ~= nil) + +local state2 = session:getstate's4' +assert(state2 == nil) + +s1:close() +state:close() + +session:close() diff --git a/lib/tests/list.lua b/lib/tests/list.lua new file mode 100644 index 000000000..f5a6264f8 --- /dev/null +++ b/lib/tests/list.lua @@ -0,0 +1,39 @@ +local lunatik = require'lunatik' +local session = lunatik.session() +local session2 = lunatik.session() + +-- Create states that will be present on the list +local s1 = session:new's1' +local s2 = session:new's2' +local s3 = session:new('s3', 100000) + +local ss1 = session2:new'ss1' +local ss2 = session2:new'ss2' +local ss3 = session2:new('ss3', 100000) + +-- Create states that are not be present on the list +session:new('s4', 1) +session2:new('ss4', 1) + +-- Get the states information from kernel +local states = session:list() +local states2 = session2:list() + +assert(#states == 6) +assert(#states2 == 6) + + +-- Close some states and check if they are gone when list +s1:close() +s2:close() +s3:close() + +states = session:list() +states2 = session2:list() + +assert(#states == 3) +assert(#states2 == 3) + +ss1:close() +ss2:close() +ss3:close() diff --git a/lib/tests/receive.lua b/lib/tests/receive.lua new file mode 100644 index 000000000..4020a8921 --- /dev/null +++ b/lib/tests/receive.lua @@ -0,0 +1,25 @@ +local lunatik = require'lunatik' +local memory = require'memory' +local session = lunatik.session() + +local kscript = [[ + local buffer = memory.create(3) + memory.set(buffer, 1, 65, 66, 67) + netlink.send(buffer) + memory.set(buffer, 1, 68, 69, 70) + netlink.send(buffer) +]] + +local s1 = session:new's1' +assert(s1 ~= nil) + +local err = s1:dostring(kscript, 'receive') +assert(err ~= nil) + +local buffer = s1:receive() +assert(memory.tostring(buffer) == 'ABC') + +buffer = s1:receive() +assert(memory.tostring(buffer) == 'DEF') + +s1:close() diff --git a/lib/tests/send.lua b/lib/tests/send.lua new file mode 100644 index 000000000..c971f6508 --- /dev/null +++ b/lib/tests/send.lua @@ -0,0 +1,31 @@ +local lunatik = require'lunatik' +local memory = require'memory' +local session = lunatik.session() + +local buffer = memory.create(3) +memory.set(buffer, 1, 0x1, 0x2, 0x3) + +local kscript = [[ + function receive_callback(mem) + print'A memory has been received' + memory.tostring(mem) + end +]] + +local s1 = session:new's1' +assert(s1 ~= nil) + +local s2 = session:new's2' +assert(s2 ~= nil) + +local err = s1:dostring(kscript, 'send script') +assert(err ~= nil) + +err = s1:send(buffer) +assert(err ~= nil) + +err = s2:send(buffer) +assert(err == nil) + +s1:close() +s2:close() diff --git a/lib/tests/session.lua b/lib/tests/session.lua new file mode 100644 index 000000000..64371d34c --- /dev/null +++ b/lib/tests/session.lua @@ -0,0 +1,7 @@ +local lunatik = require'lunatik' + +local session = lunatik.session() +local session2 = lunatik.session() + +session:close() +session2:close() From d2bebc6a51772ecb9a592555e5d81d2765ad4877 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Sat, 15 Aug 2020 15:55:03 +0000 Subject: [PATCH 27/48] Add lua memory compilation from user lib --- lib/Makefile | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index e7e182dc3..70beb6d21 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -27,7 +27,10 @@ OBJS = $(patsubst %.c,%.o,$(wildcard *.c)) DEPS = $(OBJS:.o=.d) .PHONY: all -all: $(LIBS) +all: lua_memory $(LIBS) + +lua_memory: + $(MAKE) -C ../deps/lua-memory/src linux CFLAGS="-fPIC -I/usr/include/lua5.3" %.so: $(CC) -o $@ $^ $(LDFLAGS) @@ -38,7 +41,10 @@ all: $(LIBS) -include $(DEPS) .PHONY: clean -clean: +clean: lua_clean $(RM) $(LIBS) $(OBJS) $(DEPS) +lua_clean: + $(MAKE) -C ../deps/lua-memory/src clean + $(LIBS): $(OBJS) From a2f28418e45ffbc3640d0aec30c16544318f41ea Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Sat, 15 Aug 2020 21:51:00 +0000 Subject: [PATCH 28/48] Functions refatoration --- luanetlink.c | 2 +- states.h => lunatik.h | 12 ++++++------ lunatik_conf.h | 2 ++ lunatik_core.c | 6 +++--- netlink.c | 28 +++++++++++----------------- netlink.h | 2 +- states.c | 42 +++++++++++++++--------------------------- 7 files changed, 39 insertions(+), 55 deletions(-) rename states.h => lunatik.h (81%) diff --git a/luanetlink.c b/luanetlink.c index 9a73ae923..77109c403 100644 --- a/luanetlink.c +++ b/luanetlink.c @@ -22,7 +22,7 @@ #include #include "luautil.h" -#include "states.h" +#include "lunatik.h" extern int lunatikN_send_data(lunatik_State *state, const char *payload, size_t size); diff --git a/states.h b/lunatik.h similarity index 81% rename from states.h rename to lunatik.h index 0f55e2f6d..b20c834ff 100644 --- a/states.h +++ b/lunatik.h @@ -48,15 +48,15 @@ typedef struct lunatik_state { unsigned char name[LUNATIK_NAME_MAXSIZE]; } lunatik_State; -lunatik_State *lunatik_newstate(size_t maxalloc, const char *name); +lunatik_State *lunatik_newstate(const char *name, size_t maxalloc); int lunatik_close(const char *name); lunatik_State *lunatik_statelookup(const char *name); -bool lunatik_stateget(lunatik_State *s); -void lunatik_stateput(lunatik_State *s); +bool lunatik_getstate(lunatik_State *s); +void lunatik_putstate(lunatik_State *s); -lunatik_State *lunatik_netnewstate(struct net *net, size_t maxalloc, const char *name); -int lunatik_netclosestate(struct net *net, const char *name); -lunatik_State *lunatik_netstatelookup(struct net *net, const char *name); +lunatik_State *lunatik_netnewstate(const char *name, size_t maxalloc, struct net *net); +int lunatik_netclosestate(const char *name, struct net *net); +lunatik_State *lunatik_netstatelookup(const char *name, struct net *net); #endif /* LUNATIK_STATES_H */ diff --git a/lunatik_conf.h b/lunatik_conf.h index e44c81f44..de2cffe11 100644 --- a/lunatik_conf.h +++ b/lunatik_conf.h @@ -24,6 +24,8 @@ #define LUNATIK_SCRIPTNAME_MAXSIZE 255 /* Max length of script name */ +#define LUNATIK_DEFAULT_NS get_net_ns_by_pid(1) + #define LUNATIK_MIN_ALLOC_BYTES (32 * 1024UL) #define LUNATIK_HASH_BUCKETS 32 diff --git a/lunatik_core.c b/lunatik_core.c index 318a67380..053c0df81 100644 --- a/lunatik_core.c +++ b/lunatik_core.c @@ -31,7 +31,7 @@ #include "lua/lauxlib.h" #include "lua/lualib.h" -#include "states.h" +#include "lunatik.h" #include "netlink_common.h" EXPORT_SYMBOL(lua_checkstack); @@ -175,8 +175,8 @@ EXPORT_SYMBOL(luaopen_utf8); EXPORT_SYMBOL(lunatik_newstate); EXPORT_SYMBOL(lunatik_close); EXPORT_SYMBOL(lunatik_statelookup); -EXPORT_SYMBOL(lunatik_stateget); -EXPORT_SYMBOL(lunatik_stateput); +EXPORT_SYMBOL(lunatik_getstate); +EXPORT_SYMBOL(lunatik_putstate); EXPORT_SYMBOL(lunatik_netnewstate); EXPORT_SYMBOL(lunatik_netclosestate); diff --git a/netlink.c b/netlink.c index 916a6f1c7..7a9da5aa4 100644 --- a/netlink.c +++ b/netlink.c @@ -30,7 +30,7 @@ #include #include "luautil.h" -#include "states.h" +#include "lunatik.h" #include "netlink_common.h" #define DATA_RECV_FUNC "receive_callback" @@ -79,7 +79,6 @@ static const struct genl_ops l_ops[] = { .cmd = EXECUTE_CODE, .doit = lunatikN_dostring, #if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) - /*Before kernel 5.2.0, each operation has its own policy*/ .policy = lunatik_policy #endif }, @@ -87,7 +86,6 @@ static const struct genl_ops l_ops[] = { .cmd = DESTROY_STATE, .doit = lunatikN_close, #if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) - /*Before kernel 5.2.0, each operation has its own policy*/ .policy = lunatik_policy #endif }, @@ -95,7 +93,6 @@ static const struct genl_ops l_ops[] = { .cmd = LIST_STATES, .doit = lunatikN_list, #if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) - /*Before kernel 5.2.0, each operation has its own policy*/ .policy = lunatik_policy #endif }, @@ -103,7 +100,6 @@ static const struct genl_ops l_ops[] = { .cmd = DATA, .doit = lunatikN_data, #if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) - /*Before kernel 5.2.0, each operation has its own policy*/ .policy = lunatik_policy #endif }, @@ -111,7 +107,6 @@ static const struct genl_ops l_ops[] = { .cmd = DATA_INIT, .doit = lunatikN_datainit, #if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) - /*Before kernel 5.2.0, each operation has its own policy*/ .policy = lunatik_policy #endif }, @@ -119,7 +114,6 @@ static const struct genl_ops l_ops[] = { .cmd = GET_STATE, .doit = lunatikN_sendstate, #if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) - /*Before kernel 5.2.0, each operation has its own policy*/ .policy = lunatik_policy #endif } @@ -234,7 +228,7 @@ static int lunatikN_newstate(struct sk_buff *buff, struct genl_info *info) state_name = (char *)nla_data(info->attrs[STATE_NAME]); max_alloc = (u32 *)nla_data(info->attrs[MAX_ALLOC]); - s = lunatik_netnewstate(genl_info_net(info), *max_alloc, state_name); + s = lunatik_netnewstate(state_name, *max_alloc, genl_info_net(info)); if (s == NULL) { reply_with(OP_ERROR, CREATE_STATE, info); @@ -271,7 +265,7 @@ static int dostring(char *code, lunatik_State *s, const char *script_name) int base; spin_lock_bh(&s->lock); - if (!lunatik_stateget(s)) { + if (!lunatik_getstate(s)) { pr_err("Failed to get state\n"); err = -1; goto out; @@ -282,7 +276,7 @@ static int dostring(char *code, lunatik_State *s, const char *script_name) pr_err("%s\n", lua_tostring(s->L, -1)); } - lunatik_stateput(s); + lunatik_putstate(s); lua_settop(s->L, base); out: @@ -306,7 +300,7 @@ static int lunatikN_dostring(struct sk_buff *buff, struct genl_info *info) fragment = (char *)nla_data(info->attrs[CODE]); flags = *((u8*)nla_data(info->attrs[FLAGS])); - if ((s = lunatik_netstatelookup(genl_info_net(info), state_name)) == NULL) { + if ((s = lunatik_netstatelookup(state_name, genl_info_net(info))) == NULL) { pr_err("Error finding klua state\n"); reply_with(OP_ERROR, EXECUTE_CODE, info); return 0; @@ -338,7 +332,7 @@ static int lunatikN_close(struct sk_buff *buff, struct genl_info *info) pr_debug("Received a DESTROY_STATE command\n"); - if (lunatik_netclosestate(genl_info_net(info), state_name)) + if (lunatik_netclosestate(state_name, genl_info_net(info))) reply_with(OP_ERROR, DESTROY_STATE, info); else reply_with(OP_SUCESS, DESTROY_STATE, info); @@ -493,7 +487,7 @@ static int lunatikN_data(struct sk_buff *buff, struct genl_info *info) state_name = nla_data(info->attrs[STATE_NAME]); - if ((state = lunatik_netstatelookup(genl_info_net(info), state_name)) == NULL) { + if ((state = lunatik_netstatelookup(state_name, genl_info_net(info))) == NULL) { pr_err("State %s not found\n", state_name); goto error; } @@ -505,7 +499,7 @@ static int lunatikN_data(struct sk_buff *buff, struct genl_info *info) if (err) goto error; - if (!lunatik_stateget(state)) { + if (!lunatik_getstate(state)) { pr_err("Failed to get state %s\n", state_name); goto error; } @@ -524,7 +518,7 @@ static int lunatikN_data(struct sk_buff *buff, struct genl_info *info) unlock: spin_unlock_bh(&state->lock); lua_settop(state->L, base); - lunatik_stateput(state); + lunatik_putstate(state); err ? reply_with(OP_ERROR, DATA, info) : reply_with(OP_SUCESS, DATA, info); @@ -542,7 +536,7 @@ static int lunatikN_datainit(struct sk_buff *buff, struct genl_info *info) name = nla_data(info->attrs[STATE_NAME]); - if ((state = lunatik_netstatelookup(genl_info_net(info), name)) == NULL) { + if ((state = lunatik_netstatelookup(name, genl_info_net(info))) == NULL) { pr_err("Failed to find the state %s\n", name); reply_with(OP_ERROR, DATA_INIT, info); return 0; @@ -627,7 +621,7 @@ static int lunatikN_sendstate(struct sk_buff *buff, struct genl_info *info) state_name = nla_data(info->attrs[STATE_NAME]); - if(((state = lunatik_netstatelookup(genl_info_net(info), state_name)) == NULL)) { + if(((state = lunatik_netstatelookup(state_name, genl_info_net(info))) == NULL)) { pr_err("State %s not found\n", state_name); reply_with(STATE_NOT_FOUND, GET_STATE, info); return 0; diff --git a/netlink.h b/netlink.h index 71e413504..9151143cc 100644 --- a/netlink.h +++ b/netlink.h @@ -2,7 +2,7 @@ #define NETLINK_H #include -#include "states.h" +#include "lunatik.h" extern struct genl_family lunatik_family; diff --git a/states.c b/states.c index 3dc8e6d6d..1e4f27808 100644 --- a/states.c +++ b/states.c @@ -28,7 +28,7 @@ #include "lua/lualib.h" #include "luautil.h" -#include "states.h" +#include "lunatik.h" #ifndef LUNATIK_SETPAUSE #define LUNATIK_SETPAUSE 100 @@ -52,7 +52,7 @@ static inline int name_hash(void *salt, const char *name) inline lunatik_State *lunatik_statelookup(const char *name) { - return lunatik_netstatelookup(NULL, name); + return lunatik_netstatelookup(name, LUNATIK_DEFAULT_NS); } void state_destroy(lunatik_State *s) @@ -67,7 +67,7 @@ void state_destroy(lunatik_State *s) } spin_unlock_bh(&s->lock); - lunatik_stateput(s); + lunatik_putstate(s); } static void *lua_alloc(void *ud, void *ptr, size_t osize, size_t nsize) @@ -115,26 +115,24 @@ static int state_init(lunatik_State *s) return 0; } -inline lunatik_State *lunatik_newstate(size_t maxalloc, const char *name) +inline lunatik_State *lunatik_newstate(const char *name, size_t maxalloc) { - return lunatik_netnewstate(NULL, maxalloc, name); + return lunatik_netnewstate(name, maxalloc, LUNATIK_DEFAULT_NS); } inline int lunatik_close(const char *name) { - return lunatik_netclosestate(NULL, name); + return lunatik_netclosestate(name, LUNATIK_DEFAULT_NS); } void lunatik_closeall_from_default_ns(void) { struct lunatik_instance *instance; - struct net *net; struct hlist_node *tmp; lunatik_State *s; int bkt; - net = get_net_ns_by_pid(1); - instance = lunatik_pernet(net); + instance = lunatik_pernet(LUNATIK_DEFAULT_NS); spin_lock_bh(&(instance->statestable_lock)); hash_for_each_safe (instance->states_table, bkt, tmp, s, node) { @@ -143,12 +141,12 @@ void lunatik_closeall_from_default_ns(void) spin_unlock_bh(&(instance->statestable_lock)); } -inline bool lunatik_stateget(lunatik_State *s) +inline bool lunatik_getstate(lunatik_State *s) { return refcount_inc_not_zero(&s->users); } -void lunatik_stateput(lunatik_State *s) +void lunatik_putstate(lunatik_State *s) { refcount_t *users = &s->users; spinlock_t *refcnt_lock = &(s->instance.rfcnt_lock); @@ -168,16 +166,12 @@ void lunatik_stateput(lunatik_State *s) spin_unlock_bh(refcnt_lock); } -lunatik_State *lunatik_netstatelookup(struct net *net, const char *name) +lunatik_State *lunatik_netstatelookup(const char *name, struct net *net) { lunatik_State *state; struct lunatik_instance *instance; int key; - if (net == NULL) { - net = get_net_ns_by_pid(1); - } - instance = lunatik_pernet(net); key = name_hash(instance, name); @@ -189,14 +183,11 @@ lunatik_State *lunatik_netstatelookup(struct net *net, const char *name) return NULL; } -lunatik_State *lunatik_netnewstate(struct net *net, size_t maxalloc, const char *name) +lunatik_State *lunatik_netnewstate(const char *name, size_t maxalloc, struct net *net) { - lunatik_State *s = lunatik_netstatelookup(net, name); + lunatik_State *s = lunatik_netstatelookup(name, net); struct lunatik_instance *instance; - if (net == NULL) - net = get_net_ns_by_pid(1); - instance = lunatik_pernet(net); int namelen = strnlen(name, LUNATIK_NAME_MAXSIZE); @@ -247,14 +238,11 @@ lunatik_State *lunatik_netnewstate(struct net *net, size_t maxalloc, const char return s; } -int lunatik_netclosestate(struct net *net, const char *name) +int lunatik_netclosestate(const char *name, struct net *net) { - lunatik_State *s = lunatik_netstatelookup(net, name); + lunatik_State *s = lunatik_netstatelookup(name, net); struct lunatik_instance *instance; - if (net == NULL) - net = get_net_ns_by_pid(1); - instance = lunatik_pernet(net); if (s == NULL || refcount_read(&s->users) > 1) @@ -271,7 +259,7 @@ int lunatik_netclosestate(struct net *net, const char *name) s->L = NULL; } spin_unlock_bh(&s->lock); - lunatik_stateput(s); + lunatik_putstate(s); spin_unlock_bh(&(instance->statestable_lock)); From 694d9cc1ed32e11e28b342a53c11ed2cc1cc38e4 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Tue, 11 Aug 2020 21:07:30 +0000 Subject: [PATCH 29/48] Update documentation --- doc/klua_doc.md | 65 ---------------------------- doc/lunatik.md | 113 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 65 deletions(-) delete mode 100644 doc/klua_doc.md create mode 100644 doc/lunatik.md diff --git a/doc/klua_doc.md b/doc/klua_doc.md deleted file mode 100644 index cf31a030a..000000000 --- a/doc/klua_doc.md +++ /dev/null @@ -1,65 +0,0 @@ -# Lunatik API Documentation - -This document provides a documentation of the portion of Lunatik responsable for thread-safe states management. One API is provided to user in order to access all operations related to states management. - -The API is based on the data structure `lunatik_State` which is used to perform all needed operations. - -## The `lunatik_state` struct - -Defined at `states.h` as: - -```c -typedef struct lunatik_state { - struct hlist_node node; - lua_State *L; - spinlock_t lock; - refcount_t users; - size_t maxalloc; - size_t curralloc; - unsigned char name[LUNATIK_NAME_MAXSIZE]; -} lunatik_State; -``` - -The elements in the struct has the following meaning: - - **`struct hlist_node node`** - -Is a variable used by kernel hash table API to storage the `lunatik_State` structure. - -**`lua_State L`** - -Is the Lua state used by Lunatik to do all operations related to Lua. - -**`spinlock_t lock`** - -Is a spinlock variable used to manage concurrency control. - -**`refcount_t users`** - -Represents how many users are referring to a given `lunatik_State`. - -**`size_t maxalloc`** - -Represents the maximum memory that the lua state `L` can use. - -**`size_t curralloc`** - -Represents the current memory that the lua state `L` is using. - -**`unsigned char name[LUNATIK_NAME_MAXSIZE]`** - -Is the unique identifier to `lunatik_State`, used to search it in the kernel hash table, note that this is limited by `LUNATIK_NAME_MAXSIZE`. - -## Functions offered by the API - -**`lunatik_State *lunatik_statelookup(const char *name);`** - -Searches for a `lunatik_State` with the name `name`. If a state with that name is found returns a pointer to the `lunatik_State` or `NULL` otherwise. - -**`lunatik_State *lunatik_newstate(size_t maxalloc, const char *name)`** - -Creates a `lunatik_State` with the max memory usage defined by `maxalloc` and a unique identifier to acess such state defined by `name`. Return a pointer to `lunatik_State` represeting the lunatik state or `NULL` if any errors occours during the creation. - -**`int lunatik_close(const char *name)`** - -Searchs and close a `lunatik_State`, returns `0` if no errors occours during this operation or `-1` otherwise. diff --git a/doc/lunatik.md b/doc/lunatik.md new file mode 100644 index 000000000..e2bd347b8 --- /dev/null +++ b/doc/lunatik.md @@ -0,0 +1,113 @@ +# Lunatik API Documentation + +## Introduction + +This document provides a documentation of the Lunatik kernel module, this module is resposible for safe states management. Two main APIs are offered to the user, the first one has correlation with [network namespaces](https://man7.org/linux/man-pages/man8/ip-netns.8.html#DESCRIPTION), and provides a full isolation of the states based on each namespace, the second one provides a state management without relation with namespace, and all operations related to this API will be made based on the global network namespace. + +The API is based on the data structure `lunatik_State` which is used to perform all needed operations. + +## The `lunatik_State` struct + +Defined at `states.h` as: + +```c +typedef struct lunatik_state { + struct hlist_node node; + struct lunatik_instance instance; + struct genl_info usr_state_info; + lua_State *L; + char *code_buffer; + int buffer_offset; + spinlock_t lock; + refcount_t users; + size_t maxalloc; + size_t curralloc; + size_t scriptsize; + unsigned char name[LUNATIK_NAME_MAXSIZE]; +} lunatik_State; +``` + +The elements in the struct has the following meaning: + +**`struct hlist_node node`** + +Is a variable used by kernel hash table API to storage the `lunatik_State` structure. + +**`struct lunatik_instance instance`** + +The instance of lunatik that some state belongs to. This is used to have access to informations related to the instance of lunatik that that state belongs. As mentioned at the [introduction](#introduction), its possible to have multiples set of states stored based on network namespaces, we know in what set this state belongs through this variable. + +**`struct genl_info usr_state_info`** + +Information related to the user space API. This variable is used to hold information about the user space API and consequently send needed informations through generic netlink. + +**`lua_State L`** + +Is the Lua state used by Lunatik to do all operations related to Lua. + +**`char *code_buffer`** + +A buffer used to store code through multiples function calls and contexts switchs between kernel and user space. + +**`int buffer_offset`** + +The buffer offset, used to hold information about where the cursor of `code_buffer` is at some time. + +**`spinlock_t lock`** + +Is a spinlock variable used to manage concurrency control. + +**`refcount_t users`** + +Represents how many users are referring to a given `lunatik_State`. + +**`size_t maxalloc`** + +Represents the maximum memory that the lua state `L` can use. + +**`size_t curralloc`** + +Represents the current memory that the lua state `L` is using. + +**`unsigned char name[LUNATIK_NAME_MAXSIZE]`** + +Is the unique identifier to `lunatik_State`, used to search it in the kernel hash table, note that this is limited by `LUNATIK_NAME_MAXSIZE`. + +## Namespace independent functions + +"Namespace independent functions" means that you don't have concern about namespaces management, this can be used when your aplication don't need to work isolated of other aplications. If this is not the case, then use the namespace dependent functions. + +#### `lunatik_State *lunatik_statelookup(const char *name)` + +Searches for a state with the name `name`. If a state with that name is found returns a pointer to the `lunatik_State`, returns `NULL` otherwise. + +#### `lunatik_State *lunatik_newstate(const char *name, size_t maxalloc)` + +Creates a `lunatik_State` with the max memory usage defined by `maxalloc` and a unique identifier to acess such state defined by `name`. Return a pointer to `lunatik_State` represeting the lunatik state or `NULL` if any errors occours during the creation. + +#### `int lunatik_close(const char *name)` + +Searchs and close a `lunatik_State` with the name `name`, returns `0` if no errors occours during this operation and `-1` if any error occours. + +#### `bool lunatik_getstate(lunatik_State *s)` + +Tries to get a reference to the state `s`, return `true` if such reference is succesfully acquired and `false` otherwise. +It's important to get a reference to the state before perform any action because this is the way that Lunatik knows if there is someone using the state or not (to close a state for example), so if you don't acquire the state to perform the action, the state can be closed and you will try to perform actions on a memory area that have been freed. + +#### `void lunatik_putstate(lunatik_State *s)` + +Put back the reference of the state. This tells the lunatik that you're are done with that state. + +## Namespace depedent functions + +#### `lunatik_State *lunatik_netnewstate(const char *name, size_t maxalloc, struct net *net)` + +Does the same of [`lunatik_newstate`](#lunatik_state-lunatik_newstatesize_t-maxalloc-const-char-name) but stores the state on the lunatik instance present on the network namespace referenced by `net`. + +#### `int lunatik_netclosestate(const char *name, struct net *net)` + +Does the same of [`lunatik_close`](#int-lunatik_closeconst-char-name) but closes the state stored on the lunatik instance present on the namespace referenced by `net`. + +#### `lunatik_State *lunatik_netstatelookup(const char *name, struct net *net)` + +Does the same of [`lunatik_statelookup`](#lunatik_state-lunatik_statelookupconst-char-name) but searching on the lunatik instance present on the namespace referenced by `net`. From 56208727b137e906f24eb5f8b8548ed6233c3fdb Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Sun, 16 Aug 2020 17:42:22 -0300 Subject: [PATCH 30/48] Add lunatik_getenv function --- lunatik.h | 3 +++ lunatik_core.c | 2 ++ netlink.h | 21 +++++++++++++++++++-- netlink_common.h | 2 +- states.c | 5 +++++ 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/lunatik.h b/lunatik.h index b20c834ff..7d58849da 100644 --- a/lunatik.h +++ b/lunatik.h @@ -23,6 +23,7 @@ #include "lua/lua.h" #include "lunatik_conf.h" #include "netlink.h" +#include "luautil.h" struct lunatik_instance { struct hlist_head states_table[LUNATIK_HASH_BUCKETS]; @@ -59,4 +60,6 @@ lunatik_State *lunatik_netnewstate(const char *name, size_t maxalloc, struct net int lunatik_netclosestate(const char *name, struct net *net); lunatik_State *lunatik_netstatelookup(const char *name, struct net *net); +lunatik_State *lunatik_getenv(lua_State *L); + #endif /* LUNATIK_STATES_H */ diff --git a/lunatik_core.c b/lunatik_core.c index 053c0df81..233ba4220 100644 --- a/lunatik_core.c +++ b/lunatik_core.c @@ -182,6 +182,8 @@ EXPORT_SYMBOL(lunatik_netnewstate); EXPORT_SYMBOL(lunatik_netclosestate); EXPORT_SYMBOL(lunatik_netstatelookup); +EXPORT_SYMBOL(lunatik_getenv); + extern struct genl_family lunatik_family; extern void lunatik_statesinit(void); extern void lunatik_closeall_from_default_ns(void); diff --git a/netlink.h b/netlink.h index 9151143cc..dc1a92649 100644 --- a/netlink.h +++ b/netlink.h @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2020 Matheus Rodrigues + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + #ifndef NETLINK_H #define NETLINK_H #include @@ -23,5 +41,4 @@ struct lunatik_data { size_t size; }; -#endif - +#endif /* NETLINK_H */ diff --git a/netlink_common.h b/netlink_common.h index 359b53436..6eef08f71 100644 --- a/netlink_common.h +++ b/netlink_common.h @@ -4,7 +4,7 @@ #ifdef _KERNEL extern struct genl_family lunatik_family; #include -#endif +#endif /* _KERNEL */ #define LUNATIK_FRAGMENT_SIZE (3000) // TODO Find, a size more precise #define DELIMITER 3 //How many delimiters will be necessary in each part of the message diff --git a/states.c b/states.c index 1e4f27808..f6af397ce 100644 --- a/states.c +++ b/states.c @@ -265,3 +265,8 @@ int lunatik_netclosestate(const char *name, struct net *net) return 0; } + +lunatik_State *lunatik_getenv(lua_State *L) +{ + return luaU_getenv(L, lunatik_State); +} From e863b1cd1ed66eb29f502aa46aa798c6cfed6e82 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Sun, 16 Aug 2020 20:12:08 -0300 Subject: [PATCH 31/48] Add support to get namespace from a given lunatik state --- lunatik.h | 1 + lunatik_core.c | 1 + 2 files changed, 2 insertions(+) diff --git a/lunatik.h b/lunatik.h index 7d58849da..d450741ae 100644 --- a/lunatik.h +++ b/lunatik.h @@ -28,6 +28,7 @@ struct lunatik_instance { struct hlist_head states_table[LUNATIK_HASH_BUCKETS]; struct reply_buffer reply_buffer; + struct net namespace; spinlock_t statestable_lock; spinlock_t rfcnt_lock; spinlock_t sendmessage_lock; diff --git a/lunatik_core.c b/lunatik_core.c index 233ba4220..b97bfe068 100644 --- a/lunatik_core.c +++ b/lunatik_core.c @@ -205,6 +205,7 @@ static int __net_init lunatik_instancenew(struct net *net) spin_lock_init(&(instance->rfcnt_lock)); hash_init(instance->states_table); (instance->reply_buffer).status = RB_INIT; + instance->namespace = *net; return 0; } From 4256e8d9944ffbee44b5139b986820b8edd595dc Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Sun, 23 Aug 2020 16:17:59 +0000 Subject: [PATCH 32/48] Change socket of states related operation to the state instead of session --- lib/lunatik.c | 109 ++++++++++++++++++++++++++++++++--------- lib/lunatik.h | 9 ++-- lib/lunatik_module.c | 16 +++--- lib/tests/close.lua | 14 ++++++ lib/tests/getstate.lua | 8 +-- lunatik.h | 1 + netlink.c | 27 +++++++--- 7 files changed, 137 insertions(+), 47 deletions(-) diff --git a/lib/lunatik.c b/lib/lunatik.c index 867f6da16..59b0a6e87 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -81,8 +81,8 @@ static int send_simple_control_msg(struct lunatik_session *session, int command, return err; } -static int send_fragment(struct lunatik_session *session, const char *original_script, int offset, - const char *state_name, const char *script_name, int flags) +static int send_fragment(struct lunatik_nl_state *state, const char *original_script, int offset, + const char *script_name, int flags) { struct nl_msg *msg; char *fragment; @@ -98,7 +98,7 @@ static int send_fragment(struct lunatik_session *session, const char *original_s } strncpy(fragment, original_script + (offset * LUNATIK_FRAGMENT_SIZE), LUNATIK_FRAGMENT_SIZE); - NLA_PUT_STRING(msg, STATE_NAME, state_name); + NLA_PUT_STRING(msg, STATE_NAME, state->name); NLA_PUT_STRING(msg, CODE, fragment); if (offset == 0) @@ -109,7 +109,7 @@ static int send_fragment(struct lunatik_session *session, const char *original_s NLA_PUT_U8(msg, FLAGS, flags); - if ((err = nl_send_auto(session->control_sock, msg)) < 0) { + if ((err = nl_send_auto(state->control_sock, msg)) < 0) { printf("Failed to send fragment\n %s\n", nl_geterror(err)); nlmsg_free(msg); return err; @@ -125,7 +125,7 @@ static int send_fragment(struct lunatik_session *session, const char *original_s return err; } -static int receive_op_result(struct lunatik_session *session){ +static int receive_session_op_result(struct lunatik_session *session){ int ret; if ((ret = nl_recvmsgs_default(session->control_sock))) { @@ -143,6 +143,24 @@ static int receive_op_result(struct lunatik_session *session){ return 0; } +static int receive_state_op_result(struct lunatik_nl_state *state){ + int ret; + + if ((ret = nl_recvmsgs_default(state->control_sock))) { + printf("Failed to receive message from kernel: %s\n", nl_geterror(ret)); + return ret; + } + + nl_wait_for_ack(state->control_sock); + + if (state->cb_result == CB_ERROR){ + state->cb_result = CB_EMPTY_RESULT; + return -1; + } + + return 0; +} + int init_recv_datasocket_on_kernel(struct lunatik_nl_state *state) { struct nl_msg *msg; @@ -197,49 +215,49 @@ int lunatikS_newstate(struct lunatik_session *session, struct lunatik_nl_state * return ret; } - return receive_op_result(session); + return receive_session_op_result(session); nla_put_failure: printf("Failed to put attributes on message\n"); return ret; } -int lunatikS_closestate(struct lunatik_nl_state *state) +int lunatik_closestate(struct lunatik_nl_state *state) { - struct lunatik_session *session; struct nl_msg *msg; int ret = -1; - session = state->session; - if ((msg = prepare_message(DESTROY_STATE, 0)) == NULL) return ret; NLA_PUT_STRING(msg, STATE_NAME, state->name); - if ((ret = nl_send_auto(session->control_sock, msg)) < 0) { - printf("Failed to send destroy message:\n %s\n", nl_geterror(ret)); + if ((ret = nl_send_auto(state->control_sock, msg)) < 0) { + printf("Failed to send destroy message:\n\t%s\n", nl_geterror(ret)); return ret; } + ret = receive_state_op_result(state); + nl_socket_free(state->send_datasock); nl_socket_free(state->recv_datasock); + nl_socket_free(state->control_sock); - return receive_op_result(session); + return ret; nla_put_failure: printf("Failed to put attributes on netlink message\n"); return ret; } -int lunatikS_dostring(struct lunatik_session *session, const char *state_name, +int lunatik_dostring(struct lunatik_nl_state *state, const char *script, const char *script_name, size_t total_code_size) { int err = -1; int parts = 0; if (total_code_size <= LUNATIK_FRAGMENT_SIZE) { - err = send_fragment(session, script, 0, state_name, script_name, LUNATIK_INIT | LUNATIK_DONE); + err = send_fragment(state, script, 0, script_name, LUNATIK_INIT | LUNATIK_DONE); if (err) return err; } else { @@ -249,22 +267,22 @@ int lunatikS_dostring(struct lunatik_session *session, const char *state_name, for (int i = 0; i < parts - 1; i++) { if (i == 0) - err = send_fragment(session, script, i, state_name, script_name, LUNATIK_INIT | LUNATIK_MULTI); + err = send_fragment(state, script, i, script_name, LUNATIK_INIT | LUNATIK_MULTI); else - err = send_fragment(session, script, i, state_name, script_name, LUNATIK_MULTI); + err = send_fragment(state, script, i, script_name, LUNATIK_MULTI); - nl_wait_for_ack(session->control_sock); + nl_wait_for_ack(state->control_sock); if (err) return err; } - err = send_fragment(session, script, parts - 1, state_name, script_name, LUNATIK_DONE); + err = send_fragment(state, script, parts - 1, script_name, LUNATIK_DONE); if (err) return err; } - return receive_op_result(session); + return receive_state_op_result(state); } int lunatikS_list(struct lunatik_session *session) @@ -446,7 +464,6 @@ static int response_handler(struct nl_msg *msg, void *arg) { case CREATE_STATE: case DESTROY_STATE: - case EXECUTE_CODE: if (attrs_tb[OP_SUCESS] && nla_get_u8(attrs_tb[OP_SUCESS])) { session->cb_result = CB_SUCCESS; } else if (attrs_tb[OP_ERROR] && nla_get_u8(attrs_tb[OP_ERROR])) { @@ -510,6 +527,30 @@ static int response_handler(struct nl_msg *msg, void *arg) return NL_OK; } +static int response_state_handler(struct nl_msg *msg, void *arg) +{ + struct nlmsghdr *nh = nlmsg_hdr(msg); + struct genlmsghdr *gnlh = genlmsg_hdr(nh); + struct nlattr * attrs_tb[ATTRS_COUNT + 1]; + struct lunatik_nl_state *state = (struct lunatik_nl_state *)arg; + + if (nla_parse(attrs_tb, ATTRS_COUNT, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL)) + { + printf("Error parsing attributes\n"); + state->cb_result = CB_ERROR; + return NL_OK; + } + + if (attrs_tb[OP_SUCESS] && nla_get_u8(attrs_tb[OP_SUCESS])) { + state->cb_result = CB_SUCCESS; + } else if (attrs_tb[OP_ERROR] && nla_get_u8(attrs_tb[OP_ERROR])) { + state->cb_result = CB_ERROR; + } + + return NL_OK; +} + static int init_data_buffer(struct data_buffer *data_buffer, size_t size); static int data_handler(struct nl_msg *msg, void *arg) @@ -657,7 +698,7 @@ void release_data_buffer(struct data_buffer *data_buffer) data_buffer->size = 0; } -int lunatikS_receive(struct lunatik_nl_state *state) +int lunatik_receive(struct lunatik_nl_state *state) { int err = 0; @@ -671,7 +712,7 @@ int lunatikS_receive(struct lunatik_nl_state *state) return err; } -int lunatikS_initdata(struct lunatik_nl_state *state) +static int lunatik_initdata(struct lunatik_nl_state *state) { int ret = 0; @@ -712,7 +753,7 @@ struct lunatik_nl_state *lunatikS_getstate(struct lunatik_session *session, cons return NULL; } - if (receive_op_result(session)) + if (receive_session_op_result(session)) return NULL; if ((session->cb_result == CB_STATE_NOT_FOUND) || (session->cb_result == CB_ERROR)) { @@ -726,3 +767,23 @@ struct lunatik_nl_state *lunatikS_getstate(struct lunatik_session *session, cons printf("Failed to put attributes on netlink message\n"); return NULL; } + +int lunatik_initstate(struct lunatik_nl_state *state) +{ + int err; + + if ((err = lunatik_initdata(state))) { + return err; + } + + if ((err = init_socket(&state->control_sock))) { + printf("Failed to initialize the control socket for state %s\n", state->name); + nl_socket_free(state->control_sock); + return err; + } + + nl_socket_modify_cb(state->control_sock, NL_CB_MSG_IN, NL_CB_CUSTOM, response_state_handler, state); + + return 0; +} + diff --git a/lib/lunatik.h b/lib/lunatik.h index 733f3dfb3..fdf7077d0 100644 --- a/lib/lunatik.h +++ b/lib/lunatik.h @@ -48,6 +48,7 @@ struct lunatik_nl_state { struct lunatik_session *session; struct nl_sock *send_datasock; struct nl_sock *recv_datasock; + struct nl_sock *control_sock; struct data_buffer data_buffer; enum callback_result cb_result; uint32_t maxalloc; @@ -94,16 +95,16 @@ void lunatikS_close(struct lunatik_session *session); int lunatikS_newstate(struct lunatik_session *session, struct lunatik_nl_state *s); -int lunatikS_closestate(struct lunatik_nl_state *state); +int lunatik_closestate(struct lunatik_nl_state *state); -int lunatikS_dostring(struct lunatik_session *session, const char *state_name, +int lunatik_dostring(struct lunatik_nl_state *state, const char *script, const char *script_name, size_t total_code_size); int lunatikS_list(struct lunatik_session *session); -int lunatikS_receive(struct lunatik_nl_state *state); +int lunatik_receive(struct lunatik_nl_state *state); -int lunatikS_initdata(struct lunatik_nl_state *state); +int lunatik_initstate(struct lunatik_nl_state *state); struct lunatik_nl_state *lunatikS_getstate(struct lunatik_session *session, const char *name); diff --git a/lib/lunatik_module.c b/lib/lunatik_module.c index b4409e02f..1c0609858 100644 --- a/lib/lunatik_module.c +++ b/lib/lunatik_module.c @@ -141,8 +141,8 @@ static int lsession_newstate(lua_State *L) return 2; } - if (lunatikS_initdata(state)) { - lua_pushnil(L); + if (lunatik_initstate(state)) { + pusherrmsg(L, "Failed to initialize state\n"); return 1; } @@ -154,7 +154,7 @@ static int lsession_newstate(lua_State *L) static int lstate_close(lua_State *L) { struct lunatik_nl_state *state = getnlstate(L); - if (lunatikS_closestate(state)){ + if (lunatik_closestate(state)){ lua_pushnil(L); return 1; } @@ -166,8 +166,6 @@ static int lstate_close(lua_State *L) static int lstate_dostring(lua_State *L) { struct lunatik_nl_state *s = getnlstate(L); - struct lunatik_session *session = s->session; - const char *name = s->name; size_t len; const char *payload = luaL_checklstring(L, 2, &len); const char *script_name = luaL_optstring(L, 3, "Lunatik"); @@ -176,7 +174,7 @@ static int lstate_dostring(lua_State *L) printf("script name too long\n"); goto error; } - int status = lunatikS_dostring(session, name, payload, script_name, len); + int status = lunatik_dostring(s, payload, script_name, len); if (status) goto error; @@ -243,8 +241,8 @@ static int lsession_getstate(lua_State *L) *state = *received_state; - if (lunatikS_initdata(state)) { - lua_pushnil(L); + if (lunatik_initstate(state)) { + pusherrmsg(L, "Failed to initialize the state\n"); return 1; } @@ -292,7 +290,7 @@ static int lstate_datareceive(lua_State *L) struct lunatik_nl_state *state = getnlstate(L); char *memory; - if (lunatikS_receive(state)) + if (lunatik_receive(state)) goto error; memory = luamem_newalloc(L, state->data_buffer.size); diff --git a/lib/tests/close.lua b/lib/tests/close.lua index 38fa69c85..7946ff898 100644 --- a/lib/tests/close.lua +++ b/lib/tests/close.lua @@ -7,3 +7,17 @@ assert(s1 ~= nil) local err = s1:close() assert(err ~= nil) + +-- Using state after close session +s1 = session:new's1' +assert(s1 ~= nil) + +session:close() +assert(s1:getname() == 's1') + +err = s1:close() +assert(err) + +-- Trying to close nonexistent state +err = s1:close() +assert(err == nil) diff --git a/lib/tests/getstate.lua b/lib/tests/getstate.lua index eadf62d1a..a62549482 100644 --- a/lib/tests/getstate.lua +++ b/lib/tests/getstate.lua @@ -7,20 +7,20 @@ local kscript = [[ print'olá mundo!' ]] +-- Testing state normal state creation local s1 = session:new's1' assert(s1 ~= nil) local err = s1:dostring(kscript) assert(err ~= nil) +-- Trying to get a state created on user space local state = session:getstate's1' -assert(state ~= nil) -err = state:dostring(kscript) -assert(err ~= nil) +assert(state == nil) +-- Try to get a state nonexistent state local state2 = session:getstate's4' assert(state2 == nil) s1:close() -state:close() session:close() diff --git a/lunatik.h b/lunatik.h index d450741ae..ff8392281 100644 --- a/lunatik.h +++ b/lunatik.h @@ -47,6 +47,7 @@ typedef struct lunatik_state { size_t maxalloc; size_t curralloc; size_t scriptsize; + bool inuse; unsigned char name[LUNATIK_NAME_MAXSIZE]; } lunatik_State; diff --git a/netlink.c b/netlink.c index 7a9da5aa4..11c5e1834 100644 --- a/netlink.c +++ b/netlink.c @@ -230,13 +230,20 @@ static int lunatikN_newstate(struct sk_buff *buff, struct genl_info *info) s = lunatik_netnewstate(state_name, *max_alloc, genl_info_net(info)); - if (s == NULL) { - reply_with(OP_ERROR, CREATE_STATE, info); - } else { - s->instance = *instance; - reply_with(OP_SUCESS, CREATE_STATE, info); - } + if (s == NULL) + goto error; + + if (s->inuse) + goto error; + + s->instance = *instance; + reply_with(OP_SUCESS, CREATE_STATE, info); + s->inuse = true; + + return 0; +error: + reply_with(OP_ERROR, CREATE_STATE, info); return 0; } @@ -627,11 +634,19 @@ static int lunatikN_sendstate(struct sk_buff *buff, struct genl_info *info) return 0; } + if (state->inuse) { + pr_info("State %s is already in use\n", state_name); + reply_with(OP_ERROR, GET_STATE, info); + return 0; + } + if (sendstate_msg(state, info)) { pr_err("Failed to send message to user space\n"); reply_with(OP_ERROR, GET_STATE, info); } + state->inuse = true; + return 0; } From 2987ecafa8f5f22611a623392d1796cc6841823e Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Sun, 23 Aug 2020 21:33:38 +0000 Subject: [PATCH 33/48] Add function to get current memory usage of states, update documentation and rename state creation API --- doc/lib.md | 20 ++++++++++++-- doc/lunatik.md | 9 ++++++ lib/lunatik.c | 26 +++++++++++++++++ lib/lunatik.h | 2 ++ lib/lunatik_module.c | 17 +++++++++++- lib/tests/close.lua | 4 +-- lib/tests/create.lua | 21 ++++++++------ lib/tests/getstate.lua | 2 +- lib/tests/list.lua | 16 +++++------ lib/tests/receive.lua | 2 +- lib/tests/send.lua | 4 +-- netlink.c | 63 ++++++++++++++++++++++++++++++++++++++++++ netlink_common.h | 1 + 13 files changed, 161 insertions(+), 26 deletions(-) diff --git a/doc/lib.md b/doc/lib.md index 2477a6ead..ce32b745d 100644 --- a/doc/lib.md +++ b/doc/lib.md @@ -49,7 +49,7 @@ local session = lunatik.session() Now you can use the variable `session` to do all operations related to control API. These operations will be showed next. -#### `session:new(name [, maxalloc])` +#### `session:newstate(name [, maxalloc])` Tells the lunatik kernel module to create a state with the name `name`. If some value is passed to `maxalloc` that you be the maximum amount of memory that the state `name` can use during it execution, if no value is passed, a state with a default `maxalloc` will be created. If the state is succesfully created, the function returns a userdata, such userdata is used to perform all needed operations on that state. You can imagine this userdata as your user space representation of the state created on the kernel side. If the state creation fails, this function returns a `nil` value alongside with a error message. @@ -65,12 +65,16 @@ Closes the connection with the kernel, after that, all references for the states Gets a user representation of the state with the name `name` which was created on kernel. Returns a userdata as described on [`session:new`](#sessionnewname--maxalloc) if such state is found and `nil` otherwise. +#### `session:getfd()` + +Returns the session file descriptor of the control socket. + ### State related operations As mentioned at [`session:new`](#sessionnewname--maxalloc) function, when you call that function, if the state is succesfully created, it will be returned a userdata. That userdata is used to perform all operations related to that state, for example: ```lua -local mystate = session:new'somename' +local mystate = session:newstate'somename' ``` This code will create a state named `somename` on kernel and store the userdata to perform all operations related to the state `somename` on the variable `mystate`. From now on, it will be used `mystate` to explain all operations that can be done at that state. @@ -83,6 +87,18 @@ Runs on the kernel, the code given by `code`, you can give a name for that code, Closes on the kernel the state that `mystate` represents. +#### `mystate:getname()` + +Returns the name of state `mystate` as it is in the kernel. + +#### `mystate:getmaxalloc()` + +Return the maximum amount of memory that `mystate` can use in the kernel. + +#### `mystate:getcurralloc()` + +Return the current memory usage in the kernel of the state represent by `mystate`. + ## Data API To transmit data from kernel to user space (and vice versa), we use lua memory (see [lua memory](https://github.com/luainkernel/lua-memory)). diff --git a/doc/lunatik.md b/doc/lunatik.md index e2bd347b8..8c5726ed1 100644 --- a/doc/lunatik.md +++ b/doc/lunatik.md @@ -23,6 +23,7 @@ typedef struct lunatik_state { size_t maxalloc; size_t curralloc; size_t scriptsize; + bool inuse; unsigned char name[LUNATIK_NAME_MAXSIZE]; } lunatik_State; ``` @@ -69,6 +70,10 @@ Represents the maximum memory that the lua state `L` can use. Represents the current memory that the lua state `L` is using. +**`bool inuse`** + +Tells if the states is in use for some process on the user space. + **`unsigned char name[LUNATIK_NAME_MAXSIZE]`** Is the unique identifier to `lunatik_State`, used to search it in the kernel hash table, note that this is limited by `LUNATIK_NAME_MAXSIZE`. @@ -98,6 +103,10 @@ It's important to get a reference to the state before perform any action because Put back the reference of the state. This tells the lunatik that you're are done with that state. +#### `lunatik_State *lunatik_getenv(lua_State *L)` + +Returns the lunatik state which the lua state `L` is contained into. + ## Namespace depedent functions #### `lunatik_State *lunatik_netnewstate(const char *name, size_t maxalloc, struct net *net)` diff --git a/lib/lunatik.c b/lib/lunatik.c index 59b0a6e87..95961d994 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -544,8 +544,14 @@ static int response_state_handler(struct nl_msg *msg, void *arg) if (attrs_tb[OP_SUCESS] && nla_get_u8(attrs_tb[OP_SUCESS])) { state->cb_result = CB_SUCCESS; + return NL_OK; } else if (attrs_tb[OP_ERROR] && nla_get_u8(attrs_tb[OP_ERROR])) { state->cb_result = CB_ERROR; + return NL_OK; + } + + if (attrs_tb[CURR_ALLOC]) { + state->curralloc = nla_get_u32(attrs_tb[CURR_ALLOC]); } return NL_OK; @@ -787,3 +793,23 @@ int lunatik_initstate(struct lunatik_nl_state *state) return 0; } +int lunatik_getcurralloc(struct lunatik_nl_state *state) +{ + struct nl_msg *msg; + int err = -1; + + if ((msg = prepare_message(GET_CURRALLOC, 0)) == NULL) + return err; + + NLA_PUT_STRING(msg, STATE_NAME, state->name); + + if ((err = nl_send_auto(state->control_sock, msg)) < 0) + return err; + + return receive_state_op_result(state); + +nla_put_failure: + printf("Failed to put attribute to get current alloc of state %s\n", state->name); + return -1; +} + diff --git a/lib/lunatik.h b/lib/lunatik.h index fdf7077d0..afd015416 100644 --- a/lib/lunatik.h +++ b/lib/lunatik.h @@ -111,4 +111,6 @@ struct lunatik_nl_state *lunatikS_getstate(struct lunatik_session *session, cons int lunatik_datasend(struct lunatik_nl_state *state, const char *payload, size_t len); +int lunatik_getcurralloc(struct lunatik_nl_state *state); + #endif /* LUNATIK_H */ diff --git a/lib/lunatik_module.c b/lib/lunatik_module.c index 1c0609858..ca962678e 100644 --- a/lib/lunatik_module.c +++ b/lib/lunatik_module.c @@ -305,10 +305,24 @@ static int lstate_datareceive(lua_State *L) return 1; } +static int lstate_getcurralloc(lua_State *L) +{ + struct lunatik_nl_state *state = getnlstate(L); + + if (lunatik_getcurralloc(state)) { + lua_pushnil(L); + return 1; + } + + lua_pushinteger(L, state->curralloc); + + return 1; +} + static const luaL_Reg session_mt[] = { {"close", lsession_close}, {"getfd", lsession_getfd}, - {"new", lsession_newstate}, + {"newstate", lsession_newstate}, {"list", lsession_list}, {"getstate", lsession_getstate}, {"__gc", lsession_gc}, @@ -319,6 +333,7 @@ static const luaL_Reg state_mt[] = { {"dostring", lstate_dostring}, {"getname", lstate_getname}, {"getmaxalloc", lstate_getmaxalloc}, + {"getcurralloc", lstate_getcurralloc}, {"close", lstate_close}, {"send", lstate_datasend}, {"receive", lstate_datareceive}, diff --git a/lib/tests/close.lua b/lib/tests/close.lua index 7946ff898..faf23229b 100644 --- a/lib/tests/close.lua +++ b/lib/tests/close.lua @@ -2,14 +2,14 @@ local lunatik = require'lunatik' local session = lunatik.session() -- Normal close -local s1 = session:new's1' +local s1 = session:newstate's1' assert(s1 ~= nil) local err = s1:close() assert(err ~= nil) -- Using state after close session -s1 = session:new's1' +s1 = session:newstate's1' assert(s1 ~= nil) session:close() diff --git a/lib/tests/create.lua b/lib/tests/create.lua index 1b3183cb1..6f71c26c6 100644 --- a/lib/tests/create.lua +++ b/lib/tests/create.lua @@ -3,30 +3,33 @@ local lunatik = require'lunatik' local session = lunatik.session() -- Normal creation -local s1 = session:new's1' -assert(s1 ~= nil) +local s1 = session:newstate's1' +assert(s1) +assert(s1:getname() == 's1') +assert(s1:getmaxalloc() == lunatik.defaultmaxallocbytes) +-- assert(s1:getcurralloc() ~= nil) -- Max alloc greater than MIN_ALLOC -local s2 = session:new('s2', 100000) -assert(s2 ~= nil) +local s2 = session:newstate('s2', 100000) +assert(s2) -- Max alloc less than MIN_ALLOC -local s3 = session:new('s3', 1) +local s3 = session:newstate('s3', 1) assert(s3 == nil) -- State already exists -local s4 = session:new's1' +local s4 = session:newstate's1' assert(s4 == nil) -- State creation from another session local session2 = lunatik.session() -- Normal creation -ss1 = session2:new'ss1' -assert(ss1 ~= nil) +ss1 = session2:newstate'ss1' +assert(ss1) -- State created from another session -ss2 = session2:new's1' +ss2 = session2:newstate's1' assert(ss2 == nil) diff --git a/lib/tests/getstate.lua b/lib/tests/getstate.lua index a62549482..07ce41cd7 100644 --- a/lib/tests/getstate.lua +++ b/lib/tests/getstate.lua @@ -8,7 +8,7 @@ local kscript = [[ ]] -- Testing state normal state creation -local s1 = session:new's1' +local s1 = session:newstate's1' assert(s1 ~= nil) local err = s1:dostring(kscript) assert(err ~= nil) diff --git a/lib/tests/list.lua b/lib/tests/list.lua index f5a6264f8..a8433340b 100644 --- a/lib/tests/list.lua +++ b/lib/tests/list.lua @@ -3,17 +3,17 @@ local session = lunatik.session() local session2 = lunatik.session() -- Create states that will be present on the list -local s1 = session:new's1' -local s2 = session:new's2' -local s3 = session:new('s3', 100000) +local s1 = session:newstate's1' +local s2 = session:newstate's2' +local s3 = session:newstate('s3', 100000) -local ss1 = session2:new'ss1' -local ss2 = session2:new'ss2' -local ss3 = session2:new('ss3', 100000) +local ss1 = session2:newstate'ss1' +local ss2 = session2:newstate'ss2' +local ss3 = session2:newstate('ss3', 100000) -- Create states that are not be present on the list -session:new('s4', 1) -session2:new('ss4', 1) +session:newstate('s4', 1) +session2:newstate('ss4', 1) -- Get the states information from kernel local states = session:list() diff --git a/lib/tests/receive.lua b/lib/tests/receive.lua index 4020a8921..76fe5183f 100644 --- a/lib/tests/receive.lua +++ b/lib/tests/receive.lua @@ -10,7 +10,7 @@ local kscript = [[ netlink.send(buffer) ]] -local s1 = session:new's1' +local s1 = session:newstate's1' assert(s1 ~= nil) local err = s1:dostring(kscript, 'receive') diff --git a/lib/tests/send.lua b/lib/tests/send.lua index c971f6508..d2562f0c3 100644 --- a/lib/tests/send.lua +++ b/lib/tests/send.lua @@ -12,10 +12,10 @@ local kscript = [[ end ]] -local s1 = session:new's1' +local s1 = session:newstate's1' assert(s1 ~= nil) -local s2 = session:new's2' +local s2 = session:newstate's2' assert(s2 ~= nil) local err = s1:dostring(kscript, 'send script') diff --git a/netlink.c b/netlink.c index 11c5e1834..3e9e14128 100644 --- a/netlink.c +++ b/netlink.c @@ -50,6 +50,7 @@ static int lunatikN_list(struct sk_buff *buff, struct genl_info *info); static int lunatikN_data(struct sk_buff *buff, struct genl_info *info); static int lunatikN_datainit(struct sk_buff *buff, struct genl_info *info); static int lunatikN_sendstate(struct sk_buff *buff, struct genl_info *info); +static int lunatikN_getcurralloc(struct sk_buff *buff, struct genl_info *info); struct nla_policy lunatik_policy[ATTRS_COUNT] = { [STATE_NAME] = { .type = NLA_STRING }, @@ -115,6 +116,13 @@ static const struct genl_ops l_ops[] = { .doit = lunatikN_sendstate, #if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) .policy = lunatik_policy +#endif + }, + { + .cmd = GET_CURRALLOC, + .doit = lunatikN_getcurralloc, +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) + .policy = lunatik_policy #endif } }; @@ -651,6 +659,61 @@ static int lunatikN_sendstate(struct sk_buff *buff, struct genl_info *info) } +static int send_curralloc(int curralloc, struct genl_info *info) +{ + struct sk_buff *obuff; + void *msg_head; + + if ((obuff = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL)) == NULL) { + pr_err("Failed allocating message to an reply\n"); + return -1; + } + + if ((msg_head = genlmsg_put_reply(obuff, info, &lunatik_family, 0, GET_CURRALLOC)) == NULL) { + pr_err("Failed to put generic netlink header\n"); + return -1; + } + + if (nla_put_u32(obuff, CURR_ALLOC, curralloc)) { + pr_err("Failed to put attributes on socket buffer\n"); + return -1; + } + + genlmsg_end(obuff, msg_head); + + if (genlmsg_reply(obuff, info) < 0) { + pr_err("Failed to send message to user space\n"); + return -1; + } + + pr_debug("Message sent to user space\n"); + return 0; +} + +static int lunatikN_getcurralloc(struct sk_buff *buff, struct genl_info *info) +{ + struct lunatik_state *s; + char *state_name; + + pr_debug("Received a GET_CURRALLOC message\n"); + + state_name = (char *)nla_data(info->attrs[STATE_NAME]); + + s = lunatik_netstatelookup(state_name, genl_info_net(info)); + + if (s == NULL) + goto error; + + if (send_curralloc(s->curralloc, info)) + goto error; + + return 0; + +error: + reply_with(OP_ERROR, GET_CURRALLOC, info); + return 0; +} + /* Note: Most of the function below is copied from NFLua: https://github.com/cujoai/nflua * Copyright (C) 2017-2019 CUJO LLC * diff --git a/netlink_common.h b/netlink_common.h index 6eef08f71..3717baf00 100644 --- a/netlink_common.h +++ b/netlink_common.h @@ -25,6 +25,7 @@ enum lunatik_operations { DATA, DATA_INIT, GET_STATE, + GET_CURRALLOC, }; enum lunatik_attrs { From ea758c80bb90dc910c8ed17be244cf2e8372b943 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Mon, 24 Aug 2020 15:51:12 +0000 Subject: [PATCH 34/48] Update makefile to automatically remove unecessary objects (Last GSoC 2020 commit) --- deps/lua-memory | 2 +- lib/Makefile | 11 +++++++---- luanetlink.c | 1 + netlink_common.h | 18 ++++++++++++++++++ 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/deps/lua-memory b/deps/lua-memory index 6909c01bf..3fa98360a 160000 --- a/deps/lua-memory +++ b/deps/lua-memory @@ -1 +1 @@ -Subproject commit 6909c01bf3b333f23fa1466dd60208f35ffc5aca +Subproject commit 3fa98360a2a39d777dd8876772504f317c076b28 diff --git a/lib/Makefile b/lib/Makefile index 70beb6d21..3354af122 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -27,9 +27,9 @@ OBJS = $(patsubst %.c,%.o,$(wildcard *.c)) DEPS = $(OBJS:.o=.d) .PHONY: all -all: lua_memory $(LIBS) +all: lua_memory $(LIBS) clean_objs -lua_memory: +lua_memory: lua_memory_clean $(MAKE) -C ../deps/lua-memory/src linux CFLAGS="-fPIC -I/usr/include/lua5.3" %.so: @@ -41,10 +41,13 @@ lua_memory: -include $(DEPS) .PHONY: clean -clean: lua_clean +clean: lua_memory_clean $(RM) $(LIBS) $(OBJS) $(DEPS) -lua_clean: +lua_memory_clean: $(MAKE) -C ../deps/lua-memory/src clean +clean_objs: + $(MAKE) -C ../deps/lua-memory/src clean_objs + $(LIBS): $(OBJS) diff --git a/luanetlink.c b/luanetlink.c index 77109c403..fe54ae633 100644 --- a/luanetlink.c +++ b/luanetlink.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2020 Matheus Rodrigues * Copyright (C) 2017-2019 CUJO LLC * * This program is free software; you can redistribute it and/or modify diff --git a/netlink_common.h b/netlink_common.h index 3717baf00..a16acb9c1 100644 --- a/netlink_common.h +++ b/netlink_common.h @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2020 Matheus Rodrigues + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + #ifndef NETLINK_COMMOM_H #define NETLINK_COMMOM_H From b325f156f246ac45698ddabf8e8fa70a8d0bb4d3 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Fri, 4 Sep 2020 12:34:31 +0000 Subject: [PATCH 35/48] fixup! Netlink implementation --- netlink_common.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/netlink_common.h b/netlink_common.h index a16acb9c1..d986518e7 100644 --- a/netlink_common.h +++ b/netlink_common.h @@ -24,16 +24,16 @@ extern struct genl_family lunatik_family; #include #endif /* _KERNEL */ -#define LUNATIK_FRAGMENT_SIZE (3000) // TODO Find, a size more precise -#define DELIMITER 3 //How many delimiters will be necessary in each part of the message +#define LUNATIK_FRAGMENT_SIZE (3000) /* TODO Find, a more precise size */ +#define DELIMITER (3) /* How many delimiters will be necessary in each part of the message */ /*Lunatik generic netlink protocol flags*/ -#define LUNATIK_INIT 0x01 /* Initializes the needed variables for script execution */ -#define LUNATIK_MULTI 0x02 /* A Fragment of a multipart message */ -#define LUNATIK_DONE 0x04 /* Last message of a multipart message */ +#define LUNATIK_INIT (0x01) /* Initializes the needed variables for script execution */ +#define LUNATIK_MULTI (0x02) /* A Fragment of a multipart message */ +#define LUNATIK_DONE (0x04) /* Last message of a multipart message */ -#define LUNATIK_FAMILY "lunatik_family" -#define LUNATIK_NLVERSION 1 +#define LUNATIK_FAMILY ("lunatik_family") +#define LUNATIK_NLVERSION (1) enum lunatik_operations { CREATE_STATE = 1, /* Starts at 1 because 0 is used by generic netlink */ @@ -64,7 +64,7 @@ enum lunatik_attrs { CURR_ALLOC, STATE_NOT_FOUND, ATTRS_COUNT -#define ATTRS_MAX (ATTRS_COUNT - 1) +#define ATTRS_MAX (ATTRS_COUNT - 1) }; #endif /* NETLINK_COMMOM_H */ From 103e61f8931c8ffaeda53899b70ef03d9371395c Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Mon, 7 Sep 2020 21:54:43 +0000 Subject: [PATCH 36/48] Update lua-memory submodule --- deps/lua-memory | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/lua-memory b/deps/lua-memory index 3fa98360a..3fe2285c2 160000 --- a/deps/lua-memory +++ b/deps/lua-memory @@ -1 +1 @@ -Subproject commit 3fa98360a2a39d777dd8876772504f317c076b28 +Subproject commit 3fe2285c2c0db27db58d52605d668ce5435f779d From 5bffd2a9211a46fb515f33ce5ee0309648bb995f Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Tue, 8 Sep 2020 12:33:31 +0000 Subject: [PATCH 37/48] fixup! Change lua_Buffer to a normal buffer --- netlink.c | 6 +++--- netlink.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/netlink.c b/netlink.c index 3e9e14128..6752a1562 100644 --- a/netlink.c +++ b/netlink.c @@ -257,10 +257,10 @@ static int lunatikN_newstate(struct sk_buff *buff, struct genl_info *info) static void init_codebuffer(lunatik_State *s, struct genl_info *info) { - s->scriptsize = *((u32*)nla_data(info->attrs[SCRIPT_SIZE])); + s->scriptsize = *((u32*)nla_data(info->attrs[SCRIPT_SIZE])); - if ((s->code_buffer = kmalloc(s->scriptsize, GFP_KERNEL)) == NULL) { - pr_err("Failed allocating memory to code buffer\n"); + if ((s->code_buffer = kmalloc(s->scriptsize, GFP_KERNEL)) == NULL) { + pr_err("Failed allocating memory to code buffer\n"); reply_with(OP_ERROR, EXECUTE_CODE, info); } diff --git a/netlink.h b/netlink.h index dc1a92649..caa286f75 100644 --- a/netlink.h +++ b/netlink.h @@ -37,8 +37,8 @@ struct reply_buffer { }; struct lunatik_data { - char *buffer; - size_t size; + char *buffer; + size_t size; }; #endif /* NETLINK_H */ From 63021158280f15a00de85fc193b10f239df050f6 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Tue, 8 Sep 2020 12:57:07 +0000 Subject: [PATCH 38/48] fixup! Add function to get current memory usage of states, update documentation and rename state creation API --- lib/lunatik.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/lunatik.c b/lib/lunatik.c index 95961d994..6bb1fda45 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -812,4 +812,3 @@ int lunatik_getcurralloc(struct lunatik_nl_state *state) printf("Failed to put attribute to get current alloc of state %s\n", state->name); return -1; } - From de406cf98c857386d52676a57ffe6099cd560549 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Tue, 8 Sep 2020 19:58:17 +0000 Subject: [PATCH 39/48] fixup! Adapt NFLua states management to Lunatik --- Makefile | 18 +++++++++--------- lunatik_conf.h | 10 +++++----- states.c | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 5ea5da821..b43ce3582 100644 --- a/Makefile +++ b/Makefile @@ -28,19 +28,19 @@ endif obj-$(CONFIG_LUNATIK) += lunatik.o lua-objs = lua/lapi.o lua/lcode.o lua/lctype.o lua/ldebug.o lua/ldo.o \ - lua/ldump.o lua/lfunc.o lua/lgc.o lua/llex.o lua/lmem.o \ - lua/lobject.o lua/lopcodes.o lua/lparser.o lua/lstate.o \ - lua/lstring.o lua/ltable.o lua/ltm.o \ - lua/lundump.o lua/lvm.o lua/lzio.o lua/lauxlib.o lua/lbaselib.o \ - lua/lbitlib.o lua/lcorolib.o lua/ldblib.o lua/lstrlib.o \ - lua/ltablib.o lua/lutf8lib.o lua/loslib.o lua/lmathlib.o lua/linit.o \ - lua/loadlib.o luautil.o + lua/ldump.o lua/lfunc.o lua/lgc.o lua/llex.o lua/lmem.o \ + lua/lobject.o lua/lopcodes.o lua/lparser.o lua/lstate.o \ + lua/lstring.o lua/ltable.o lua/ltm.o \ + lua/lundump.o lua/lvm.o lua/lzio.o lua/lauxlib.o lua/lbaselib.o \ + lua/lbitlib.o lua/lcorolib.o lua/ldblib.o lua/lstrlib.o \ + lua/ltablib.o lua/lutf8lib.o lua/loslib.o lua/lmathlib.o lua/linit.o \ + lua/loadlib.o luautil.o lua_memory-objs = deps/lua-memory/src/lmemlib.o deps/lua-memory/src/lmemmod.o lunatik-objs += $(lua-objs) \ - arch/$(ARCH)/setjmp.o util/modti3.o lunatik_core.o states.o netlink.o $(lua_memory-objs) \ - luanetlink.o + arch/$(ARCH)/setjmp.o util/modti3.o lunatik_core.o states.o netlink.o $(lua_memory-objs) \ + luanetlink.o ifeq ($(shell [ "${VERSION}" -lt "4" ] && [ "${VERSION}${PATCHLEVEL}" -lt "312" ] && echo y),y) lunatik-objs += util/div64.o diff --git a/lunatik_conf.h b/lunatik_conf.h index de2cffe11..cd800b300 100644 --- a/lunatik_conf.h +++ b/lunatik_conf.h @@ -20,14 +20,14 @@ #ifndef LUNATIK_CONF_H #define LUNATIK_CONF_H -#define LUNATIK_NAME_MAXSIZE 64 /* Max length of Lua state name */ +#define LUNATIK_NAME_MAXSIZE (64) /* Max length of Lua state name */ -#define LUNATIK_SCRIPTNAME_MAXSIZE 255 /* Max length of script name */ +#define LUNATIK_SCRIPTNAME_MAXSIZE (255) /* Max length of script name */ -#define LUNATIK_DEFAULT_NS get_net_ns_by_pid(1) +#define LUNATIK_DEFAULT_NS (get_net_ns_by_pid(1)) -#define LUNATIK_MIN_ALLOC_BYTES (32 * 1024UL) +#define LUNATIK_MIN_ALLOC_BYTES (32 * 1024UL) -#define LUNATIK_HASH_BUCKETS 32 +#define LUNATIK_HASH_BUCKETS (32) #endif /* LUNATIK_CONF_H */ diff --git a/states.c b/states.c index f6af397ce..11166f921 100644 --- a/states.c +++ b/states.c @@ -31,7 +31,7 @@ #include "lunatik.h" #ifndef LUNATIK_SETPAUSE -#define LUNATIK_SETPAUSE 100 +#define LUNATIK_SETPAUSE (100) #endif /* LUNATIK_SETPAUSE */ extern int luaopen_memory(lua_State *); From cb6b7697d1b23e9c4847265a7842ddbaf2c97116 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Fri, 4 Sep 2020 13:08:45 +0000 Subject: [PATCH 40/48] fixup! Add lua-memory as dependecy --- Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index b43ce3582..1ba684f4d 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ ccflags-y += -D_LUNATIK -D_KERNEL -I$(src) -D_CONFIG_FULL_PANIC -DLUNATIK_UNUSED \ - -I$(src)/lua -I$(src)/deps/lua-memory/src + -I$(src)/lua -I$(src)/deps/lua-memory/src asflags-y += -D_LUNATIK -D_KERNEL ifeq ($(ARCH), $(filter $(ARCH),i386 x86)) @@ -36,7 +36,9 @@ lua-objs = lua/lapi.o lua/lcode.o lua/lctype.o lua/ldebug.o lua/ldo.o \ lua/ltablib.o lua/lutf8lib.o lua/loslib.o lua/lmathlib.o lua/linit.o \ lua/loadlib.o luautil.o -lua_memory-objs = deps/lua-memory/src/lmemlib.o deps/lua-memory/src/lmemmod.o +lua_memory-path = deps/lua-memory/src + +lua_memory-objs = $(lua_memory-path)/lmemlib.o $(lua_memory-path)/lmemmod.o lunatik-objs += $(lua-objs) \ arch/$(ARCH)/setjmp.o util/modti3.o lunatik_core.o states.o netlink.o $(lua_memory-objs) \ From be94eca22583d583cbdfcd80e342dea5cff7f22a Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Fri, 11 Sep 2020 16:37:51 +0000 Subject: [PATCH 41/48] fixup! Add tests --- lib/runtests.sh | 6 +++--- lib/tests/create.lua | 2 -- lib/tests/getstate.lua | 2 +- lib/tests/list.lua | 2 -- lib/tests/receive.lua | 10 +++++----- lib/tests/send.lua | 8 ++++---- 6 files changed, 13 insertions(+), 17 deletions(-) diff --git a/lib/runtests.sh b/lib/runtests.sh index 1d8554cea..602848f69 100755 --- a/lib/runtests.sh +++ b/lib/runtests.sh @@ -3,7 +3,7 @@ set -e for file in tests/*; do - echo "Running $file" - LD_LIBRARY_PATH=../deps/lua-memory/src LUA_CPATH='../deps/lua-memory/src/?.so;;' lua $file - echo "$file executed with no errors!" + echo "Running $file" + LD_LIBRARY_PATH=../deps/lua-memory/src LUA_CPATH='../deps/lua-memory/src/?.so;;' lua $file + echo "$file executed with no errors!" done diff --git a/lib/tests/create.lua b/lib/tests/create.lua index 6f71c26c6..3765d6e65 100644 --- a/lib/tests/create.lua +++ b/lib/tests/create.lua @@ -1,5 +1,4 @@ local lunatik = require'lunatik' - local session = lunatik.session() -- Normal creation @@ -32,7 +31,6 @@ assert(ss1) ss2 = session2:newstate's1' assert(ss2 == nil) - s1:close() s2:close() ss1:close() diff --git a/lib/tests/getstate.lua b/lib/tests/getstate.lua index 07ce41cd7..1f996d6ed 100644 --- a/lib/tests/getstate.lua +++ b/lib/tests/getstate.lua @@ -4,7 +4,7 @@ local buffer = memory.create(3) local session = lunatik.session() local kscript = [[ - print'olá mundo!' + print'olá mundo!' ]] -- Testing state normal state creation diff --git a/lib/tests/list.lua b/lib/tests/list.lua index a8433340b..5a7575e51 100644 --- a/lib/tests/list.lua +++ b/lib/tests/list.lua @@ -22,7 +22,6 @@ local states2 = session2:list() assert(#states == 6) assert(#states2 == 6) - -- Close some states and check if they are gone when list s1:close() s2:close() @@ -30,7 +29,6 @@ s3:close() states = session:list() states2 = session2:list() - assert(#states == 3) assert(#states2 == 3) diff --git a/lib/tests/receive.lua b/lib/tests/receive.lua index 76fe5183f..8c1e659cd 100644 --- a/lib/tests/receive.lua +++ b/lib/tests/receive.lua @@ -3,11 +3,11 @@ local memory = require'memory' local session = lunatik.session() local kscript = [[ - local buffer = memory.create(3) - memory.set(buffer, 1, 65, 66, 67) - netlink.send(buffer) - memory.set(buffer, 1, 68, 69, 70) - netlink.send(buffer) + local buffer = memory.create(3) + memory.set(buffer, 1, 65, 66, 67) + netlink.send(buffer) + memory.set(buffer, 1, 68, 69, 70) + netlink.send(buffer) ]] local s1 = session:newstate's1' diff --git a/lib/tests/send.lua b/lib/tests/send.lua index d2562f0c3..2f0a55cb5 100644 --- a/lib/tests/send.lua +++ b/lib/tests/send.lua @@ -6,10 +6,10 @@ local buffer = memory.create(3) memory.set(buffer, 1, 0x1, 0x2, 0x3) local kscript = [[ - function receive_callback(mem) - print'A memory has been received' - memory.tostring(mem) - end + function receive_callback(mem) + print'A memory has been received' + memory.tostring(mem) + end ]] local s1 = session:newstate's1' From 8f8d8aa93884b6953fa0b4961fda1f278b2125bd Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Fri, 11 Sep 2020 16:44:09 +0000 Subject: [PATCH 42/48] fixup! Send data to kernel --- lib/Makefile | 2 +- lib/lunatik.c | 2 +- netlink.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index 3354af122..fe215227c 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -18,7 +18,7 @@ CC = gcc CFLAGS = -fPIC -Wall -Wextra -O2 -g -I/usr/include/lua5.3/ -I/usr/include/libnl3 -D_UNUSED \ - -I$(src)../deps/lua-memory/src + -I$(src)../deps/lua-memory/src LDFLAGS = -shared -lnl-genl-3 -lnl-3 -llua5.3 -L../deps/lua-memory/src -lluamemlib RM = rm -f diff --git a/lib/lunatik.c b/lib/lunatik.c index 6bb1fda45..f13fe22f5 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -571,7 +571,7 @@ static int data_handler(struct nl_msg *msg, void *arg) int err; if (nla_parse(attrs_tb, ATTRS_COUNT, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL)) + genlmsg_attrlen(gnlh, 0), NULL)) { printf("Error parsing attributes\n"); state->cb_result = CB_ERROR; diff --git a/netlink.c b/netlink.c index 6752a1562..8e2db178b 100644 --- a/netlink.c +++ b/netlink.c @@ -33,7 +33,7 @@ #include "lunatik.h" #include "netlink_common.h" -#define DATA_RECV_FUNC "receive_callback" +#define DATA_RECV_FUNC ("receive_callback") struct lunatik_nl_state { char name[LUNATIK_NAME_MAXSIZE]; From d103135ecc17db3c17aaaa2624be99f1c17e8877 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Fri, 11 Sep 2020 16:47:44 +0000 Subject: [PATCH 43/48] fixup! Adapt control API from NFLua --- lib/lunatik.c | 4 +-- lib/lunatik.h | 68 +++++++++++++++++++++++++-------------------------- 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/lib/lunatik.c b/lib/lunatik.c index f13fe22f5..2060cf128 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -30,8 +30,6 @@ #include "lunatik.h" -#define MIN(x,y) ((x) < (y) ? (x) : (y)) - static int lunatik_family; static struct nl_msg *prepare_message(int command, int flags) @@ -454,7 +452,7 @@ static int response_handler(struct nl_msg *msg, void *arg) int err = 0; if (nla_parse(attrs_tb, ATTRS_COUNT, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL)) + genlmsg_attrlen(gnlh, 0), NULL)) { printf("Error parsing attributes\n"); session->cb_result = CB_ERROR; diff --git a/lib/lunatik.h b/lib/lunatik.h index afd015416..5c54f4b9c 100644 --- a/lib/lunatik.h +++ b/lib/lunatik.h @@ -27,38 +27,38 @@ #include "../lunatik_conf.h" enum callback_result { - CB_SUCCESS, - CB_ERROR, - CB_EMPTY_RESULT, - CB_LIST_EMPTY, - CB_STATE_NOT_FOUND, + CB_SUCCESS, + CB_ERROR, + CB_EMPTY_RESULT, + CB_LIST_EMPTY, + CB_STATE_NOT_FOUND, }; enum session_status { - SESSION_FREE, - SESSION_RECEIVING, + SESSION_FREE, + SESSION_RECEIVING, }; struct data_buffer { - char *buffer; - int size; + char *buffer; + int size; }; struct lunatik_nl_state { - struct lunatik_session *session; - struct nl_sock *send_datasock; - struct nl_sock *recv_datasock; - struct nl_sock *control_sock; - struct data_buffer data_buffer; - enum callback_result cb_result; - uint32_t maxalloc; - uint32_t curralloc; - char name[LUNATIK_NAME_MAXSIZE]; + struct lunatik_session *session; + struct nl_sock *send_datasock; + struct nl_sock *recv_datasock; + struct nl_sock *control_sock; + struct data_buffer data_buffer; + enum callback_result cb_result; + uint32_t maxalloc; + uint32_t curralloc; + char name[LUNATIK_NAME_MAXSIZE]; }; struct states_list { - struct lunatik_nl_state *states; - size_t list_size; + struct lunatik_nl_state *states; + size_t list_size; }; struct received_buffer { @@ -67,26 +67,26 @@ struct received_buffer { }; struct lunatik_session { - struct nl_sock *control_sock; - struct states_list states_list; - struct received_buffer recv_buffer; - struct lunatik_nl_state state_holder; - enum session_status status; - enum callback_result cb_result; - int family; - int control_fd; - int data_fd; - uint32_t pid; + struct nl_sock *control_sock; + struct states_list states_list; + struct received_buffer recv_buffer; + struct lunatik_nl_state state_holder; + enum session_status status; + enum callback_result cb_result; + int family; + int control_fd; + int data_fd; + uint32_t pid; }; static inline int lunatikS_getfd(const struct lunatik_session *session) { - return session->control_fd; + return session->control_fd; } static inline int lunatikS_isopen(const struct lunatik_session *session) { - return session->control_fd >= 0; + return session->control_fd >= 0; } int lunatikS_init(struct lunatik_session *session); @@ -98,7 +98,7 @@ int lunatikS_newstate(struct lunatik_session *session, struct lunatik_nl_state * int lunatik_closestate(struct lunatik_nl_state *state); int lunatik_dostring(struct lunatik_nl_state *state, - const char *script, const char *script_name, size_t total_code_size); + const char *script, const char *script_name, size_t total_code_size); int lunatikS_list(struct lunatik_session *session); @@ -109,7 +109,7 @@ int lunatik_initstate(struct lunatik_nl_state *state); struct lunatik_nl_state *lunatikS_getstate(struct lunatik_session *session, const char *name); int lunatik_datasend(struct lunatik_nl_state *state, - const char *payload, size_t len); + const char *payload, size_t len); int lunatik_getcurralloc(struct lunatik_nl_state *state); From e335ddce89342432962fcfe633790b1172e1952a Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Fri, 11 Sep 2020 16:48:36 +0000 Subject: [PATCH 44/48] fixup! Adapt messages sent to kernel --- lib/lunatik.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lunatik.c b/lib/lunatik.c index 2060cf128..02d2d0473 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -405,7 +405,7 @@ static int send_data_cb_handler(struct nl_msg *msg, void *arg) struct lunatik_nl_state *state = (struct lunatik_nl_state *)arg; if (nla_parse(attrs_tb, ATTRS_COUNT, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL)) + genlmsg_attrlen(gnlh, 0), NULL)) { printf("Error parsing attributes\n"); state->cb_result = CB_ERROR; From 21f35ea400096043d5de4706dcc5b16184893148 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Fri, 11 Sep 2020 16:49:26 +0000 Subject: [PATCH 45/48] fixup! Change socket of states related operation to the state instead of session --- lib/lunatik.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/lunatik.c b/lib/lunatik.c index 02d2d0473..31deb6a7e 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -249,7 +249,7 @@ int lunatik_closestate(struct lunatik_nl_state *state) } int lunatik_dostring(struct lunatik_nl_state *state, - const char *script, const char *script_name, size_t total_code_size) + const char *script, const char *script_name, size_t total_code_size) { int err = -1; int parts = 0; @@ -533,7 +533,7 @@ static int response_state_handler(struct nl_msg *msg, void *arg) struct lunatik_nl_state *state = (struct lunatik_nl_state *)arg; if (nla_parse(attrs_tb, ATTRS_COUNT, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL)) + genlmsg_attrlen(gnlh, 0), NULL)) { printf("Error parsing attributes\n"); state->cb_result = CB_ERROR; From 6388358739e5eac6868ad4907ba6be2dce3f30a3 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Fri, 11 Sep 2020 18:23:01 +0000 Subject: [PATCH 46/48] fixup! RABID-561 adjust Makefiles for generic compilation --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 1ba684f4d..a4497d537 100644 --- a/Makefile +++ b/Makefile @@ -19,10 +19,10 @@ ifeq ($(ARCH), mips) endif AFLAGS_setjmp.o += -D_MIPS_ISA_MIPS64 \ -D_MIPS_ISA=_MIPS_ISA_MIPS64 - else + else AFLAGS_setjmp.o += -D__mips_o32 -D_MIPS_ISA_MIPS32 \ -D_MIPS_ISA=_MIPS_ISA_MIPS32 - endif + endif endif obj-$(CONFIG_LUNATIK) += lunatik.o From 9277e14bf330516adeba082eb1ceda2a0bbe4ea7 Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Wed, 14 Oct 2020 00:37:28 +0000 Subject: [PATCH 47/48] Solved bug on module remotion --- lunatik_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lunatik_core.c b/lunatik_core.c index b97bfe068..f06d3381b 100644 --- a/lunatik_core.c +++ b/lunatik_core.c @@ -213,15 +213,16 @@ static void __net_exit lunatik_instanceclose(struct net *net) { struct lunatik_instance *instance; lunatik_State *s; - struct hlist_node *tmp; int bkt; instance = lunatik_pernet(net); spin_lock_bh(&(instance->statestable_lock)); - hash_for_each_safe(instance->states_table, bkt, tmp, s, node) { + hash_for_each(instance->states_table, bkt, s, node) { state_destroy(s); + if (hash_empty(instance->states_table)) + break; } spin_unlock_bh(&(instance->statestable_lock)); From e9663d312735b34cb9a8a5ccb3e88dad05993f9c Mon Sep 17 00:00:00 2001 From: Matheus Rodrigues Date: Sat, 17 Oct 2020 16:39:46 +0000 Subject: [PATCH 48/48] Implementation of put state function --- Makefile | 2 +- lib/lunatik.c | 24 +++++++++++++++++++++ lib/lunatik.h | 4 ++++ lib/lunatik_module.c | 51 ++++++++++++++++++++++++++++++++++++++++---- lib/tests/send.lua | 2 ++ lunatik.h | 2 +- netlink.c | 41 +++++++++++++++++++++++++++++++++++ netlink_common.h | 2 ++ states.c | 15 ++++++++----- 9 files changed, 132 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index a4497d537..d1594d575 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -ccflags-y += -D_LUNATIK -D_KERNEL -I$(src) -D_CONFIG_FULL_PANIC -DLUNATIK_UNUSED \ +ccflags-y += -D_LUNATIK -D_KERNEL -I$(src) -D_CONFIG_FULL_PANIC -DLUNATIK_UNUSED -DDEBUG\ -I$(src)/lua -I$(src)/deps/lua-memory/src asflags-y += -D_LUNATIK -D_KERNEL diff --git a/lib/lunatik.c b/lib/lunatik.c index 31deb6a7e..3a5456683 100644 --- a/lib/lunatik.c +++ b/lib/lunatik.c @@ -546,6 +546,9 @@ static int response_state_handler(struct nl_msg *msg, void *arg) } else if (attrs_tb[OP_ERROR] && nla_get_u8(attrs_tb[OP_ERROR])) { state->cb_result = CB_ERROR; return NL_OK; + } else if (attrs_tb[NOT_IN_USE] && nla_get_u8(attrs_tb[NOT_IN_USE])) { + state->cb_result = CB_ERROR; + return NL_OK; } if (attrs_tb[CURR_ALLOC]) { @@ -810,3 +813,24 @@ int lunatik_getcurralloc(struct lunatik_nl_state *state) printf("Failed to put attribute to get current alloc of state %s\n", state->name); return -1; } + +int lunatik_putstate(struct lunatik_nl_state *state) +{ + struct nl_msg *msg; + + int err = -1; + + if ((msg = prepare_message(PUT_STATE, 0)) == NULL) + return err; + + NLA_PUT_STRING(msg, STATE_NAME, state->name); + + if ((err = nl_send_auto(state->control_sock, msg)) < 0) + return err; + + return receive_state_op_result(state); + +nla_put_failure: + printf("Failed to put attribute to put state\n"); + return -1; +} diff --git a/lib/lunatik.h b/lib/lunatik.h index 5c54f4b9c..e9713d7ae 100644 --- a/lib/lunatik.h +++ b/lib/lunatik.h @@ -22,6 +22,7 @@ #include #include +#include #include #include "../netlink_common.h" #include "../lunatik_conf.h" @@ -53,6 +54,7 @@ struct lunatik_nl_state { enum callback_result cb_result; uint32_t maxalloc; uint32_t curralloc; + bool isvalid; char name[LUNATIK_NAME_MAXSIZE]; }; @@ -113,4 +115,6 @@ int lunatik_datasend(struct lunatik_nl_state *state, int lunatik_getcurralloc(struct lunatik_nl_state *state); +int lunatik_putstate(struct lunatik_nl_state *state); + #endif /* LUNATIK_H */ diff --git a/lib/lunatik_module.c b/lib/lunatik_module.c index ca962678e..b4651cefb 100644 --- a/lib/lunatik_module.c +++ b/lib/lunatik_module.c @@ -135,6 +135,8 @@ static int lsession_newstate(lua_State *L) strcpy(state->name, name); state->maxalloc = maxalloc; state->session = session; + state->isvalid = true; + if (lunatikS_newstate(session, state)) { pusherrmsg(L, "Failed to create the state\n"); @@ -154,6 +156,10 @@ static int lsession_newstate(lua_State *L) static int lstate_close(lua_State *L) { struct lunatik_nl_state *state = getnlstate(L); + + if (!state->isvalid) + return luaL_error(L, "invalid state"); + if (lunatik_closestate(state)){ lua_pushnil(L); return 1; @@ -170,10 +176,12 @@ static int lstate_dostring(lua_State *L) const char *payload = luaL_checklstring(L, 2, &len); const char *script_name = luaL_optstring(L, 3, "Lunatik"); - if (strlen(script_name) > LUNATIK_SCRIPTNAME_MAXSIZE) { - printf("script name too long\n"); - goto error; - } + if (strlen(script_name) > LUNATIK_SCRIPTNAME_MAXSIZE) + return luaL_argerror(L, 3, "script name too long"); + + if (!s->isvalid) + return luaL_error(L, "invalid state"); + int status = lunatik_dostring(s, payload, script_name, len); if (status) @@ -189,12 +197,20 @@ static int lstate_dostring(lua_State *L) static int lstate_getname(lua_State *L) { struct lunatik_nl_state *s = getnlstate(L); + + if (!s->isvalid) + return luaL_error(L, "invalid state"); + lua_pushstring(L, s->name); return 1; } static int lstate_getmaxalloc(lua_State *L) { struct lunatik_nl_state *s = getnlstate(L); + + if (!s->isvalid) + return luaL_error(L, "invalid state"); + lua_pushinteger(L, s->maxalloc); return 1; } @@ -240,6 +256,7 @@ static int lsession_getstate(lua_State *L) } *state = *received_state; + state->isvalid = true; if (lunatik_initstate(state)) { pusherrmsg(L, "Failed to initialize the state\n"); @@ -277,6 +294,10 @@ static int lstate_datasend(lua_State *L) if (buffer == NULL) luaL_argerror(L, 2, "expected non NULL memory object"); + if (!state->isvalid) + return luaL_error(L, "invalid state"); + + err = lunatik_datasend(state, buffer, size); err ? lua_pushnil(L) : lua_pushboolean(L, true); @@ -290,6 +311,9 @@ static int lstate_datareceive(lua_State *L) struct lunatik_nl_state *state = getnlstate(L); char *memory; + if (!state->isvalid) + return luaL_error(L, "invalid state"); + if (lunatik_receive(state)) goto error; @@ -309,6 +333,9 @@ static int lstate_getcurralloc(lua_State *L) { struct lunatik_nl_state *state = getnlstate(L); + if (!state->isvalid) + return luaL_error(L, "invalid state"); + if (lunatik_getcurralloc(state)) { lua_pushnil(L); return 1; @@ -319,6 +346,21 @@ static int lstate_getcurralloc(lua_State *L) return 1; } +static int lstate_put(lua_State *L) +{ + struct lunatik_nl_state *state = getnlstate(L); + + if (lunatik_putstate(state)) { + lua_pushnil(L); + return 1; + } + + lua_pushboolean(L, true); + state->isvalid = false; + + return 1; +} + static const luaL_Reg session_mt[] = { {"close", lsession_close}, {"getfd", lsession_getfd}, @@ -337,6 +379,7 @@ static const luaL_Reg state_mt[] = { {"close", lstate_close}, {"send", lstate_datasend}, {"receive", lstate_datareceive}, + {"put", lstate_put}, {NULL, NULL} }; diff --git a/lib/tests/send.lua b/lib/tests/send.lua index 2f0a55cb5..45db082b0 100644 --- a/lib/tests/send.lua +++ b/lib/tests/send.lua @@ -5,7 +5,9 @@ local session = lunatik.session() local buffer = memory.create(3) memory.set(buffer, 1, 0x1, 0x2, 0x3) +-- TODO the kscript variable starts with \n, if such variable starts with \t then a kernel panic along with a deadlock will occour local kscript = [[ + function receive_callback(mem) print'A memory has been received' memory.tostring(mem) diff --git a/lunatik.h b/lunatik.h index ff8392281..708b6190d 100644 --- a/lunatik.h +++ b/lunatik.h @@ -56,7 +56,7 @@ int lunatik_close(const char *name); lunatik_State *lunatik_statelookup(const char *name); bool lunatik_getstate(lunatik_State *s); -void lunatik_putstate(lunatik_State *s); +int lunatik_putstate(lunatik_State *s); lunatik_State *lunatik_netnewstate(const char *name, size_t maxalloc, struct net *net); int lunatik_netclosestate(const char *name, struct net *net); diff --git a/netlink.c b/netlink.c index 8e2db178b..21338c310 100644 --- a/netlink.c +++ b/netlink.c @@ -51,6 +51,7 @@ static int lunatikN_data(struct sk_buff *buff, struct genl_info *info); static int lunatikN_datainit(struct sk_buff *buff, struct genl_info *info); static int lunatikN_sendstate(struct sk_buff *buff, struct genl_info *info); static int lunatikN_getcurralloc(struct sk_buff *buff, struct genl_info *info); +static int lunatikN_putstate(struct sk_buff *buff, struct genl_info *info); struct nla_policy lunatik_policy[ATTRS_COUNT] = { [STATE_NAME] = { .type = NLA_STRING }, @@ -123,8 +124,16 @@ static const struct genl_ops l_ops[] = { .doit = lunatikN_getcurralloc, #if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) .policy = lunatik_policy +#endif + }, + { + .cmd = PUT_STATE, + .doit = lunatikN_putstate, +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) + .policy = lunatik_policy #endif } + }; struct genl_family lunatik_family = { @@ -714,6 +723,38 @@ static int lunatikN_getcurralloc(struct sk_buff *buff, struct genl_info *info) return 0; } +static int lunatikN_putstate(struct sk_buff *buff, struct genl_info *info) +{ + struct lunatik_state *s; + char *state_name; + + pr_debug("Received a PUT_STATE command\n"); + + state_name = (char*)nla_data(info->attrs[STATE_NAME]); + s = lunatik_netstatelookup(state_name, genl_info_net(info)); + + if (s == NULL) + goto error; + + if (!s->inuse) { + reply_with(NOT_IN_USE, PUT_STATE, info); + return 0; + } + + if (lunatik_putstate(s)) + goto error; + + + s->inuse = false; + reply_with(OP_SUCESS, PUT_STATE, info); + + return 0; + +error: + reply_with(OP_ERROR, PUT_STATE, info); + return 0; +} + /* Note: Most of the function below is copied from NFLua: https://github.com/cujoai/nflua * Copyright (C) 2017-2019 CUJO LLC * diff --git a/netlink_common.h b/netlink_common.h index d986518e7..396a4dc02 100644 --- a/netlink_common.h +++ b/netlink_common.h @@ -44,6 +44,7 @@ enum lunatik_operations { DATA_INIT, GET_STATE, GET_CURRALLOC, + PUT_STATE, }; enum lunatik_attrs { @@ -63,6 +64,7 @@ enum lunatik_attrs { LUNATIK_DATA_LEN, CURR_ALLOC, STATE_NOT_FOUND, + NOT_IN_USE, ATTRS_COUNT #define ATTRS_MAX (ATTRS_COUNT - 1) }; diff --git a/states.c b/states.c index 11166f921..404d25e94 100644 --- a/states.c +++ b/states.c @@ -146,24 +146,29 @@ inline bool lunatik_getstate(lunatik_State *s) return refcount_inc_not_zero(&s->users); } -void lunatik_putstate(lunatik_State *s) +int lunatik_putstate(lunatik_State *s) { refcount_t *users = &s->users; spinlock_t *refcnt_lock = &(s->instance.rfcnt_lock); if (WARN_ON(s == NULL)) - return; + return 1; if (refcount_dec_not_one(users)) - return; + return 1; spin_lock_bh(refcnt_lock); if (!refcount_dec_and_test(users)) - goto out; + goto error_and_unlock; + hash_del_rcu(&s->node); kfree(s); -out: spin_unlock_bh(refcnt_lock); + return 0; + +error_and_unlock: + spin_unlock_bh(refcnt_lock); + return 1; } lunatik_State *lunatik_netstatelookup(const char *name, struct net *net)