aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2010-11-30 03:49:02 -0500
committerHerbert Xu <herbert@gondor.apana.org.au>2010-11-30 03:49:02 -0500
commit0f6bb83cb12e4617e696ffa566f3fc6c092686e2 (patch)
treec871ab8acedb25ba19de73be427620af8475236d
parent7451708f39db19a8303bb7fb95f00aca9f673cb5 (diff)
crypto: algif_skcipher - Fixed overflow when sndbuf is page aligned
When sk_sndbuf is not a multiple of PAGE_SIZE, the limit tests in sendmsg fail as the limit variable becomes negative and we're using an unsigned comparison. The same thing can happen if sk_sndbuf is lowered after a sendmsg call. This patch fixes this by always taking the signed maximum of limit and 0 before we perform the comparison. It also rounds the value of sk_sndbuf down to a multiple of PAGE_SIZE so that we don't end up allocating a page only to use a small number of bytes in it because we're bound by sk_sndbuf. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--crypto/algif_skcipher.c32
1 files changed, 11 insertions, 21 deletions
diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
index 9b2f440e88a6..1f33480e3260 100644
--- a/crypto/algif_skcipher.c
+++ b/crypto/algif_skcipher.c
@@ -52,12 +52,18 @@ struct skcipher_ctx {
52#define MAX_SGL_ENTS ((PAGE_SIZE - sizeof(struct skcipher_sg_list)) / \ 52#define MAX_SGL_ENTS ((PAGE_SIZE - sizeof(struct skcipher_sg_list)) / \
53 sizeof(struct scatterlist) - 1) 53 sizeof(struct scatterlist) - 1)
54 54
55static inline bool skcipher_writable(struct sock *sk) 55static inline int skcipher_sndbuf(struct sock *sk)
56{ 56{
57 struct alg_sock *ask = alg_sk(sk); 57 struct alg_sock *ask = alg_sk(sk);
58 struct skcipher_ctx *ctx = ask->private; 58 struct skcipher_ctx *ctx = ask->private;
59 59
60 return ctx->used + PAGE_SIZE <= max_t(int, sk->sk_sndbuf, PAGE_SIZE); 60 return max_t(int, max_t(int, sk->sk_sndbuf & PAGE_MASK, PAGE_SIZE) -
61 ctx->used, 0);
62}
63
64static inline bool skcipher_writable(struct sock *sk)
65{
66 return PAGE_SIZE <= skcipher_sndbuf(sk);
61} 67}
62 68
63static int skcipher_alloc_sgl(struct sock *sk) 69static int skcipher_alloc_sgl(struct sock *sk)
@@ -245,7 +251,6 @@ static int skcipher_sendmsg(struct kiocb *unused, struct socket *sock,
245 struct af_alg_control con = {}; 251 struct af_alg_control con = {};
246 long copied = 0; 252 long copied = 0;
247 bool enc = 0; 253 bool enc = 0;
248 int limit;
249 int err; 254 int err;
250 int i; 255 int i;
251 256
@@ -281,9 +286,6 @@ static int skcipher_sendmsg(struct kiocb *unused, struct socket *sock,
281 memcpy(ctx->iv, con.iv->iv, ivsize); 286 memcpy(ctx->iv, con.iv->iv, ivsize);
282 } 287 }
283 288
284 limit = max_t(int, sk->sk_sndbuf, PAGE_SIZE);
285 limit -= ctx->used;
286
287 while (size) { 289 while (size) {
288 struct scatterlist *sg; 290 struct scatterlist *sg;
289 unsigned long len = size; 291 unsigned long len = size;
@@ -309,20 +311,16 @@ static int skcipher_sendmsg(struct kiocb *unused, struct socket *sock,
309 ctx->used += len; 311 ctx->used += len;
310 copied += len; 312 copied += len;
311 size -= len; 313 size -= len;
312 limit -= len;
313 continue; 314 continue;
314 } 315 }
315 316
316 if (limit < PAGE_SIZE) { 317 if (!skcipher_writable(sk)) {
317 err = skcipher_wait_for_wmem(sk, msg->msg_flags); 318 err = skcipher_wait_for_wmem(sk, msg->msg_flags);
318 if (err) 319 if (err)
319 goto unlock; 320 goto unlock;
320
321 limit = max_t(int, sk->sk_sndbuf, PAGE_SIZE);
322 limit -= ctx->used;
323 } 321 }
324 322
325 len = min_t(unsigned long, len, limit); 323 len = min_t(unsigned long, len, skcipher_sndbuf(sk));
326 324
327 err = skcipher_alloc_sgl(sk); 325 err = skcipher_alloc_sgl(sk);
328 if (err) 326 if (err)
@@ -352,7 +350,6 @@ static int skcipher_sendmsg(struct kiocb *unused, struct socket *sock,
352 ctx->used += plen; 350 ctx->used += plen;
353 copied += plen; 351 copied += plen;
354 size -= plen; 352 size -= plen;
355 limit -= plen;
356 sgl->cur++; 353 sgl->cur++;
357 } while (len && sgl->cur < MAX_SGL_ENTS); 354 } while (len && sgl->cur < MAX_SGL_ENTS);
358 355
@@ -380,7 +377,6 @@ static ssize_t skcipher_sendpage(struct socket *sock, struct page *page,
380 struct skcipher_ctx *ctx = ask->private; 377 struct skcipher_ctx *ctx = ask->private;
381 struct skcipher_sg_list *sgl; 378 struct skcipher_sg_list *sgl;
382 int err = -EINVAL; 379 int err = -EINVAL;
383 int limit;
384 380
385 lock_sock(sk); 381 lock_sock(sk);
386 if (!ctx->more && ctx->used) 382 if (!ctx->more && ctx->used)
@@ -389,16 +385,10 @@ static ssize_t skcipher_sendpage(struct socket *sock, struct page *page,
389 if (!size) 385 if (!size)
390 goto done; 386 goto done;
391 387
392 limit = max_t(int, sk->sk_sndbuf, PAGE_SIZE); 388 if (!skcipher_writable(sk)) {
393 limit -= ctx->used;
394
395 if (limit < PAGE_SIZE) {
396 err = skcipher_wait_for_wmem(sk, flags); 389 err = skcipher_wait_for_wmem(sk, flags);
397 if (err) 390 if (err)
398 goto unlock; 391 goto unlock;
399
400 limit = max_t(int, sk->sk_sndbuf, PAGE_SIZE);
401 limit -= ctx->used;
402 } 392 }
403 393
404 err = skcipher_alloc_sgl(sk); 394 err = skcipher_alloc_sgl(sk);