signal: Introduce copy_siginfo_from_user and use it's return value

In preparation for using a smaller version of siginfo in the kernel
introduce copy_siginfo_from_user and use it when siginfo is copied from
userspace.

Make the pattern for using copy_siginfo_from_user and
copy_siginfo_from_user32 to capture the return value and return that
value on error.

This is a necessary prerequisite for using a smaller siginfo
in the kernel than the kernel exports to userspace.

Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
This commit is contained in:
Eric W. Biederman 2018-04-18 17:30:19 -05:00
parent f283801851
commit 4cd2e0e70a
3 changed files with 22 additions and 16 deletions

View File

@ -22,6 +22,7 @@ static inline void clear_siginfo(struct siginfo *info)
} }
int copy_siginfo_to_user(struct siginfo __user *to, const struct siginfo *from); int copy_siginfo_to_user(struct siginfo __user *to, const struct siginfo *from);
int copy_siginfo_from_user(struct siginfo *to, const struct siginfo __user *from);
enum siginfo_layout { enum siginfo_layout {
SIL_KILL, SIL_KILL,

View File

@ -919,9 +919,8 @@ int ptrace_request(struct task_struct *child, long request,
break; break;
case PTRACE_SETSIGINFO: case PTRACE_SETSIGINFO:
if (copy_from_user(&siginfo, datavp, sizeof siginfo)) ret = copy_siginfo_from_user(&siginfo, datavp);
ret = -EFAULT; if (!ret)
else
ret = ptrace_setsiginfo(child, &siginfo); ret = ptrace_setsiginfo(child, &siginfo);
break; break;
@ -1215,10 +1214,9 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
break; break;
case PTRACE_SETSIGINFO: case PTRACE_SETSIGINFO:
if (copy_siginfo_from_user32( ret = copy_siginfo_from_user32(
&siginfo, (struct compat_siginfo __user *) datap)) &siginfo, (struct compat_siginfo __user *) datap);
ret = -EFAULT; if (!ret)
else
ret = ptrace_setsiginfo(child, &siginfo); ret = ptrace_setsiginfo(child, &siginfo);
break; break;
#ifdef CONFIG_HAVE_ARCH_TRACEHOOK #ifdef CONFIG_HAVE_ARCH_TRACEHOOK

View File

@ -2896,6 +2896,13 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
return 0; return 0;
} }
int copy_siginfo_from_user(siginfo_t *to, const siginfo_t __user *from)
{
if (copy_from_user(to, from, sizeof(struct siginfo)))
return -EFAULT;
return 0;
}
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
int copy_siginfo_to_user32(struct compat_siginfo __user *to, int copy_siginfo_to_user32(struct compat_siginfo __user *to,
const struct siginfo *from) const struct siginfo *from)
@ -3323,8 +3330,9 @@ SYSCALL_DEFINE3(rt_sigqueueinfo, pid_t, pid, int, sig,
siginfo_t __user *, uinfo) siginfo_t __user *, uinfo)
{ {
siginfo_t info; siginfo_t info;
if (copy_from_user(&info, uinfo, sizeof(siginfo_t))) int ret = copy_siginfo_from_user(&info, uinfo);
return -EFAULT; if (unlikely(ret))
return ret;
return do_rt_sigqueueinfo(pid, sig, &info); return do_rt_sigqueueinfo(pid, sig, &info);
} }
@ -3365,10 +3373,9 @@ SYSCALL_DEFINE4(rt_tgsigqueueinfo, pid_t, tgid, pid_t, pid, int, sig,
siginfo_t __user *, uinfo) siginfo_t __user *, uinfo)
{ {
siginfo_t info; siginfo_t info;
int ret = copy_siginfo_from_user(&info, uinfo);
if (copy_from_user(&info, uinfo, sizeof(siginfo_t))) if (unlikely(ret))
return -EFAULT; return ret;
return do_rt_tgsigqueueinfo(tgid, pid, sig, &info); return do_rt_tgsigqueueinfo(tgid, pid, sig, &info);
} }
@ -3380,9 +3387,9 @@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo,
struct compat_siginfo __user *, uinfo) struct compat_siginfo __user *, uinfo)
{ {
siginfo_t info; siginfo_t info;
int ret = copy_siginfo_from_user32(&info, uinfo);
if (copy_siginfo_from_user32(&info, uinfo)) if (unlikely(ret))
return -EFAULT; return ret;
return do_rt_tgsigqueueinfo(tgid, pid, sig, &info); return do_rt_tgsigqueueinfo(tgid, pid, sig, &info);
} }
#endif #endif