Merge branch 'next-general' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[sfrench/cifs-2.6.git] / kernel / seccomp.c
index df27e499956a1a5a816fd31081c15292cdeb6777..a635ecba6fe25a9c5abed70e7d42990b502774cc 100644 (file)
@@ -331,7 +331,7 @@ static int is_ancestor(struct seccomp_filter *parent,
  * Expects sighand and cred_guard_mutex locks to be held.
  *
  * Returns 0 on success, -ve on error, or the pid of a thread which was
- * either not in the correct seccomp mode or it did not have an ancestral
+ * either not in the correct seccomp mode or did not have an ancestral
  * seccomp filter.
  */
 static inline pid_t seccomp_can_sync_threads(void)
@@ -502,7 +502,10 @@ out:
  *
  * Caller must be holding current->sighand->siglock lock.
  *
- * Returns 0 on success, -ve on error.
+ * Returns 0 on success, -ve on error, or
+ *   - in TSYNC mode: the pid of a thread which was either not in the correct
+ *     seccomp mode or did not have an ancestral seccomp filter
+ *   - in NEW_LISTENER mode: the fd of the new listener
  */
 static long seccomp_attach_filter(unsigned int flags,
                                  struct seccomp_filter *filter)
@@ -1258,6 +1261,16 @@ static long seccomp_set_mode_filter(unsigned int flags,
        if (flags & ~SECCOMP_FILTER_FLAG_MASK)
                return -EINVAL;
 
+       /*
+        * In the successful case, NEW_LISTENER returns the new listener fd.
+        * But in the failure case, TSYNC returns the thread that died. If you
+        * combine these two flags, there's no way to tell whether something
+        * succeeded or failed. So, let's disallow this combination.
+        */
+       if ((flags & SECCOMP_FILTER_FLAG_TSYNC) &&
+           (flags & SECCOMP_FILTER_FLAG_NEW_LISTENER))
+               return -EINVAL;
+
        /* Prepare the new filter before holding any locks. */
        prepared = seccomp_prepare_user_filter(filter);
        if (IS_ERR(prepared))
@@ -1304,7 +1317,7 @@ out:
                mutex_unlock(&current->signal->cred_guard_mutex);
 out_put_fd:
        if (flags & SECCOMP_FILTER_FLAG_NEW_LISTENER) {
-               if (ret < 0) {
+               if (ret) {
                        listener_f->private_data = NULL;
                        fput(listener_f);
                        put_unused_fd(listener);