When kernel is compiled with CONFIG_DEBUG_ATOMIC_SLEEP enabled, it prints
the following splat in dmesg during post boot:
[ 6.739169] init: Opening SELinux policy
[ 6.751520] init: Loading SELinux policy
[ 6.894684] SELinux: policy capability network_peer_controls=1
[ 6.894688] SELinux: policy capability open_perms=1
[ 6.894690] SELinux: policy capability extended_socket_class=1
[ 6.894691] SELinux: policy capability always_check_network=0
[ 6.894693] SELinux: policy capability cgroup_seclabel=0
[ 6.894695] SELinux: policy capability nnp_nosuid_transition=1
[ 7.214323] selinux: SELinux: Loaded file context from:
[ 7.214332] selinux: /system/etc/selinux/plat_file_contexts
[ 7.214339] selinux: /system_ext/etc/selinux/system_ext_file_contexts
[ 7.214345] selinux: /product/etc/selinux/product_file_contexts
[ 7.214350] selinux: /vendor/etc/selinux/vendor_file_contexts
[ 7.214356] selinux: /odm/etc/selinux/odm_file_contexts
[ 7.216398] KernelSU: /system/bin/init argc: 2
[ 7.216401] KernelSU: /system/bin/init first arg: second_stage
[ 7.216403] KernelSU: /system/bin/init second_stage executed
[ 7.216506] BUG: sleeping function called from invalid context at security/selinux/ss/hashtab.c:47
[ 7.216512] in_atomic(): 0, irqs_disabled(): 0, non_block: 0, pid: 1, name: init
[ 7.216516] preempt_count: 0, expected: 0
[ 7.216518] RCU nest depth: 1, expected: 0
[ 7.216524] CPU: 6 PID: 1 Comm: init Not tainted 5.4.289-Scarlet-v2.0-beta3 #1
[ 7.216526] Hardware name: redwood based Qualcomm Technologies, Inc. SM7325 (DT)
[ 7.216528] Call trace:
[ 7.216536] dump_backtrace+0x0/0x210
[ 7.216539] show_stack+0x14/0x20
[ 7.216544] dump_stack+0x9c/0xec
[ 7.216548] __might_resched+0x1f0/0x210
[ 7.216552] hashtab_insert+0x38/0x230
[ 7.216557] add_type+0xd4/0x2e0
[ 7.216559] ksu_type+0x24/0x60
[ 7.216562] apply_kernelsu_rules+0xa8/0x650
[ 7.216565] ksu_handle_execveat_ksud+0x2a8/0x460
[ 7.216568] ksu_handle_execveat+0x2c/0x60
[ 7.216571] __arm64_sys_execve+0xe8/0xf0
[ 7.216574] el0_svc_common+0xf4/0x1a0
[ 7.216577] do_el0_svc+0x2c/0x40
[ 7.216579] el0_sync_handler+0x18c/0x200
[ 7.216582] el0_sync+0x140/0x180
This is because apply_kernelsu_rules() uses rcu_read_lock() to protect
SELinux policy modifications. However, cond_resched() from
hashtab_insert() at security/selinux/ss/hashtab.c is internally called
and it sleeps which is illegal under an RCU read-side critical section.
While replacing it with a spinlock would suppress the warning, this is
fundamentally incorrect because sleeping is illegal while holding a
spinlock and spinlock would turn off preemption which isn't an ideal
solution since it intentionally turns off rescheduling, and can lead
to deadlocks.
Instead, replace the RCU lock with a mutex lock. Mutex lock allows
sleeping when necessary, which is appropriate here because
apply_kernelsu_rules() runs in process context, not in atomic or
interrupt context. As apply_kernelsu_rules() is invoked only once during
post boot (SYSTEM_RUNNING), the mutex lock does not introduce any major
runtime performance regression and provides correct synchronization.
Fixes: tiann#2637
Signed-off-by: Tashfin Shakeer Rhythm <tashfinshakeerrhythm@gmail.com>
kernel/selinux: fix pointer mismatch with 32-bit ksud on 64-bit kernels
Since KernelSU Manager can now be built for 32-bit, theres this problematic
setup where userspace is 32-bit (armeabi-v7a) and kernel is 64bit (aarch64).
On 64-bit kernels with CONFIG_COMPAT=y, 32-bit userspace passes 32-bit pointers.
These values are interpreted as 64-bit pointers without proper casting and that
results in invalid or near-null memory access.
This patch adds proper compat-mode handling with the ff changes:
- introduce a dedicated struct (`sepol_compat_data`) using u32 fields
- use `compat_ptr()` to safely convert 32-bit user pointers to kernel pointers
- adding a runtime `ksu_is_compat` flag to dynamically select between struct layouts
This prevents a near-null pointer dereference when handling SELinux
policy updates from 32-bit ksud in a 64-bit kernel.
Truth table:
kernel 32 + ksud 32, struct is u32, no compat_ptr
kernel 64 + ksud 32, struct is u32, yes compat_ptr
kernel 64 + ksud 64, struct is u64, no compat_ptr
Preprocessor check
64BIT=y COMPAT=y: define both structs, select dynamically
64BIT=y COMPAT=n: struct u64
64BIT=n: struct u32
kernel/throne_tracker: we just uninstalled the manager, stop looking for it
When the manager UID disappears from packages.list, we correctly
invalidate it — good. But, in the very next breath, we start scanning
/data/app hoping to find it again?
This event is just unnecessary I/O, exactly when we should be doing less.
Apparently this causes hangups and stuckups which is REALLY noticeable
on Ultra-Legacy devices.
Skip the scan — we’ll catch the reinstall next time packages.list updates.
This is done like how vfs_read_hook, input_hook and execve_hook is disabled.
While this is not exactly the same thing, this CAN achieve the same results.
The complete disabling of all KernelSU hooks.
While this is likely unneeded, It keeps feature parity to non-kprobe builds.
adapted from upstream:
kernel: Allow to re-enable sucompat - 4593ae81c7
Rejected: https://github.com/tiann/KernelSU/pull/2506
Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>