get_policydb() uses rcu_dereference() to read pointers to selinux_state.policy.
But in the SELinux implementation, these pointers are assigned once during
initialization and never changed with rcu_assign_pointer(), rendering the
rcu_dereference() call in get_policydb() completely useless. This just adds
unwanted overhead and implies concurrency pattern that is not even present in
the kernel.
Therefore, read the pointers directly since it's safe.
* selinux_state.ss needs more context.
Signed-off-by: Tashfin Shakeer Rhythm <tashfinshakeerrhythm@gmail.com>
Currently, handle_sepolicy() holds an RCU read lock across the entire
function including calls to strncpy_from_user() which can sleep, which
is illegal in RCU semantics.
This triggers the following warning when the kernel is compiled with
CONFIG_DEBUG_ATOMIC_SLEEP enabled:
[ 8.526345] BUG: sleeping function called from invalid context at lib/strncpy_from_user.c:40
[ 8.526349] in_atomic(): 0, irqs_disabled(): 0, non_block: 0, pid: 683, name: ksud
[ 8.526351] preempt_count: 0, expected: 0
[ 8.526352] RCU nest depth: 1, expected: 0
[ 8.526354] 1 lock held by ksud/683:
[ 8.526355] #0: ffffffe013e1b970 (rcu_read_lock){....}, at: handle_sepolicy+0xe4/0xaa0
[ 8.526365] CPU: 6 PID: 683 Comm: ksud Tainted: G W 5.4.289-Scarlet-v2.2-beta2 #1
[ 8.526366] Hardware name: redwood based Qualcomm Technologies, Inc. SM7325 (DT)
[ 8.526367] Call trace:
[ 8.526371] dump_backtrace+0x0/0x1c0
[ 8.526374] dump_stack+0x90/0xcc
[ 8.526376] __might_sleep+0x1a0/0x200
[ 8.526378] __might_fault+0x28/0x40
[ 8.526381] strncpy_from_user+0xac/0x300
[ 8.526383] handle_sepolicy+0x588/0xaa0
[ 8.526385] ksu_handle_prctl+0x368/0xd60
[ 8.526386] ksu_task_prctl+0xc/0x20
[ 8.526389] security_task_prctl+0x5c/0xa0
[ 8.526391] __arm64_sys_prctl+0x58/0x7e0
[ 8.526393] do_el0_svc+0x68/0x120
[ 8.526394] el0_sync_handler+0x11c/0x1c0
[ 8.526395] el0_sync+0x140/0x180
To fix this, replace the rcu_read_lock() with the `ksu_rules` mutex_lock()
introduced with commit 9014c663d1eb4 ("kernel: selinux: rules: Fix illegal RCU
lock usage in apply_kernelsu_rules()") which allows sleeping.
This mutex_lock() ensures mutual exclusion between threads invoking dynamic
policy modifications via handle_sepolicy() and those applying KernelSU rules
via apply_kernelsu_rules(), both of which access the policydb structure through
get_policydb().
Signed-off-by: Tashfin Shakeer Rhythm <tashfinshakeerrhythm@gmail.com>
* We got a splat related to atomic sleep.
* The trace is from strncpy_from_user and might_fault
Same case:
e47115e009
Signed-off-by: rsuntk <rsuntk@yukiprjkt.my.id>
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>
Use huawei_hisi_check.h to determine whether it is an old Huawei
HiSilicon device.
Solve:
1. Compatible with non-GKI Huawei HiSilicon devices
2. Solve different bugs in EMUI of different system versions
3. Does not affect other devices
EMUI 10 kernel version is 4.14.xxx.
The SELinux of Huawei's modified EMUI10 kernel is still similar to the
EMUI 9 version. This commit not support HarmonyOS 2 based EMUI 10.
Hi @tiann.
Thanks for the great project, I had great fun playing around with it.
This PR mainly tries to further minimize the possible delays caused by
KernelSU hooking.
There are 3 major changes:
- Processes with 0 < UID < 2000 are blocked straight-up before going
through the allow_list.
I don't see any need for such processes to be interested in root, and
this allows returning early before going through a more expensive
lookup.
If there's an expected breakage due to this change, I'll remove it. Let
me know.
- A page-sized (4K) bitmap is added.
This allows O(1) lookup for UID <= 32767.
This speeds up `ksu_is_allow_uid()` by about 4.8x by sacrificing a 4K
memory. IMHO, a good trade-off.
Most notably, this reduces the 99.999% result previously from worrying
milliseconds scale to microseconds scale.
For UID > 32767, another page-sized (4K) sequential array is used to
cache allow_list.
Compared to the previous PR #557, this new approach gives another nice
25% performance boost in average, 63-96% boost in worst cases.
Benchmark results are available at
https://docs.google.com/spreadsheets/d/1w_tO1zRLPNMFRer49pL1TQfL6ndEhilRrDU1XFIcWXY/edit?usp=sharing
Thanks!
---------
Signed-off-by: Juhyung Park <qkrwngud825@gmail.com>
- Seen with Linux 4.14 kernel with error message:
In file included from ../drivers/android/kernelsu/selinux/sepolicy.c:1:
In file included from ../drivers/android/kernelsu/selinux/sepolicy.h:6:
In file included from ../security/selinux/ss/policydb.h:30: In file
included from ../security/selinux/ss/avtab.h:26:
../security/selinux/include/security.h:240:10: error: use of undeclared
identifier 'EIDRM'
return -EIDRM;
^
CC drivers/base/transport_class.o
CC kernel/rcu/update.o
../security/selinux/include/security.h:246:10: error: use of undeclared
identifier 'ENOENT'
return -ENOENT;
^
This checks `selinux_state` and `current_sid` supports in a raw way.
Feels more reliable than the version checks.
Supersedes #401, fixes#280, fixes#400.
4.9's last release aka 4.9.337 still needs the same fallbacks as 4.9.212
and breaks otherwise, upgrade this to fix compilation
Tested and working on POCO F1, 4.9.337
_selinux_state_ is backported to 4.9 kernel with the 4.9.212 release,
use it to fix the build.
many thanks to @reallysnow for figuring this out.
inspired by
d7c2c5f02a