Skip to content

lua-lsm: support loadable API producers - #26

Open
chenzongyao200127 wants to merge 150 commits into
openanolis:lua-lsmfrom
chenzongyao200127:lua-lsm-per-lib-ko
Open

lua-lsm: support loadable API producers#26
chenzongyao200127 wants to merge 150 commits into
openanolis:lua-lsmfrom
chenzongyao200127:lua-lsm-per-lib-ko

Conversation

@chenzongyao200127

@chenzongyao200127 chenzongyao200127 commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

Add a registration path for Lua-LSM API libraries so the Lua-callable
surface can be provided by independent producer modules instead of being
fully tied to the core LSM object.

This allows the existing kernel, fs, net, errno, capability,
and signal libraries to be built either into vmlinux or as loadable
producer modules, documents how external producers can register their
own Lua APIs, and exposes the live API library registry through
securityfs for inspection.

Changes

  • Add the public Lua API producer descriptor and registration ABI.
  • Add the API library registry, replay, generation tracking, audit, and
    rollback handling.
  • Add metatable installation support for producer modules.
  • Convert the existing Lua API libraries to producer descriptors.
  • Preserve module lifetime by pinning loadable producers while their C
    closures may be reachable from Lua VMs.
  • Rebuild stale task VMs on demand after new API libraries register.
  • Require module signature support when signed API producer enforcement is
    enabled.
  • Expose the live API library registry in
    /sys/kernel/security/lua/api_libraries.
  • Document in-tree and out-of-tree Lua API producer usage.

securityfs example

cat /sys/kernel/security/lua/api_libraries

Example output:

API libraries for lua-lsm
API set version: 3
name                 provider              funcs extra-init  abi
----------------------------------------------------------------------------------------------
kernel               builtin                  12        yes    1
fs                   lua_fs.ko                 8         no    1
net                  lua_net.ko               10        yes    1

API set version increments when the registered Lua API library set
changes. extra-init indicates whether the library defines an
open_extras callback in addition to the plain luaL_Reg function
array.

Validation

# Per commit:
git show --format=email --no-ext-diff --patch <commit> |
  scripts/checkpatch.pl --strict --show-types \
    --ignore CAMELCASE,FILE_PATH_CHANGES --no-tree -

# Whole series:
git diff --check origin/lua-lsm..HEAD
make -s M=security/lua modules
make -s W=1 M=security/lua modules

The ignored checkpatch message types are limited to Lua API naming
(luaL_Reg) and the standard new-file MAINTAINERS reminder.

uudiin added 30 commits March 24, 2026 14:12
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>
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
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>
Export the Lua runtime and lua-lsm auxiliary helpers needed by
loadable API producer modules.  Keep the exported surface limited to the
functions used by the per-library modules.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Add the descriptor and registration entry points used by API
libraries to publish their Lua functions to the lua-lsm core.  The ABI
also documents ownership, versioning, and metatable install contracts.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Move API object metatable creation behind a core-owned installer.
Producer modules can attach their method tables without exporting the raw
metatable construction helpers.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Add the registry that validates producer descriptors, audits
registration attempts, replays libraries into live Lua VMs, and keeps CPU
hotplug state synchronized.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Teach the lua-lsm core to build Lua states from the dynamic API
library registry.  Expose the VM and pool helpers needed by registry
replay and invalidate stale pooled VMs by generation.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Register the kernel API surface through the new producer ABI.  Keep
object metatable setup in an open_extras callback, and route
non-exported task lookup helpers through lua-lsm wrappers.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Register the filesystem API surface as an independent producer.
Move filesystem object metatable installation into the producer callback
so the library can be built separately from the core.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Register the networking API surface as an independent producer.
Install socket-related object methods through the shared metatable helper
instead of opening the library from the core.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Register the errno API surface through the producer ABI.  Publish the
errname helper and errno constants from the library callback.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Register the capability API surface through the producer ABI.  Attach
capability object methods through the shared metatable helper before
publishing constants.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Register the signal API surface through the producer ABI.  Use an
empty function table and publish signal constants from the extras callback.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Document how lua-lsm API libraries register with the core and how the
registry updates live Lua VMs.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Only task_blob_free() walked _MODULES before reusing a dirty VM, so
pool overflow, drain, and register-time swap paths leaked policy
module references and made unregister fail with -EBUSY.

Move the walk into lua_state_free() under srcu_read_lock(&modules_ss)
so every destruction path accounts uniformly.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Built-in (owner==NULL) producers are part of vmlinux text, already
covered by the boot-time signature gate.  The lockdown gate matches
the signed-API gate and lets them through.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Make the helper name describe its actual contract more clearly.

It recovers the owning lvm_state from a lua_State created by
lua-lsm. The old name, lvm_state_from_state(), was ambiguous
because both objects are kinds of state. Rename it and tighten
the comment so the call sites read more clearly.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Rename lua_modules_free() to lvm_put_loaded_modules() so the
helper name reflects its actual job: drop the loaded-module
references recorded in a Lua VM and decrement module->nloaded.

Update the associated comment and log messages to match.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Rename the heap-owned lvm_state cleanup helper so callers can tell it
frees both the Lua state and the lvm_state storage.  Keep the embedded
state cleanup path separate through lua_state_free().

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Make the signed API producer gate depend on module signature support.
Without module signatures, the runtime signature check cannot make a
trustworthy unsigned-module decision.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Mark replacement IRQ and current task VMs with the generation that will
be published when API library registration commits.  Also stamp offline
CPU IRQ VMs after hotplug replay succeeds.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Detect task-owned Lua VMs that were built before the latest API library
registration and replace them before returning the VM to hook dispatch.
This lets existing tasks observe newly registered API libraries without
mutating a VM that is currently in use.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Replace the internal registration notes with a user-facing guide for
building Lua API producer modules outside the kernel tree.  Include a
small time library example, build commands, and policy usage.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
@chenzongyao200127
chenzongyao200127 requested a review from uudiin June 17, 2026 09:40
Tighten Lua API producer admission around loadable modules. Rename the
optional table initializer field to init_table, keep the reserved open
hook opaque, and update in-tree producers accordingly.

Drop the unconditional lockdown rejection and rely on the signed-producer
policy when configured. Validate published callbacks against the pinned
owner module's core text before replaying the library into live VMs.

Reject API library names already occupied by the kernel Lua standard
libraries so registration cannot silently succeed without installing the
producer.

Signed-off-by: Zongyao Chen <ZongYao.Chen@linux.alibaba.com>
@chenzongyao200127

Copy link
Copy Markdown
Collaborator Author

@uudiin Hi, please take a look at this PR when. If the diff is too large to review comfortably, I'm happy to split it into smaller logical commits (or separate PRs) to make the review easier — just let me know.

uudiin pushed a commit that referenced this pull request Aug 21, 2026
The xfstests' test-case generic/642 finishes with
corrupted HFS+ volume:

sudo ./check generic/642
[sudo] password for slavad:
FSTYP -- hfsplus
PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #26 SMP PREEMPT_DYNAMIC Mon Mar 23 17:24:32 PDT 2026
MKFS_OPTIONS -- /dev/loop51
MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch

generic/642 6s ... _check_generic_filesystem: filesystem on /dev/loop51 is inconsistent
(see xfstests-dev/results//generic/642.full for details)

Ran: generic/642
Failures: generic/642
Failed 1 of 1 tests

sudo fsck.hfs -d /dev/loop51
** /dev/loop51
Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K.
Executing fsck_hfs (version 540.1-Linux).
** Checking non-journaled HFS Plus Volume.
The volume name is untitled
** Checking extents overflow file.
** Checking catalog file.
** Checking multi-linked files.
** Checking catalog hierarchy.
** Checking extended attributes file.
invalid free nodes - calculated 1637 header 1260
Invalid B-tree header
Invalid map node
(8, 0)
** Checking volume bitmap.
** Checking volume information.
Verify Status: VIStat = 0x0000, ABTStat = 0xc000 EBTStat = 0x0000
CBTStat = 0x0000 CatStat = 0x00000000
** Repairing volume.
** Rechecking volume.
** Checking non-journaled HFS Plus Volume.
The volume name is untitled
** Checking extents overflow file.
** Checking catalog file.
** Checking multi-linked files.
** Checking catalog hierarchy.
** Checking extended attributes file.
** Checking volume bitmap.
** Checking volume information.
** The volume untitled was repaired successfully.

The fsck tool detected that Extended Attributes b-tree is corrupted.
Namely, the free nodes number is incorrect and map node
bitmap has inconsistent state. Analysis has shown that during
b-tree closing there are still some lost b-tree's nodes in
the hash out of b-tree structure. But this orphaned b-tree nodes
are still accounted as used in map node bitmap:

tree_cnid 8, nidx 0, node_count 1408, free_nodes 1403
tree_cnid 8, nidx 1, node_count 1408, free_nodes 1403
tree_cnid 8, nidx 3, node_count 1408, free_nodes 1403
tree_cnid 8, nidx 54, node_count 1408, free_nodes 1403
tree_cnid 8, nidx 67, node_count 1408, free_nodes 1403
tree_cnid 8, nidx 0, prev 0, next 0, parent 0, num_recs 3, type 0x1, height 0
tree_cnid 8, nidx 1, prev 0, next 0, parent 3, num_recs 1, type 0xff, height 1
tree_cnid 8, nidx 3, prev 0, next 0, parent 0, num_recs 1, type 0x0, height 2
tree_cnid 8, nidx 54, prev 29, next 46, parent 3, num_recs 0, type 0xff, height 1
tree_cnid 8, nidx 67, prev 8, next 14, parent 3, num_recs 0, type 0xff, height 1

This issue happens in hfs_bnode_split() logic during detection
the possibility of moving half ot the records out of the node.
The hfs_bnode_split() contains a loop that implements
a roughly 50/50 split of the B-tree node's records by scanning
the offset table to find where the data crosses the node's midpoint.
If this logic detects the incapability of spliting the node, then
it simply calls hfs_bnode_put() for newly created node. However,
node is not set as HFS_BNODE_DELETED and real deletion of node
doesn't happen. As a result, the empty node becomes orphaned but
it is still accounted as used. Finally, fsck tool detects this
inconsistency of HFS+ volume.

This patch adds call of hfs_bnode_unlink() before hfs_bnode_put()
for the case if new node cannot be used for spliting the existing
node.

sudo ./check generic/642
FSTYP         -- hfsplus
PLATFORM      -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #26 SMP PREEMPT_DYNAMIC Fri Apr  3 12:39:13 PDT 2026
MKFS_OPTIONS  -- /dev/loop51
MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch

generic/642 40s ...  39s
Ran: generic/642
Passed all 1 tests

Closes: hfs-linux-kernel/hfs-linux-kernel#242
cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
cc: Yangtao Li <frank.li@vivo.com>
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
Link: https://lore.kernel.org/r/20260403230556.614171-6-slava@dubeyko.com
Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
uudiin pushed a commit that referenced this pull request Aug 21, 2026
ath12k_core_get_wsi_info() traverses the WSI (Wired Serial Interface)
device graph starting from dev->of_node. The current code uses
dev->of_node directly as the local traversal pointer and calls
of_node_put() on error.

Since the driver does not own a reference to dev->of_node, dropping it
during traversal results in the following OF refcount underflow:

OF: ERROR: of_node_release() detected bad of_node_put() on /soc@0/wifi@c000000
CPU: 1 UID: 0 PID: 210 Comm: insmod Not tainted 6.19.0-rc4-next-20260109-00023-g797dd36dc178 #26 PREEMPT
Hardware name: Qualcomm Technologies, Inc. IPQ5332 MI01.2 (DT)
Call trace:
 show_stack+0x18/0x24 (C)
 dump_stack_lvl+0x60/0x80
 dump_stack+0x18/0x24
 of_node_release+0x164/0x1a0
 kobject_put+0xb4/0x278
 of_node_put+0x18/0x28
 ath12k_core_init+0x29c/0x5d4 [ath12k]
 ath12k_ahb_probe+0x950/0xc14 [ath12k]
 platform_probe+0x5c/0xa4
 really_probe+0xc0/0x3ec
 __driver_probe_device+0x80/0x170
 driver_probe_device+0x3c/0x120
 __driver_attach+0xc4/0x218
OF: ERROR: next of_node_put() on this node will result in a kobject warning 'refcount_t: underflow; use-after-free.'

Fix this by explicitly acquiring a reference to the starting node
using of_node_get() and attaching automatic cleanup via
__free(device_node).

Each discovered WSI node is stored in ag->wsi_node[] with its own
of_node_get() reference. These references are later released in
ath12k_core_free_wsi_info() during driver teardown.

Also remove unnecessary memset() of wsi_node array since cleanup now
explicitly sets pointers to NULL.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1
Tested-on: IPQ5332 hw1.0 AHB WLAN.WBE.1.6-01275-QCAHKSWPL_SILICONZ-1

Fixes: 908c10c ("wifi: ath12k: parse multiple device information from Device Tree")
Signed-off-by: Aaradhana Sahu <aaradhana.sahu@oss.qualcomm.com>
Reviewed-by: Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Link: https://patch.msgid.link/20260410071300.2323603-1-aaradhana.sahu@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants