Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[firefly-linux-kernel-4.4.55.git] / security / keys / compat.c
index 792c0a611a6d115a5a272ca748af6c1804c762ef..338b510e90275b1da873ed83aa907c404997d353 100644 (file)
@@ -1,4 +1,4 @@
-/* compat.c: 32-bit compatibility syscall for 64-bit systems
+/* 32-bit compatibility syscall for 64-bit systems
  *
  * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
 #include <linux/syscalls.h>
 #include <linux/keyctl.h>
 #include <linux/compat.h>
+#include <linux/slab.h>
 #include "internal.h"
 
-/*****************************************************************************/
 /*
- * the key control system call, 32-bit compatibility version for 64-bit archs
- * - this should only be called if the 64-bit arch uses weird pointers in
- *   32-bit mode or doesn't guarantee that the top 32-bits of the argument
- *   registers on taking a 32-bit syscall are zero
- * - if you can, you should call sys_keyctl directly
+ * Instantiate a key with the specified compatibility multipart payload and
+ * link the key into the destination keyring if one is given.
+ *
+ * The caller must have the appropriate instantiation permit set for this to
+ * work (see keyctl_assume_authority).  No other permissions are required.
+ *
+ * If successful, 0 will be returned.
+ */
+long compat_keyctl_instantiate_key_iov(
+       key_serial_t id,
+       const struct compat_iovec __user *_payload_iov,
+       unsigned ioc,
+       key_serial_t ringid)
+{
+       struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
+       long ret;
+
+       if (_payload_iov == 0 || ioc == 0)
+               goto no_payload;
+
+       ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc,
+                                          ARRAY_SIZE(iovstack),
+                                          iovstack, &iov);
+       if (ret < 0)
+               return ret;
+       if (ret == 0)
+               goto no_payload_free;
+
+       ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid);
+
+       if (iov != iovstack)
+               kfree(iov);
+       return ret;
+
+no_payload_free:
+       if (iov != iovstack)
+               kfree(iov);
+no_payload:
+       return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
+}
+
+/*
+ * The key control system call, 32-bit compatibility version for 64-bit archs
+ *
+ * This should only be called if the 64-bit arch uses weird pointers in 32-bit
+ * mode or doesn't guarantee that the top 32-bits of the argument registers on
+ * taking a 32-bit syscall are zero.  If you can, you should call sys_keyctl()
+ * directly.
  */
 asmlinkage long compat_sys_keyctl(u32 option,
                                  u32 arg2, u32 arg3, u32 arg4, u32 arg5)
@@ -85,8 +128,14 @@ asmlinkage long compat_sys_keyctl(u32 option,
        case KEYCTL_SESSION_TO_PARENT:
                return keyctl_session_to_parent();
 
+       case KEYCTL_REJECT:
+               return keyctl_reject_key(arg2, arg3, arg4, arg5);
+
+       case KEYCTL_INSTANTIATE_IOV:
+               return compat_keyctl_instantiate_key_iov(
+                       arg2, compat_ptr(arg3), arg4, arg5);
+
        default:
                return -EOPNOTSUPP;
        }
-
-} /* end compat_sys_keyctl() */
+}