diff --git a/security/lua/lsm_defs.c b/security/lua/lsm_defs.c index 788d9d280916..37afc422ccc1 100644 --- a/security/lua/lsm_defs.c +++ b/security/lua/lsm_defs.c @@ -22,6 +22,7 @@ #include /* for __MAP */ #include /* for ktime_get */ #include +#include #include #include #include @@ -2662,8 +2663,17 @@ static int build_sockaddr(lua_State *L, struct sockaddr *address, int addrlen) if (addrlen < SIN6_LEN_RFC2133) return 0; break; + case AF_UNIX: + if (addrlen < offsetof(struct sockaddr_un, sun_path)) + return 0; + break; + } + { + struct lua_sockaddr *p = newsockaddr(L); + + p->addr = address; + p->addrlen = addrlen; } - *newsockaddr(L) = address; return 1; } diff --git a/security/lua/lua_net.c b/security/lua/lua_net.c index ba701c79b019..1f550692d6f0 100644 --- a/security/lua/lua_net.c +++ b/security/lua/lua_net.c @@ -7,6 +7,7 @@ #include "debug.h" #include +#include #include #include #include @@ -70,6 +71,30 @@ static const char *family_tostring(sa_family_t sa_family) return family; } +static size_t sockaddr_un_path_len(const struct sockaddr_un *sunaddr, int addrlen) +{ + int offset = offsetof(struct sockaddr_un, sun_path); + size_t path_len; + + if (addrlen <= offset) + return 0; + + path_len = addrlen - offset; + + /* + * Pathname sockets are C strings; abstract sockets keep their full + * declared length, including embedded NUL bytes. + */ + if (sunaddr->sun_path[0] != '\0') { + const char *nul = memchr(sunaddr->sun_path, '\0', path_len); + + if (nul) + path_len = nul - sunaddr->sun_path; + } + + return path_len; +} + /*********************************** sock ***********************************/ static int net_sock_socket(lua_State *L) @@ -368,11 +393,16 @@ static int sockaddr_addrs(lua_State *L) } lua_pushinteger(L, ntohs(((struct sockaddr_in6 *)sa)->sin6_port)); return 3; - case AF_UNIX: + case AF_UNIX: { + struct sockaddr_un *sunaddr = (struct sockaddr_un *)sa; + int addrlen = tosockaddr_addrlen(L, 1); + size_t path_len = sockaddr_un_path_len(sunaddr, addrlen); + lua_pushstring(L, "unix"); - lua_pushstring(L, ((struct sockaddr_un *)sa)->sun_path); + lua_pushlstring(L, sunaddr->sun_path, path_len); return 2; } + } return 0; } @@ -391,9 +421,16 @@ static int meth_sockaddr_tostring(lua_State *L) l = snprintf(buffer, sizeof(buffer), "sa.inet6: %pISpc", sa); lua_pushlstring(L, buffer, l); break; - case AF_UNIX: - lua_pushfstring(L, "sa.unix: %s", ((struct sockaddr_un *)sa)->sun_path); + case AF_UNIX: { + struct sockaddr_un *sunaddr = (struct sockaddr_un *)sa; + int addrlen = tosockaddr_addrlen(L, 1); + size_t sp_len = sockaddr_un_path_len(sunaddr, addrlen); + + lua_pushliteral(L, "sa.unix: "); + lua_pushlstring(L, sunaddr->sun_path, sp_len); + lua_concat(L, 2); break; + } case AF_NETLINK: lua_pushfstring(L, "sa.netlink: %d", ((struct sockaddr_nl *)sa)->nl_pid); break; diff --git a/security/lua/lua_object.h b/security/lua/lua_object.h index d7588acc1815..94fdaf86ff5a 100644 --- a/security/lua/lua_object.h +++ b/security/lua/lua_object.h @@ -137,7 +137,6 @@ LUA_OBJECT(func, net, tundev, void *, NULL) \ LUA_OBJECT(func, net, socket, struct socket *, NULL) \ LUA_OBJECT(func, net, skb, struct sk_buff *, NULL) \ - LUA_OBJECT(func, net, sockaddr, struct sockaddr *, NULL) \ LUA_OBJECT(func, security, key, struct key *, NULL) \ LUA_OBJECT(object, block, bdev, struct block_device *, NULL) \ LUA_OBJECT(object, fs, inode, struct inode *, NULL) \ @@ -157,4 +156,83 @@ LUA_OBJECTS_LIST #undef LUA_OBJECT +/* + * sockaddr is defined manually because it needs to carry addrlen alongside + * the pointer, so Lua-side methods can derive correct bounds for AF_UNIX + * sun_path (including abstract namespace sockets with embedded NULs). + * + * NOTE: These definitions mirror what LUA_OBJECT_func_DEFINE would generate. + * If that macro is ever extended (e.g. new raw/gc helpers), update this + * section to stay in sync. + */ +struct lua_sockaddr { + struct sockaddr *addr; + int addrlen; +}; + +static inline struct lua_sockaddr *newsockaddr_nomain(lua_State *L) +{ + struct lua_sockaddr *p = lua_newuserdata(L, sizeof(*p)); + + p->addr = NULL; + p->addrlen = 0; + luaL_getmetatable(L, METHOD_NAME(sockaddr)); + lua_setmetatable(L, -2); + return p; +} + +static inline struct lua_sockaddr *newsockaddr(lua_State *L) +{ + struct lua_sockaddr *p = newsockaddr_nomain(L); + + lua_getfield(L, LUA_REGISTRYINDEX, CURR_ENV); + lua_setfenv(L, -2); + return p; +} + +static inline struct lua_sockaddr *tosockaddarp(lua_State *L, int idx) +{ + return (struct lua_sockaddr *)checkudata3(L, idx, METHOD_NAME(sockaddr)); +} + +static inline struct sockaddr *tosockaddr(lua_State *L, int idx) +{ + return tosockaddarp(L, idx)->addr; +} + +static inline int tosockaddr_addrlen(lua_State *L, int idx) +{ + return tosockaddarp(L, idx)->addrlen; +} + +static int rawmeth_sockaddr_type(lua_State *L) +{ + lua_pushstring(L, "sockaddr"); + lua_pushboolean(L, 0); + return 2; +} + +static int rawmeth_sockaddr_tostring(lua_State *L) +{ + struct sockaddr *o = tosockaddr(L, 1); + + lua_pushfstring(L, "sockaddr: <%p>", o); + return 1; +} + +static inline void create_sockaddr_meta(lua_State *L, + const luaL_Reg *funcs, const luaL_Reg *gc) +{ + static const luaL_Reg basemeths[] = { + { "__tostring", rawmeth_sockaddr_tostring }, + { NULL, NULL } + }; + static const luaL_Reg rawmeths[] = { + { "type", rawmeth_sockaddr_type }, + { NULL, NULL } + }; + createmeta3(L, "sockaddr", basemeths, METHOD_NAME_GC(sockaddr), gc, + METHOD_NAME(sockaddr), funcs, METHOD_NAME_RAW(sockaddr), rawmeths); +} + #endif /* ! _SECURITY_LUA_LSM_LUA_OBJECT_H */