Skip to content

Commit ce72a16

Browse files
author
Al Viro
committed
wait4(2)/waitid(2): separate copying rusage to userland
New helpers: kernel_waitid() and kernel_wait4(). sys_waitid(), sys_wait4() and their compat variants switched to those. Copying struct rusage to userland is left to syscall itself. For compat_sys_wait4() that eliminates the use of set_fs() completely. For compat_sys_waitid() it's still needed (for siginfo handling); that will change shortly. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
1 parent 7e95a22 commit ce72a16

File tree

3 files changed

+59
-48
lines changed

3 files changed

+59
-48
lines changed

include/linux/resource.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
struct task_struct;
88

9-
int getrusage(struct task_struct *p, int who, struct rusage __user *ru);
9+
void getrusage(struct task_struct *p, int who, struct rusage *ru);
1010
int do_prlimit(struct task_struct *tsk, unsigned int resource,
1111
struct rlimit *new_rlim, struct rlimit *old_rlim);
1212

kernel/exit.c

Lines changed: 52 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,7 +1003,7 @@ struct wait_opts {
10031003

10041004
struct siginfo __user *wo_info;
10051005
int __user *wo_stat;
1006-
struct rusage __user *wo_rusage;
1006+
struct rusage *wo_rusage;
10071007

10081008
wait_queue_t child_wait;
10091009
int notask_error;
@@ -1054,8 +1054,10 @@ static int wait_noreap_copyout(struct wait_opts *wo, struct task_struct *p,
10541054
pid_t pid, uid_t uid, int why, int status)
10551055
{
10561056
struct siginfo __user *infop;
1057-
int retval = wo->wo_rusage
1058-
? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0;
1057+
int retval = 0;
1058+
1059+
if (wo->wo_rusage)
1060+
getrusage(p, RUSAGE_BOTH, wo->wo_rusage);
10591061

10601062
put_task_struct(p);
10611063
infop = wo->wo_info;
@@ -1182,8 +1184,9 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
11821184
spin_unlock_irq(&current->sighand->siglock);
11831185
}
11841186

1185-
retval = wo->wo_rusage
1186-
? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0;
1187+
if (wo->wo_rusage)
1188+
getrusage(p, RUSAGE_BOTH, wo->wo_rusage);
1189+
retval = 0;
11871190
status = (p->signal->flags & SIGNAL_GROUP_EXIT)
11881191
? p->signal->group_exit_code : p->exit_code;
11891192
if (!retval && wo->wo_stat)
@@ -1316,8 +1319,9 @@ static int wait_task_stopped(struct wait_opts *wo,
13161319
if (unlikely(wo->wo_flags & WNOWAIT))
13171320
return wait_noreap_copyout(wo, p, pid, uid, why, exit_code);
13181321

1319-
retval = wo->wo_rusage
1320-
? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0;
1322+
if (wo->wo_rusage)
1323+
getrusage(p, RUSAGE_BOTH, wo->wo_rusage);
1324+
retval = 0;
13211325
if (!retval && wo->wo_stat)
13221326
retval = put_user((exit_code << 8) | 0x7f, wo->wo_stat);
13231327

@@ -1377,8 +1381,9 @@ static int wait_task_continued(struct wait_opts *wo, struct task_struct *p)
13771381
sched_annotate_sleep();
13781382

13791383
if (!wo->wo_info) {
1380-
retval = wo->wo_rusage
1381-
? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0;
1384+
if (wo->wo_rusage)
1385+
getrusage(p, RUSAGE_BOTH, wo->wo_rusage);
1386+
retval = 0;
13821387
put_task_struct(p);
13831388
if (!retval && wo->wo_stat)
13841389
retval = put_user(0xffff, wo->wo_stat);
@@ -1618,8 +1623,8 @@ static long do_wait(struct wait_opts *wo)
16181623
return retval;
16191624
}
16201625

1621-
SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,
1622-
infop, int, options, struct rusage __user *, ru)
1626+
static long kernel_waitid(int which, pid_t upid, struct siginfo __user *infop,
1627+
int options, struct rusage *ru)
16231628
{
16241629
struct wait_opts wo;
16251630
struct pid *pid = NULL;
@@ -1687,8 +1692,21 @@ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,
16871692
return ret;
16881693
}
16891694

1690-
SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr,
1691-
int, options, struct rusage __user *, ru)
1695+
SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,
1696+
infop, int, options, struct rusage __user *, ru)
1697+
{
1698+
struct rusage r;
1699+
long err = kernel_waitid(which, upid, infop, options, ru ? &r : NULL);
1700+
1701+
if (!err) {
1702+
if (ru && copy_to_user(ru, &r, sizeof(struct rusage)))
1703+
return -EFAULT;
1704+
}
1705+
return err;
1706+
}
1707+
1708+
static long kernel_wait4(pid_t upid, int __user *stat_addr,
1709+
int options, struct rusage *ru)
16921710
{
16931711
struct wait_opts wo;
16941712
struct pid *pid = NULL;
@@ -1724,6 +1742,19 @@ SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr,
17241742
return ret;
17251743
}
17261744

1745+
SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr,
1746+
int, options, struct rusage __user *, ru)
1747+
{
1748+
struct rusage r;
1749+
long err = kernel_wait4(upid, stat_addr, options, ru ? &r : NULL);
1750+
1751+
if (err > 0) {
1752+
if (ru && copy_to_user(ru, &r, sizeof(struct rusage)))
1753+
return -EFAULT;
1754+
}
1755+
return err;
1756+
}
1757+
17271758
#ifdef __ARCH_WANT_SYS_WAITPID
17281759

17291760
/*
@@ -1744,29 +1775,13 @@ COMPAT_SYSCALL_DEFINE4(wait4,
17441775
int, options,
17451776
struct compat_rusage __user *, ru)
17461777
{
1747-
if (!ru) {
1748-
return sys_wait4(pid, stat_addr, options, NULL);
1749-
} else {
1750-
struct rusage r;
1751-
int ret;
1752-
unsigned int status;
1753-
mm_segment_t old_fs = get_fs();
1754-
1755-
set_fs (KERNEL_DS);
1756-
ret = sys_wait4(pid,
1757-
(stat_addr ?
1758-
(unsigned int __user *) &status : NULL),
1759-
options, (struct rusage __user *) &r);
1760-
set_fs (old_fs);
1761-
1762-
if (ret > 0) {
1763-
if (put_compat_rusage(&r, ru))
1764-
return -EFAULT;
1765-
if (stat_addr && put_user(status, stat_addr))
1766-
return -EFAULT;
1767-
}
1768-
return ret;
1778+
struct rusage r;
1779+
long err = kernel_wait4(pid, stat_addr, options, ru ? &r : NULL);
1780+
if (err > 0) {
1781+
if (ru && put_compat_rusage(&r, ru))
1782+
return -EFAULT;
17691783
}
1784+
return err;
17701785
}
17711786

17721787
COMPAT_SYSCALL_DEFINE5(waitid,
@@ -1782,8 +1797,8 @@ COMPAT_SYSCALL_DEFINE5(waitid,
17821797
memset(&info, 0, sizeof(info));
17831798

17841799
set_fs(KERNEL_DS);
1785-
ret = sys_waitid(which, pid, (siginfo_t __user *)&info, options,
1786-
uru ? (struct rusage __user *)&ru : NULL);
1800+
ret = kernel_waitid(which, pid, (siginfo_t __user *)&info, options,
1801+
uru ? &ru : NULL);
17871802
set_fs(old_fs);
17881803

17891804
if ((ret < 0) || (info.si_signo == 0))

kernel/sys.c

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1552,7 +1552,7 @@ static void accumulate_thread_rusage(struct task_struct *t, struct rusage *r)
15521552
r->ru_oublock += task_io_get_oublock(t);
15531553
}
15541554

1555-
static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
1555+
void getrusage(struct task_struct *p, int who, struct rusage *r)
15561556
{
15571557
struct task_struct *t;
15581558
unsigned long flags;
@@ -1626,20 +1626,16 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
16261626
r->ru_maxrss = maxrss * (PAGE_SIZE / 1024); /* convert pages to KBs */
16271627
}
16281628

1629-
int getrusage(struct task_struct *p, int who, struct rusage __user *ru)
1629+
SYSCALL_DEFINE2(getrusage, int, who, struct rusage __user *, ru)
16301630
{
16311631
struct rusage r;
16321632

1633-
k_getrusage(p, who, &r);
1634-
return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
1635-
}
1636-
1637-
SYSCALL_DEFINE2(getrusage, int, who, struct rusage __user *, ru)
1638-
{
16391633
if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN &&
16401634
who != RUSAGE_THREAD)
16411635
return -EINVAL;
1642-
return getrusage(current, who, ru);
1636+
1637+
getrusage(current, who, &r);
1638+
return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
16431639
}
16441640

16451641
#ifdef CONFIG_COMPAT
@@ -1651,7 +1647,7 @@ COMPAT_SYSCALL_DEFINE2(getrusage, int, who, struct compat_rusage __user *, ru)
16511647
who != RUSAGE_THREAD)
16521648
return -EINVAL;
16531649

1654-
k_getrusage(current, who, &r);
1650+
getrusage(current, who, &r);
16551651
return put_compat_rusage(&r, ru);
16561652
}
16571653
#endif

0 commit comments

Comments
 (0)