Skip to content

Commit 67d7ddd

Browse files
author
Al Viro
committed
waitid(2): leave copyout of siginfo to syscall itself
have kernel_waitid() collect the information needed for siginfo into a small structure (waitid_info) passed to it; deal with copyout in sys_waitid()/compat_sys_waitid(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
1 parent 359566f commit 67d7ddd

File tree

1 file changed

+64
-104
lines changed

1 file changed

+64
-104
lines changed

kernel/exit.c

Lines changed: 64 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -996,12 +996,19 @@ SYSCALL_DEFINE1(exit_group, int, error_code)
996996
return 0;
997997
}
998998

999+
struct waitid_info {
1000+
pid_t pid;
1001+
uid_t uid;
1002+
int status;
1003+
int cause;
1004+
};
1005+
9991006
struct wait_opts {
10001007
enum pid_type wo_type;
10011008
int wo_flags;
10021009
struct pid *wo_pid;
10031010

1004-
struct siginfo __user *wo_info;
1011+
struct waitid_info *wo_info;
10051012
int wo_stat;
10061013
struct rusage *wo_rusage;
10071014

@@ -1053,31 +1060,20 @@ eligible_child(struct wait_opts *wo, bool ptrace, struct task_struct *p)
10531060
static int wait_noreap_copyout(struct wait_opts *wo, struct task_struct *p,
10541061
pid_t pid, uid_t uid, int why, int status)
10551062
{
1056-
struct siginfo __user *infop;
1057-
int retval = 0;
1063+
struct waitid_info *infop;
10581064

10591065
if (wo->wo_rusage)
10601066
getrusage(p, RUSAGE_BOTH, wo->wo_rusage);
10611067

10621068
put_task_struct(p);
10631069
infop = wo->wo_info;
10641070
if (infop) {
1065-
if (!retval)
1066-
retval = put_user(SIGCHLD, &infop->si_signo);
1067-
if (!retval)
1068-
retval = put_user(0, &infop->si_errno);
1069-
if (!retval)
1070-
retval = put_user((short)why, &infop->si_code);
1071-
if (!retval)
1072-
retval = put_user(pid, &infop->si_pid);
1073-
if (!retval)
1074-
retval = put_user(uid, &infop->si_uid);
1075-
if (!retval)
1076-
retval = put_user(status, &infop->si_status);
1071+
infop->cause = why;
1072+
infop->pid = pid;
1073+
infop->uid = uid;
1074+
infop->status = status;
10771075
}
1078-
if (!retval)
1079-
retval = pid;
1080-
return retval;
1076+
return pid;
10811077
}
10821078

10831079
/*
@@ -1088,10 +1084,10 @@ static int wait_noreap_copyout(struct wait_opts *wo, struct task_struct *p,
10881084
*/
10891085
static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
10901086
{
1091-
int state, retval, status;
1087+
int state, status;
10921088
pid_t pid = task_pid_vnr(p);
10931089
uid_t uid = from_kuid_munged(current_user_ns(), task_uid(p));
1094-
struct siginfo __user *infop;
1090+
struct waitid_info *infop;
10951091

10961092
if (!likely(wo->wo_flags & WEXITED))
10971093
return 0;
@@ -1186,36 +1182,22 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
11861182

11871183
if (wo->wo_rusage)
11881184
getrusage(p, RUSAGE_BOTH, wo->wo_rusage);
1189-
retval = 0;
11901185
status = (p->signal->flags & SIGNAL_GROUP_EXIT)
11911186
? p->signal->group_exit_code : p->exit_code;
11921187
wo->wo_stat = status;
11931188

11941189
infop = wo->wo_info;
1195-
if (!retval && infop)
1196-
retval = put_user(SIGCHLD, &infop->si_signo);
1197-
if (!retval && infop)
1198-
retval = put_user(0, &infop->si_errno);
1199-
if (!retval && infop) {
1200-
int why;
1201-
1190+
if (infop) {
12021191
if ((status & 0x7f) == 0) {
1203-
why = CLD_EXITED;
1204-
status >>= 8;
1192+
infop->cause = CLD_EXITED;
1193+
infop->status = status >> 8;
12051194
} else {
1206-
why = (status & 0x80) ? CLD_DUMPED : CLD_KILLED;
1207-
status &= 0x7f;
1195+
infop->cause = (status & 0x80) ? CLD_DUMPED : CLD_KILLED;
1196+
infop->status = status & 0x7f;
12081197
}
1209-
retval = put_user((short)why, &infop->si_code);
1210-
if (!retval)
1211-
retval = put_user(status, &infop->si_status);
1198+
infop->pid = pid;
1199+
infop->uid = uid;
12121200
}
1213-
if (!retval && infop)
1214-
retval = put_user(pid, &infop->si_pid);
1215-
if (!retval && infop)
1216-
retval = put_user(uid, &infop->si_uid);
1217-
if (!retval)
1218-
retval = pid;
12191201

12201202
if (state == EXIT_TRACE) {
12211203
write_lock_irq(&tasklist_lock);
@@ -1232,7 +1214,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
12321214
if (state == EXIT_DEAD)
12331215
release_task(p);
12341216

1235-
return retval;
1217+
return pid;
12361218
}
12371219

12381220
static int *task_stopped_code(struct task_struct *p, bool ptrace)
@@ -1268,8 +1250,8 @@ static int *task_stopped_code(struct task_struct *p, bool ptrace)
12681250
static int wait_task_stopped(struct wait_opts *wo,
12691251
int ptrace, struct task_struct *p)
12701252
{
1271-
struct siginfo __user *infop;
1272-
int retval, exit_code, *p_code, why;
1253+
struct waitid_info *infop;
1254+
int exit_code, *p_code, why;
12731255
uid_t uid = 0; /* unneeded, required by compiler */
12741256
pid_t pid;
12751257

@@ -1320,28 +1302,19 @@ static int wait_task_stopped(struct wait_opts *wo,
13201302

13211303
if (wo->wo_rusage)
13221304
getrusage(p, RUSAGE_BOTH, wo->wo_rusage);
1323-
retval = 0;
13241305
wo->wo_stat = (exit_code << 8) | 0x7f;
13251306

13261307
infop = wo->wo_info;
1327-
if (!retval && infop)
1328-
retval = put_user(SIGCHLD, &infop->si_signo);
1329-
if (!retval && infop)
1330-
retval = put_user(0, &infop->si_errno);
1331-
if (!retval && infop)
1332-
retval = put_user((short)why, &infop->si_code);
1333-
if (!retval && infop)
1334-
retval = put_user(exit_code, &infop->si_status);
1335-
if (!retval && infop)
1336-
retval = put_user(pid, &infop->si_pid);
1337-
if (!retval && infop)
1338-
retval = put_user(uid, &infop->si_uid);
1339-
if (!retval)
1340-
retval = pid;
1308+
if (infop) {
1309+
infop->cause = why;
1310+
infop->status = exit_code;
1311+
infop->pid = pid;
1312+
infop->uid = uid;
1313+
}
13411314
put_task_struct(p);
13421315

1343-
BUG_ON(!retval);
1344-
return retval;
1316+
BUG_ON(!pid);
1317+
return pid;
13451318
}
13461319

13471320
/*
@@ -1618,7 +1591,7 @@ static long do_wait(struct wait_opts *wo)
16181591
return retval;
16191592
}
16201593

1621-
static long kernel_waitid(int which, pid_t upid, struct siginfo __user *infop,
1594+
static long kernel_waitid(int which, pid_t upid, struct waitid_info *infop,
16221595
int options, struct rusage *ru)
16231596
{
16241597
struct wait_opts wo;
@@ -1660,27 +1633,8 @@ static long kernel_waitid(int which, pid_t upid, struct siginfo __user *infop,
16601633
wo.wo_rusage = ru;
16611634
ret = do_wait(&wo);
16621635

1663-
if (ret > 0) {
1636+
if (ret > 0)
16641637
ret = 0;
1665-
} else if (infop) {
1666-
/*
1667-
* For a WNOHANG return, clear out all the fields
1668-
* we would set so the user can easily tell the
1669-
* difference.
1670-
*/
1671-
if (!ret)
1672-
ret = put_user(0, &infop->si_signo);
1673-
if (!ret)
1674-
ret = put_user(0, &infop->si_errno);
1675-
if (!ret)
1676-
ret = put_user(0, &infop->si_code);
1677-
if (!ret)
1678-
ret = put_user(0, &infop->si_pid);
1679-
if (!ret)
1680-
ret = put_user(0, &infop->si_uid);
1681-
if (!ret)
1682-
ret = put_user(0, &infop->si_status);
1683-
}
16841638

16851639
put_pid(pid);
16861640
return ret;
@@ -1690,12 +1644,24 @@ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,
16901644
infop, int, options, struct rusage __user *, ru)
16911645
{
16921646
struct rusage r;
1693-
long err = kernel_waitid(which, upid, infop, options, ru ? &r : NULL);
1647+
struct waitid_info info = {.status = 0};
1648+
long err = kernel_waitid(which, upid, &info, options, ru ? &r : NULL);
16941649

16951650
if (!err) {
16961651
if (ru && copy_to_user(ru, &r, sizeof(struct rusage)))
16971652
return -EFAULT;
16981653
}
1654+
if (!infop)
1655+
return err;
1656+
1657+
if (put_user(err ? 0 : SIGCHLD, &infop->si_signo) ||
1658+
put_user(0, &infop->si_errno) ||
1659+
put_user((short)info.cause, &infop->si_code) ||
1660+
put_user(info.pid, &infop->si_pid) ||
1661+
put_user(info.uid, &infop->si_uid) ||
1662+
put_user(info.status, &infop->si_status))
1663+
err = -EFAULT;
1664+
16991665
return err;
17001666
}
17011667

@@ -1785,33 +1751,27 @@ COMPAT_SYSCALL_DEFINE5(waitid,
17851751
struct compat_siginfo __user *, infop, int, options,
17861752
struct compat_rusage __user *, uru)
17871753
{
1788-
siginfo_t info;
17891754
struct rusage ru;
1790-
long ret;
1791-
mm_segment_t old_fs = get_fs();
1792-
1793-
memset(&info, 0, sizeof(info));
1755+
struct waitid_info info = {.status = 0};
1756+
long err = kernel_waitid(which, pid, &info, options, uru ? &ru : NULL);
17941757

1795-
set_fs(KERNEL_DS);
1796-
ret = kernel_waitid(which, pid, (siginfo_t __user *)&info, options,
1797-
uru ? &ru : NULL);
1798-
set_fs(old_fs);
1799-
1800-
if ((ret < 0) || (info.si_signo == 0))
1801-
return ret;
1802-
1803-
if (uru) {
1804-
/* sys_waitid() overwrites everything in ru */
1758+
if (!err && uru) {
1759+
/* kernel_waitid() overwrites everything in ru */
18051760
if (COMPAT_USE_64BIT_TIME)
1806-
ret = copy_to_user(uru, &ru, sizeof(ru));
1761+
err = copy_to_user(uru, &ru, sizeof(ru));
18071762
else
1808-
ret = put_compat_rusage(&ru, uru);
1809-
if (ret)
1763+
err = put_compat_rusage(&ru, uru);
1764+
if (err)
18101765
return -EFAULT;
18111766
}
18121767

1813-
BUG_ON(info.si_code & __SI_MASK);
1814-
info.si_code |= __SI_CHLD;
1815-
return copy_siginfo_to_user32(infop, &info);
1768+
if (put_user(err ? 0 : SIGCHLD, &infop->si_signo) ||
1769+
put_user(0, &infop->si_errno) ||
1770+
put_user((short)info.cause, &infop->si_code) ||
1771+
put_user(info.pid, &infop->si_pid) ||
1772+
put_user(info.uid, &infop->si_uid) ||
1773+
put_user(info.status, &infop->si_status))
1774+
err = -EFAULT;
1775+
return err;
18161776
}
18171777
#endif

0 commit comments

Comments
 (0)