summaryrefslogtreecommitdiff
path: root/security/keys/keyctl.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-04-14 15:31:03 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2015-04-14 15:31:03 -0700
commitca2ec32658db160745990496f0f4580056a5dc9f (patch)
treed211f239219c85214da46dc1cbad4184a81d0248 /security/keys/keyctl.c
parent6c8a53c9e6a151fffb07f8b4c34bd1e33dddd467 (diff)
parentfdc81f45e9f57858da6351836507fbcf1b7583ee (diff)
Merge branch 'for-linus-1' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs update from Al Viro: "Part one: - struct filename-related cleanups - saner iov_iter_init() replacements (and switching the syscalls to use of those) - ntfs switch to ->write_iter() (Anton) - aio cleanups and splitting iocb into common and async parts (Christoph) - assorted fixes (me, bfields, Andrew Elble) There's a lot more, including the completion of switchover to ->{read,write}_iter(), d_inode/d_backing_inode annotations, f_flags race fixes, etc, but that goes after #for-davem merge. David has pulled it, and once it's in I'll send the next vfs pull request" * 'for-linus-1' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (35 commits) sg_start_req(): use import_iovec() sg_start_req(): make sure that there's not too many elements in iovec blk_rq_map_user(): use import_single_range() sg_io(): use import_iovec() process_vm_access: switch to {compat_,}import_iovec() switch keyctl_instantiate_key_common() to iov_iter switch {compat_,}do_readv_writev() to {compat_,}import_iovec() aio_setup_vectored_rw(): switch to {compat_,}import_iovec() vmsplice_to_user(): switch to import_iovec() kill aio_setup_single_vector() aio: simplify arguments of aio_setup_..._rw() aio: lift iov_iter_init() into aio_setup_..._rw() lift iov_iter into {compat_,}do_readv_writev() NFS: fix BUG() crash in notify_change() with patch to chown_common() dcache: return -ESTALE not -EBUSY on distributed fs race NTFS: Version 2.1.32 - Update file write from aio_write to write_iter. VFS: Add iov_iter_fault_in_multipages_readable() drop bogus check in file_open_root() switch security_inode_getattr() to struct path * constify tomoyo_realpath_from_path() ...
Diffstat (limited to 'security/keys/keyctl.c')
-rw-r--r--security/keys/keyctl.c78
1 files changed, 27 insertions, 51 deletions
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 4743d71e4aa6..0b9ec78a7a7a 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -998,21 +998,6 @@ static int keyctl_change_reqkey_auth(struct key *key)
}
/*
- * 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
* destination keyring if one is given.
*
@@ -1022,20 +1007,21 @@ static long copy_from_user_iovec(void *buffer, const struct iovec *iov,
* If successful, 0 will be returned.
*/
long keyctl_instantiate_key_common(key_serial_t id,
- const struct iovec *payload_iov,
- unsigned ioc,
- size_t plen,
+ struct iov_iter *from,
key_serial_t ringid)
{
const struct cred *cred = current_cred();
struct request_key_auth *rka;
struct key *instkey, *dest_keyring;
+ size_t plen = from ? iov_iter_count(from) : 0;
void *payload;
long ret;
- bool vm = false;
kenter("%d,,%zu,%d", id, plen, ringid);
+ if (!plen)
+ from = NULL;
+
ret = -EINVAL;
if (plen > 1024 * 1024 - 1)
goto error;
@@ -1054,20 +1040,19 @@ long keyctl_instantiate_key_common(key_serial_t id,
/* pull the payload in if one was supplied */
payload = NULL;
- if (payload_iov) {
+ if (from) {
ret = -ENOMEM;
payload = kmalloc(plen, GFP_KERNEL);
if (!payload) {
if (plen <= PAGE_SIZE)
goto error;
- vm = true;
payload = vmalloc(plen);
if (!payload)
goto error;
}
- ret = copy_from_user_iovec(payload, payload_iov, ioc);
- if (ret < 0)
+ ret = -EFAULT;
+ if (copy_from_iter(payload, plen, from) != plen)
goto error2;
}
@@ -1089,10 +1074,7 @@ long keyctl_instantiate_key_common(key_serial_t id,
keyctl_change_reqkey_auth(NULL);
error2:
- if (!vm)
- kfree(payload);
- else
- vfree(payload);
+ kvfree(payload);
error:
return ret;
}
@@ -1112,15 +1094,19 @@ long keyctl_instantiate_key(key_serial_t id,
key_serial_t ringid)
{
if (_payload && plen) {
- struct iovec iov[1] = {
- [0].iov_base = (void __user *)_payload,
- [0].iov_len = plen
- };
+ struct iovec iov;
+ struct iov_iter from;
+ int ret;
- return keyctl_instantiate_key_common(id, iov, 1, plen, ringid);
+ ret = import_single_range(WRITE, (void __user *)_payload, plen,
+ &iov, &from);
+ if (unlikely(ret))
+ return ret;
+
+ return keyctl_instantiate_key_common(id, &from, ringid);
}
- return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
+ return keyctl_instantiate_key_common(id, NULL, ringid);
}
/*
@@ -1138,29 +1124,19 @@ long keyctl_instantiate_key_iov(key_serial_t id,
key_serial_t ringid)
{
struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
+ struct iov_iter from;
long ret;
- if (!_payload_iov || !ioc)
- goto no_payload;
+ if (!_payload_iov)
+ ioc = 0;
- ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc,
- ARRAY_SIZE(iovstack), iovstack, &iov);
+ ret = import_iovec(WRITE, _payload_iov, ioc,
+ ARRAY_SIZE(iovstack), &iov, &from);
if (ret < 0)
- goto err;
- if (ret == 0)
- goto no_payload_free;
-
- ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid);
-err:
- if (iov != iovstack)
- kfree(iov);
+ return ret;
+ ret = keyctl_instantiate_key_common(id, &from, ringid);
+ kfree(iov);
return ret;
-
-no_payload_free:
- if (iov != iovstack)
- kfree(iov);
-no_payload:
- return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
}
/*