mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-17 13:58:46 +00:00
KEYS: Add an iovec version of KEYCTL_INSTANTIATE
Add a keyctl op (KEYCTL_INSTANTIATE_IOV) that is like KEYCTL_INSTANTIATE, but takes an iovec array and concatenates the data in-kernel into one buffer. Since the KEYCTL_INSTANTIATE copies the data anyway, this isn't too much of a problem. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: James Morris <jmorris@namei.org>
This commit is contained in:
parent
fdd1b94581
commit
ee009e4a0d
@ -637,6 +637,9 @@ The keyctl syscall functions are:
|
|||||||
long keyctl(KEYCTL_INSTANTIATE, key_serial_t key,
|
long keyctl(KEYCTL_INSTANTIATE, key_serial_t key,
|
||||||
const void *payload, size_t plen,
|
const void *payload, size_t plen,
|
||||||
key_serial_t keyring);
|
key_serial_t keyring);
|
||||||
|
long keyctl(KEYCTL_INSTANTIATE_IOV, key_serial_t key,
|
||||||
|
const struct iovec *payload_iov, unsigned ioc,
|
||||||
|
key_serial_t keyring);
|
||||||
|
|
||||||
If the kernel calls back to userspace to complete the instantiation of a
|
If the kernel calls back to userspace to complete the instantiation of a
|
||||||
key, userspace should use this call to supply data for the key before the
|
key, userspace should use this call to supply data for the key before the
|
||||||
@ -652,6 +655,9 @@ The keyctl syscall functions are:
|
|||||||
|
|
||||||
The payload and plen arguments describe the payload data as for add_key().
|
The payload and plen arguments describe the payload data as for add_key().
|
||||||
|
|
||||||
|
The payload_iov and ioc arguments describe the payload data in an iovec
|
||||||
|
array instead of a single buffer.
|
||||||
|
|
||||||
|
|
||||||
(*) Negatively instantiate a partially constructed key.
|
(*) Negatively instantiate a partially constructed key.
|
||||||
|
|
||||||
@ -1244,10 +1250,11 @@ hand the request off to (perhaps a path held in placed in another key by, for
|
|||||||
example, the KDE desktop manager).
|
example, the KDE desktop manager).
|
||||||
|
|
||||||
The program (or whatever it calls) should finish construction of the key by
|
The program (or whatever it calls) should finish construction of the key by
|
||||||
calling KEYCTL_INSTANTIATE, which also permits it to cache the key in one of
|
calling KEYCTL_INSTANTIATE or KEYCTL_INSTANTIATE_IOV, which also permits it to
|
||||||
the keyrings (probably the session ring) before returning. Alternatively, the
|
cache the key in one of the keyrings (probably the session ring) before
|
||||||
key can be marked as negative with KEYCTL_NEGATE or KEYCTL_REJECT; this also
|
returning. Alternatively, the key can be marked as negative with KEYCTL_NEGATE
|
||||||
permits the key to be cached in one of the keyrings.
|
or KEYCTL_REJECT; this also permits the key to be cached in one of the
|
||||||
|
keyrings.
|
||||||
|
|
||||||
If it returns with the key remaining in the unconstructed state, the key will
|
If it returns with the key remaining in the unconstructed state, the key will
|
||||||
be marked as being negative, it will be added to the session keyring, and an
|
be marked as being negative, it will be added to the session keyring, and an
|
||||||
|
@ -2138,6 +2138,11 @@ config SYSVIPC_COMPAT
|
|||||||
def_bool y
|
def_bool y
|
||||||
depends on COMPAT && SYSVIPC
|
depends on COMPAT && SYSVIPC
|
||||||
|
|
||||||
|
config KEYS_COMPAT
|
||||||
|
bool
|
||||||
|
depends on COMPAT && KEYS
|
||||||
|
default y
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,5 +54,6 @@
|
|||||||
#define KEYCTL_GET_SECURITY 17 /* get key security label */
|
#define KEYCTL_GET_SECURITY 17 /* get key security label */
|
||||||
#define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */
|
#define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */
|
||||||
#define KEYCTL_REJECT 19 /* reject a partially constructed key */
|
#define KEYCTL_REJECT 19 /* reject a partially constructed key */
|
||||||
|
#define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */
|
||||||
|
|
||||||
#endif /* _LINUX_KEYCTL_H */
|
#endif /* _LINUX_KEYCTL_H */
|
||||||
|
@ -12,8 +12,51 @@
|
|||||||
#include <linux/syscalls.h>
|
#include <linux/syscalls.h>
|
||||||
#include <linux/keyctl.h>
|
#include <linux/keyctl.h>
|
||||||
#include <linux/compat.h>
|
#include <linux/compat.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
* The key control system call, 32-bit compatibility version for 64-bit archs
|
||||||
*
|
*
|
||||||
@ -88,6 +131,10 @@ asmlinkage long compat_sys_keyctl(u32 option,
|
|||||||
case KEYCTL_REJECT:
|
case KEYCTL_REJECT:
|
||||||
return keyctl_reject_key(arg2, arg3, arg4, arg5);
|
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:
|
default:
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
@ -215,6 +215,13 @@ extern long keyctl_get_security(key_serial_t keyid, char __user *buffer,
|
|||||||
size_t buflen);
|
size_t buflen);
|
||||||
extern long keyctl_session_to_parent(void);
|
extern long keyctl_session_to_parent(void);
|
||||||
extern long keyctl_reject_key(key_serial_t, unsigned, unsigned, key_serial_t);
|
extern long keyctl_reject_key(key_serial_t, unsigned, unsigned, key_serial_t);
|
||||||
|
extern long keyctl_instantiate_key_iov(key_serial_t,
|
||||||
|
const struct iovec __user *,
|
||||||
|
unsigned, key_serial_t);
|
||||||
|
|
||||||
|
extern long keyctl_instantiate_key_common(key_serial_t,
|
||||||
|
const struct iovec __user *,
|
||||||
|
unsigned, size_t, key_serial_t);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Debugging key validation
|
* Debugging key validation
|
||||||
|
@ -912,6 +912,21 @@ static int keyctl_change_reqkey_auth(struct key *key)
|
|||||||
return commit_creds(new);
|
return commit_creds(new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy the iovec data from userspace
|
||||||
|
*/
|
||||||
|
static long copy_from_user_iovec(void *buffer, const struct iovec *iov,
|
||||||
|
unsigned ioc)
|
||||||
|
{
|
||||||
|
for (; ioc > 0; ioc--) {
|
||||||
|
if (copy_from_user(buffer, iov->iov_base, iov->iov_len) != 0)
|
||||||
|
return -EFAULT;
|
||||||
|
buffer += iov->iov_len;
|
||||||
|
iov++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Instantiate a key with the specified payload and link the key into the
|
* Instantiate a key with the specified payload and link the key into the
|
||||||
* destination keyring if one is given.
|
* destination keyring if one is given.
|
||||||
@ -921,8 +936,9 @@ static int keyctl_change_reqkey_auth(struct key *key)
|
|||||||
*
|
*
|
||||||
* If successful, 0 will be returned.
|
* If successful, 0 will be returned.
|
||||||
*/
|
*/
|
||||||
long keyctl_instantiate_key(key_serial_t id,
|
long keyctl_instantiate_key_common(key_serial_t id,
|
||||||
const void __user *_payload,
|
const struct iovec *payload_iov,
|
||||||
|
unsigned ioc,
|
||||||
size_t plen,
|
size_t plen,
|
||||||
key_serial_t ringid)
|
key_serial_t ringid)
|
||||||
{
|
{
|
||||||
@ -953,7 +969,7 @@ long keyctl_instantiate_key(key_serial_t id,
|
|||||||
/* pull the payload in if one was supplied */
|
/* pull the payload in if one was supplied */
|
||||||
payload = NULL;
|
payload = NULL;
|
||||||
|
|
||||||
if (_payload) {
|
if (payload_iov) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
payload = kmalloc(plen, GFP_KERNEL);
|
payload = kmalloc(plen, GFP_KERNEL);
|
||||||
if (!payload) {
|
if (!payload) {
|
||||||
@ -965,8 +981,8 @@ long keyctl_instantiate_key(key_serial_t id,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = -EFAULT;
|
ret = copy_from_user_iovec(payload, payload_iov, ioc);
|
||||||
if (copy_from_user(payload, _payload, plen) != 0)
|
if (ret < 0)
|
||||||
goto error2;
|
goto error2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -996,6 +1012,72 @@ error:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Instantiate a key with the specified 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 keyctl_instantiate_key(key_serial_t id,
|
||||||
|
const void __user *_payload,
|
||||||
|
size_t plen,
|
||||||
|
key_serial_t ringid)
|
||||||
|
{
|
||||||
|
if (_payload && plen) {
|
||||||
|
struct iovec iov[1] = {
|
||||||
|
[0].iov_base = (void __user *)_payload,
|
||||||
|
[0].iov_len = plen
|
||||||
|
};
|
||||||
|
|
||||||
|
return keyctl_instantiate_key_common(id, iov, 1, plen, ringid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Instantiate a key with the specified 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 keyctl_instantiate_key_iov(key_serial_t id,
|
||||||
|
const struct 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 = 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);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Negatively instantiate the key with the given timeout (in seconds) and link
|
* Negatively instantiate the key with the given timeout (in seconds) and link
|
||||||
* the key into the destination keyring if one is given.
|
* the key into the destination keyring if one is given.
|
||||||
@ -1528,6 +1610,13 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
|
|||||||
(unsigned) arg4,
|
(unsigned) arg4,
|
||||||
(key_serial_t) arg5);
|
(key_serial_t) arg5);
|
||||||
|
|
||||||
|
case KEYCTL_INSTANTIATE_IOV:
|
||||||
|
return keyctl_instantiate_key_iov(
|
||||||
|
(key_serial_t) arg2,
|
||||||
|
(const struct iovec __user *) arg3,
|
||||||
|
(unsigned) arg4,
|
||||||
|
(key_serial_t) arg5);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user