Skip to content

Commit c3b3f52

Browse files
Christoph HellwigAl Viro
authored andcommitted
signal: refactor copy_siginfo_to_user32
Factor out a copy_siginfo_to_external32 helper from copy_siginfo_to_user32 that fills out the compat_siginfo, but does so on a kernel space data structure. With that we can let architectures override copy_siginfo_to_user32 with their own implementations using copy_siginfo_to_external32. That allows moving the x32 SIGCHLD purely to x86 architecture code. As a nice side effect copy_siginfo_to_external32 also comes in handy for avoiding a set_fs() call in the coredump code later on. Contains improvements from Eric W. Biederman <[email protected]> and Arnd Bergmann <[email protected]>. Signed-off-by: Christoph Hellwig <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent 5456ffd commit c3b3f52

File tree

5 files changed

+96
-59
lines changed

5 files changed

+96
-59
lines changed

arch/x86/ia32/ia32_signal.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
350350
unsafe_put_user(*(__u64 *)set, (__u64 *)&frame->uc.uc_sigmask, Efault);
351351
user_access_end();
352352

353-
if (__copy_siginfo_to_user32(&frame->info, &ksig->info, false))
353+
if (__copy_siginfo_to_user32(&frame->info, &ksig->info))
354354
return -EFAULT;
355355

356356
/* Set up registers for signal handler */

arch/x86/include/asm/compat.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,11 @@ static inline bool in_compat_syscall(void)
214214
#endif
215215

216216
struct compat_siginfo;
217-
int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
218-
const kernel_siginfo_t *from, bool x32_ABI);
217+
218+
#ifdef CONFIG_X86_X32_ABI
219+
int copy_siginfo_to_user32(struct compat_siginfo __user *to,
220+
const kernel_siginfo_t *from);
221+
#define copy_siginfo_to_user32 copy_siginfo_to_user32
222+
#endif /* CONFIG_X86_X32_ABI */
219223

220224
#endif /* _ASM_X86_COMPAT_H */

arch/x86/kernel/signal.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <asm/vm86.h>
3838

3939
#ifdef CONFIG_X86_64
40+
#include <linux/compat.h>
4041
#include <asm/proto.h>
4142
#include <asm/ia32_unistd.h>
4243
#endif /* CONFIG_X86_64 */
@@ -511,6 +512,31 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,
511512
}
512513
#endif /* CONFIG_X86_32 */
513514

515+
#ifdef CONFIG_X86_X32_ABI
516+
static int x32_copy_siginfo_to_user(struct compat_siginfo __user *to,
517+
const struct kernel_siginfo *from)
518+
{
519+
struct compat_siginfo new;
520+
521+
copy_siginfo_to_external32(&new, from);
522+
if (from->si_signo == SIGCHLD) {
523+
new._sifields._sigchld_x32._utime = from->si_utime;
524+
new._sifields._sigchld_x32._stime = from->si_stime;
525+
}
526+
if (copy_to_user(to, &new, sizeof(struct compat_siginfo)))
527+
return -EFAULT;
528+
return 0;
529+
}
530+
531+
int copy_siginfo_to_user32(struct compat_siginfo __user *to,
532+
const struct kernel_siginfo *from)
533+
{
534+
if (in_x32_syscall())
535+
return x32_copy_siginfo_to_user(to, from);
536+
return __copy_siginfo_to_user32(to, from);
537+
}
538+
#endif /* CONFIG_X86_X32_ABI */
539+
514540
static int x32_setup_rt_frame(struct ksignal *ksig,
515541
compat_sigset_t *set,
516542
struct pt_regs *regs)
@@ -543,7 +569,7 @@ static int x32_setup_rt_frame(struct ksignal *ksig,
543569
user_access_end();
544570

545571
if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
546-
if (__copy_siginfo_to_user32(&frame->info, &ksig->info, true))
572+
if (x32_copy_siginfo_to_user(&frame->info, &ksig->info))
547573
return -EFAULT;
548574
}
549575

include/linux/compat.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -402,8 +402,15 @@ long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
402402
unsigned long bitmap_size);
403403
long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
404404
unsigned long bitmap_size);
405-
int copy_siginfo_from_user32(kernel_siginfo_t *to, const struct compat_siginfo __user *from);
406-
int copy_siginfo_to_user32(struct compat_siginfo __user *to, const kernel_siginfo_t *from);
405+
void copy_siginfo_to_external32(struct compat_siginfo *to,
406+
const struct kernel_siginfo *from);
407+
int copy_siginfo_from_user32(kernel_siginfo_t *to,
408+
const struct compat_siginfo __user *from);
409+
int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
410+
const kernel_siginfo_t *from);
411+
#ifndef copy_siginfo_to_user32
412+
#define copy_siginfo_to_user32 __copy_siginfo_to_user32
413+
#endif
407414
int get_compat_sigevent(struct sigevent *event,
408415
const struct compat_sigevent __user *u_event);
409416

kernel/signal.c

Lines changed: 53 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3235,94 +3235,94 @@ int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from)
32353235
}
32363236

32373237
#ifdef CONFIG_COMPAT
3238-
int copy_siginfo_to_user32(struct compat_siginfo __user *to,
3239-
const struct kernel_siginfo *from)
3240-
#if defined(CONFIG_X86_X32_ABI) || defined(CONFIG_IA32_EMULATION)
3241-
{
3242-
return __copy_siginfo_to_user32(to, from, in_x32_syscall());
3243-
}
3244-
int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
3245-
const struct kernel_siginfo *from, bool x32_ABI)
3246-
#endif
3238+
/**
3239+
* copy_siginfo_to_external32 - copy a kernel siginfo into a compat user siginfo
3240+
* @to: compat siginfo destination
3241+
* @from: kernel siginfo source
3242+
*
3243+
* Note: This function does not work properly for the SIGCHLD on x32, but
3244+
* fortunately it doesn't have to. The only valid callers for this function are
3245+
* copy_siginfo_to_user32, which is overriden for x32 and the coredump code.
3246+
* The latter does not care because SIGCHLD will never cause a coredump.
3247+
*/
3248+
void copy_siginfo_to_external32(struct compat_siginfo *to,
3249+
const struct kernel_siginfo *from)
32473250
{
3248-
struct compat_siginfo new;
3249-
memset(&new, 0, sizeof(new));
3251+
memset(to, 0, sizeof(*to));
32503252

3251-
new.si_signo = from->si_signo;
3252-
new.si_errno = from->si_errno;
3253-
new.si_code = from->si_code;
3253+
to->si_signo = from->si_signo;
3254+
to->si_errno = from->si_errno;
3255+
to->si_code = from->si_code;
32543256
switch(siginfo_layout(from->si_signo, from->si_code)) {
32553257
case SIL_KILL:
3256-
new.si_pid = from->si_pid;
3257-
new.si_uid = from->si_uid;
3258+
to->si_pid = from->si_pid;
3259+
to->si_uid = from->si_uid;
32583260
break;
32593261
case SIL_TIMER:
3260-
new.si_tid = from->si_tid;
3261-
new.si_overrun = from->si_overrun;
3262-
new.si_int = from->si_int;
3262+
to->si_tid = from->si_tid;
3263+
to->si_overrun = from->si_overrun;
3264+
to->si_int = from->si_int;
32633265
break;
32643266
case SIL_POLL:
3265-
new.si_band = from->si_band;
3266-
new.si_fd = from->si_fd;
3267+
to->si_band = from->si_band;
3268+
to->si_fd = from->si_fd;
32673269
break;
32683270
case SIL_FAULT:
3269-
new.si_addr = ptr_to_compat(from->si_addr);
3271+
to->si_addr = ptr_to_compat(from->si_addr);
32703272
#ifdef __ARCH_SI_TRAPNO
3271-
new.si_trapno = from->si_trapno;
3273+
to->si_trapno = from->si_trapno;
32723274
#endif
32733275
break;
32743276
case SIL_FAULT_MCEERR:
3275-
new.si_addr = ptr_to_compat(from->si_addr);
3277+
to->si_addr = ptr_to_compat(from->si_addr);
32763278
#ifdef __ARCH_SI_TRAPNO
3277-
new.si_trapno = from->si_trapno;
3279+
to->si_trapno = from->si_trapno;
32783280
#endif
3279-
new.si_addr_lsb = from->si_addr_lsb;
3281+
to->si_addr_lsb = from->si_addr_lsb;
32803282
break;
32813283
case SIL_FAULT_BNDERR:
3282-
new.si_addr = ptr_to_compat(from->si_addr);
3284+
to->si_addr = ptr_to_compat(from->si_addr);
32833285
#ifdef __ARCH_SI_TRAPNO
3284-
new.si_trapno = from->si_trapno;
3286+
to->si_trapno = from->si_trapno;
32853287
#endif
3286-
new.si_lower = ptr_to_compat(from->si_lower);
3287-
new.si_upper = ptr_to_compat(from->si_upper);
3288+
to->si_lower = ptr_to_compat(from->si_lower);
3289+
to->si_upper = ptr_to_compat(from->si_upper);
32883290
break;
32893291
case SIL_FAULT_PKUERR:
3290-
new.si_addr = ptr_to_compat(from->si_addr);
3292+
to->si_addr = ptr_to_compat(from->si_addr);
32913293
#ifdef __ARCH_SI_TRAPNO
3292-
new.si_trapno = from->si_trapno;
3294+
to->si_trapno = from->si_trapno;
32933295
#endif
3294-
new.si_pkey = from->si_pkey;
3296+
to->si_pkey = from->si_pkey;
32953297
break;
32963298
case SIL_CHLD:
3297-
new.si_pid = from->si_pid;
3298-
new.si_uid = from->si_uid;
3299-
new.si_status = from->si_status;
3300-
#ifdef CONFIG_X86_X32_ABI
3301-
if (x32_ABI) {
3302-
new._sifields._sigchld_x32._utime = from->si_utime;
3303-
new._sifields._sigchld_x32._stime = from->si_stime;
3304-
} else
3305-
#endif
3306-
{
3307-
new.si_utime = from->si_utime;
3308-
new.si_stime = from->si_stime;
3309-
}
3299+
to->si_pid = from->si_pid;
3300+
to->si_uid = from->si_uid;
3301+
to->si_status = from->si_status;
3302+
to->si_utime = from->si_utime;
3303+
to->si_stime = from->si_stime;
33103304
break;
33113305
case SIL_RT:
3312-
new.si_pid = from->si_pid;
3313-
new.si_uid = from->si_uid;
3314-
new.si_int = from->si_int;
3306+
to->si_pid = from->si_pid;
3307+
to->si_uid = from->si_uid;
3308+
to->si_int = from->si_int;
33153309
break;
33163310
case SIL_SYS:
3317-
new.si_call_addr = ptr_to_compat(from->si_call_addr);
3318-
new.si_syscall = from->si_syscall;
3319-
new.si_arch = from->si_arch;
3311+
to->si_call_addr = ptr_to_compat(from->si_call_addr);
3312+
to->si_syscall = from->si_syscall;
3313+
to->si_arch = from->si_arch;
33203314
break;
33213315
}
3316+
}
33223317

3318+
int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
3319+
const struct kernel_siginfo *from)
3320+
{
3321+
struct compat_siginfo new;
3322+
3323+
copy_siginfo_to_external32(&new, from);
33233324
if (copy_to_user(to, &new, sizeof(struct compat_siginfo)))
33243325
return -EFAULT;
3325-
33263326
return 0;
33273327
}
33283328

0 commit comments

Comments
 (0)