Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions security/lua/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ obj-$(CONFIG_SECURITY_LUA_LSM) := lua-lsm.o
ccflags-$(CONFIG_SECURITY_LUA_LSM_DEBUG) += -DDEBUG

lua-lsm-y := lsm.o securityfs.o auxlib.o kvcache.o lsm_defs.o \
lua_mm.o \
lua_kernel.o lua_fs.o lua_net.o \
lua_errno.o lua_capability.o lua_signal.o
5 changes: 3 additions & 2 deletions security/lua/lsm_defs.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <linux/lauxlib.h>
#include "lsm.h"
#include "lua_object.h"
#include "lua_mm.h"
#include "lsm_defs.h"


Expand Down Expand Up @@ -1529,13 +1530,13 @@ LUA_LSM_INT_DEFINE4(mmap_file, struct file *, file, unsigned long, reqprot,
}

/**
* TODO: file_mprotect
* file_mprotect
* Default: 0
*/
LUA_LSM_INT_DEFINE3(file_mprotect, struct vm_area_struct *, vma,
unsigned long, reqprot, unsigned long, prot)
{
lua_pushnil(L); /* TODO: vma */
newmprotectctx(L, vma, reqprot, prot);
lua_pushnumber(L, (lua_Number)reqprot);
lua_pushnumber(L, (lua_Number)prot);
}
Expand Down
204 changes: 204 additions & 0 deletions security/lua/lua_mm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Lua based LSM
*
* Copyright (C) 2025 The Alibaba Cloud Linux Authors.
*/

#include "debug.h"
#include <linux/fs.h>
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/mm_types.h>
#include <linux/lua.h>
#include <linux/lauxlib.h>
#include <linux/lualib.h>
#include "auxlib.h"
#include "lua_object.h"
#include "lua_mm.h"

#define MPROTECT_CTX_META "lua_lsm.mprotect_ctx"

struct lua_lsm_mprotect_ctx {
struct file *file;
};

static struct lua_lsm_mprotect_ctx *tomprotectctx(lua_State *L, int idx)
{
return luaL_checkudata(L, idx, MPROTECT_CTX_META);
}

static void mprotect_ctx_set_bool(lua_State *L, const char *name, bool value)
{
lua_pushboolean(L, value);
lua_setfield(L, -2, name);
}

static void mprotect_ctx_set_ulong(lua_State *L, const char *name,
unsigned long value)
{
lua_pushnumber(L, (lua_Number)value);
lua_setfield(L, -2, name);
}

static void mprotect_ctx_copy_module(lua_State *L, int idx)
{
lua_getfield(L, LUA_REGISTRYINDEX, CURR_ENV);
if (!lua_istable(L, -1)) {
lua_pop(L, 1);
return;
}

lua_pushlightuserdata(L, MODULE_KEY);
lua_gettable(L, -2);
if (lua_islightuserdata(L, -1)) {
lua_pushlightuserdata(L, MODULE_KEY);
lua_pushvalue(L, -2);
lua_rawset(L, idx);
}
lua_pop(L, 2);
}

static void mprotect_ctx_build_table(lua_State *L, struct vm_area_struct *vma,
unsigned long reqprot, unsigned long prot)
{
vm_flags_t flags = vma->vm_flags;
bool file_backed = !!vma->vm_file;
bool shared = !!(flags & VM_SHARED);
bool was_readable = !!(flags & VM_READ);
bool was_writable = !!(flags & VM_WRITE);
bool was_executable = !!(flags & VM_EXEC);
bool requested_read = !!(reqprot & PROT_READ);
bool requested_write = !!(reqprot & PROT_WRITE);
bool requested_exec = !!(reqprot & PROT_EXEC);
bool readable = !!(prot & PROT_READ);
bool writable = !!(prot & PROT_WRITE);
bool executable = !!(prot & PROT_EXEC);
bool heap = vma->vm_mm &&
vma->vm_start >= vma->vm_mm->start_brk &&
vma->vm_end <= vma->vm_mm->brk;
bool stack = vma->vm_mm &&
(vma_is_initial_stack(vma) || vma_is_stack_for_current(vma));

luaL_checkstack(L, 32, "mprotect_ctx");
lua_newtable(L);

mprotect_ctx_copy_module(L, lua_gettop(L));

mprotect_ctx_set_ulong(L, "start", vma->vm_start);
mprotect_ctx_set_ulong(L, "finish", vma->vm_end);
mprotect_ctx_set_ulong(L, "size", vma->vm_end - vma->vm_start);

mprotect_ctx_set_bool(L, "file_backed", file_backed);
mprotect_ctx_set_bool(L, "anonymous", vma_is_anonymous(vma));
mprotect_ctx_set_bool(L, "shared", shared);
mprotect_ctx_set_bool(L, "private", !shared);
mprotect_ctx_set_bool(L, "heap", heap);
mprotect_ctx_set_bool(L, "stack", stack);
mprotect_ctx_set_bool(L, "file_cow", file_backed && vma->anon_vma);

mprotect_ctx_set_bool(L, "readable", readable);
mprotect_ctx_set_bool(L, "writable", writable);
mprotect_ctx_set_bool(L, "executable", executable);
mprotect_ctx_set_bool(L, "requested_read", requested_read);
mprotect_ctx_set_bool(L, "requested_write", requested_write);
mprotect_ctx_set_bool(L, "requested_exec", requested_exec);
mprotect_ctx_set_bool(L, "was_readable", was_readable);
mprotect_ctx_set_bool(L, "was_writable", was_writable);
mprotect_ctx_set_bool(L, "was_executable", was_executable);

mprotect_ctx_set_bool(L, "gaining_exec",
executable && !was_executable);
mprotect_ctx_set_bool(L, "gaining_write", writable && !was_writable);
mprotect_ctx_set_bool(L, "write_to_exec",
was_writable && executable && !was_executable);
mprotect_ctx_set_bool(L, "implied_exec", executable && !requested_exec);
mprotect_ctx_set_bool(L, "wx", writable && executable);
}

static int mprotect_ctx_file(lua_State *L)
{
struct lua_lsm_mprotect_ctx *ctx = tomprotectctx(L, 1);

if (!ctx->file) {
lua_pushnil(L);
return 1;
}

*newgcfile_nomain(L) = get_file(ctx->file);
lua_getfenv(L, 1);
lua_setfenv(L, -2);
return 1;
}

static int mprotect_ctx_index(lua_State *L)
{
lua_getfenv(L, 1);
lua_pushvalue(L, 2);
lua_rawget(L, -2);
if (!lua_isnil(L, -1)) {
lua_remove(L, -2);
return 1;
}
lua_pop(L, 2);

if (!lua_getmetatable(L, 1)) {
lua_pushnil(L);
return 1;
}
lua_pushvalue(L, 2);
lua_rawget(L, -2);
lua_remove(L, -2);
return 1;
}

static int mprotect_ctx_gc(lua_State *L)
{
struct lua_lsm_mprotect_ctx *ctx = tomprotectctx(L, 1);

if (ctx->file) {
fput(ctx->file);
ctx->file = NULL;
}
return 0;
}

static int mprotect_ctx_tostring(lua_State *L)
{
struct lua_lsm_mprotect_ctx *ctx = tomprotectctx(L, 1);

lua_pushfstring(L, "mprotect_ctx: <%p>", ctx);
return 1;
}

static void mprotect_ctx_set_meta(lua_State *L)
{
static const luaL_Reg meth[] = {
{ "file", mprotect_ctx_file },
{ "__gc", mprotect_ctx_gc },
{ "__tostring", mprotect_ctx_tostring },
{ NULL, NULL }
};

if (luaL_newmetatable(L, MPROTECT_CTX_META)) {
lua_pushstring(L, "cannot set a protected metatable");
lua_setfield(L, -2, "__metatable");
luaL_register(L, NULL, meth);
lua_pushcfunction(L, mprotect_ctx_index);
lua_setfield(L, -2, "__index");
}
lua_setmetatable(L, -2);
}

void newmprotectctx(lua_State *L, struct vm_area_struct *vma,
unsigned long reqprot, unsigned long prot)
{
struct lua_lsm_mprotect_ctx *ctx;

ctx = lua_newuserdata(L, sizeof(*ctx));
ctx->file = vma->vm_file ? get_file(vma->vm_file) : NULL;

mprotect_ctx_set_meta(L);
mprotect_ctx_build_table(L, vma, reqprot, prot);
lua_setfenv(L, -2);
}
18 changes: 18 additions & 0 deletions security/lua/lua_mm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Lua based LSM
*
* Copyright (C) 2025 The Alibaba Cloud Linux Authors.
*/

#ifndef _SECURITY_LUA_LSM_LUA_MM_H
#define _SECURITY_LUA_LSM_LUA_MM_H

#include <linux/lua.h>

struct vm_area_struct;

void newmprotectctx(lua_State *L, struct vm_area_struct *vma,
unsigned long reqprot, unsigned long prot);

#endif /* ! _SECURITY_LUA_LSM_LUA_MM_H */