2019-07-14 12:03:14

by Dmitry V. Levin

[permalink] [raw]
Subject: [PATCH] clone: fix CLONE_PIDFD support

The introduction of clone3 syscall accidentally broke CLONE_PIDFD
support in traditional clone syscall on compat x86 and those
architectures that use do_fork to implement clone syscall.

This bug was found by strace test suite.

Link: https://strace.io/logs/strace/2019-07-12
Fixes: 7f192e3cd316 ("fork: add clone3")
Bisected-and-tested-by: Anatoly Pugachev <[email protected]>
Signed-off-by: Dmitry V. Levin <[email protected]>
---
arch/x86/ia32/sys_ia32.c | 1 +
kernel/fork.c | 1 +
2 files changed, 2 insertions(+)

diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c
index 64a6c952091e..98754baf411a 100644
--- a/arch/x86/ia32/sys_ia32.c
+++ b/arch/x86/ia32/sys_ia32.c
@@ -239,6 +239,7 @@ COMPAT_SYSCALL_DEFINE5(x86_clone, unsigned long, clone_flags,
{
struct kernel_clone_args args = {
.flags = (clone_flags & ~CSIGNAL),
+ .pidfd = parent_tidptr,
.child_tid = child_tidptr,
.parent_tid = parent_tidptr,
.exit_signal = (clone_flags & CSIGNAL),
diff --git a/kernel/fork.c b/kernel/fork.c
index 8f3e2d97d771..2c3cbad807b6 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -2417,6 +2417,7 @@ long do_fork(unsigned long clone_flags,
{
struct kernel_clone_args args = {
.flags = (clone_flags & ~CSIGNAL),
+ .pidfd = parent_tidptr,
.child_tid = child_tidptr,
.parent_tid = parent_tidptr,
.exit_signal = (clone_flags & CSIGNAL),
--
ldv


2019-07-14 12:20:28

by Christian Brauner

[permalink] [raw]
Subject: Re: [PATCH] clone: fix CLONE_PIDFD support

On Sun, Jul 14, 2019 at 03:02:06PM +0300, Dmitry V. Levin wrote:
> The introduction of clone3 syscall accidentally broke CLONE_PIDFD
> support in traditional clone syscall on compat x86 and those
> architectures that use do_fork to implement clone syscall.
>
> This bug was found by strace test suite.
>
> Link: https://strace.io/logs/strace/2019-07-12
> Fixes: 7f192e3cd316 ("fork: add clone3")
> Bisected-and-tested-by: Anatoly Pugachev <[email protected]>
> Signed-off-by: Dmitry V. Levin <[email protected]>

Good catch! Thank you Dmitry.

One change request below.

> ---
> arch/x86/ia32/sys_ia32.c | 1 +
> kernel/fork.c | 1 +
> 2 files changed, 2 insertions(+)
>
> diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c
> index 64a6c952091e..98754baf411a 100644
> --- a/arch/x86/ia32/sys_ia32.c
> +++ b/arch/x86/ia32/sys_ia32.c
> @@ -239,6 +239,7 @@ COMPAT_SYSCALL_DEFINE5(x86_clone, unsigned long, clone_flags,
> {
> struct kernel_clone_args args = {
> .flags = (clone_flags & ~CSIGNAL),
> + .pidfd = parent_tidptr,
> .child_tid = child_tidptr,
> .parent_tid = parent_tidptr,
> .exit_signal = (clone_flags & CSIGNAL),
> diff --git a/kernel/fork.c b/kernel/fork.c
> index 8f3e2d97d771..2c3cbad807b6 100644
> --- a/kernel/fork.c
> +++ b/kernel/fork.c
> @@ -2417,6 +2417,7 @@ long do_fork(unsigned long clone_flags,
> {
> struct kernel_clone_args args = {
> .flags = (clone_flags & ~CSIGNAL),
> + .pidfd = parent_tidptr,
> .child_tid = child_tidptr,
> .parent_tid = parent_tidptr,
> .exit_signal = (clone_flags & CSIGNAL),
> --

Both of these legacy clone helpers need to make CLONE_PIDFD and
CLONE_PARENT_SETTID incompatible, i.e. could you please add a helper to
kernel/fork.c:

bool legacy_clone_args_valid(const struct kernel_clone_args *kargs)
{
/* clone(CLONE_PIDFD) uses parent_tidptr to return a pidfd */
if ((kargs->flags & CLONE_PIDFD) && (kargs->flags & CLONE_PARENT_SETTID))
return false;
}

and export it and use it in ia32 too?

Then resend and I'll put it into my tree that already has a few other
fixes about to be sent.

Christian

2019-07-14 14:11:04

by Dmitry V. Levin

[permalink] [raw]
Subject: Re: [PATCH] clone: fix CLONE_PIDFD support

On Sun, Jul 14, 2019 at 02:17:25PM +0200, Christian Brauner wrote:
> On Sun, Jul 14, 2019 at 03:02:06PM +0300, Dmitry V. Levin wrote:
> > The introduction of clone3 syscall accidentally broke CLONE_PIDFD
> > support in traditional clone syscall on compat x86 and those
> > architectures that use do_fork to implement clone syscall.
> >
> > This bug was found by strace test suite.
> >
> > Link: https://strace.io/logs/strace/2019-07-12
> > Fixes: 7f192e3cd316 ("fork: add clone3")
> > Bisected-and-tested-by: Anatoly Pugachev <[email protected]>
> > Signed-off-by: Dmitry V. Levin <[email protected]>
>
> Good catch! Thank you Dmitry.
>
> One change request below.
>
> > ---
> > arch/x86/ia32/sys_ia32.c | 1 +
> > kernel/fork.c | 1 +
> > 2 files changed, 2 insertions(+)
> >
> > diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c
> > index 64a6c952091e..98754baf411a 100644
> > --- a/arch/x86/ia32/sys_ia32.c
> > +++ b/arch/x86/ia32/sys_ia32.c
> > @@ -239,6 +239,7 @@ COMPAT_SYSCALL_DEFINE5(x86_clone, unsigned long, clone_flags,
> > {
> > struct kernel_clone_args args = {
> > .flags = (clone_flags & ~CSIGNAL),
> > + .pidfd = parent_tidptr,
> > .child_tid = child_tidptr,
> > .parent_tid = parent_tidptr,
> > .exit_signal = (clone_flags & CSIGNAL),
> > diff --git a/kernel/fork.c b/kernel/fork.c
> > index 8f3e2d97d771..2c3cbad807b6 100644
> > --- a/kernel/fork.c
> > +++ b/kernel/fork.c
> > @@ -2417,6 +2417,7 @@ long do_fork(unsigned long clone_flags,
> > {
> > struct kernel_clone_args args = {
> > .flags = (clone_flags & ~CSIGNAL),
> > + .pidfd = parent_tidptr,
> > .child_tid = child_tidptr,
> > .parent_tid = parent_tidptr,
> > .exit_signal = (clone_flags & CSIGNAL),
> > --
>
> Both of these legacy clone helpers need to make CLONE_PIDFD and
> CLONE_PARENT_SETTID incompatible, i.e. could you please add a helper to
> kernel/fork.c:
>
> bool legacy_clone_args_valid(const struct kernel_clone_args *kargs)
> {
> /* clone(CLONE_PIDFD) uses parent_tidptr to return a pidfd */
> if ((kargs->flags & CLONE_PIDFD) && (kargs->flags & CLONE_PARENT_SETTID))
> return false;
> }
>
> and export it and use it in ia32 too?

copy_process already performs the check, isn't this enough?
Also, the check in sys_clone looks redundant and I was going to suggest
its removal.


--
ldv


Attachments:
(No filename) (2.37 kB)
signature.asc (817.00 B)
Download all attachments

2019-07-14 14:29:35

by Christian Brauner

[permalink] [raw]
Subject: Re: [PATCH] clone: fix CLONE_PIDFD support

On Sun, Jul 14, 2019 at 05:10:08PM +0300, Dmitry V. Levin wrote:
> On Sun, Jul 14, 2019 at 02:17:25PM +0200, Christian Brauner wrote:
> > On Sun, Jul 14, 2019 at 03:02:06PM +0300, Dmitry V. Levin wrote:
> > > The introduction of clone3 syscall accidentally broke CLONE_PIDFD
> > > support in traditional clone syscall on compat x86 and those
> > > architectures that use do_fork to implement clone syscall.
> > >
> > > This bug was found by strace test suite.
> > >
> > > Link: https://strace.io/logs/strace/2019-07-12
> > > Fixes: 7f192e3cd316 ("fork: add clone3")
> > > Bisected-and-tested-by: Anatoly Pugachev <[email protected]>
> > > Signed-off-by: Dmitry V. Levin <[email protected]>
> >
> > Good catch! Thank you Dmitry.
> >
> > One change request below.
> >
> > > ---
> > > arch/x86/ia32/sys_ia32.c | 1 +
> > > kernel/fork.c | 1 +
> > > 2 files changed, 2 insertions(+)
> > >
> > > diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c
> > > index 64a6c952091e..98754baf411a 100644
> > > --- a/arch/x86/ia32/sys_ia32.c
> > > +++ b/arch/x86/ia32/sys_ia32.c
> > > @@ -239,6 +239,7 @@ COMPAT_SYSCALL_DEFINE5(x86_clone, unsigned long, clone_flags,
> > > {
> > > struct kernel_clone_args args = {
> > > .flags = (clone_flags & ~CSIGNAL),
> > > + .pidfd = parent_tidptr,
> > > .child_tid = child_tidptr,
> > > .parent_tid = parent_tidptr,
> > > .exit_signal = (clone_flags & CSIGNAL),
> > > diff --git a/kernel/fork.c b/kernel/fork.c
> > > index 8f3e2d97d771..2c3cbad807b6 100644
> > > --- a/kernel/fork.c
> > > +++ b/kernel/fork.c
> > > @@ -2417,6 +2417,7 @@ long do_fork(unsigned long clone_flags,
> > > {
> > > struct kernel_clone_args args = {
> > > .flags = (clone_flags & ~CSIGNAL),
> > > + .pidfd = parent_tidptr,
> > > .child_tid = child_tidptr,
> > > .parent_tid = parent_tidptr,
> > > .exit_signal = (clone_flags & CSIGNAL),
> > > --
> >
> > Both of these legacy clone helpers need to make CLONE_PIDFD and
> > CLONE_PARENT_SETTID incompatible, i.e. could you please add a helper to
> > kernel/fork.c:
> >
> > bool legacy_clone_args_valid(const struct kernel_clone_args *kargs)
> > {
> > /* clone(CLONE_PIDFD) uses parent_tidptr to return a pidfd */
> > if ((kargs->flags & CLONE_PIDFD) && (kargs->flags & CLONE_PARENT_SETTID))
> > return false;
> > }
> >
> > and export it and use it in ia32 too?
>
> copy_process already performs the check, isn't this enough?

No it doesn't anymore. clone3() allows CLONE_PIDFD + CLONE_PARENT_SETTID
since struct clone_args has a dedicated pidfd return argument.

> Also, the check in sys_clone looks redundant and I was going to suggest
> its removal.

See above.

2019-07-14 16:17:00

by Dmitry V. Levin

[permalink] [raw]
Subject: Re: [PATCH] clone: fix CLONE_PIDFD support

On Sun, Jul 14, 2019 at 04:23:05PM +0200, Christian Brauner wrote:
> On Sun, Jul 14, 2019 at 05:10:08PM +0300, Dmitry V. Levin wrote:
> > On Sun, Jul 14, 2019 at 02:17:25PM +0200, Christian Brauner wrote:
> > > On Sun, Jul 14, 2019 at 03:02:06PM +0300, Dmitry V. Levin wrote:
> > > > The introduction of clone3 syscall accidentally broke CLONE_PIDFD
> > > > support in traditional clone syscall on compat x86 and those
> > > > architectures that use do_fork to implement clone syscall.
> > > >
> > > > This bug was found by strace test suite.
> > > >
> > > > Link: https://strace.io/logs/strace/2019-07-12
> > > > Fixes: 7f192e3cd316 ("fork: add clone3")
> > > > Bisected-and-tested-by: Anatoly Pugachev <[email protected]>
> > > > Signed-off-by: Dmitry V. Levin <[email protected]>
> > >
> > > Good catch! Thank you Dmitry.
> > >
> > > One change request below.
> > >
> > > > ---
> > > > arch/x86/ia32/sys_ia32.c | 1 +
> > > > kernel/fork.c | 1 +
> > > > 2 files changed, 2 insertions(+)
> > > >
> > > > diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c
> > > > index 64a6c952091e..98754baf411a 100644
> > > > --- a/arch/x86/ia32/sys_ia32.c
> > > > +++ b/arch/x86/ia32/sys_ia32.c
> > > > @@ -239,6 +239,7 @@ COMPAT_SYSCALL_DEFINE5(x86_clone, unsigned long, clone_flags,
> > > > {
> > > > struct kernel_clone_args args = {
> > > > .flags = (clone_flags & ~CSIGNAL),
> > > > + .pidfd = parent_tidptr,
> > > > .child_tid = child_tidptr,
> > > > .parent_tid = parent_tidptr,
> > > > .exit_signal = (clone_flags & CSIGNAL),
> > > > diff --git a/kernel/fork.c b/kernel/fork.c
> > > > index 8f3e2d97d771..2c3cbad807b6 100644
> > > > --- a/kernel/fork.c
> > > > +++ b/kernel/fork.c
> > > > @@ -2417,6 +2417,7 @@ long do_fork(unsigned long clone_flags,
> > > > {
> > > > struct kernel_clone_args args = {
> > > > .flags = (clone_flags & ~CSIGNAL),
> > > > + .pidfd = parent_tidptr,
> > > > .child_tid = child_tidptr,
> > > > .parent_tid = parent_tidptr,
> > > > .exit_signal = (clone_flags & CSIGNAL),
> > > > --
> > >
> > > Both of these legacy clone helpers need to make CLONE_PIDFD and
> > > CLONE_PARENT_SETTID incompatible, i.e. could you please add a helper to
> > > kernel/fork.c:
> > >
> > > bool legacy_clone_args_valid(const struct kernel_clone_args *kargs)
> > > {
> > > /* clone(CLONE_PIDFD) uses parent_tidptr to return a pidfd */
> > > if ((kargs->flags & CLONE_PIDFD) && (kargs->flags & CLONE_PARENT_SETTID))
> > > return false;
> > > }
> > >
> > > and export it and use it in ia32 too?
> >
> > copy_process already performs the check, isn't this enough?
>
> No it doesn't anymore. clone3() allows CLONE_PIDFD + CLONE_PARENT_SETTID
> since struct clone_args has a dedicated pidfd return argument.

Indeed, I must've missed it, thanks.

OK, I'll send a new fix with legacy_clone_args_valid.


--
ldv


Attachments:
(No filename) (2.89 kB)
signature.asc (817.00 B)
Download all attachments

2019-07-14 16:21:49

by Dmitry V. Levin

[permalink] [raw]
Subject: [PATCH v2] clone: fix CLONE_PIDFD support

The introduction of clone3 syscall accidentally broke CLONE_PIDFD
support in traditional clone syscall on compat x86 and those
architectures that use do_fork to implement clone syscall.

This bug was found by strace test suite.

Link: https://strace.io/logs/strace/2019-07-12
Fixes: 7f192e3cd316 ("fork: add clone3")
Bisected-and-tested-by: Anatoly Pugachev <[email protected]>
Signed-off-by: Dmitry V. Levin <[email protected]>
---
arch/x86/ia32/sys_ia32.c | 4 ++++
include/linux/sched/task.h | 1 +
kernel/fork.c | 17 +++++++++++++++--
3 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c
index 64a6c952091e..21790307121e 100644
--- a/arch/x86/ia32/sys_ia32.c
+++ b/arch/x86/ia32/sys_ia32.c
@@ -239,6 +239,7 @@ COMPAT_SYSCALL_DEFINE5(x86_clone, unsigned long, clone_flags,
{
struct kernel_clone_args args = {
.flags = (clone_flags & ~CSIGNAL),
+ .pidfd = parent_tidptr,
.child_tid = child_tidptr,
.parent_tid = parent_tidptr,
.exit_signal = (clone_flags & CSIGNAL),
@@ -246,5 +247,8 @@ COMPAT_SYSCALL_DEFINE5(x86_clone, unsigned long, clone_flags,
.tls = tls_val,
};

+ if (!legacy_clone_args_valid(&args))
+ return -EINVAL;
+
return _do_fork(&args);
}
diff --git a/include/linux/sched/task.h b/include/linux/sched/task.h
index 109a0df5af39..0497091e40c1 100644
--- a/include/linux/sched/task.h
+++ b/include/linux/sched/task.h
@@ -89,6 +89,7 @@ extern void exit_files(struct task_struct *);
extern void exit_itimers(struct signal_struct *);

extern long _do_fork(struct kernel_clone_args *kargs);
+extern bool legacy_clone_args_valid(const struct kernel_clone_args *kargs);
extern long do_fork(unsigned long, unsigned long, unsigned long, int __user *, int __user *);
struct task_struct *fork_idle(int);
struct mm_struct *copy_init_mm(void);
diff --git a/kernel/fork.c b/kernel/fork.c
index 8f3e2d97d771..ef1e05a68827 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -2406,6 +2406,16 @@ long _do_fork(struct kernel_clone_args *args)
return nr;
}

+bool legacy_clone_args_valid(const struct kernel_clone_args *kargs)
+{
+ /* clone(CLONE_PIDFD) uses parent_tidptr to return a pidfd */
+ if ((kargs->flags & CLONE_PIDFD) &&
+ (kargs->flags & CLONE_PARENT_SETTID))
+ return false;
+
+ return true;
+}
+
#ifndef CONFIG_HAVE_COPY_THREAD_TLS
/* For compatibility with architectures that call do_fork directly rather than
* using the syscall entry points below. */
@@ -2417,6 +2427,7 @@ long do_fork(unsigned long clone_flags,
{
struct kernel_clone_args args = {
.flags = (clone_flags & ~CSIGNAL),
+ .pidfd = parent_tidptr,
.child_tid = child_tidptr,
.parent_tid = parent_tidptr,
.exit_signal = (clone_flags & CSIGNAL),
@@ -2424,6 +2435,9 @@ long do_fork(unsigned long clone_flags,
.stack_size = stack_size,
};

+ if (!legacy_clone_args_valid(&args))
+ return -EINVAL;
+
return _do_fork(&args);
}
#endif
@@ -2505,8 +2519,7 @@ SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
.tls = tls,
};

- /* clone(CLONE_PIDFD) uses parent_tidptr to return a pidfd */
- if ((clone_flags & CLONE_PIDFD) && (clone_flags & CLONE_PARENT_SETTID))
+ if (!legacy_clone_args_valid(&args))
return -EINVAL;

return _do_fork(&args);
--
ldv

2019-07-14 18:22:41

by Christian Brauner

[permalink] [raw]
Subject: Re: [PATCH v2] clone: fix CLONE_PIDFD support

On Sun, Jul 14, 2019 at 07:20:47PM +0300, Dmitry V. Levin wrote:
> The introduction of clone3 syscall accidentally broke CLONE_PIDFD
> support in traditional clone syscall on compat x86 and those
> architectures that use do_fork to implement clone syscall.
>
> This bug was found by strace test suite.
>
> Link: https://strace.io/logs/strace/2019-07-12
> Fixes: 7f192e3cd316 ("fork: add clone3")
> Bisected-and-tested-by: Anatoly Pugachev <[email protected]>
> Signed-off-by: Dmitry V. Levin <[email protected]>

This looks good; moving this into my tree.

Thanks!
Christian