aboutsummaryrefslogtreecommitdiffstats
path: root/security/keys
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2017-11-01 20:47:03 -0400
committerJames Morris <james.l.morris@oracle.com>2017-11-02 05:58:05 -0400
commit3239b6f29bdfb4b0a2ba59df995fc9e6f4df7f1f (patch)
treeaaca6a6994664d8c704b49fd3cc7f995e75007a8 /security/keys
parent3a99df9a3d14cd866b5516f8cba515a3bfd554ab (diff)
KEYS: return full count in keyring_read() if buffer is too small
Commit e645016abc80 ("KEYS: fix writing past end of user-supplied buffer in keyring_read()") made keyring_read() stop corrupting userspace memory when the user-supplied buffer is too small. However it also made the return value in that case be the short buffer size rather than the size required, yet keyctl_read() is actually documented to return the size required. Therefore, switch it over to the documented behavior. Note that for now we continue to have it fill the short buffer, since it did that before (pre-v3.13) and dump_key_tree_aux() in keyutils arguably relies on it. Fixes: e645016abc80 ("KEYS: fix writing past end of user-supplied buffer in keyring_read()") Reported-by: Ben Hutchings <ben@decadent.org.uk> Cc: <stable@vger.kernel.org> # v3.13+ Signed-off-by: Eric Biggers <ebiggers@google.com> Signed-off-by: David Howells <dhowells@redhat.com> Reviewed-by: James Morris <james.l.morris@oracle.com> Signed-off-by: James Morris <james.l.morris@oracle.com>
Diffstat (limited to 'security/keys')
-rw-r--r--security/keys/keyring.c39
1 files changed, 19 insertions, 20 deletions
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index a7e51f793867..36f842ec87f0 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -459,34 +459,33 @@ static long keyring_read(const struct key *keyring,
459 char __user *buffer, size_t buflen) 459 char __user *buffer, size_t buflen)
460{ 460{
461 struct keyring_read_iterator_context ctx; 461 struct keyring_read_iterator_context ctx;
462 unsigned long nr_keys; 462 long ret;
463 int ret;
464 463
465 kenter("{%d},,%zu", key_serial(keyring), buflen); 464 kenter("{%d},,%zu", key_serial(keyring), buflen);
466 465
467 if (buflen & (sizeof(key_serial_t) - 1)) 466 if (buflen & (sizeof(key_serial_t) - 1))
468 return -EINVAL; 467 return -EINVAL;
469 468
470 nr_keys = keyring->keys.nr_leaves_on_tree; 469 /* Copy as many key IDs as fit into the buffer */
471 if (nr_keys == 0) 470 if (buffer && buflen) {
472 return 0; 471 ctx.buffer = (key_serial_t __user *)buffer;
473 472 ctx.buflen = buflen;
474 /* Calculate how much data we could return */ 473 ctx.count = 0;
475 if (!buffer || !buflen) 474 ret = assoc_array_iterate(&keyring->keys,
476 return nr_keys * sizeof(key_serial_t); 475 keyring_read_iterator, &ctx);
477 476 if (ret < 0) {
478 /* Copy the IDs of the subscribed keys into the buffer */ 477 kleave(" = %ld [iterate]", ret);
479 ctx.buffer = (key_serial_t __user *)buffer; 478 return ret;
480 ctx.buflen = buflen; 479 }
481 ctx.count = 0;
482 ret = assoc_array_iterate(&keyring->keys, keyring_read_iterator, &ctx);
483 if (ret < 0) {
484 kleave(" = %d [iterate]", ret);
485 return ret;
486 } 480 }
487 481
488 kleave(" = %zu [ok]", ctx.count); 482 /* Return the size of the buffer needed */
489 return ctx.count; 483 ret = keyring->keys.nr_leaves_on_tree * sizeof(key_serial_t);
484 if (ret <= buflen)
485 kleave("= %ld [ok]", ret);
486 else
487 kleave("= %ld [buffer too small]", ret);
488 return ret;
490} 489}
491 490
492/* 491/*