namespaces && fork fixes/cleanups
Subsystems (3)
v2 cover namespaces && fork fixes/cleanups
Hello.
To remind, 1/3 fixes the regression, perhaps it should cc -stable.
v2:
changed the comment, added the acks from Andy.
Still needs the review from Eric.
Oleg.
kernel/fork.c | 22 ++++++++-------------- 1 files changed, 8 insertions(+), 14 deletions(-)
PATCH v2 1/3 pidns: fix vfork() after unshare(CLONE_NEWPID)
8382fcac "pidns: Outlaw thread creation after unshare(CLONE_NEWPID)" nacks CLONE_VM if the forking process unshared pid_ns, this obviously breaks vfork:
int main(void)
{
assert(unshare(CLONE_NEWUSER | CLONE_NEWPID) == 0);
assert(vfork() >= 0);
_exit(0);
return 0;
}fails without this patch.
Change this check to use CLONE_SIGHAND instead. This also forbids CLONE_THREAD automatically, and this is what the comment implies.
We could probably even drop CLONE_SIGHAND and use CLONE_THREAD, but it would be safer to not do this. The current check denies CLONE_SIGHAND implicitely and there is no reason to change this.
--- kernel/fork.c | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-)
kernel/fork.c +4 -3
@@ -1173,10 +1173,11 @@ static struct task_struct *copy_process(unsigned long clone_flags,return ERR_PTR (-EINVAL );/* -* If the new process will be in a different pid namespace -* don't allow the creation of threads. +* If the new process will be in a different pid namespace don't +* allow it to share a thread group or signal handlers with the +* forking task. */ -if ((clone_flags & (CLONE_VM |CLONE_NEWPID )) && +if ((clone_flags & (CLONE_SIGHAND |CLONE_NEWPID )) && (task_active_pid_ns (current) != current->nsproxy->pid_ns))return ERR_PTR (-EINVAL );
Signature · 1 line
1.5.5.1
PATCH v2 2/3 pidns: kill the unnecessary CLONE_NEWPID in copy_process()
In reply to Oleg Nesterov8382fcac "pidns: Outlaw thread creation after unshare(CLONE_NEWPID)" nacks CLONE_NEWPID if the forking process unshared pid_ns. This is correct but unnecessary, copy_pid_ns() does the same check.
Remove the CLONE_NEWPID check to cleanup the code and prepare for the next change.
Test-case:
static int child(void *arg)
{
return 0;
}
static char stack[16 * 1024];
int main(void)
{
pid_t pid;
assert(unshare(CLONE_NEWUSER | CLONE_NEWPID) == 0);
pid = clone(child, stack + sizeof(stack) / 2,
CLONE_NEWPID | SIGCHLD, NULL);
assert(pid < 0 && errno == EINVAL);
return 0;
}clone(CLONE_NEWPID) correctly fails with or without this change.
--- kernel/fork.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
kernel/fork.c +1 -1
@@ -1177,7 +1177,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,* allow it to share a thread group or signal handlers with the * forking task. */ -if ((clone_flags & (CLONE_SIGHAND |CLONE_NEWPID )) && +if ((clone_flags &CLONE_SIGHAND ) && (task_active_pid_ns (current) != current->nsproxy->pid_ns))return ERR_PTR (-EINVAL );
Signature · 1 line
1.5.5.1
PATCH v2 3/3 fork: unify and tighten up CLONE_NEWUSER/CLONE_NEWPID checks
In reply to Oleg Nesterovdo_fork() denies CLONE_THREAD | CLONE_PARENT if NEWUSER | NEWPID.
Then later copy_process() denies CLONE_SIGHAND if the new process will be in a different pid namespace (task_active_pid_ns() doesn't match current->nsproxy->pid_ns).
This looks confusing and inconsistent. CLONE_NEWPID is very similar to the case when ->pid_ns was already unshared, we want the same restrictions so copy_process() should also nack CLONE_PARENT.
And it would be better to deny CLONE_NEWUSER && CLONE_SIGHAND as well just for consistency.
Kill the "CLONE_NEWUSER | CLONE_NEWPID" check in do_fork() and change copy_process() to do the same check along with ->pid_ns check we already have.
--- kernel/fork.c | 23 ++++++++--------------- 1 files changed, 8 insertions(+), 15 deletions(-)
kernel/fork.c +8 -15
@@ -1173,13 +1173,15 @@ static struct task_struct *copy_process(unsigned long clone_flags,return ERR_PTR (-EINVAL );/* -* If the new process will be in a different pid namespace don't -* allow it to share a thread group or signal handlers with the -* forking task. +* If the new process will be in a different pid or user namespace +* do not allow it to share a thread group or signal handlers or +* parent with the forking task. */ -if ((clone_flags &CLONE_SIGHAND ) && - (task_active_pid_ns (current) != current->nsproxy->pid_ns)) -return ERR_PTR (-EINVAL ); +if (clone_flags & (CLONE_SIGHAND |CLONE_PARENT )) { +if ((clone_flags & (CLONE_NEWUSER |CLONE_NEWPID )) || + (task_active_pid_ns (current) != current->nsproxy->pid_ns)) +return ERR_PTR (-EINVAL ); + } retval =security_task_create (clone_flags);if (retval)
@@ -1576,15 +1578,6 @@ long do_fork(unsigned long clone_flags,long nr;/* -* Do some preliminary argument and permissions checking before we -* actually start allocating stuff -*/ -if (clone_flags & (CLONE_NEWUSER |CLONE_NEWPID )) { -if (clone_flags & (CLONE_THREAD |CLONE_PARENT )) -return -EINVAL ; - } - -/* * Determine whether and which event to report to ptracer. When * called from kernel_thread or CLONE_UNTRACED is explicitly * requested, no event is reported; otherwise, report if the event
Signature · 1 line
1.5.5.1