Skip to content

Commit df387a1

Browse files
tiannbackslashxx
authored andcommitted
kernel: kp_ksud: add security_bounded_transition hook for < 4.14 (tiann#1704)
- torvalds/linux@af63f41 - SELinux domain transitions under NNP/nosuid environment was introduced in 4.14 by the above commit, for older kernels, we need to make sure our domain transitions are allowed when calling ksud at boot from the init - Adapted from tiann#270 (comment) tiann@0950fbb - tiann#1704 tiann@d664fe3 Difference to tiann's version: - use a kretprobe to force a 0 return - grab sids outside of kprobe context to avoid stuckups / hangups Logs: daisy:/ # dmesg | grep -E "transition|grab_sids" [ 5.977810] KernelSU: ksud_grab_sids: got init sid: 62 [ 5.977907] KernelSU: ksud_grab_sids: got su sid: 537 [ 5.980497] KernelSU: kp_ksud: register kretprobe: security_bounded_transition ret: 0 [ 32.008560] KernelSU: kp_ksud: security_bounded_transition: allowing init (62) -> su (537) [ 32.008663] type=1401 audit(2247197.199:61): op=security_bounded_transition seresult=denied oldcontext=u:r:init:s0 newcontext=u:r:su:s0 [ 36.946527] KernelSU: kp_ksud: security_bounded_transition: allowing init (62) -> su (537) [ 61.202278] KernelSU: kp_ksud: security_bounded_transition: allowing init (62) -> su (537) [ 61.202395] type=1401 audit(1761288080.219:1045): op=security_bounded_transition seresult=denied oldcontext=u:r:init:s0 newcontext=u:r:su:s0 daisy:/ # uname -a Linux localhost 4.9.337+64-daikura/db23b17 tiann#634 SMP PREEMPT Fri Oct 24 14:37:19 PST 2025 aarch64 Toybox Signed-off-by: backslashxx <[email protected]>
1 parent a46ffe4 commit df387a1

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

kernel/kp_ksud.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,92 @@ static struct kprobe key_permission_kp = {
198198
};
199199
#endif // key_permission
200200

201+
// security_bounded_transition
202+
#if defined(CONFIG_KRETPROBES) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
203+
#include "avc_ss.h"
204+
#include "selinux/selinux.h"
205+
206+
static u32 init_sid = 0;
207+
static u32 su_sid = 0;
208+
209+
// get sids outside of kprobe context
210+
static int grab_sids()
211+
{
212+
int error = security_secctx_to_secid("u:r:init:s0", strlen("u:r:init:s0"), &init_sid);
213+
if (error)
214+
return 1;
215+
216+
pr_info("kp_ksud/grab_sids: got init sid: %d\n", init_sid);
217+
218+
error = security_secctx_to_secid("u:r:su:s0", strlen("u:r:su:s0"), &su_sid);
219+
if (error)
220+
return 1;
221+
222+
pr_info("kp_ksud/grab_sids: got su sid: %d\n", su_sid);
223+
224+
return 0;
225+
}
226+
227+
// int security_bounded_transition(u32 old_sid, u32 new_sid)
228+
static int bounded_transition_entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
229+
{
230+
// grab sids on entry
231+
u32 *sid = (u32 *)ri->data;
232+
sid[0] = PT_REGS_PARM1(regs); // old_sid
233+
sid[1] = PT_REGS_PARM2(regs); // new_sid
234+
return 0;
235+
}
236+
237+
static int bounded_transition_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
238+
{
239+
u32 *sid = (u32 *)ri->data;
240+
u32 old_sid = sid[0];
241+
u32 new_sid = sid[1];
242+
243+
if (!ss_initialized)
244+
return 0;
245+
246+
// so if old sid is 'init' and trying to transition to a new sid of 'su'
247+
// force the function to return 0
248+
if (old_sid == init_sid && new_sid == su_sid) {
249+
pr_info("kp_ksud: security_bounded_transition: allowing init (%d) -> su (%d)\n", init_sid, su_sid);
250+
PT_REGS_RC(regs) = 0; // make the original func return 0
251+
}
252+
253+
return 0;
254+
}
255+
256+
static struct kretprobe bounded_transition_rp = {
257+
.kp.symbol_name = "security_bounded_transition",
258+
.handler = bounded_transition_ret_handler,
259+
.entry_handler = bounded_transition_entry_handler,
260+
.data_size = sizeof(u32) * 2, // need to keep 2x u32's, one per sid
261+
.maxactive = 20,
262+
};
263+
264+
// unused for now
265+
void kp_ksud_transition_routine_end()
266+
{
267+
unregister_kretprobe(&bounded_transition_rp);
268+
pr_info("kp_ksud: unregister kretprobe: security_bounded_transition ret: ??\n");
269+
}
270+
271+
void kp_ksud_transition_routine_start()
272+
{
273+
// we only need to run this once.
274+
// once we got sids, we are ready
275+
if (su_sid != 0)
276+
return;
277+
278+
int ret = grab_sids();
279+
if (ret)
280+
return;
281+
282+
ret = register_kretprobe(&bounded_transition_rp);
283+
pr_info("kp_ksud: register kretprobe: security_bounded_transition ret: %d\n", ret);
284+
}
285+
#endif // security_bounded_transition
286+
201287
static void unregister_kprobe_logged(struct kprobe *kp)
202288
{
203289
const char *symbol_name = kp->symbol_name;

kernel/ksud.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ void on_boot_completed(void){
121121
pr_info("on_boot_completed!\n");
122122
}
123123

124+
#if defined(CONFIG_KRETPROBES) && defined(CONFIG_KSU_KPROBES_KSUD) && \
125+
LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
126+
extern void kp_ksud_transition_routine_start();
127+
#endif
128+
124129
// since _ksud handler only uses argv and envp for comparisons
125130
// this can probably work
126131
// adapted from ksu_handle_execveat_ksud
@@ -208,6 +213,12 @@ int ksu_handle_bprm_ksud(const char *filename, const char *argv1, const char *en
208213
}
209214

210215
first_app_process:
216+
#if defined(CONFIG_KRETPROBES) && defined(CONFIG_KSU_KPROBES_KSUD) && \
217+
LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
218+
if (init_second_stage_executed == true)
219+
kp_ksud_transition_routine_start();
220+
#endif
221+
211222
if (first_app_process && !memcmp(filename, app_process, sizeof(app_process) - 1)) {
212223
first_app_process = false;
213224
pr_info("%s: exec app_process, /data prepared, second_stage: %d\n", __func__, init_second_stage_executed);

0 commit comments

Comments
 (0)