From 49a2ab9060af223e81ec05c46cd1e974453784ea Mon Sep 17 00:00:00 2001 From: "Solar1s." Date: Mon, 11 May 2026 17:46:50 +0800 Subject: [PATCH 1/2] lua-lsm: fix inode_init_security xattr output handling (#6) * lua-lsm: validate inode_init_security xattr output * lua-lsm: own inode_init_security xattr name storage * lua-lsm: document OCFS2 xattr name lifetime issue --------- Signed-off-by: Zongyao Chen --- security/lua/lsm_defs.c | 58 +++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/security/lua/lsm_defs.c b/security/lua/lsm_defs.c index 4326c13dec3d..17ecd3fe102f 100644 --- a/security/lua/lsm_defs.c +++ b/security/lua/lsm_defs.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include /* for __MAP */ @@ -769,6 +770,44 @@ LUA_LSM_VOID_DEFINE1(inode_free_security_rcu, void *, inode_security) lua_pushnil(L); /* TODO: inode_security */ } +static int lua_lsm_init_xattr(lua_State *L, int name_idx, int value_idx, + struct xattr *xattr) +{ + size_t name_len, value_len; + const char *name, *value; + char *buffer; + + name = lua_tolstring(L, name_idx, &name_len); + value = lua_tolstring(L, value_idx, &value_len); + + if (!name_len || name_len > XATTR_NAME_MAX - XATTR_SECURITY_PREFIX_LEN) + return -EINVAL; + if (memchr(name, '\0', name_len)) + return -EINVAL; + if (value_len > XATTR_SIZE_MAX) + return -E2BIG; + + buffer = kmalloc(value_len + name_len + 1, GFP_NOFS); + if (!buffer) + return -ENOMEM; + + memcpy(buffer, value, value_len); + memcpy(buffer + value_len, name, name_len); + buffer[value_len + name_len] = '\0'; + + /* + * FIXME: xattr->name must not share xattr->value storage. Some + * initxattrs users, notably OCFS2, duplicate only value and keep + * the name pointer after security_inode_init_security() frees value. + * This needs separate name storage with a lifetime that covers those + * delayed users. + */ + xattr->value = buffer; + xattr->value_len = value_len; + xattr->name = buffer + value_len; + return 0; +} + /** * inode_init_security * Default: -EOPNOTSUPP @@ -780,7 +819,7 @@ LUA_LSM_VOID_DEFINE1(inode_free_security_rcu, void *, inode_security) * false : -EPERM * false, errno : -errno * nil, errno : -errno - * name, value : fill the xattr struct, XXX: name must not be freed + * name, value : fill the xattr struct */ LUA_LSM_INT_NAKED_DEFINE5(inode_init_security, struct inode *, inode, struct inode *, dir, const struct qstr *, qstr, @@ -822,23 +861,10 @@ LUA_LSM_INT_NAKED_DEFINE5(inode_init_security, struct inode *, inode, ret = -errno; } else if (lua_isstring(L, top) && lua_isstring(L, top + 1)) { struct xattr *xattr; - const char *value; - size_t len; xattr = lsm_get_xattr_slot(xattrs, xattr_count); - if (xattr) { - value = lua_tolstring(L, top + 1, &len); - xattr->value = kmemdup(value, len, GFP_NOFS); - if (xattr->value == NULL) { - ret = -ENOMEM; - break; - } - xattr->value_len = len; - xattr->name = lua_tostring(L, top); - ret = 0; - } else { - /* TODO */ - } + if (xattr) + ret = lua_lsm_init_xattr(L, top, top + 1, xattr); } break; } From 1a163e309a1bf271c469431e6c582e4db6d79ddd Mon Sep 17 00:00:00 2001 From: Zongyao Chen Date: Mon, 11 May 2026 17:38:53 +0800 Subject: [PATCH 2/2] lua-lsm: validate numeric capability arguments arg2cap() accepts capability names and numeric capability values. The name path resolves values from a fixed table, but the numeric path returned the Lua integer without checking that it names a valid capability. Callers pass the result to helpers such as cap_raise(), cap_lower(), and cap_capable(). Reject invalid values in arg2cap() so Lua policy cannot drive capability helpers with out-of-range bit numbers. Signed-off-by: Zongyao Chen --- security/lua/auxlib.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/security/lua/auxlib.c b/security/lua/auxlib.c index d1667d5ec26b..5a17abba4984 100644 --- a/security/lua/auxlib.c +++ b/security/lua/auxlib.c @@ -540,6 +540,8 @@ int arg2cap(lua_State *L, int idx) default: return luaL_argerror(L, idx, "integer or string expected"); } + if (!cap_valid(cap)) + return luaL_argerror(L, idx, "invalid capability"); return cap; }