lua-lsm: add skb payload accessors and hand out only full socks - #31
Open
chenzongyao200127 wants to merge 139 commits into
Open
lua-lsm: add skb payload accessors and hand out only full socks#31chenzongyao200127 wants to merge 139 commits into
chenzongyao200127 wants to merge 139 commits into
Conversation
This reverts commit 97169cd.
The folling is main instructions: export PATH="$(brew --prefix make)/libexec/gnubin:$PATH" export PATH="$(brew --prefix llvm)/bin:$PATH" export PATH="$(brew --prefix lld)/bin:$PATH" # Eliminate compile errors of scripts/mod/file2alias.c export HOSTCFLAGS="-D_UUID_T -D__GETHOSTUUID_H" # Maybe the symlink is missed on macOS #ln -s ../../../scripts/syscall.tbl arch/arm64/tools/syscall_64.tbl #ln -s qcom,sm8550-dispcc.h include/dt-bindings/clock/qcom,sm8650-dispcc.h #make ARCH=arm64 LLVM=1 #make LLVM=1 menuconfig #make LLVM=1 -j8 Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
When developing a dedicated LSM module, we need to operate on the file object within the LSM function, such as retrieving the path. However, in `security_file_alloc()`, the passed-in `filp` is only a valid pointer; the content of `filp` is completely uninitialized and entirely random, which confuses the LSM function. Therefore, it is necessary to call `security_file_alloc()` only after the main fields of the `filp` object have been initialized. This patch only moves the call to `security_file_alloc()` to the end of the `init_file()` function. Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
Standard C provides basic library functions for jumping between functions. They were introduced to support the upcoming Lua language interpreter, which uses the setjmp/longjmp functions to implement exception handling. Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
Standard C provides basic library functions for jumping between functions. They were introduced to support the upcoming Lua language interpreter, which uses the setjmp/longjmp functions to implement exception handling. Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
Lua is an extension programming language designed to support general procedural programming with data description facilities. It also offers good support for object-oriented programming, functional programming, and data-driven programming. Lua is intended to be used as a powerful, light-weight scripting language for any program that needs one. Lua is implemented as a library, written in clean C (that is, in the common subset of ANSI C and C++). Lua is embedded in the kernel. Leveraging Lua's simplicity and powerful metaprogramming capabilities, it allows the use of scripting languages to develop complex security access control policies. The reason for choosing version 5.1 is that Lua has been mature enough since version 5.1, and secondly, LuaJIT may be introduced in the future for JIT acceleration. Currently, LuaJIT is compatible with version 5.1. Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
queue.h and tree.h are borrowed from freebsd
d342ae67192f ("uath: add support for GCMP-128 encryption")
bitmap.h is borrowed from bitops of latest netbsd.
Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
Fixes for queue and tree
Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com> Co-developed-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
This module leverages Lua's metaprogramming capabilities to develop complex access control logic and policies in Lua. Let us using a programmatic approach close to natural language, significantly lowers the barrier to entry for developing LSM access control. This module has the following notable features: * Supports developing LSM policies as mini-programs or LSM plugins. Multiple mini-programs or LSM plugins can be loaded simultaneously, and dynamic, on-demand uninstallation is supported. * Each mini-program runs in a secure sandbox environment. Script errors will not trigger kernel panics, and mini-programs are isolated from each other, ensuring no impact. * Mini-programs interact with the kernel through a specific, limited API, ensuring kernel security. * The LSM module features deep integration with the Lua language, enabling the most natural way to share data and set kernel object attributes. Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com> Co-developed-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
The reason is that the modules_lock is held for a period of time during module registration. A softirq occurs within this critical section, and the softirq handler reenters the LSM function, causing a deadlock. This issue can be resolved by disabling softirq while holding the modules_lock lock during module registration. Some logs are as follows: [28031.294632] rcu: INFO: rcu_preempt self-detected stall on CPU [28031.294801] rcu: 2-...!: (886811 ticks this GP) idle=ea9c/1/0x4000000000000000 softirq=243287/243287 fqs=0 [28031.295043] rcu: (t=887418 jiffies g=263373 q=454 ncpus=4) [28031.295183] rcu: rcu_preempt kthread starved for 887418 jiffies! g263373 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x0 ->cpu=2 [28031.295524] rcu: Unless rcu_preempt kthread gets sufficient CPU time, OOM is now expected behavior. [28031.295872] rcu: RCU grace-period kthread stack dump: [28031.296001] task:rcu_preempt state:R running task stack:0 pid:15 tgid:15 ppid:2 task_flags:0x208040 flags:0x00000010 [28031.296319] Call trace: [28031.296381] __switch_to+0x194/0x2b4 (T) [28031.296484] __schedule+0x5b4/0x980 [28031.296572] schedule+0x54/0xf8 [28031.296652] schedule_timeout+0x88/0xf8 [28031.296750] rcu_gp_fqs_loop+0x1c4/0x6b0 [28031.296851] rcu_gp_kthread+0x60/0x134 [28031.296946] kthread+0x140/0x254 [28031.297030] ret_from_fork+0x10/0x20 [28031.297123] Sending NMI from CPU 2 to CPUs 1: [28031.297242] NMI backtrace for cpu 1 [28031.297247] CPU: 1 UID: 0 PID: 81146 Comm: sh Not tainted 6.17.0-rc3+ #511 PREEMPT [28031.297249] Hardware name: QEMU QEMU Virtual Machine, BIOS edk2-stable202408-prebuilt.qemu.org 08/13/2024 [28031.297250] pstate: 01400005 (nzcv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--) [28031.297250] pc : queued_read_lock_slowpath+0x80/0x14c [28031.297253] lr : _raw_read_lock_bh+0x64/0x68 [28031.297254] sp : ffff800088ee39e0 [28031.297254] x29: ffff800088ee39e0 x28: 0000000000002e2e x27: 0000000000000501 [28031.297256] x26: 0000000000000030 x25: 2f2f2f2f2f2f2f2f x24: 61c8864680b583eb [28031.297257] x23: fefefefefefefeff x22: 0000000000000000 x21: ffff0000c2671138 [28031.297257] x20: 0000000000000081 x19: 00001643fef959e4 x18: 0000000000000000 [28031.297258] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [28031.297259] x14: 0000000000000000 x13: 0000000000000000 x12: 8080808080808000 [28031.297259] x11: 000000000000002e x10: 0000000000000018 x9 : 0000000000000000 [28031.297260] x8 : 00000000000008ff x7 : 0000000000000000 x6 : 0000000000000000 [28031.297261] x5 : 0000000000000000 x4 : 0000000000000000 x3 : ffff800088ee3c98 [28031.297261] x2 : 0000000000000000 x1 : 0000000000013cee x0 : ffff8000818ae3c8 [28031.297262] Call trace: [28031.297262] queued_read_lock_slowpath+0x80/0x14c (P) [28031.297264] _raw_read_lock_bh+0x64/0x68 [28031.297265] lua_lsm_inode_permission+0x54/0x35c [28031.297268] security_inode_permission+0x54/0xb0 [28031.297269] inode_permission+0x64/0x170 [28031.297270] link_path_walk+0xb4/0x388 [28031.297272] path_lookupat+0x68/0x120 [28031.297272] filename_lookup+0xe0/0x1e0 [28031.297273] vfs_statx+0x7c/0x1a0 [28031.297276] vfs_fstatat+0xb4/0xe0 [28031.297277] __arm64_sys_newfstatat+0x68/0xa8 [28031.297278] invoke_syscall+0x40/0xf8 [28031.297280] el0_svc_common+0xa8/0xd8 [28031.297281] do_el0_svc+0x1c/0x28 [28031.297282] el0_svc+0x38/0x8c [28031.297283] el0t_64_sync_handler+0x84/0x12c [28031.297284] el0t_64_sync+0x198/0x19c [28031.298239] CPU: 2 UID: 0 PID: 81145 Comm: cat Not tainted 6.17.0-rc3+ #511 PREEMPT [28031.303082] Hardware name: QEMU QEMU Virtual Machine, BIOS edk2-stable202408-prebuilt.qemu.org 08/13/2024 [28031.303326] pstate: 01400005 (nzcv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--) [28031.303504] pc : queued_read_lock_slowpath+0x80/0x14c [28031.303634] lr : _raw_read_lock_bh+0x64/0x68 [28031.303743] sp : ffff8000818ebe00 [28031.303828] x29: ffff8000818ebe00 x28: 0000000000000200 x27: 000000000000000a [28031.304011] x26: ffff800081788000 x25: ffff8000800fa104 x24: 0000000000000001 [28031.304192] x23: 0000000000000000 x22: 000000000000000a x21: 0000000000000000 [28031.304374] x20: ffff000008774600 x19: 00001643fef8ae04 x18: 0000000000000000 [28031.304556] x17: ffff80007e099000 x16: ffff8000818e8000 x15: 0000000000000000 [28031.304739] x14: 0000000000000004 x13: ffff0000ff6187a8 x12: 0000000000000002 [28031.304922] x11: ffff0000c2288a18 x10: 0000000000000018 x9 : 0000000000000000 [28031.305104] x8 : 00000000000008ff x7 : 7fffffffffffffff x6 : 00003d0900007d00 [28031.305285] x5 : ffff800081874120 x4 : 0000000000000008 x3 : ffff80008a153710 [28031.305470] x2 : 00000000000404d4 x1 : 00000000000138ce x0 : ffff8000818ae3c8 [28031.305651] Call trace: [28031.305714] queued_read_lock_slowpath+0x80/0x14c (P) [28031.305844] _raw_read_lock_bh+0x64/0x68 [28031.305945] lua_lsm_cred_free+0x54/0x2bc [28031.306048] security_cred_free+0x5c/0x90 [28031.306151] put_cred_rcu+0x28/0x15c [28031.306244] rcu_core+0x2c0/0x5e0 [28031.306330] rcu_core_si+0x10/0x1c [28031.306418] handle_softirqs+0xdc/0x200 [28031.306517] __do_softirq+0x14/0x20 [28031.306686] ____do_softirq+0x10/0x1c [28031.306782] call_on_irq_stack+0x30/0x48 [28031.306884] do_softirq_own_stack+0x1c/0x28 [28031.306993] __irq_exit_rcu+0x54/0xf8 [28031.307087] irq_exit_rcu+0x10/0x1c [28031.307176] el1_interrupt+0x38/0x54 [28031.307269] el1h_64_irq_handler+0x18/0x24 [28031.307375] el1h_64_irq+0x6c/0x70 [28031.307463] lua_module_register+0x550/0x588 (P) [28031.307582] register_write+0x78/0xac [28031.307676] vfs_write+0x160/0x3bc [28031.307764] ksys_write+0x70/0xe4 [28031.307849] __arm64_sys_write+0x1c/0x28 [28031.307950] invoke_syscall+0x40/0xf8 [28031.308044] el0_svc_common+0xa8/0xd8 [28031.308138] do_el0_svc+0x1c/0x28 [28031.308225] el0_svc+0x38/0x8c [28031.308311] el0t_64_sync_handler+0x84/0x12c [28031.308422] el0t_64_sync+0x198/0x19c
When interrupts are disabled, file system operations triggered by memory
allocation may cause a potential deadlock.
The log is as follows:
[ 37.041540] =====================================================
[ 37.041790] WARNING: SOFTIRQ-safe -> SOFTIRQ-unsafe lock order detected
[ 37.042170] 6.17.0-rc3+ #515 Tainted: G W
[ 37.042492] -----------------------------------------------------
[ 37.042953] cat/1610 [HC0[0]:SC0[2]:HE1:SE0] is trying to acquire:
[ 37.043316] ffff800081f2b9f8 (fs_reclaim){+.+.}-{0:0}, at: __kmalloc_noprof+0xb0/0x4d4
[ 37.043783]
[ 37.043783] and this task is already holding:
[ 37.044121] ffff0000c177e138 (&dict->lock){+.-.}-{3:3}, at: kvcache_incr+0x68/0x21c
[ 37.044569] which would create a new lock dependency:
[ 37.044861] (&dict->lock){+.-.}-{3:3} -> (fs_reclaim){+.+.}-{0:0}
[ 37.045222]
[ 37.045222] but this new dependency connects a SOFTIRQ-irq-safe lock:
[ 37.045685] (&dict->lock){+.-.}-{3:3}
[ 37.045687]
[ 37.045687] ... which became SOFTIRQ-irq-safe at:
[ 37.046273] lock_acquire+0x118/0x26c
[ 37.046479] _raw_write_lock+0x4c/0x88
[ 37.046736] kvcache_dict_free+0x24/0x104
[ 37.046950] lua_lsm_inode_free_security_rcu+0x1d4/0x274
[ 37.047231] inode_free_by_rcu+0x54/0x9c
[ 37.047442] rcu_core+0x474/0xa50
[ 37.047623] rcu_core_si+0x10/0x1c
[ 37.047805] handle_softirqs+0x178/0x42c
[ 37.048018] __do_softirq+0x14/0x20
[ 37.048205] ____do_softirq+0x10/0x1c
[ 37.048404] call_on_irq_stack+0x30/0x48
[ 37.048614] do_softirq_own_stack+0x1c/0x28
[ 37.048838] __irq_exit_rcu+0xd4/0x194
[ 37.049039] irq_exit_rcu+0x10/0x34
[ 37.049226] el1_interrupt+0x38/0x54
[ 37.049418] el1h_64_irq_handler+0x18/0x24
[ 37.049636] el1h_64_irq+0x6c/0x70
[ 37.049818] do_idle+0xe8/0x26c
[ 37.049994] cpu_startup_entry+0x34/0x38
[ 37.050206] kernel_init+0x0/0x128
[ 37.050389] start_kernel+0x304/0x3c0
[ 37.050659] __primary_switched+0x88/0x90
[ 37.050881]
[ 37.050881] to a SOFTIRQ-irq-unsafe lock:
[ 37.051169] (fs_reclaim){+.+.}-{0:0}
[ 37.051171]
[ 37.051171] ... which became SOFTIRQ-irq-unsafe at:
[ 37.051699] ...
[ 37.051704] lock_acquire+0x118/0x26c
[ 37.051997] fs_reclaim_acquire+0x64/0xd0
[ 37.052215] mem_cgroup_css_alloc+0xdc/0x6e4
[ 37.052436] cgroup_init_subsys+0x7c/0x1d0
[ 37.052642] cgroup_init+0x2d8/0x490
[ 37.052822] start_kernel+0x2f4/0x3c0
[ 37.053006] __primary_switched+0x88/0x90
[ 37.053210]
[ 37.053210] other info that might help us debug this:
[ 37.053210]
[ 37.053598] Possible interrupt unsafe locking scenario:
[ 37.053598]
[ 37.053929] CPU0 CPU1
[ 37.054152] ---- ----
[ 37.054372] lock(fs_reclaim);
[ 37.054649] local_irq_disable();
[ 37.055469] lock(&dict->lock);
[ 37.055751] lock(fs_reclaim);
[ 37.056024] <Interrupt>
[ 37.056151] lock(&dict->lock);
[ 37.056316]
[ 37.056316] *** DEADLOCK ***
[ 37.056316]
[ 37.056602] 2 locks held by cat/1610:
[ 37.056779] #0: ffff800081fdaf18 (modules_lock){++.-}-{3:3}, at: lua_lsm_file_permission+0x58/0x36c
[ 37.057221] openanolis#1: ffff0000c177e138 (&dict->lock){+.-.}-{3:3}, at: kvcache_incr+0x68/0x21c
[ 37.057611]
[ 37.057611] the dependencies between SOFTIRQ-irq-safe lock and the holding lock:
[ 37.058091] -> (&dict->lock){+.-.}-{3:3} {
[ 37.058303] HARDIRQ-ON-W at:
[ 37.058495] lock_acquire+0x118/0x26c
[ 37.058777] _raw_write_lock+0x4c/0x88
[ 37.059053] kvcache_dict_free+0x24/0x104
[ 37.059353] lua_lsm_file_free_security+0x210/0x2bc
[ 37.059691] security_file_free+0x5c/0xa4
[ 37.059991] __fput+0x1a0/0x2f0
[ 37.060242] delayed_fput+0x44/0x58
[ 37.060514] process_one_work+0x210/0x548
[ 37.060815] worker_thread+0x244/0x380
[ 37.061096] kthread+0x138/0x260
[ 37.061348] ret_from_fork+0x10/0x20
[ 37.061622] IN-SOFTIRQ-W at:
[ 37.061790] lock_acquire+0x118/0x26c
[ 37.062117] _raw_write_lock+0x4c/0x88
[ 37.062405] kvcache_dict_free+0x24/0x104
[ 37.062730] lua_lsm_inode_free_security_rcu+0x1d4/0x274
[ 37.063097] inode_free_by_rcu+0x54/0x9c
[ 37.063390] rcu_core+0x474/0xa50
[ 37.063652] rcu_core_si+0x10/0x1c
[ 37.063917] handle_softirqs+0x178/0x42c
[ 37.064213] __do_softirq+0x14/0x20
[ 37.064475] ____do_softirq+0x10/0x1c
[ 37.064739] call_on_irq_stack+0x30/0x48
[ 37.065014] do_softirq_own_stack+0x1c/0x28
[ 37.065307] __irq_exit_rcu+0xd4/0x194
[ 37.065583] irq_exit_rcu+0x10/0x34
[ 37.065901] el1_interrupt+0x38/0x54
[ 37.066155] el1h_64_irq_handler+0x18/0x24
[ 37.066399] el1h_64_irq+0x6c/0x70
[ 37.066660] do_idle+0xe8/0x26c
[ 37.066891] cpu_startup_entry+0x34/0x38
[ 37.067168] kernel_init+0x0/0x128
[ 37.067418] start_kernel+0x304/0x3c0
[ 37.067679] __primary_switched+0x88/0x90
[ 37.067959] INITIAL USE at:
[ 37.068115] lock_acquire+0x118/0x26c
[ 37.068375] _raw_write_lock+0x4c/0x88
[ 37.068637] kvcache_dict_free+0x24/0x104
[ 37.068917] lua_lsm_file_free_security+0x210/0x2bc
[ 37.069222] security_file_free+0x5c/0xa4
[ 37.069499] __fput+0x1a0/0x2f0
[ 37.069726] delayed_fput+0x44/0x58
[ 37.070043] process_one_work+0x210/0x548
[ 37.070282] worker_thread+0x244/0x380
[ 37.070499] kthread+0x138/0x260
[ 37.070713] ret_from_fork+0x10/0x20
[ 37.070923] }
[ 37.070992] ... key at: [<ffff800082ce7398>] kvcache_dict_init.__key+0x0/0x10
[ 37.071308]
[ 37.071308] the dependencies between the lock to be acquired
[ 37.071309] and SOFTIRQ-irq-unsafe lock:
[ 37.071759] -> (fs_reclaim){+.+.}-{0:0} {
[ 37.071923] HARDIRQ-ON-W at:
[ 37.072052] lock_acquire+0x118/0x26c
[ 37.072268] fs_reclaim_acquire+0x64/0xd0
[ 37.072499] mem_cgroup_css_alloc+0xdc/0x6e4
[ 37.072740] cgroup_init_subsys+0x7c/0x1d0
[ 37.072974] cgroup_init+0x2d8/0x490
[ 37.073187] start_kernel+0x2f4/0x3c0
[ 37.073403] __primary_switched+0x88/0x90
[ 37.073633] SOFTIRQ-ON-W at:
[ 37.073761] lock_acquire+0x118/0x26c
[ 37.074010] fs_reclaim_acquire+0x64/0xd0
[ 37.074241] mem_cgroup_css_alloc+0xdc/0x6e4
[ 37.074482] cgroup_init_subsys+0x7c/0x1d0
[ 37.074735] cgroup_init+0x2d8/0x490
[ 37.074947] start_kernel+0x2f4/0x3c0
[ 37.075160] __primary_switched+0x88/0x90
[ 37.075388] INITIAL USE at:
[ 37.075512] lock_acquire+0x118/0x26c
[ 37.075722] fs_reclaim_acquire+0x64/0xd0
[ 37.075944] mem_cgroup_css_alloc+0xdc/0x6e4
[ 37.076169] cgroup_init_subsys+0x7c/0x1d0
[ 37.076399] cgroup_init+0x2d8/0x490
[ 37.076598] start_kernel+0x2f4/0x3c0
[ 37.076798] __primary_switched+0x88/0x90
[ 37.077012] }
[ 37.077078] ... key at: [<ffff800081f2b9f8>] __fs_reclaim_map+0x0/0x30
[ 37.077349] ... acquired at:
[ 37.077464] fs_reclaim_acquire+0x64/0xd0
[ 37.077628] __kmalloc_noprof+0xb0/0x4d4
[ 37.077787] kvcache_incr+0xe0/0x21c
[ 37.077967] shdict_incr+0x34/0x44
[ 37.078108] luaD_precall+0x330/0x674
[ 37.078259] luaV_execute+0xaac/0x119c
[ 37.078413] luaD_call+0xb0/0x128
[ 37.078550] f_call+0x1c/0x28
[ 37.078692] luaD_rawrunprotected+0x7c/0xb8
[ 37.078862] luaD_pcall+0x40/0x184
[ 37.079003] lua_pcall+0xac/0x190
[ 37.079191] lua_lsm_file_permission+0x1fc/0x36c
[ 37.079379] security_file_permission+0x4c/0xa8
[ 37.079562] rw_verify_area+0x54/0x138
[ 37.079715] vfs_read+0xa4/0x2b0
[ 37.079846] ksys_read+0x70/0xe4
[ 37.079974] __arm64_sys_read+0x1c/0x28
[ 37.080123] invoke_syscall+0x40/0xf8
[ 37.080269] el0_svc_common+0xa8/0xd8
[ 37.080413] do_el0_svc+0x1c/0x28
[ 37.080544] el0_svc+0x50/0xcc
[ 37.080665] el0t_64_sync_handler+0x84/0x12c
[ 37.080831] el0t_64_sync+0x198/0x19c
[ 37.080975]
[ 37.081031]
[ 37.081031] stack backtrace:
[ 37.081195] CPU: 1 UID: 0 PID: 1610 Comm: cat Tainted: G W 6.17.0-rc3+ #515 PREEMPT
[ 37.081535] Tainted: [W]=WARN
[ 37.081646] Hardware name: QEMU QEMU Virtual Machine, BIOS edk2-stable202408-prebuilt.qemu.org 08/13/2024
[ 37.082039] Call trace:
[ 37.082130] show_stack+0x18/0x24 (C)
[ 37.082269] __dump_stack+0x28/0x38
[ 37.082400] dump_stack_lvl+0x64/0x84
[ 37.082537] dump_stack+0x18/0x24
[ 37.082688] __lock_acquire+0x2b2c/0x2b90
[ 37.082837] lock_acquire+0x118/0x26c
[ 37.082972] fs_reclaim_acquire+0x64/0xd0
[ 37.083119] __kmalloc_noprof+0xb0/0x4d4
[ 37.083264] kvcache_incr+0xe0/0x21c
[ 37.083395] shdict_incr+0x34/0x44
[ 37.083520] luaD_precall+0x330/0x674
[ 37.083656] luaV_execute+0xaac/0x119c
[ 37.083793] luaD_call+0xb0/0x128
[ 37.083916] f_call+0x1c/0x28
[ 37.084025] luaD_rawrunprotected+0x7c/0xb8
[ 37.084180] luaD_pcall+0x40/0x184
[ 37.084306] lua_pcall+0xac/0x190
[ 37.084428] lua_lsm_file_permission+0x1fc/0x36c
[ 37.084598] security_file_permission+0x4c/0xa8
[ 37.084765] rw_verify_area+0x54/0x138
[ 37.084902] vfs_read+0xa4/0x2b0
[ 37.085021] ksys_read+0x70/0xe4
[ 37.085139] __arm64_sys_read+0x1c/0x28
[ 37.085280] invoke_syscall+0x40/0xf8
[ 37.085416] el0_svc_common+0xa8/0xd8
[ 37.085553] do_el0_svc+0x1c/0x28
[ 37.085676] el0_svc+0x50/0xcc
[ 37.085790] el0t_64_sync_handler+0x84/0x12c
[ 37.086018] el0t_64_sync+0x198/0x19c
Lua-LSM left the id arguments for kernel_load_data(), kernel_post_load_data(), kernel_read_file(), and kernel_post_read_file() as nil placeholders. Expose those ids as the stable strings returned by kernel_load_data_id_str() and kernel_read_file_id_str(). Lua policies can compare descriptive values such as "kernel-module" or "security-policy" without depending on kernel enum numbers. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
kernel_post_load_data() and kernel_post_read_file() expose file data to Lua as binary-safe strings. Lua policy can get the byte length with the Lua length operator, so passing a separate size argument duplicates information already carried by the string. Drop the Lua-visible size argument from those hooks while keeping the kernel hook signatures unchanged. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Lazy VM allocation failure is a dispatcher error, not a Lua hook result. Return it through the generated dispatcher status and map it at the LSM wrapper boundary. Keep errno-style hooks failing with -ENOMEM. Add boolean result classes for predicate hooks and bool-or-errno hooks so Lua true/false are translated to each hook's native 1/0 semantics instead of permission-style 0/-EPERM. Stop Lua module dispatch when a result differs from the LSM default, matching call_int_hook(). Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
security_xfrm_state_pol_flow_match() is not a normal stacking hook. The hook default return value is 1, and the security core stops after the first registered implementation because the result is a boolean match decision. Lua-LSM currently generates a generic wrapper for the hook. If that wrapper is registered before SELinux, the XFRM lookup path can use the Lua-LSM result and never ask SELinux whether the state, policy, and flow labels match. A dispatch failure also falls back to the default value, which reports a match. Keep the hook out of lua_lsm_hook_supported() until Lua-LSM can provide semantics that do not shadow the provider that owns the XFRM decision. This hides it from registration, module introspection, and module load validation. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
The lazy per-task VM path published lvm->L before moving the VM allocator userdata from the temporary build owner to the target task lvm. Unregister can observe any non-NULL lvm->L through task_call_func(). That window let it treat a half-initialized VM as ready and race with the first hook dispatch. Take the task VM refcount before first-use construction, move the allocator owner and stats before publication, and publish lvm->L only after the VM is ready. The unregister path now either sees an untouched VM or fails the idle-required get while the first dispatch owns the VM. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Keep the per-task Lua VM pointer NULL until hook dispatch needs it. This avoids VM allocation from task allocation and free paths when no Lua policy is active. Module unregister and task free still handle already-published states. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Leave object kvcache dictionaries uninitialized until Lua writes need storage. Reads and frees treat the zero state as empty. This reduces no-policy allocation work without changing object cleanup semantics. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Bypass stats, SRCU, VM preparation, and Lua dispatch when a hook has no active handlers. Keep the inactive cleanup allowlist for free hooks so postponed object teardown still runs for state created while policy was active. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Skip inactive cleanup before any Lua policy has been registered. Once a policy is accepted, keep the key enabled permanently so objects that outlive module unload still run free-hook cleanup. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Lazy kvcache initialization leaves a dictionary in INITING until __kvcache_dict_init() finishes. A same-CPU softirq hook can reenter the Lua path in that window, observe INITING for the current task's dictionary, and spin in kvcache_dict_ready() until the interrupted task context runs again. Disable bottom halves around the UNINIT -> INITING -> READY publication window so same-CPU softirq reentry cannot observe the transient state. While here, rename the inactive-cleanup static key from *_possible to *_armed to better match its one-way semantics after the first policy load. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
lua_lsm_hook_supported() only excluded the procattr and xfrm hooks, so lua-LSM still registered the key, key-notification, perf_event, tun_dev and infiniband hooks. Those operate on object classes for which lua-LSM reserves no security blob (lbs_key, lbs_perf_event, lbs_tun_dev and lbs_ib are all 0), so a policy can neither attach nor manage state on them and the hooks were never usefully supported. Add them to the exclusion list so lua-LSM is not registered on hooks it cannot back, trimming its footprint on those paths. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
The *_alloc_security prepare hooks ran kvcache_dict_init() on every LSM object blob at allocation time. Those blobs are kzalloc'd, and kvcache promotes the embedded dict from the zero UNINIT state to READY lazily on first use, so the eager init is redundant work on a hot allocation path (every inode, file, cred, ipc and sock). Drop the eager initializers and document that KVCACHE_DICT_UNINIT must stay the zero value, so a zero-filled blob is valid without them. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Each lua_lsm hook was a single function: a fast "no policy loaded" early return followed by the srcu walk and VM dispatch. The slow part takes the address of a local (the return slot passed to __prepare_) and uses callee-saved registers, so the compiler gave the whole function a stack frame and a -fstack-protector-strong canary. Even with no policy loaded, every guarded syscall then executed that prologue and two %gs canary accesses just to reach the early return, whereas an empty hook such as bpf_lsm's compiles to a bare "xor %eax, %eax; ret". Split each hook into a thin wrapper and a noinline slow path. When no policy is loaded both static branches are patched to nops, so the wrapper takes no local's address and needs no callee-saved registers: the compiler emits neither a stack frame nor a canary, and the idle path collapses to two nops and a constant return, matching the empty hook. The srcu walk, VM dispatch and inactive object cleanup move into the slow path, entered only once a policy is live. perf confirms the dormant stub then carries no frame or canary; the measurable gain is a few ns per guarded syscall on file-permission-heavy workloads. The residual per-hook cost is the LSM dispatch call itself, which this change does not touch. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Commit "lua-lsm: drop eager kvcache dict init" removed the eager kvcache_dict_init() from the *_alloc_security prepare hooks but missed task_blob_init(), which still initialized the task blob's dict on every task_alloc. The task blob is kzalloc'd like the other LSM object blobs, so its embedded dict starts in the zero UNINIT state and is promoted to READY lazily on first use; the eager init is the same redundant work. Drop it from task_blob_init() too. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
A policy can only report an event through kernel.printk(), whose free-form text auditd can neither parse into fields nor correlate with the syscall that triggered it, so policy decisions stay invisible to the audit trail that records every other security event. Add an audit library that emits one AUDIT_LUA record per call from a table of fields. A field value commonly carries attacker-influenced data such as a path name, so values are escaped rather than trusted. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
A netlink or packet policy has to look at message contents to make a decision, but the skb object only exposed metadata, so such policies could not be written at all. Expose the payload, and the raw protocol number that suites() cannot name, so content-aware policies become possible. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
So policy authors can find the accessors and know a bad read yields nil rather than an error, keeping the decision in the policy's hands. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
On handshake and time-wait paths skb->sk is a request or time-wait sock, which stops short of the fields sock:proto() and sock:suites() read. A policy asking for the protocol number therefore got neighbouring slab bytes, and since those pass for a valid number the rule they feed fails open rather than erroring. Resolve skb->sk through skb_to_full_sk() so a sock handed to a policy is always a full sock, making the guarantee a property of the object rather than of each accessor. skb:full_sk() then duplicates skb:sock() and has no users, so drop it. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
A policy author cannot tell from the method name that a half-open or time-wait connection resolves to the listener or to nil, and would read the nil as "no owning socket" instead of "not a full sock". Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
The helper is local to lua_net.c, but skb_ is netcore's prefix and the function sits two lines from skb_copy_bits() and skb_to_full_sk(), so nothing tells a reader it is not a core networking helper. Every other static function in the file carries the module prefix. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
skb:len() was documented as "payload length", but it measures the window starting at skb->data, and each layer advances that pointer past its own header, so at most hooks the window still covers a header. A policy author trusting the word "payload" computes every skb:read() offset from the wrong base, and an out-of-range read yields nil rather than an error, so the mistake never surfaces. Define the window once for both accessors and record where it starts in each hook that passes an skb, since that is the only thing an offset can be computed from. Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
uudiin
pushed a commit
that referenced
this pull request
Aug 21, 2026
…g FLR During Function Level Reset recovery, the MANA driver reads hardware BAR0 registers that may temporarily contain garbage values. The SHM (Shared Memory) offset read from GDMA_REG_SHM_OFFSET is used to compute gc->shm_base, which is later dereferenced via readl() in mana_smc_poll_register(). If the hardware returns an unaligned or out-of-range value, the driver must not blindly use it, as this would propagate the hardware error into a kernel crash. The following crash was observed on an arm64 Hyper-V guest running kernel 6.17.0-3013-azure during VF reset recovery triggered by HWC timeout. [13291.785274] Unable to handle kernel paging request at virtual address ffff8000a200001b [13291.785311] Mem abort info: [13291.785332] ESR = 0x0000000096000021 [13291.785343] EC = 0x25: DABT (current EL), IL = 32 bits [13291.785355] SET = 0, FnV = 0 [13291.785363] EA = 0, S1PTW = 0 [13291.785372] FSC = 0x21: alignment fault [13291.785382] Data abort info: [13291.785391] ISV = 0, ISS = 0x00000021, ISS2 = 0x00000000 [13291.785404] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 [13291.785412] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 [13291.785421] swapper pgtable: 4k pages, 48-bit VAs, pgdp=00000014df3a1000 [13291.785432] [ffff8000a200001b] pgd=1000000100438403, p4d=1000000100438403, pud=1000000100439403, pmd=0068000fc2000711 [13291.785703] Internal error: Oops: 0000000096000021 [#1] SMP [13291.830975] Modules linked in: tls qrtr mana_ib ib_uverbs ib_core xt_owner xt_tcpudp xt_conntrack nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nft_compat nf_tables cfg80211 8021q garp mrp stp llc binfmt_misc joydev serio_raw nls_iso8859_1 hid_generic aes_ce_blk aes_ce_cipher polyval_ce ghash_ce sm4_ce_gcm sm4_ce_ccm sm4_ce sm4_ce_cipher hid_hyperv sm4 sm3_ce sha3_ce hv_netvsc hid vmgenid hyperv_keyboard hyperv_drm sch_fq_codel nvme_fabrics efi_pstore dm_multipath nfnetlink vsock_loopback vmw_vsock_virtio_transport_common hv_sock vmw_vsock_vmci_transport vmw_vmci vsock dmi_sysfs ip_tables x_tables autofs4 [13291.862630] CPU: 122 UID: 0 PID: 61796 Comm: kworker/122:2 Tainted: G W 6.17.0-3013-azure #13-Ubuntu VOLUNTARY [13291.869902] Tainted: [W]=WARN [13291.871901] Hardware name: Microsoft Corporation Virtual Machine/Virtual Machine, BIOS Hyper-V UEFI Release v4.1 01/08/2026 [13291.878086] Workqueue: events mana_serv_func [13291.880718] pstate: 62400005 (nZCv daif +PAN -UAO +TCO -DIT -SSBS BTYPE=--) [13291.884835] pc : mana_smc_poll_register+0x48/0xb0 [13291.887902] lr : mana_smc_setup_hwc+0x70/0x1c0 [13291.890493] sp : ffff8000ab79bbb0 [13291.892364] x29: ffff8000ab79bbb0 x28: ffff00410c8b5900 x27: ffff00410d630680 [13291.896252] x26: ffff004171f9fd80 x25: 000000016ed55000 x24: 000000017f37e000 [13291.899990] x23: 0000000000000000 x22: 000000016ed55000 x21: 0000000000000000 [13291.904497] x20: ffff8000a200001b x19: 0000000000004e20 x18: ffff8000a6183050 [13291.908308] x17: 0000000000000000 x16: 0000000000000000 x15: 000000000000000a [13291.912542] x14: 0000000000000004 x13: 0000000000000000 x12: 0000000000000000 [13291.916298] x11: 0000000000000000 x10: 0000000000000001 x9 : ffffc45006af1bd8 [13291.920945] x8 : ffff000151129000 x7 : 0000000000000000 x6 : 0000000000000000 [13291.925293] x5 : 000000015f214000 x4 : 000000017217a000 x3 : 000000016ed50000 [13291.930436] x2 : 000000016ed55000 x1 : 0000000000000000 x0 : ffff8000a1ffffff [13291.934342] Call trace: [13291.935736] mana_smc_poll_register+0x48/0xb0 (P) [13291.938611] mana_smc_setup_hwc+0x70/0x1c0 [13291.941113] mana_hwc_create_channel+0x1a0/0x3a0 [13291.944283] mana_gd_setup+0x16c/0x398 [13291.946584] mana_gd_resume+0x24/0x70 [13291.948917] mana_do_service+0x13c/0x1d0 [13291.951583] mana_serv_func+0x34/0x68 [13291.953732] process_one_work+0x168/0x3d0 [13291.956745] worker_thread+0x2ac/0x480 [13291.959104] kthread+0xf8/0x110 [13291.961026] ret_from_fork+0x10/0x20 [13291.963560] Code: d2807d00 9417c551 71000673 54000220 (b9400281) [13291.967299] ---[ end trace 0000000000000000 ]--- Disassembly of mana_smc_poll_register() around the crash site: Disassembly of section .text: 00000000000047c8 <mana_smc_poll_register>: 47c8: d503201f nop 47cc: d503201f nop 47d0: d503233f paciasp 47d4: f800865e str x30, [x18], #8 47d8: a9bd7bfd stp x29, x30, [sp, #-48]! 47dc: 910003fd mov x29, sp 47e0: a90153f3 stp x19, x20, [sp, #16] 47e4: 91007014 add x20, x0, #0x1c 47e8: 5289c413 mov w19, #0x4e20 47ec: f90013f5 str x21, [sp, #32] 47f0: 12001c35 and w21, w1, #0xff 47f4: 14000008 b 4814 <mana_smc_poll_register+0x4c> 47f8: 36f801e1 tbz w1, #31, 4834 <mana_smc_poll_register+0x6c> 47fc: 52800042 mov w2, #0x2 4800: d280fa01 mov x1, #0x7d0 4804: d2807d00 mov x0, #0x3e8 4808: 94000000 bl 0 <usleep_range_state> 480c: 71000673 subs w19, w19, #0x1 4810: 54000200 b.eq 4850 <mana_smc_poll_register+0x88> 4814: b9400281 ldr w1, [x20] <-- **** CRASHED HERE ***** 4818: d50331bf dmb oshld 481c: 2a0103e2 mov w2, w1 ... From the crash signature x20 = ffff8000a200001b, this address ends in 0x1b which is not 4-byte aligned, so the 'ldr w1, [x20]' instruction (readl) triggers the arm64 alignment fault (FSC = 0x21). The root cause is in mana_gd_init_vf_regs(), which computes: gc->shm_base = gc->bar0_va + mana_gd_r64(gc, GDMA_REG_SHM_OFFSET); The offset is used without any validation. The same problem exists in mana_gd_init_pf_regs() for sriov_base_off and sriov_shm_off. Fix this by validating all offsets before use: - VF: check shm_off is within BAR0, properly aligned to 4 bytes (readl requirement), and leaves room for the full 256-bit (32-byte) SMC aperture. - PF: check sriov_base_off is within BAR0, aligned to 8 bytes (readq requirement), and leaves room to safely read the sriov_shm_off register at sriov_base_off + GDMA_PF_REG_SHM_OFF. Then check sriov_shm_off leaves room for the full SMC aperture. All arithmetic uses subtraction rather than addition to avoid integer overflow on garbage values. Define SMC_APERTURE_SIZE (32 bytes, derived from the 256-bit aperture width) Return -EPROTO on invalid values. The existing recovery path in mana_serv_reset() already handles -EPROTO by falling through to PCI device rescan, giving the hardware another chance to present valid register values after reset. Fixes: 9bf6603 ("net: mana: Handle hardware recovery events when probing the device") Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com> Link: https://patch.msgid.link/afQUMClyjmBVfD+u@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net Signed-off-by: Paolo Abeni <pabeni@redhat.com>
uudiin
pushed a commit
that referenced
this pull request
Aug 21, 2026
The bitfields are designed in assumption that fields contain unsigned
integer values, thus extracting the values from the field implies
zero-extending.
Some drivers need to sign-extend their fields, and currently do it like:
dc_re += sign_extend32(FIELD_GET(0xfff000, tmp), 11);
dc_im += sign_extend32(FIELD_GET(0xfff, tmp), 11);
It's error-prone because it relies on user to provide the correct
index of the most significant bit and proper 32 vs 64 function flavor.
Thus, introduce a FIELD_GET_SIGNED(). With the new API, the above
snippet turns into the more convenient:
dc_re += FIELD_GET_SIGNED(0xfff000, tmp);
dc_im += FIELD_GET_SIGNED(0xfff, tmp);
It compiles (on x86_64) into just a couple instructions: shl and sar.
When the mask includes MSB, the '<< __builtin_clzll(mask)' part becomes
a NOP, and the compiler only emits a single sar:
long long foo(long long reg)
{
10: f3 0f 1e fa endbr64
return FIELD_GET_SIGNED(GENMASK_ULL(63, 60), reg);
14: 48 89 f8 mov %rdi,%rax
17: 48 c1 f8 3c sar $0x3c,%rax
}
32-bit code generation is equally well. On arm32:
long long foo(long long reg)
{
return FIELD_GET_SIGNED(0x00f00000ULL, reg);
}
generates:
foo(long long):
lsls r1, r0, #8
asrs r0, r1, #28
asrs r1, r1, #31
bx lr
Signed-off-by: Yury Norov <ynorov@nvidia.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Netlink and packet hooks receive an
sk_buff, but the skb object only exposedmetadata (
sock,protocol,iif,secmark). A policy that has to decide onmessage contents — which netlink command is being issued, for instance — could
not be written at all.
This series adds the payload accessors, fixes a fail-open in
skb:sock(), anddocuments the one thing a content-aware policy cannot guess: where offset 0 is.
skb:len()/skb:read(off, len)—read()returns the bytes as a string,or
nilwhen the range falls outside the window, so the policy keeps theverdict instead of taking a Lua error that would fall back to the hook default
and allow the operation. Reads go through
skb_copy_bits(), so a non-linearskb is stitched together transparently, and one read is bounded by a fixed
256-byte on-stack buffer.
sock:proto()— the rawsk_protocol.suites()renders that number throughthe
IPPROTO_*namespace, which cannot name protocols of other families suchas netlink's
NETLINK_ROUTE.skb:sock()now resolvesskb->skthroughskb_to_full_sk(). On handshakeand time-wait paths
skb->skis a request or time-wait sock, which stops shortof the fields
sock:proto()andsock:suites()read, so a policy asking forthe protocol number got neighbouring slab bytes — and since those pass for a
valid number, the rule they feed failed open. A half-open connection now
resolves to its listener and a time-wait sock yields
nil.skb:full_sk()became a duplicate of
skb:sock()and is dropped.docs/API.mddefines the data window (skb->lenbytes fromskb->data) oncefor both accessors and records where it starts in each hook that passes an skb.
Each layer advances
skb->datapast its own header, so the base is a propertyof the hook, not of the packet — and getting it wrong is quiet: an out-of-range
read yields
nil, an in-range one yields whatever field happens to sit there.Multi-byte fields are decoded in Lua, since the in-kernel Lua has no bit
library; the examples below use
string.byteand modulo arithmetic.Example policies
Deny route deletions over rtnetlink. Under
netlink_sendthe window spanseverything one
sendmsg()wrote, so a batch arrives as consecutivelength-delimited messages and the policy has to walk them.
Log inbound TCP SYNs to a port. Under
socket_sock_rcv_skboffset 0 is the TCPheader on the IPv4/IPv6 TCP path — but the same hook fires for netlink, SCTP,
unix and raw sockets, where the window starts somewhere else, so the family
check is not optional.
skb:sock()can returnnil— no owning socket, or a time-wait sock that isnot a full sock — so a policy that reads through it needs the nil check;
indexing
nilraises, and a Lua error inside a hook falls back to that hook'sdefault, which is "allow" for most hooks. Wrap parsing in
pcall()where thepolicy must fail closed.
Test plan
ip route deldenied,SYNs to port 22 audited).
skb:read()boundaries:off == skb:len()withlen == 0,len == 256,len > 256, negativeoff/len, and a read spanning a non-linear skb.skb:sock()on a SYN (inet_conn_request) returns the listener, and on atime-wait skb returns
nilrather than a mini-sock.docs/API.mdre-checked against the hook call sites for eachrow of the table.