Hi,

there is a small bug that causes issues with this patch, see below.

On Thu, 2024-10-10 at 23:12 +0200, Johannes Berg wrote:
> [SNIP]
> diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
> index cdaee3e94273..378e6e1815b9 100644
> --- a/arch/um/kernel/trap.c
> +++ b/arch/um/kernel/trap.c
> @@ -16,6 +16,7 @@
>  #include <kern_util.h>
>  #include <os.h>
>  #include <skas.h>
> +#include <arch.h>
>  
>  /*
>   * Note this is constrained to return 0, -EFAULT, -EACCES, -ENOMEM by
> @@ -180,7 +181,8 @@ void fatal_sigsegv(void)
>   * If the userfault did not happen in an UML userspace process, bad_segv is 
> called.
>   * Otherwise the signal did happen in a cloned userspace process, handle it.
>   */
> -void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs 
> *regs)
> +void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs 
> *regs,
> +               void *mc)
>  {
>       struct faultinfo * fi = UPT_FAULTINFO(regs);
>  
> @@ -189,7 +191,7 @@ void segv_handler(int sig, struct siginfo *unused_si, 
> struct uml_pt_regs *regs)
>               bad_segv(*fi, UPT_IP(regs));
>               return;
>       }
> -     segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs);
> +     segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs, mc);
>  }
>  
>  /*
> @@ -199,7 +201,7 @@ void segv_handler(int sig, struct siginfo *unused_si, 
> struct uml_pt_regs *regs)
>   * give us bad data!
>   */
>  unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
> -                struct uml_pt_regs *regs)
> +                struct uml_pt_regs *regs, void *mc)
>  {
>       int si_code;
>       int err;
> @@ -223,6 +225,19 @@ unsigned long segv(struct faultinfo fi, unsigned long 
> ip, int is_user,
>               goto out;
>       }
>       else if (current->mm == NULL) {
> +             if (current->pagefault_disabled) {
> +                     if (!mc) {
> +                             show_regs(container_of(regs, struct pt_regs, 
> regs));
> +                             panic("Segfault with pagefaults disabled but no 
> mcontext");
> +                     }
> +                     if (!current->thread.segv_continue) {
> +                             show_regs(container_of(regs, struct pt_regs, 
> regs));
> +                             panic("Segfault without recovery target");
> +                     }
> +                     mc_set_rip(mc, current->thread.segv_continue);
> +                     current->thread.segv_continue = NULL;
> +                     return 0;

This needs to be "goto out". Otherwise segv_regs is still set, which
will result in a crash later on if the stacktrace code reads an
incorrect stack pointer from there.

Benjamin

> +             }
>               show_regs(container_of(regs, struct pt_regs, regs));
>               panic("Segfault with no mm");
>       }
> @@ -274,7 +289,8 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, 
> int is_user,
>       return 0;
>  }
>  
> -void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs)
> +void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs,
> +               void *mc)
>  {
>       int code, err;
>       if (!UPT_IS_USER(regs)) {
> @@ -302,7 +318,8 @@ void relay_signal(int sig, struct siginfo *si, struct 
> uml_pt_regs *regs)
>       }
>  }
>  
> -void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
> +void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs,
> +        void *mc)
>  {
>       do_IRQ(WINCH_IRQ, regs);
>  }
> diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
> index 1978eaa557e9..2aa02657ee78 100644
> --- a/arch/um/os-Linux/signal.c
> +++ b/arch/um/os-Linux/signal.c
> @@ -21,7 +21,7 @@
>  #include <sys/ucontext.h>
>  #include <timetravel.h>
>  
> -void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = {
> +void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *, void 
> *mc) = {
>       [SIGTRAP]       = relay_signal,
>       [SIGFPE]        = relay_signal,
>       [SIGILL]        = relay_signal,
> @@ -47,7 +47,7 @@ static void sig_handler_common(int sig, struct siginfo *si, 
> mcontext_t *mc)
>       if ((sig != SIGIO) && (sig != SIGWINCH))
>               unblock_signals_trace();
>  
> -     (*sig_info[sig])(sig, si, &r);
> +     (*sig_info[sig])(sig, si, &r, mc);
>  
>       errno = save_errno;
>  }
> diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
> index 2286486bb0f3..1447be7a4bf2 100644
> --- a/arch/um/os-Linux/skas/process.c
> +++ b/arch/um/os-Linux/skas/process.c
> @@ -166,7 +166,7 @@ static void get_skas_faultinfo(int pid, struct faultinfo 
> *fi)
>  static void handle_segv(int pid, struct uml_pt_regs *regs)
>  {
>       get_skas_faultinfo(pid, &regs->faultinfo);
> -     segv(regs->faultinfo, 0, 1, NULL);
> +     segv(regs->faultinfo, 0, 1, NULL, NULL);
>  }
>  
>  static void handle_trap(int pid, struct uml_pt_regs *regs)
> @@ -489,7 +489,7 @@ void userspace(struct uml_pt_regs *regs)
>                                       get_skas_faultinfo(pid,
>                                                          &regs->faultinfo);
>                                       (*sig_info[SIGSEGV])(SIGSEGV, (struct 
> siginfo *)&si,
> -                                                          regs);
> +                                                          regs, NULL);
>                               }
>                               else handle_segv(pid, regs);
>                               break;
> @@ -497,7 +497,7 @@ void userspace(struct uml_pt_regs *regs)
>                               handle_trap(pid, regs);
>                               break;
>                       case SIGTRAP:
> -                             relay_signal(SIGTRAP, (struct siginfo *)&si, 
> regs);
> +                             relay_signal(SIGTRAP, (struct siginfo *)&si, 
> regs, NULL);
>                               break;
>                       case SIGALRM:
>                               break;
> @@ -507,7 +507,7 @@ void userspace(struct uml_pt_regs *regs)
>                       case SIGFPE:
>                       case SIGWINCH:
>                               block_signals_trace();
> -                             (*sig_info[sig])(sig, (struct siginfo *)&si, 
> regs);
> +                             (*sig_info[sig])(sig, (struct siginfo *)&si, 
> regs, NULL);
>                               unblock_signals_trace();
>                               break;
>                       default:
> diff --git a/arch/x86/um/os-Linux/mcontext.c b/arch/x86/um/os-Linux/mcontext.c
> index e80ab7d28117..d2f3a595b4ef 100644
> --- a/arch/x86/um/os-Linux/mcontext.c
> +++ b/arch/x86/um/os-Linux/mcontext.c
> @@ -4,6 +4,7 @@
>  #include <asm/ptrace.h>
>  #include <sysdep/ptrace.h>
>  #include <sysdep/mcontext.h>
> +#include <arch.h>
>  
>  void get_regs_from_mc(struct uml_pt_regs *regs, mcontext_t *mc)
>  {
> @@ -31,3 +32,14 @@ void get_regs_from_mc(struct uml_pt_regs *regs, mcontext_t 
> *mc)
>       regs->gp[CS / sizeof(unsigned long)] |= 3;
>  #endif
>  }
> +
> +void mc_set_rip(void *_mc, void *target)
> +{
> +     mcontext_t *mc = _mc;
> +
> +#ifdef __i386__
> +     mc->gregs[REG_EIP] = (unsigned long)target;
> +#else
> +     mc->gregs[REG_RIP] = (unsigned long)target;
> +#endif
> +}
> diff --git a/arch/x86/um/shared/sysdep/faultinfo_32.h 
> b/arch/x86/um/shared/sysdep/faultinfo_32.h
> index b6f2437ec29c..ab5c8e47049c 100644
> --- a/arch/x86/um/shared/sysdep/faultinfo_32.h
> +++ b/arch/x86/um/shared/sysdep/faultinfo_32.h
> @@ -29,4 +29,16 @@ struct faultinfo {
>  
>  #define PTRACE_FULL_FAULTINFO 0
>  
> +#define ___backtrack_faulted(_faulted)                                       
> \
> +     asm volatile (                                                  \
> +             "mov $0, %0\n"                                          \
> +             "movl $__get_kernel_nofault_faulted_%=,%1\n"            \
> +             "jmp _end_%=\n"                                         \
> +             "__get_kernel_nofault_faulted_%=:\n"                    \
> +             "mov $1, %0;"                                           \
> +             "_end_%=:"                                              \
> +             : "=r" (_faulted),                                      \
> +               "=m" (current->thread.segv_continue) ::               \
> +     )
> +
>  #endif
> diff --git a/arch/x86/um/shared/sysdep/faultinfo_64.h 
> b/arch/x86/um/shared/sysdep/faultinfo_64.h
> index ee88f88974ea..26fb4835d3e9 100644
> --- a/arch/x86/um/shared/sysdep/faultinfo_64.h
> +++ b/arch/x86/um/shared/sysdep/faultinfo_64.h
> @@ -29,4 +29,16 @@ struct faultinfo {
>  
>  #define PTRACE_FULL_FAULTINFO 1
>  
> +#define ___backtrack_faulted(_faulted)                                       
> \
> +     asm volatile (                                                  \
> +             "mov $0, %0\n"                                          \
> +             "movq $__get_kernel_nofault_faulted_%=,%1\n"            \
> +             "jmp _end_%=\n"                                         \
> +             "__get_kernel_nofault_faulted_%=:\n"                    \
> +             "mov $1, %0;"                                           \
> +             "_end_%=:"                                              \
> +             : "=r" (_faulted),                                      \
> +               "=m" (current->thread.segv_continue) ::               \
> +     )
> +
>  #endif

Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

Reply via email to