diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2018-10-05 03:02:48 -0400 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2018-10-08 03:35:26 -0400 |
commit | 601d5abfeaf244b86bb68c1e05c6e0d57be2f6b0 (patch) | |
tree | ebadc93b46b98afd8bba2e0bf759657d06ce5e93 | |
parent | 4ce5f9c9e7546915c559ffae594e6d73f918db00 (diff) |
signal: In sigqueueinfo prefer sig not si_signo
Andrei Vagin <avagin@gmail.com> reported:
> Accoding to the man page, the user should not set si_signo, it has to be set
> by kernel.
>
> $ man 2 rt_sigqueueinfo
>
> The uinfo argument specifies the data to accompany the signal. This
> argument is a pointer to a structure of type siginfo_t, described in
> sigaction(2) (and defined by including <sigaction.h>). The caller
> should set the following fields in this structure:
>
> si_code
> This must be one of the SI_* codes in the Linux kernel source
> file include/asm-generic/siginfo.h, with the restriction that
> the code must be negative (i.e., cannot be SI_USER, which is
> used by the kernel to indicate a signal sent by kill(2)) and
> cannot (since Linux 2.6.39) be SI_TKILL (which is used by the
> kernel to indicate a signal sent using tgkill(2)).
>
> si_pid This should be set to a process ID, typically the process ID of
> the sender.
>
> si_uid This should be set to a user ID, typically the real user ID of
> the sender.
>
> si_value
> This field contains the user data to accompany the signal. For
> more information, see the description of the last (union sigval)
> argument of sigqueue(3).
>
> Internally, the kernel sets the si_signo field to the value specified
> in sig, so that the receiver of the signal can also obtain the signal
> number via that field.
>
> On Tue, Sep 25, 2018 at 07:19:02PM +0200, Eric W. Biederman wrote:
>>
>> If there is some application that calls sigqueueinfo directly that has
>> a problem with this added sanity check we can revisit this when we see
>> what kind of crazy that application is doing.
>
>
> I already know two "applications" ;)
>
> https://github.com/torvalds/linux/blob/master/tools/testing/selftests/ptrace/peeksiginfo.c
> https://github.com/checkpoint-restore/criu/blob/master/test/zdtm/static/sigpending.c
>
> Disclaimer: I'm the author of both of them.
Looking at the kernel code the historical behavior has alwasy been to prefer
the signal number passed in by the kernel.
So sigh. Implmenet __copy_siginfo_from_user and __copy_siginfo_from_user32 to
take that signal number and prefer it. The user of ptrace will still
use copy_siginfo_from_user and copy_siginfo_from_user32 as they do not and
never have had a signal number there.
Luckily this change has never made it farther than linux-next.
Fixes: e75dc036c445 ("signal: Fail sigqueueinfo if si_signo != sig")
Reported-by: Andrei Vagin <avagin@gmail.com>
Tested-by: Andrei Vagin <avagin@gmail.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
-rw-r--r-- | kernel/signal.c | 141 |
1 files changed, 84 insertions, 57 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 1c2dd117fee0..2bffc5a50183 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -2925,11 +2925,10 @@ int copy_siginfo_to_user(siginfo_t __user *to, const kernel_siginfo_t *from) | |||
2925 | return 0; | 2925 | return 0; |
2926 | } | 2926 | } |
2927 | 2927 | ||
2928 | int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from) | 2928 | static int post_copy_siginfo_from_user(kernel_siginfo_t *info, |
2929 | const siginfo_t __user *from) | ||
2929 | { | 2930 | { |
2930 | if (copy_from_user(to, from, sizeof(struct kernel_siginfo))) | 2931 | if (unlikely(!known_siginfo_layout(info->si_signo, info->si_code))) { |
2931 | return -EFAULT; | ||
2932 | if (unlikely(!known_siginfo_layout(to->si_signo, to->si_code))) { | ||
2933 | char __user *expansion = si_expansion(from); | 2932 | char __user *expansion = si_expansion(from); |
2934 | char buf[SI_EXPANSION_SIZE]; | 2933 | char buf[SI_EXPANSION_SIZE]; |
2935 | int i; | 2934 | int i; |
@@ -2949,6 +2948,22 @@ int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from) | |||
2949 | return 0; | 2948 | return 0; |
2950 | } | 2949 | } |
2951 | 2950 | ||
2951 | static int __copy_siginfo_from_user(int signo, kernel_siginfo_t *to, | ||
2952 | const siginfo_t __user *from) | ||
2953 | { | ||
2954 | if (copy_from_user(to, from, sizeof(struct kernel_siginfo))) | ||
2955 | return -EFAULT; | ||
2956 | to->si_signo = signo; | ||
2957 | return post_copy_siginfo_from_user(to, from); | ||
2958 | } | ||
2959 | |||
2960 | int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from) | ||
2961 | { | ||
2962 | if (copy_from_user(to, from, sizeof(struct kernel_siginfo))) | ||
2963 | return -EFAULT; | ||
2964 | return post_copy_siginfo_from_user(to, from); | ||
2965 | } | ||
2966 | |||
2952 | #ifdef CONFIG_COMPAT | 2967 | #ifdef CONFIG_COMPAT |
2953 | int copy_siginfo_to_user32(struct compat_siginfo __user *to, | 2968 | int copy_siginfo_to_user32(struct compat_siginfo __user *to, |
2954 | const struct kernel_siginfo *from) | 2969 | const struct kernel_siginfo *from) |
@@ -3041,88 +3056,106 @@ int __copy_siginfo_to_user32(struct compat_siginfo __user *to, | |||
3041 | return 0; | 3056 | return 0; |
3042 | } | 3057 | } |
3043 | 3058 | ||
3044 | int copy_siginfo_from_user32(struct kernel_siginfo *to, | 3059 | static int post_copy_siginfo_from_user32(kernel_siginfo_t *to, |
3045 | const struct compat_siginfo __user *ufrom) | 3060 | const struct compat_siginfo *from) |
3046 | { | 3061 | { |
3047 | struct compat_siginfo from; | ||
3048 | |||
3049 | if (copy_from_user(&from, ufrom, sizeof(struct compat_siginfo))) | ||
3050 | return -EFAULT; | ||
3051 | |||
3052 | clear_siginfo(to); | 3062 | clear_siginfo(to); |
3053 | to->si_signo = from.si_signo; | 3063 | to->si_signo = from->si_signo; |
3054 | to->si_errno = from.si_errno; | 3064 | to->si_errno = from->si_errno; |
3055 | to->si_code = from.si_code; | 3065 | to->si_code = from->si_code; |
3056 | switch(siginfo_layout(from.si_signo, from.si_code)) { | 3066 | switch(siginfo_layout(from->si_signo, from->si_code)) { |
3057 | case SIL_KILL: | 3067 | case SIL_KILL: |
3058 | to->si_pid = from.si_pid; | 3068 | to->si_pid = from->si_pid; |
3059 | to->si_uid = from.si_uid; | 3069 | to->si_uid = from->si_uid; |
3060 | break; | 3070 | break; |
3061 | case SIL_TIMER: | 3071 | case SIL_TIMER: |
3062 | to->si_tid = from.si_tid; | 3072 | to->si_tid = from->si_tid; |
3063 | to->si_overrun = from.si_overrun; | 3073 | to->si_overrun = from->si_overrun; |
3064 | to->si_int = from.si_int; | 3074 | to->si_int = from->si_int; |
3065 | break; | 3075 | break; |
3066 | case SIL_POLL: | 3076 | case SIL_POLL: |
3067 | to->si_band = from.si_band; | 3077 | to->si_band = from->si_band; |
3068 | to->si_fd = from.si_fd; | 3078 | to->si_fd = from->si_fd; |
3069 | break; | 3079 | break; |
3070 | case SIL_FAULT: | 3080 | case SIL_FAULT: |
3071 | to->si_addr = compat_ptr(from.si_addr); | 3081 | to->si_addr = compat_ptr(from->si_addr); |
3072 | #ifdef __ARCH_SI_TRAPNO | 3082 | #ifdef __ARCH_SI_TRAPNO |
3073 | to->si_trapno = from.si_trapno; | 3083 | to->si_trapno = from->si_trapno; |
3074 | #endif | 3084 | #endif |
3075 | break; | 3085 | break; |
3076 | case SIL_FAULT_MCEERR: | 3086 | case SIL_FAULT_MCEERR: |
3077 | to->si_addr = compat_ptr(from.si_addr); | 3087 | to->si_addr = compat_ptr(from->si_addr); |
3078 | #ifdef __ARCH_SI_TRAPNO | 3088 | #ifdef __ARCH_SI_TRAPNO |
3079 | to->si_trapno = from.si_trapno; | 3089 | to->si_trapno = from->si_trapno; |
3080 | #endif | 3090 | #endif |
3081 | to->si_addr_lsb = from.si_addr_lsb; | 3091 | to->si_addr_lsb = from->si_addr_lsb; |
3082 | break; | 3092 | break; |
3083 | case SIL_FAULT_BNDERR: | 3093 | case SIL_FAULT_BNDERR: |
3084 | to->si_addr = compat_ptr(from.si_addr); | 3094 | to->si_addr = compat_ptr(from->si_addr); |
3085 | #ifdef __ARCH_SI_TRAPNO | 3095 | #ifdef __ARCH_SI_TRAPNO |
3086 | to->si_trapno = from.si_trapno; | 3096 | to->si_trapno = from->si_trapno; |
3087 | #endif | 3097 | #endif |
3088 | to->si_lower = compat_ptr(from.si_lower); | 3098 | to->si_lower = compat_ptr(from->si_lower); |
3089 | to->si_upper = compat_ptr(from.si_upper); | 3099 | to->si_upper = compat_ptr(from->si_upper); |
3090 | break; | 3100 | break; |
3091 | case SIL_FAULT_PKUERR: | 3101 | case SIL_FAULT_PKUERR: |
3092 | to->si_addr = compat_ptr(from.si_addr); | 3102 | to->si_addr = compat_ptr(from->si_addr); |
3093 | #ifdef __ARCH_SI_TRAPNO | 3103 | #ifdef __ARCH_SI_TRAPNO |
3094 | to->si_trapno = from.si_trapno; | 3104 | to->si_trapno = from->si_trapno; |
3095 | #endif | 3105 | #endif |
3096 | to->si_pkey = from.si_pkey; | 3106 | to->si_pkey = from->si_pkey; |
3097 | break; | 3107 | break; |
3098 | case SIL_CHLD: | 3108 | case SIL_CHLD: |
3099 | to->si_pid = from.si_pid; | 3109 | to->si_pid = from->si_pid; |
3100 | to->si_uid = from.si_uid; | 3110 | to->si_uid = from->si_uid; |
3101 | to->si_status = from.si_status; | 3111 | to->si_status = from->si_status; |
3102 | #ifdef CONFIG_X86_X32_ABI | 3112 | #ifdef CONFIG_X86_X32_ABI |
3103 | if (in_x32_syscall()) { | 3113 | if (in_x32_syscall()) { |
3104 | to->si_utime = from._sifields._sigchld_x32._utime; | 3114 | to->si_utime = from->_sifields._sigchld_x32._utime; |
3105 | to->si_stime = from._sifields._sigchld_x32._stime; | 3115 | to->si_stime = from->_sifields._sigchld_x32._stime; |
3106 | } else | 3116 | } else |
3107 | #endif | 3117 | #endif |
3108 | { | 3118 | { |
3109 | to->si_utime = from.si_utime; | 3119 | to->si_utime = from->si_utime; |
3110 | to->si_stime = from.si_stime; | 3120 | to->si_stime = from->si_stime; |
3111 | } | 3121 | } |
3112 | break; | 3122 | break; |
3113 | case SIL_RT: | 3123 | case SIL_RT: |
3114 | to->si_pid = from.si_pid; | 3124 | to->si_pid = from->si_pid; |
3115 | to->si_uid = from.si_uid; | 3125 | to->si_uid = from->si_uid; |
3116 | to->si_int = from.si_int; | 3126 | to->si_int = from->si_int; |
3117 | break; | 3127 | break; |
3118 | case SIL_SYS: | 3128 | case SIL_SYS: |
3119 | to->si_call_addr = compat_ptr(from.si_call_addr); | 3129 | to->si_call_addr = compat_ptr(from->si_call_addr); |
3120 | to->si_syscall = from.si_syscall; | 3130 | to->si_syscall = from->si_syscall; |
3121 | to->si_arch = from.si_arch; | 3131 | to->si_arch = from->si_arch; |
3122 | break; | 3132 | break; |
3123 | } | 3133 | } |
3124 | return 0; | 3134 | return 0; |
3125 | } | 3135 | } |
3136 | |||
3137 | static int __copy_siginfo_from_user32(int signo, struct kernel_siginfo *to, | ||
3138 | const struct compat_siginfo __user *ufrom) | ||
3139 | { | ||
3140 | struct compat_siginfo from; | ||
3141 | |||
3142 | if (copy_from_user(&from, ufrom, sizeof(struct compat_siginfo))) | ||
3143 | return -EFAULT; | ||
3144 | |||
3145 | from.si_signo = signo; | ||
3146 | return post_copy_siginfo_from_user32(to, &from); | ||
3147 | } | ||
3148 | |||
3149 | int copy_siginfo_from_user32(struct kernel_siginfo *to, | ||
3150 | const struct compat_siginfo __user *ufrom) | ||
3151 | { | ||
3152 | struct compat_siginfo from; | ||
3153 | |||
3154 | if (copy_from_user(&from, ufrom, sizeof(struct compat_siginfo))) | ||
3155 | return -EFAULT; | ||
3156 | |||
3157 | return post_copy_siginfo_from_user32(to, &from); | ||
3158 | } | ||
3126 | #endif /* CONFIG_COMPAT */ | 3159 | #endif /* CONFIG_COMPAT */ |
3127 | 3160 | ||
3128 | /** | 3161 | /** |
@@ -3359,9 +3392,6 @@ static int do_rt_sigqueueinfo(pid_t pid, int sig, kernel_siginfo_t *info) | |||
3359 | (task_pid_vnr(current) != pid)) | 3392 | (task_pid_vnr(current) != pid)) |
3360 | return -EPERM; | 3393 | return -EPERM; |
3361 | 3394 | ||
3362 | if (info->si_signo != sig) | ||
3363 | return -EINVAL; | ||
3364 | |||
3365 | /* POSIX.1b doesn't mention process groups. */ | 3395 | /* POSIX.1b doesn't mention process groups. */ |
3366 | return kill_proc_info(sig, info, pid); | 3396 | return kill_proc_info(sig, info, pid); |
3367 | } | 3397 | } |
@@ -3376,7 +3406,7 @@ SYSCALL_DEFINE3(rt_sigqueueinfo, pid_t, pid, int, sig, | |||
3376 | siginfo_t __user *, uinfo) | 3406 | siginfo_t __user *, uinfo) |
3377 | { | 3407 | { |
3378 | kernel_siginfo_t info; | 3408 | kernel_siginfo_t info; |
3379 | int ret = copy_siginfo_from_user(&info, uinfo); | 3409 | int ret = __copy_siginfo_from_user(sig, &info, uinfo); |
3380 | if (unlikely(ret)) | 3410 | if (unlikely(ret)) |
3381 | return ret; | 3411 | return ret; |
3382 | return do_rt_sigqueueinfo(pid, sig, &info); | 3412 | return do_rt_sigqueueinfo(pid, sig, &info); |
@@ -3389,7 +3419,7 @@ COMPAT_SYSCALL_DEFINE3(rt_sigqueueinfo, | |||
3389 | struct compat_siginfo __user *, uinfo) | 3419 | struct compat_siginfo __user *, uinfo) |
3390 | { | 3420 | { |
3391 | kernel_siginfo_t info; | 3421 | kernel_siginfo_t info; |
3392 | int ret = copy_siginfo_from_user32(&info, uinfo); | 3422 | int ret = __copy_siginfo_from_user32(sig, &info, uinfo); |
3393 | if (unlikely(ret)) | 3423 | if (unlikely(ret)) |
3394 | return ret; | 3424 | return ret; |
3395 | return do_rt_sigqueueinfo(pid, sig, &info); | 3425 | return do_rt_sigqueueinfo(pid, sig, &info); |
@@ -3409,9 +3439,6 @@ static int do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, kernel_siginfo_t | |||
3409 | (task_pid_vnr(current) != pid)) | 3439 | (task_pid_vnr(current) != pid)) |
3410 | return -EPERM; | 3440 | return -EPERM; |
3411 | 3441 | ||
3412 | if (info->si_signo != sig) | ||
3413 | return -EINVAL; | ||
3414 | |||
3415 | return do_send_specific(tgid, pid, sig, info); | 3442 | return do_send_specific(tgid, pid, sig, info); |
3416 | } | 3443 | } |
3417 | 3444 | ||
@@ -3419,7 +3446,7 @@ SYSCALL_DEFINE4(rt_tgsigqueueinfo, pid_t, tgid, pid_t, pid, int, sig, | |||
3419 | siginfo_t __user *, uinfo) | 3446 | siginfo_t __user *, uinfo) |
3420 | { | 3447 | { |
3421 | kernel_siginfo_t info; | 3448 | kernel_siginfo_t info; |
3422 | int ret = copy_siginfo_from_user(&info, uinfo); | 3449 | int ret = __copy_siginfo_from_user(sig, &info, uinfo); |
3423 | if (unlikely(ret)) | 3450 | if (unlikely(ret)) |
3424 | return ret; | 3451 | return ret; |
3425 | return do_rt_tgsigqueueinfo(tgid, pid, sig, &info); | 3452 | return do_rt_tgsigqueueinfo(tgid, pid, sig, &info); |
@@ -3433,7 +3460,7 @@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo, | |||
3433 | struct compat_siginfo __user *, uinfo) | 3460 | struct compat_siginfo __user *, uinfo) |
3434 | { | 3461 | { |
3435 | kernel_siginfo_t info; | 3462 | kernel_siginfo_t info; |
3436 | int ret = copy_siginfo_from_user32(&info, uinfo); | 3463 | int ret = __copy_siginfo_from_user32(sig, &info, uinfo); |
3437 | if (unlikely(ret)) | 3464 | if (unlikely(ret)) |
3438 | return ret; | 3465 | return ret; |
3439 | return do_rt_tgsigqueueinfo(tgid, pid, sig, &info); | 3466 | return do_rt_tgsigqueueinfo(tgid, pid, sig, &info); |