switch keyctl_instantiate_key_common() to iov_iter

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2015-03-17 09:59:38 -04:00
Родитель 0504c074b5
Коммит b353a1f7bb
3 изменённых файлов: 39 добавлений и 71 удалений

Просмотреть файл

@ -31,30 +31,21 @@ static long compat_keyctl_instantiate_key_iov(
key_serial_t ringid) key_serial_t ringid)
{ {
struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
struct iov_iter from;
long ret; long ret;
if (!_payload_iov || !ioc) if (!_payload_iov)
goto no_payload; ioc = 0;
ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc, ret = compat_import_iovec(WRITE, _payload_iov, ioc,
ARRAY_SIZE(iovstack), ARRAY_SIZE(iovstack), &iov,
iovstack, &iov); &from);
if (ret < 0) if (ret < 0)
goto err; return ret;
if (ret == 0)
goto no_payload_free;
ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid); ret = keyctl_instantiate_key_common(id, &from, ringid);
err: kfree(iov);
if (iov != iovstack)
kfree(iov);
return ret; return ret;
no_payload_free:
if (iov != iovstack)
kfree(iov);
no_payload:
return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
} }
/* /*

Просмотреть файл

@ -243,9 +243,10 @@ extern long keyctl_instantiate_key_iov(key_serial_t,
unsigned, key_serial_t); unsigned, key_serial_t);
extern long keyctl_invalidate_key(key_serial_t); extern long keyctl_invalidate_key(key_serial_t);
struct iov_iter;
extern long keyctl_instantiate_key_common(key_serial_t, extern long keyctl_instantiate_key_common(key_serial_t,
const struct iovec *, struct iov_iter *,
unsigned, size_t, key_serial_t); key_serial_t);
#ifdef CONFIG_PERSISTENT_KEYRINGS #ifdef CONFIG_PERSISTENT_KEYRINGS
extern long keyctl_get_persistent(uid_t, key_serial_t); extern long keyctl_get_persistent(uid_t, key_serial_t);
extern unsigned persistent_keyring_expiry; extern unsigned persistent_keyring_expiry;

Просмотреть файл

@ -997,21 +997,6 @@ 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.
@ -1022,20 +1007,21 @@ static long copy_from_user_iovec(void *buffer, const struct iovec *iov,
* If successful, 0 will be returned. * If successful, 0 will be returned.
*/ */
long keyctl_instantiate_key_common(key_serial_t id, long keyctl_instantiate_key_common(key_serial_t id,
const struct iovec *payload_iov, struct iov_iter *from,
unsigned ioc,
size_t plen,
key_serial_t ringid) key_serial_t ringid)
{ {
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
struct request_key_auth *rka; struct request_key_auth *rka;
struct key *instkey, *dest_keyring; struct key *instkey, *dest_keyring;
size_t plen = from ? iov_iter_count(from) : 0;
void *payload; void *payload;
long ret; long ret;
bool vm = false;
kenter("%d,,%zu,%d", id, plen, ringid); kenter("%d,,%zu,%d", id, plen, ringid);
if (!plen)
from = NULL;
ret = -EINVAL; ret = -EINVAL;
if (plen > 1024 * 1024 - 1) if (plen > 1024 * 1024 - 1)
goto error; goto error;
@ -1054,20 +1040,19 @@ long keyctl_instantiate_key_common(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_iov) { if (from) {
ret = -ENOMEM; ret = -ENOMEM;
payload = kmalloc(plen, GFP_KERNEL); payload = kmalloc(plen, GFP_KERNEL);
if (!payload) { if (!payload) {
if (plen <= PAGE_SIZE) if (plen <= PAGE_SIZE)
goto error; goto error;
vm = true;
payload = vmalloc(plen); payload = vmalloc(plen);
if (!payload) if (!payload)
goto error; goto error;
} }
ret = copy_from_user_iovec(payload, payload_iov, ioc); ret = -EFAULT;
if (ret < 0) if (copy_from_iter(payload, plen, from) != plen)
goto error2; goto error2;
} }
@ -1089,10 +1074,7 @@ long keyctl_instantiate_key_common(key_serial_t id,
keyctl_change_reqkey_auth(NULL); keyctl_change_reqkey_auth(NULL);
error2: error2:
if (!vm) kvfree(payload);
kfree(payload);
else
vfree(payload);
error: error:
return ret; return ret;
} }
@ -1112,15 +1094,19 @@ long keyctl_instantiate_key(key_serial_t id,
key_serial_t ringid) key_serial_t ringid)
{ {
if (_payload && plen) { if (_payload && plen) {
struct iovec iov[1] = { struct iovec iov;
[0].iov_base = (void __user *)_payload, struct iov_iter from;
[0].iov_len = plen 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) key_serial_t ringid)
{ {
struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
struct iov_iter from;
long ret; long ret;
if (!_payload_iov || !ioc) if (!_payload_iov)
goto no_payload; ioc = 0;
ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc, ret = import_iovec(WRITE, _payload_iov, ioc,
ARRAY_SIZE(iovstack), iovstack, &iov); ARRAY_SIZE(iovstack), &iov, &from);
if (ret < 0) if (ret < 0)
goto err; return ret;
if (ret == 0) ret = keyctl_instantiate_key_common(id, &from, ringid);
goto no_payload_free; kfree(iov);
ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid);
err:
if (iov != iovstack)
kfree(iov);
return ret; return ret;
no_payload_free:
if (iov != iovstack)
kfree(iov);
no_payload:
return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
} }
/* /*