From nobody Sun Dec 14 06:47:24 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1FE21C19F2A for ; Thu, 11 Aug 2022 17:43:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235645AbiHKRnv (ORCPT ); Thu, 11 Aug 2022 13:43:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55910 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235433AbiHKRns (ORCPT ); Thu, 11 Aug 2022 13:43:48 -0400 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 279EB9AFD9 for ; Thu, 11 Aug 2022 10:43:47 -0700 (PDT) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-32a115757b6so55642267b3.13 for ; Thu, 11 Aug 2022 10:43:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:mime-version:message-id:date:from:to:cc; bh=JwCtX3H6nms0PlfLhp/gNy4lWyXGbhPmKBMEgPVPK5U=; b=tPYw9ijUkd/XmrDWQddq9WhxVgKKWtUTUi8gfSzp8mvF1SxkeiqRo930vkpXTR4Pfy XKb8US/4PA17ySIZp0GJuCvvMYcAQ8YXhJ/YiupwcucfMN1A5+pLsaeXbdN10VOlQw6K V835Hx9nGPVIB/oShy2adWvzV0isHn8Zso0pYql8tUSqXkkGzENyyak+f6hFcqqwExuf k7Bqk0xcUW5tZWk4o4jNL+DDYGdIjtkMJKfC8LpUR/rsxg+WvQeD5LO/AsCmh9X4uIDN uPfLHesYOAynXSlB0mKvTB5kk3hdB+LXjYuiqFFlqDzseY8CZd6WxaphK9NOLx3lCrh3 0h1w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:mime-version:message-id:date:x-gm-message-state :from:to:cc; bh=JwCtX3H6nms0PlfLhp/gNy4lWyXGbhPmKBMEgPVPK5U=; b=uInAqe6L5sr6IgGNvr0ND78Rjvu/Y7w5uiwMZwrv4biCKrxjyd7/jsHfaKR6DOz1CP cTa/xmUOe08sIA9blq8rsmWCNpAXFWKwnBO3cIFeVW/7EzgIj3PekOhYaZ9x5UdwUGmQ 38ThEExkOujX+da6QWzvG6z9HPsDKZw1Zk5eSnniDdGPyS24c/use7GivtEbAhj4McoF Hioz4P8ZBMn1NSdzjFWeJdbt5RHbp2qHkt603dCl7QFHwoAhPZ8iXDiet7Cn4WW3wJ+e Jy48h8eNz7K059eWy++L8FuInMVTpWWif0vEWE+zciJOuylqoGo8qB0N+/0Hc1wE06IJ Y5vQ== X-Gm-Message-State: ACgBeo2zELcCZ5wwXB4sHiy0NQg0j4nS8EnQIZlhzDmAyHhHVBRZ7PnK ZAaRqOmWrCFS4gBWUdsHsLlAx+r8jrc= X-Google-Smtp-Source: AA6agR7Cswb/IDFwgM6iCMznMfLJ7BnBZwfFd+jFF6PraOi7i3vGuZUvUJ2MbvI9iOFvwqVDmYqUSLo7NIQ= X-Received: from fmayer.svl.corp.google.com ([2620:15c:2ce:200:8736:2c19:630b:7991]) (user=fmayer job=sendgmr) by 2002:a81:71c6:0:b0:318:38d5:37f3 with SMTP id m189-20020a8171c6000000b0031838d537f3mr344963ywc.268.1660239826342; Thu, 11 Aug 2022 10:43:46 -0700 (PDT) Date: Thu, 11 Aug 2022 10:43:34 -0700 Message-Id: <20220811174334.292259-1-fmayer@google.com> Mime-Version: 1.0 X-Mailer: git-send-email 2.37.1.595.g718a3a8f04-goog Subject: [PATCH] Add sicode to /proc//stat. From: Florian Mayer To: Jonathan Corbet , Alexander Viro , "Eric W. Biederman" Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-doc@vger.kernel.org, Florian Mayer , Oleg Nesterov , Christian Brauner Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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//stat, nor via waitpid. Tested with the following program int main(int argc, char** argv) { int pid =3D fork(); if (!pid) { if (strcmp(argv[1], "sigqueue") =3D=3D 0) { union sigval value; value.sival_int =3D 0; sigqueue(getpid(), SIGSEGV, value); } else if (strcmp(argv[1], "raise") =3D=3D 0) { raise(SIGSEGV); } else if (strcmp(argv[1], "kill") =3D=3D 0) { kill(getpid(), SIGSEGV); } else if (strcmp(argv[1], "raisestop") =3D=3D 0) { raise(SIGSTOP); } else if (strcmp(argv[1], "crash") =3D=3D 0) { volatile int* x =3D (int*)(0x23); *x =3D 1; } else if (strcmp(argv[1], "mte") =3D=3D 0) { volatile char* y =3D malloc(1); y +=3D 100; *y =3D 1; } } else { printf("%d\n", pid); sleep(5); char buf[1024]; sprintf(buf, "/proc/%d/stat", pid); int fd =3D open(buf, O_RDONLY); char statb[1024]; read(fd, statb, sizeof(statb)); printf("%s\n", statb); } } Signed-off-by: Florian Mayer --- 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(-) diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems= /proc.rst index e7aafc82be99..12ad5ecd7434 100644 --- a/Documentation/filesystems/proc.rst +++ b/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 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D =20 The /proc/PID/maps file contains the currently mapped memory regions and diff --git a/fs/coredump.c b/fs/coredump.c index 9f4aae202109..61e9f27d2bf8 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -349,7 +349,7 @@ static int format_corename(struct core_name *cn, struct= coredump_params *cprm, return ispipe; } =20 -static int zap_process(struct task_struct *start, int exit_code) +static int zap_process(struct task_struct *start, int exit_code, int sicod= e) { struct task_struct *t; int nr =3D 0; @@ -357,6 +357,7 @@ static int zap_process(struct task_struct *start, int e= xit_code) /* ignore all signals except SIGKILL, see prepare_signal() */ start->signal->flags =3D SIGNAL_GROUP_EXIT; start->signal->group_exit_code =3D exit_code; + start->signal->group_exit_sicode =3D sicode; start->signal->group_stop_count =3D 0; =20 for_each_thread(start, t) { @@ -371,8 +372,8 @@ static int zap_process(struct task_struct *start, int e= xit_code) return nr; } =20 -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_st= ate, + int exit_code, int sicode) { struct signal_struct *signal =3D tsk->signal; int nr =3D -EAGAIN; @@ -380,7 +381,7 @@ static int zap_threads(struct task_struct *tsk, spin_lock_irq(&tsk->sighand->siglock); if (!(signal->flags & SIGNAL_GROUP_EXIT) && !signal->group_exec_task) { signal->core_state =3D core_state; - nr =3D zap_process(tsk, exit_code); + nr =3D zap_process(tsk, exit_code, sicode); clear_tsk_thread_flag(tsk, TIF_SIGPENDING); tsk->flags |=3D PF_DUMPCORE; atomic_set(&core_state->nr_threads, nr); @@ -389,7 +390,8 @@ static int zap_threads(struct task_struct *tsk, return nr; } =20 -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 =3D current; int core_waiters =3D -EBUSY; @@ -398,7 +400,7 @@ static int coredump_wait(int exit_code, struct core_sta= te *core_state) core_state->dumper.task =3D tsk; core_state->dumper.next =3D NULL; =20 - core_waiters =3D zap_threads(tsk, core_state, exit_code); + core_waiters =3D zap_threads(tsk, core_state, exit_code, sicode); if (core_waiters > 0) { struct core_thread *ptr; =20 @@ -560,7 +562,8 @@ void do_coredump(const kernel_siginfo_t *siginfo) need_suid_safe =3D true; } =20 - retval =3D coredump_wait(siginfo->si_signo, &core_state); + retval =3D + coredump_wait(siginfo->si_signo, siginfo->si_code, &core_state); if (retval < 0) goto fail_creds; =20 diff --git a/fs/proc/array.c b/fs/proc/array.c index 99fcbfda8e25..23553460627c 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -474,6 +474,7 @@ static int do_task_stat(struct seq_file *m, struct pid_= namespace *ns, unsigned long rsslim =3D 0; unsigned long flags; int exit_code =3D task->exit_code; + int exit_sicode =3D 0; =20 state =3D *get_task_state(task); vsize =3D eip =3D esp =3D 0; @@ -538,8 +539,10 @@ static int do_task_stat(struct seq_file *m, struct pid= _namespace *ns, thread_group_cputime_adjusted(task, &utime, &stime); gtime +=3D sig->gtime; =20 - if (sig->flags & (SIGNAL_GROUP_EXIT | SIGNAL_STOP_STOPPED)) + if (sig->flags & (SIGNAL_GROUP_EXIT | SIGNAL_STOP_STOPPED)) { exit_code =3D sig->group_exit_code; + exit_sicode =3D sig->group_exit_sicode; + } } =20 sid =3D task_session_nr_ns(task, ns); @@ -638,10 +641,11 @@ static int do_task_stat(struct seq_file *m, struct pi= d_namespace *ns, } else seq_puts(m, " 0 0 0 0 0 0 0"); =20 - 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"); =20 seq_putc(m, '\n'); if (mm) diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index cafbe03eed01..1631dba7a7db 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -109,6 +109,7 @@ struct signal_struct { =20 /* 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; diff --git a/include/linux/sched/task.h b/include/linux/sched/task.h index 81cab4b01edc..6ff4825fc88a 100644 --- a/include/linux/sched/task.h +++ b/include/linux/sched/task.h @@ -82,7 +82,7 @@ static inline void exit_thread(struct task_struct *tsk) { } #endif -extern __noreturn void do_group_exit(int); +extern __noreturn void do_group_exit(int,int); =20 extern void exit_files(struct task_struct *); extern void exit_itimers(struct task_struct *); diff --git a/kernel/exit.c b/kernel/exit.c index 84021b24f79e..278469d13433 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -897,7 +897,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 =3D current->signal; =20 @@ -916,6 +916,7 @@ do_group_exit(int exit_code) exit_code =3D 0; else { sig->group_exit_code =3D exit_code; + sig->group_exit_sicode =3D sicode; sig->flags =3D SIGNAL_GROUP_EXIT; zap_other_threads(current); } @@ -933,7 +934,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; } diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index f4f8cb0435b4..c80db136726d 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -248,8 +248,10 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns) } __set_current_state(TASK_RUNNING); =20 - if (pid_ns->reboot) + if (pid_ns->reboot) { current->signal->group_exit_code =3D pid_ns->reboot; + current->signal->group_exit_sicode =3D 0; + } =20 acct_exit_ns(pid_ns); return; diff --git a/kernel/signal.c b/kernel/signal.c index 6f86fda5e432..180310a9171c 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -963,6 +963,7 @@ static bool prepare_signal(int sig, struct task_struct = *p, bool force) signal_set_stop_flags(signal, why | SIGNAL_STOP_CONTINUED); signal->group_stop_count =3D 0; signal->group_exit_code =3D 0; + signal->group_exit_sicode =3D 0; } } =20 @@ -994,7 +995,8 @@ static inline bool wants_signal(int sig, struct task_st= ruct *p) return task_curr(p) || !task_sigpending(p); } =20 -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 =3D p->signal; struct task_struct *t; @@ -1051,6 +1053,7 @@ static void complete_signal(int sig, struct task_stru= ct *p, enum pid_type type) */ signal->flags =3D SIGNAL_GROUP_EXIT; signal->group_exit_code =3D sig; + signal->group_exit_sicode =3D code; signal->group_stop_count =3D 0; t =3D p; do { @@ -1082,6 +1085,7 @@ static int __send_signal_locked(int sig, struct kerne= l_siginfo *info, struct sigqueue *q; int override_rlimit; int ret =3D 0, result; + int code =3D 0; =20 lockdep_assert_held(&t->sighand->siglock); =20 @@ -1129,7 +1133,7 @@ static int __send_signal_locked(int sig, struct kerne= l_siginfo *info, clear_siginfo(&q->info); q->info.si_signo =3D sig; q->info.si_errno =3D 0; - q->info.si_code =3D SI_USER; + code =3D q->info.si_code =3D SI_USER; q->info.si_pid =3D task_tgid_nr_ns(current, task_active_pid_ns(t)); rcu_read_lock(); @@ -1142,12 +1146,13 @@ static int __send_signal_locked(int sig, struct ker= nel_siginfo *info, clear_siginfo(&q->info); q->info.si_signo =3D sig; q->info.si_errno =3D 0; - q->info.si_code =3D SI_KERNEL; + code =3D q->info.si_code =3D SI_KERNEL; q->info.si_pid =3D 0; q->info.si_uid =3D 0; break; default: copy_siginfo(&q->info, info); + code =3D info->si_code; break; } } else if (!is_si_special(info) && @@ -1186,7 +1191,7 @@ static int __send_signal_locked(int sig, struct kerne= l_siginfo *info, } } =20 - complete_signal(sig, t, type); + complete_signal(sig, code, t, type); ret: trace_signal_generate(sig, info, t, type !=3D 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 =3D q->info.si_signo; + int code =3D q->info.si_code; struct sigpending *pending; struct task_struct *t; unsigned long flags; @@ -1995,7 +2001,7 @@ int send_sigqueue(struct sigqueue *q, struct pid *pid= , enum pid_type type) pending =3D (type !=3D PIDTYPE_PID) ? &t->signal->shared_pending : &t->pe= nding; list_add_tail(&q->list, &pending->list); sigaddset(&pending->signal, sig); - complete_signal(sig, t, type); + complete_signal(sig, code, t, type); result =3D TRACE_SIGNAL_DELIVERED; out: trace_signal_generate(sig, &q->info, t, type !=3D PIDTYPE_PID, result); @@ -2380,7 +2386,7 @@ int ptrace_notify(int exit_code, unsigned long messag= e) * %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 =3D 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 =3D signr; + sig->group_exit_sicode =3D sicode; + } =20 sig->group_stop_count =3D 0; =20 @@ -2701,7 +2709,7 @@ bool get_signal(struct ksignal *ksig) } =20 if (unlikely(current->jobctl & JOBCTL_STOP_PENDING) && - do_signal_stop(0)) + do_signal_stop(0, 0)) goto relock; =20 if (unlikely(current->jobctl & @@ -2806,7 +2814,8 @@ bool get_signal(struct ksignal *ksig) spin_lock_irq(&sighand->siglock); } =20 - 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 @@ bool get_signal(struct ksignal *ksig) /* * 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); --=20 2.37.1.559.g78731f0fdb-goog