Skip to content

Commit d1e7fd6

Browse files
committed
signal: Extend exec_id to 64bits
Replace the 32bit exec_id with a 64bit exec_id to make it impossible to wrap the exec_id counter. With care an attacker can cause exec_id wrap and send arbitrary signals to a newly exec'd parent. This bypasses the signal sending checks if the parent changes their credentials during exec. The severity of this problem can been seen that in my limited testing of a 32bit exec_id it can take as little as 19s to exec 65536 times. Which means that it can take as little as 14 days to wrap a 32bit exec_id. Adam Zabrocki has succeeded wrapping the self_exe_id in 7 days. Even my slower timing is in the uptime of a typical server. Which means self_exec_id is simply a speed bump today, and if exec gets noticably faster self_exec_id won't even be a speed bump. Extending self_exec_id to 64bits introduces a problem on 32bit architectures where reading self_exec_id is no longer atomic and can take two read instructions. Which means that is is possible to hit a window where the read value of exec_id does not match the written value. So with very lucky timing after this change this still remains expoiltable. I have updated the update of exec_id on exec to use WRITE_ONCE and the read of exec_id in do_notify_parent to use READ_ONCE to make it clear that there is no locking between these two locations. Link: https://lore.kernel.org/kernel-hardening/[email protected] Fixes: 2.3.23pre2 Cc: [email protected] Signed-off-by: "Eric W. Biederman" <[email protected]>
1 parent 4b871ce commit d1e7fd6

File tree

3 files changed

+4
-4
lines changed

3 files changed

+4
-4
lines changed

fs/exec.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1413,7 +1413,7 @@ void setup_new_exec(struct linux_binprm * bprm)
14131413

14141414
/* An exec changes our domain. We are no longer part of the thread
14151415
group */
1416-
current->self_exec_id++;
1416+
WRITE_ONCE(current->self_exec_id, current->self_exec_id + 1);
14171417
flush_signal_handlers(current, 0);
14181418
}
14191419
EXPORT_SYMBOL(setup_new_exec);

include/linux/sched.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -939,8 +939,8 @@ struct task_struct {
939939
struct seccomp seccomp;
940940

941941
/* Thread group tracking: */
942-
u32 parent_exec_id;
943-
u32 self_exec_id;
942+
u64 parent_exec_id;
943+
u64 self_exec_id;
944944

945945
/* Protection against (de-)allocation: mm, files, fs, tty, keyrings, mems_allowed, mempolicy: */
946946
spinlock_t alloc_lock;

kernel/signal.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1926,7 +1926,7 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
19261926
* This is only possible if parent == real_parent.
19271927
* Check if it has changed security domain.
19281928
*/
1929-
if (tsk->parent_exec_id != tsk->parent->self_exec_id)
1929+
if (tsk->parent_exec_id != READ_ONCE(tsk->parent->self_exec_id))
19301930
sig = SIGCHLD;
19311931
}
19321932

0 commit comments

Comments
 (0)