diff --git a/security/lua/auxlib.c b/security/lua/auxlib.c index 5a17abba4984..c907b9511a64 100644 --- a/security/lua/auxlib.c +++ b/security/lua/auxlib.c @@ -211,6 +211,15 @@ void luaL_requiref(lua_State *L, const char *modname, } } +const struct cflag_opt lua_lsm_cap_opts[] = { + { "noaudit", CAP_OPT_NOAUDIT }, + { "insetid", CAP_OPT_INSETID }, + { NULL, 0 } +}; + +const unsigned int lua_lsm_cap_opt_flags = CAP_OPT_NOAUDIT | + CAP_OPT_INSETID; + unsigned int tocflags(lua_State *L, int idx, int top, const struct cflag_opt *opts, unsigned int d) { @@ -548,16 +557,14 @@ int arg2cap(lua_State *L, int idx) /* * [task:]capable(CAP_MAC_ADMIN) * [task:]capable('mac_admin') + * [task:]capable(ns, CAP_MAC_ADMIN) * [task:]capable(task, 'mac_admin') * [task:]capable(task, 'mac_admin', 'noaudit', 'insetid') */ -int aux_capable(lua_State *L, const struct cred *cred, int idx) +int aux_capable(lua_State *L, const struct cred *cred, + struct user_namespace *default_ns, int idx) { - static const struct cflag_opt opts[] = { - { "noaudit", CAP_OPT_NOAUDIT }, - { "insetid", CAP_OPT_INSETID }, - { NULL, 0 } - }; + struct user_namespace *ns = default_ns; unsigned int opt = CAP_OPT_NONE; int top = lua_gettop(L); int cap; @@ -568,13 +575,21 @@ int aux_capable(lua_State *L, const struct cred *cred, int idx) if (top == idx) { cap = arg2cap(L, idx); - err = cap_capable(cred, current_user_ns(), cap, opt); + err = cap_capable(cred, ns, cap, opt); + } else if (tousernsp(L, idx)) { + ns = touserns(L, idx); + cap = arg2cap(L, idx + 1); + if (top >= idx + 2) + opt = tocflags(L, idx + 2, top, + lua_lsm_cap_opts, CAP_OPT_NONE); + err = cap_capable(cred, ns, cap, opt); } else { struct task_struct *task = totask(L, idx); cap = arg2cap(L, idx + 1); if (top >= idx + 2) - opt = tocflags(L, idx + 2, top, opts, CAP_OPT_NONE); + opt = tocflags(L, idx + 2, top, + lua_lsm_cap_opts, CAP_OPT_NONE); rcu_read_lock(); err = cap_capable(cred, __task_cred(task)->user_ns, cap, opt); diff --git a/security/lua/auxlib.h b/security/lua/auxlib.h index 113016257488..a4d2c7ee0e7f 100644 --- a/security/lua/auxlib.h +++ b/security/lua/auxlib.h @@ -14,6 +14,7 @@ struct cred; struct dentry; struct file; +struct user_namespace; static inline gfp_t lua_lsm_gfp(void) { @@ -53,6 +54,9 @@ struct cflag_opt { unsigned int flag; }; +extern const struct cflag_opt lua_lsm_cap_opts[]; +extern const unsigned int lua_lsm_cap_opt_flags; + unsigned int tocflags(lua_State *L, int idx, int top, const struct cflag_opt *opts, unsigned int d); @@ -86,6 +90,7 @@ int aux_file_path(lua_State *L, struct file *filp); int aux_dentry_path(lua_State *L, struct dentry *dentry, int rawpath); int arg2cap(lua_State *L, int idx); -int aux_capable(lua_State *L, const struct cred *cred, int idx); +int aux_capable(lua_State *L, const struct cred *cred, + struct user_namespace *default_ns, int idx); #endif /* ! _SECURITY_LUA_LSM_AUXLIB_H */ diff --git a/security/lua/lsm_defs.c b/security/lua/lsm_defs.c index 788d9d280916..f958e4ee9324 100644 --- a/security/lua/lsm_defs.c +++ b/security/lua/lsm_defs.c @@ -197,16 +197,16 @@ LUA_LSM_INT_DEFINE5(capset, struct cred *, new, const struct cred *, old, } /** - * TODO: capable + * capable * Default: 0 */ LUA_LSM_INT_DEFINE4(capable, const struct cred *, cred, struct user_namespace *, ns, int, cap, unsigned int, opts) { *(const struct cred **)newcred(L) = cred; - lua_pushnil(L); /* TODO: ns */ + *newuserns(L) = ns; lua_pushinteger(L, (lua_Integer)cap); - lua_pushinteger(L, (lua_Integer)opts); + table_fromopts(L, lua_lsm_cap_opts, lua_lsm_cap_opt_flags, opts); } /** diff --git a/security/lua/lua_capability.c b/security/lua/lua_capability.c index b31ae75d52d1..d66e82044f06 100644 --- a/security/lua/lua_capability.c +++ b/security/lua/lua_capability.c @@ -7,6 +7,7 @@ #include "debug.h" #include +#include #include "lsm.h" #include "auxlib.h" #include "lua_object.h" @@ -158,7 +159,7 @@ static int capability_cap_full(lua_State *L) static int capability_capable(lua_State *L) { - return aux_capable(L, current_cred(), 1); + return aux_capable(L, current_cred(), current_user_ns(), 1); } static const luaL_Reg capabilitylib[] = { diff --git a/security/lua/lua_kernel.c b/security/lua/lua_kernel.c index 5ed911301e17..4e12b45f5c84 100644 --- a/security/lua/lua_kernel.c +++ b/security/lua/lua_kernel.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -132,6 +133,21 @@ static int kernel_cred_securebits(lua_State *L) return 0; } +static int kernel_cred_userns(lua_State *L) +{ + const struct cred *cred = tocred(L, 1); + + *newgcuserns(L) = get_user_ns(cred->user_ns); + return 1; +} + +static int kernel_cred_capable(lua_State *L) +{ + const struct cred *cred = tocred(L, 1); + + return aux_capable(L, cred, cred->user_ns, 2); +} + static const luaL_Reg cred_meth[] = { { "uids", kernel_cred_uids }, { "gids", kernel_cred_gids }, @@ -139,6 +155,96 @@ static const luaL_Reg cred_meth[] = { { "cap_bset", kernel_cred_cap_bset }, { "cap_ambient", kernel_cred_cap_ambient }, { "securebits", kernel_cred_securebits }, + { "userns", kernel_cred_userns }, + { "capable", kernel_cred_capable }, + { NULL, NULL } +}; + +/********************************* userns *********************************/ + +static int kernel_userns_is_initial(lua_State *L) +{ + struct user_namespace *ns = touserns(L, 1); + + lua_pushboolean(L, ns == &init_user_ns); + return 1; +} + +static int kernel_userns_level(lua_State *L) +{ + struct user_namespace *ns = touserns(L, 1); + + lua_pushinteger(L, ns->level); + return 1; +} + +static int kernel_userns_owner_uid(lua_State *L) +{ + struct user_namespace *ns = touserns(L, 1); + + lua_pushinteger(L, (lua_Integer)ns->owner.val); + return 1; +} + +static int kernel_userns_owner_gid(lua_State *L) +{ + struct user_namespace *ns = touserns(L, 1); + + lua_pushinteger(L, (lua_Integer)ns->group.val); + return 1; +} + +static int kernel_userns_inum(lua_State *L) +{ + struct user_namespace *ns = touserns(L, 1); + + lua_pushinteger(L, (lua_Integer)ns->ns.inum); + return 1; +} + +static int kernel_userns_same(lua_State *L) +{ + struct user_namespace *ns = touserns(L, 1); + struct user_namespace *other = touserns(L, 2); + + lua_pushboolean(L, ns == other); + return 1; +} + +static int meth_userns_tostring(lua_State *L) +{ + struct user_namespace *ns = touserns(L, 1); + + lua_pushfstring(L, "userns: ", + (int)ns->ns.inum, ns->level); + return 1; +} + +static const luaL_Reg userns_meth[] = { + { "is_initial", kernel_userns_is_initial }, + { "level", kernel_userns_level }, + { "owner_uid", kernel_userns_owner_uid }, + { "owner_gid", kernel_userns_owner_gid }, + { "inum", kernel_userns_inum }, + { "same", kernel_userns_same }, + { "__tostring", meth_userns_tostring }, + { NULL, NULL } +}; + +static int meth_userns_gc(lua_State *L) +{ + struct user_namespace **nsp = togcusernsp(L, 1); + + if (*nsp) { + put_user_ns(*nsp); + *nsp = NULL; + } + return 0; +} + +static const luaL_Reg userns_gc_meth[] = { + { "__tostring", meth_userns_tostring }, + { "__gc", meth_userns_gc }, { NULL, NULL } }; @@ -160,6 +266,16 @@ static int kernel_task_cred(lua_State *L) return 1; } +static int kernel_task_userns(lua_State *L) +{ + struct task_struct *task = totask(L, 1); + const struct cred *cred = get_task_cred(task); + + *newgcuserns(L) = get_user_ns(cred->user_ns); + put_cred(cred); + return 1; +} + static int kernel_task_comm(lua_State *L) { struct task_struct *task = totask(L, 1); @@ -286,10 +402,12 @@ static int kernel_task_cmdline(lua_State *L) static int kernel_task_capable(lua_State *L) { struct task_struct *task = totask(L, 1); + const struct cred *cred; int nres; rcu_read_lock(); - nres = aux_capable(L, __task_cred(task), 2); + cred = __task_cred(task); + nres = aux_capable(L, cred, cred->user_ns, 2); rcu_read_unlock(); return nres; } @@ -356,6 +474,7 @@ static int meth_task_tostring(lua_State *L) static const luaL_Reg task_meth[] = { { "pids", kernel_task_pids }, { "cred", kernel_task_cred }, + { "userns", kernel_task_userns }, { "comm", kernel_task_comm }, { "nr_threads", kernel_task_nr_threads }, { "group_leader", kernel_task_group_leader }, @@ -558,6 +677,7 @@ LUALIB_API int luaopen_kernel(lua_State *L) luaL_newlib(L, kernellib); create_task_meta(L, task_meth, task_gc_meth); create_cred_meta(L, cred_meth, NULL); + create_userns_meta(L, userns_meth, userns_gc_meth); create_perfevent_meta(L, NULL, NULL); create_ipc_meta(L, NULL, NULL); create_msgmsg_meta(L, NULL, NULL); diff --git a/security/lua/lua_object.h b/security/lua/lua_object.h index d7588acc1815..84b332f8361e 100644 --- a/security/lua/lua_object.h +++ b/security/lua/lua_object.h @@ -129,6 +129,7 @@ #define LUA_OBJECTS_LIST \ LUA_OBJECT(task, kernel, task, struct task_struct *, NULL) \ LUA_OBJECT(object, kernel, cred, struct cred *, NULL) \ + LUA_OBJECT(func, kernel, userns, struct user_namespace *, NULL) \ LUA_OBJECT(func, kernel, perfevent, struct perf_event *, NULL) \ LUA_OBJECT(object, ipc, ipc, struct kern_ipc_perm *, NULL) \ LUA_OBJECT(object, ipc, msgmsg, struct msg_msg *, NULL) \