The patch titled Subject: procfs: add sicode to /proc/<PID>/stat. has been added to the -mm mm-nonmm-unstable branch. Its filename is add-sicode-to-proc-pid-stat.patch This patch will shortly appear at https://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new.git/tree/patches/add-sicode-to-proc-pid-stat.patch This patch will later appear in the mm-nonmm-unstable branch at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/process/submit-checklist.rst when testing your code *** The -mm tree is included into linux-next via the mm-everything branch at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm and is updated there every 2-3 working days ------------------------------------------------------ From: Florian Mayer <fmayer@xxxxxxxxxx> Subject: procfs: add sicode to /proc/<PID>/stat. Date: Fri, 9 Sep 2022 11:06:17 -0700 In order to enable additional debugging features, Android init needs a way to distinguish MTE-related SEGVs (with si_code of SEGV_MTEAERR) from other SEGVs. This is not possible with current APIs, neither by the existing information in /proc/<pid>/stat, nor via waitpid. Tested with the following program int main(int argc, char** argv) { int pid = fork(); if (!pid) { if (strcmp(argv[1], "sigqueue") == 0) { union sigval value; value.sival_int = 0; sigqueue(getpid(), SIGSEGV, value); } else if (strcmp(argv[1], "raise") == 0) { raise(SIGSEGV); } else if (strcmp(argv[1], "kill") == 0) { kill(getpid(), SIGSEGV); } else if (strcmp(argv[1], "raisestop") == 0) { raise(SIGSTOP); } else if (strcmp(argv[1], "crash") == 0) { volatile int* x = (int*)(0x23); *x = 1; } else if (strcmp(argv[1], "mte") == 0) { volatile char* y = malloc(1); y += 100; *y = 1; } } else { printf("%d\n", pid); sleep(5); char buf[1024]; sprintf(buf, "/proc/%d/stat", pid); int fd = open(buf, O_RDONLY); char statb[1024]; read(fd, statb, sizeof(statb)); printf("%s\n", statb); } } Link: https://lkml.kernel.org/r/20220909180617.374238-1-fmayer@xxxxxxxxxx Signed-off-by: Florian Mayer <fmayer@xxxxxxxxxx> Cc: Alexander Viro <viro@xxxxxxxxxxxxxxxxxx> Cc: Christian Brauner (Microsoft) <brauner@xxxxxxxxxx> Cc: "Eric W . Biederman" <ebiederm@xxxxxxxxxxxx> Cc: Evgenii Stepanov <eugenis@xxxxxxxxxx> Cc: Jonathan Corbet <corbet@xxxxxxx> Cc: Kees Cook <keescook@xxxxxxxxxxxx> Cc: Oleg Nesterov <oleg@xxxxxxxxxx> Cc: Peter Collingbourne <pcc@xxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- Documentation/filesystems/proc.rst | 2 + fs/coredump.c | 17 +++++++++------ fs/proc/array.c | 12 +++++++---- include/linux/sched/signal.h | 1 include/linux/sched/task.h | 2 - kernel/exit.c | 5 ++-- kernel/pid_namespace.c | 4 ++- kernel/signal.c | 29 +++++++++++++++++---------- 8 files changed, 47 insertions(+), 25 deletions(-) --- a/Documentation/filesystems/proc.rst~add-sicode-to-proc-pid-stat +++ a/Documentation/filesystems/proc.rst @@ -381,6 +381,8 @@ It's slow but very precise. env_end address below which program environment is placed exit_code the thread's exit_code in the form reported by the waitpid system call + exit_sicode if the process was stopped or terminated by a signal, the + signal's si_code. 0 otherwise ============= =============================================================== The /proc/PID/maps file contains the currently mapped memory regions and --- a/fs/coredump.c~add-sicode-to-proc-pid-stat +++ a/fs/coredump.c @@ -353,7 +353,7 @@ out: return ispipe; } -static int zap_process(struct task_struct *start, int exit_code) +static int zap_process(struct task_struct *start, int exit_code, int sicode) { struct task_struct *t; int nr = 0; @@ -361,6 +361,7 @@ static int zap_process(struct task_struc /* ignore all signals except SIGKILL, see prepare_signal() */ start->signal->flags = SIGNAL_GROUP_EXIT; start->signal->group_exit_code = exit_code; + start->signal->group_exit_sicode = sicode; start->signal->group_stop_count = 0; for_each_thread(start, t) { @@ -375,8 +376,8 @@ static int zap_process(struct task_struc return nr; } -static int zap_threads(struct task_struct *tsk, - struct core_state *core_state, int exit_code) +static int zap_threads(struct task_struct *tsk, struct core_state *core_state, + int exit_code, int sicode) { struct signal_struct *signal = tsk->signal; int nr = -EAGAIN; @@ -384,7 +385,7 @@ static int zap_threads(struct task_struc spin_lock_irq(&tsk->sighand->siglock); if (!(signal->flags & SIGNAL_GROUP_EXIT) && !signal->group_exec_task) { signal->core_state = core_state; - nr = zap_process(tsk, exit_code); + nr = zap_process(tsk, exit_code, sicode); clear_tsk_thread_flag(tsk, TIF_SIGPENDING); tsk->flags |= PF_DUMPCORE; atomic_set(&core_state->nr_threads, nr); @@ -393,7 +394,8 @@ static int zap_threads(struct task_struc return nr; } -static int coredump_wait(int exit_code, struct core_state *core_state) +static int coredump_wait(int exit_code, int sicode, + struct core_state *core_state) { struct task_struct *tsk = current; int core_waiters = -EBUSY; @@ -402,7 +404,7 @@ static int coredump_wait(int exit_code, core_state->dumper.task = tsk; core_state->dumper.next = NULL; - core_waiters = zap_threads(tsk, core_state, exit_code); + core_waiters = zap_threads(tsk, core_state, exit_code, sicode); if (core_waiters > 0) { struct core_thread *ptr; @@ -565,7 +567,8 @@ void do_coredump(const kernel_siginfo_t need_suid_safe = true; } - retval = coredump_wait(siginfo->si_signo, &core_state); + retval = + coredump_wait(siginfo->si_signo, siginfo->si_code, &core_state); if (retval < 0) goto fail_creds; --- a/fs/proc/array.c~add-sicode-to-proc-pid-stat +++ a/fs/proc/array.c @@ -474,6 +474,7 @@ static int do_task_stat(struct seq_file unsigned long rsslim = 0; unsigned long flags; int exit_code = task->exit_code; + int exit_sicode = 0; state = *get_task_state(task); vsize = eip = esp = 0; @@ -538,8 +539,10 @@ static int do_task_stat(struct seq_file thread_group_cputime_adjusted(task, &utime, &stime); gtime += sig->gtime; - if (sig->flags & (SIGNAL_GROUP_EXIT | SIGNAL_STOP_STOPPED)) + if (sig->flags & (SIGNAL_GROUP_EXIT | SIGNAL_STOP_STOPPED)) { exit_code = sig->group_exit_code; + exit_sicode = sig->group_exit_sicode; + } } sid = task_session_nr_ns(task, ns); @@ -638,10 +641,11 @@ static int do_task_stat(struct seq_file } else seq_puts(m, " 0 0 0 0 0 0 0"); - if (permitted) + if (permitted) { seq_put_decimal_ll(m, " ", exit_code); - else - seq_puts(m, " 0"); + seq_put_decimal_ll(m, " ", exit_sicode); + } else + seq_puts(m, " 0 0"); seq_putc(m, '\n'); if (mm) --- a/include/linux/sched/signal.h~add-sicode-to-proc-pid-stat +++ a/include/linux/sched/signal.h @@ -109,6 +109,7 @@ struct signal_struct { /* thread group exit support */ int group_exit_code; + int group_exit_sicode; /* notify group_exec_task when notify_count is less or equal to 0 */ int notify_count; struct task_struct *group_exec_task; --- a/include/linux/sched/task.h~add-sicode-to-proc-pid-stat +++ a/include/linux/sched/task.h @@ -82,7 +82,7 @@ static inline void exit_thread(struct ta { } #endif -extern __noreturn void do_group_exit(int); +extern __noreturn void do_group_exit(int,int); extern void exit_files(struct task_struct *); extern void exit_itimers(struct task_struct *); --- a/kernel/exit.c~add-sicode-to-proc-pid-stat +++ a/kernel/exit.c @@ -904,7 +904,7 @@ SYSCALL_DEFINE1(exit, int, error_code) * as well as by sys_exit_group (below). */ void __noreturn -do_group_exit(int exit_code) +do_group_exit(int exit_code, int sicode) { struct signal_struct *sig = current->signal; @@ -923,6 +923,7 @@ do_group_exit(int exit_code) exit_code = 0; else { sig->group_exit_code = exit_code; + sig->group_exit_sicode = sicode; sig->flags = SIGNAL_GROUP_EXIT; zap_other_threads(current); } @@ -940,7 +941,7 @@ do_group_exit(int exit_code) */ SYSCALL_DEFINE1(exit_group, int, error_code) { - do_group_exit((error_code & 0xff) << 8); + do_group_exit((error_code & 0xff) << 8, 0); /* NOTREACHED */ return 0; } --- a/kernel/pid_namespace.c~add-sicode-to-proc-pid-stat +++ a/kernel/pid_namespace.c @@ -248,8 +248,10 @@ void zap_pid_ns_processes(struct pid_nam } __set_current_state(TASK_RUNNING); - if (pid_ns->reboot) + if (pid_ns->reboot) { current->signal->group_exit_code = pid_ns->reboot; + current->signal->group_exit_sicode = 0; + } acct_exit_ns(pid_ns); return; --- a/kernel/signal.c~add-sicode-to-proc-pid-stat +++ a/kernel/signal.c @@ -963,6 +963,7 @@ static bool prepare_signal(int sig, stru signal_set_stop_flags(signal, why | SIGNAL_STOP_CONTINUED); signal->group_stop_count = 0; signal->group_exit_code = 0; + signal->group_exit_sicode = 0; } } @@ -994,7 +995,8 @@ static inline bool wants_signal(int sig, return task_curr(p) || !task_sigpending(p); } -static void complete_signal(int sig, struct task_struct *p, enum pid_type type) +static void complete_signal(int sig, int code, struct task_struct *p, + enum pid_type type) { struct signal_struct *signal = p->signal; struct task_struct *t; @@ -1051,6 +1053,7 @@ static void complete_signal(int sig, str */ signal->flags = SIGNAL_GROUP_EXIT; signal->group_exit_code = sig; + signal->group_exit_sicode = code; signal->group_stop_count = 0; t = p; do { @@ -1082,6 +1085,7 @@ static int __send_signal_locked(int sig, struct sigqueue *q; int override_rlimit; int ret = 0, result; + int code = 0; lockdep_assert_held(&t->sighand->siglock); @@ -1129,7 +1133,7 @@ static int __send_signal_locked(int sig, clear_siginfo(&q->info); q->info.si_signo = sig; q->info.si_errno = 0; - q->info.si_code = SI_USER; + code = q->info.si_code = SI_USER; q->info.si_pid = task_tgid_nr_ns(current, task_active_pid_ns(t)); rcu_read_lock(); @@ -1142,12 +1146,13 @@ static int __send_signal_locked(int sig, clear_siginfo(&q->info); q->info.si_signo = sig; q->info.si_errno = 0; - q->info.si_code = SI_KERNEL; + code = q->info.si_code = SI_KERNEL; q->info.si_pid = 0; q->info.si_uid = 0; break; default: copy_siginfo(&q->info, info); + code = info->si_code; break; } } else if (!is_si_special(info) && @@ -1186,7 +1191,7 @@ out_set: } } - complete_signal(sig, t, type); + complete_signal(sig, code, t, type); ret: trace_signal_generate(sig, info, t, type != PIDTYPE_PID, result); return ret; @@ -1960,6 +1965,7 @@ void sigqueue_free(struct sigqueue *q) int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type) { int sig = q->info.si_signo; + int code = q->info.si_code; struct sigpending *pending; struct task_struct *t; unsigned long flags; @@ -1995,7 +2001,7 @@ int send_sigqueue(struct sigqueue *q, st pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending; list_add_tail(&q->list, &pending->list); sigaddset(&pending->signal, sig); - complete_signal(sig, t, type); + complete_signal(sig, code, t, type); result = TRACE_SIGNAL_DELIVERED; out: trace_signal_generate(sig, &q->info, t, type != PIDTYPE_PID, result); @@ -2380,7 +2386,7 @@ int ptrace_notify(int exit_code, unsigne * %false if group stop is already cancelled or ptrace trap is scheduled. * %true if participated in group stop. */ -static bool do_signal_stop(int signr) +static bool do_signal_stop(int signr, int sicode) __releases(¤t->sighand->siglock) { struct signal_struct *sig = current->signal; @@ -2415,8 +2421,10 @@ static bool do_signal_stop(int signr) * an intervening stop signal is required to cause two * continued events regardless of ptrace. */ - if (!(sig->flags & SIGNAL_STOP_STOPPED)) + if (!(sig->flags & SIGNAL_STOP_STOPPED)) { sig->group_exit_code = signr; + sig->group_exit_sicode = sicode; + } sig->group_stop_count = 0; @@ -2701,7 +2709,7 @@ relock: } if (unlikely(current->jobctl & JOBCTL_STOP_PENDING) && - do_signal_stop(0)) + do_signal_stop(0, 0)) goto relock; if (unlikely(current->jobctl & @@ -2806,7 +2814,8 @@ relock: spin_lock_irq(&sighand->siglock); } - if (likely(do_signal_stop(ksig->info.si_signo))) { + if (likely(do_signal_stop(ksig->info.si_signo, + ksig->info.si_code))) { /* It released the siglock. */ goto relock; } @@ -2854,7 +2863,7 @@ relock: /* * Death signals, no core dump. */ - do_group_exit(ksig->info.si_signo); + do_group_exit(ksig->info.si_signo, ksig->info.si_code); /* NOTREACHED */ } spin_unlock_irq(&sighand->siglock); _ Patches currently in -mm which might be from fmayer@xxxxxxxxxx are add-sicode-to-proc-pid-stat.patch