|
@@ -1866,13 +1866,21 @@ static int check_unshare_flags(unsigned long unshare_flags)
|
|
|
CLONE_NEWUSER|CLONE_NEWPID))
|
|
|
return -EINVAL;
|
|
|
/*
|
|
|
- * Not implemented, but pretend it works if there is nothing to
|
|
|
- * unshare. Note that unsharing CLONE_THREAD or CLONE_SIGHAND
|
|
|
- * needs to unshare vm.
|
|
|
+ * Not implemented, but pretend it works if there is nothing
|
|
|
+ * to unshare. Note that unsharing the address space or the
|
|
|
+ * signal handlers also need to unshare the signal queues (aka
|
|
|
+ * CLONE_THREAD).
|
|
|
*/
|
|
|
if (unshare_flags & (CLONE_THREAD | CLONE_SIGHAND | CLONE_VM)) {
|
|
|
- /* FIXME: get_task_mm() increments ->mm_users */
|
|
|
- if (atomic_read(¤t->mm->mm_users) > 1)
|
|
|
+ if (!thread_group_empty(current))
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ if (unshare_flags & (CLONE_SIGHAND | CLONE_VM)) {
|
|
|
+ if (atomic_read(¤t->sighand->count) > 1)
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ if (unshare_flags & CLONE_VM) {
|
|
|
+ if (!current_is_single_threaded())
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
@@ -1940,16 +1948,16 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
|
|
|
*/
|
|
|
if (unshare_flags & CLONE_NEWUSER)
|
|
|
unshare_flags |= CLONE_THREAD | CLONE_FS;
|
|
|
- /*
|
|
|
- * If unsharing a thread from a thread group, must also unshare vm.
|
|
|
- */
|
|
|
- if (unshare_flags & CLONE_THREAD)
|
|
|
- unshare_flags |= CLONE_VM;
|
|
|
/*
|
|
|
* If unsharing vm, must also unshare signal handlers.
|
|
|
*/
|
|
|
if (unshare_flags & CLONE_VM)
|
|
|
unshare_flags |= CLONE_SIGHAND;
|
|
|
+ /*
|
|
|
+ * If unsharing a signal handlers, must also unshare the signal queues.
|
|
|
+ */
|
|
|
+ if (unshare_flags & CLONE_SIGHAND)
|
|
|
+ unshare_flags |= CLONE_THREAD;
|
|
|
/*
|
|
|
* If unsharing namespace, must also unshare filesystem information.
|
|
|
*/
|