summaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2018-12-06 18:55:41 -0500
committerHerbert Xu <herbert@gondor.apana.org.au>2018-12-13 05:24:59 -0500
commit0ac6b8fb23c724b015d9ca70a89126e8d1563166 (patch)
treeed59c82594a57217ce411dec12cebe049fa78f8b /crypto
parentc6018e1a00b5c70610cdfb3650cc5622c917ed17 (diff)
crypto: user - support incremental algorithm dumps
CRYPTO_MSG_GETALG in NLM_F_DUMP mode sometimes doesn't return all registered crypto algorithms, because it doesn't support incremental dumps. crypto_dump_report() only permits itself to be called once, yet the netlink subsystem allocates at most ~64 KiB for the skb being dumped to. Thus only the first recvmsg() returns data, and it may only include a subset of the crypto algorithms even if the user buffer passed to recvmsg() is large enough to hold all of them. Fix this by using one of the arguments in the netlink_callback structure to keep track of the current position in the algorithm list. Then userspace can do multiple recvmsg() on the socket after sending the dump request. This is the way netlink dumps work elsewhere in the kernel; it's unclear why this was different (probably just an oversight). Also fix an integer overflow when calculating the dump buffer size hint. Fixes: a38f7907b926 ("crypto: Add userspace configuration API") Signed-off-by: Eric Biggers <ebiggers@google.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto')
-rw-r--r--crypto/crypto_user_base.c37
1 files changed, 20 insertions, 17 deletions
diff --git a/crypto/crypto_user_base.c b/crypto/crypto_user_base.c
index 7021efbb35a1..5311fd7fae34 100644
--- a/crypto/crypto_user_base.c
+++ b/crypto/crypto_user_base.c
@@ -231,30 +231,33 @@ drop_alg:
231 231
232static int crypto_dump_report(struct sk_buff *skb, struct netlink_callback *cb) 232static int crypto_dump_report(struct sk_buff *skb, struct netlink_callback *cb)
233{ 233{
234 struct crypto_alg *alg; 234 const size_t start_pos = cb->args[0];
235 size_t pos = 0;
235 struct crypto_dump_info info; 236 struct crypto_dump_info info;
236 int err; 237 struct crypto_alg *alg;
237 238 int res;
238 if (cb->args[0])
239 goto out;
240
241 cb->args[0] = 1;
242 239
243 info.in_skb = cb->skb; 240 info.in_skb = cb->skb;
244 info.out_skb = skb; 241 info.out_skb = skb;
245 info.nlmsg_seq = cb->nlh->nlmsg_seq; 242 info.nlmsg_seq = cb->nlh->nlmsg_seq;
246 info.nlmsg_flags = NLM_F_MULTI; 243 info.nlmsg_flags = NLM_F_MULTI;
247 244
245 down_read(&crypto_alg_sem);
248 list_for_each_entry(alg, &crypto_alg_list, cra_list) { 246 list_for_each_entry(alg, &crypto_alg_list, cra_list) {
249 err = crypto_report_alg(alg, &info); 247 if (pos >= start_pos) {
250 if (err) 248 res = crypto_report_alg(alg, &info);
251 goto out_err; 249 if (res == -EMSGSIZE)
250 break;
251 if (res)
252 goto out;
253 }
254 pos++;
252 } 255 }
253 256 cb->args[0] = pos;
257 res = skb->len;
254out: 258out:
255 return skb->len; 259 up_read(&crypto_alg_sem);
256out_err: 260 return res;
257 return err;
258} 261}
259 262
260static int crypto_dump_report_done(struct netlink_callback *cb) 263static int crypto_dump_report_done(struct netlink_callback *cb)
@@ -442,7 +445,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
442 if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) && 445 if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) &&
443 (nlh->nlmsg_flags & NLM_F_DUMP))) { 446 (nlh->nlmsg_flags & NLM_F_DUMP))) {
444 struct crypto_alg *alg; 447 struct crypto_alg *alg;
445 u16 dump_alloc = 0; 448 unsigned long dump_alloc = 0;
446 449
447 if (link->dump == NULL) 450 if (link->dump == NULL)
448 return -EINVAL; 451 return -EINVAL;
@@ -450,16 +453,16 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
450 down_read(&crypto_alg_sem); 453 down_read(&crypto_alg_sem);
451 list_for_each_entry(alg, &crypto_alg_list, cra_list) 454 list_for_each_entry(alg, &crypto_alg_list, cra_list)
452 dump_alloc += CRYPTO_REPORT_MAXSIZE; 455 dump_alloc += CRYPTO_REPORT_MAXSIZE;
456 up_read(&crypto_alg_sem);
453 457
454 { 458 {
455 struct netlink_dump_control c = { 459 struct netlink_dump_control c = {
456 .dump = link->dump, 460 .dump = link->dump,
457 .done = link->done, 461 .done = link->done,
458 .min_dump_alloc = dump_alloc, 462 .min_dump_alloc = min(dump_alloc, 65535UL),
459 }; 463 };
460 err = netlink_dump_start(crypto_nlsk, skb, nlh, &c); 464 err = netlink_dump_start(crypto_nlsk, skb, nlh, &c);
461 } 465 }
462 up_read(&crypto_alg_sem);
463 466
464 return err; 467 return err;
465 } 468 }