diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-10-28 18:18:00 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-10-28 18:53:21 -0400 |
commit | 9d3a2260f0f4bd6379b0a0f131c743fff25b0029 (patch) | |
tree | 52e223ce02fc746865cac4bbce64b433fde53613 /net/sunrpc/auth_gss | |
parent | 5fccc5b52ee07d07a74ce53c6f174bff81e26a16 (diff) |
SUNRPC: Fix buffer overflow checking in gss_encode_v0_msg/gss_encode_v1_msg
In gss_encode_v1_msg, it is pointless to BUG() after the overflow has
happened. Replace the existing sprintf()-based code with scnprintf(),
and warn if an overflow is ever triggered.
In gss_encode_v0_msg, replace the runtime BUG_ON() with an appropriate
compile-time BUILD_BUG_ON.
Reported-by: Bruce Fields <bfields@fieldses.org>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc/auth_gss')
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 56 |
1 files changed, 37 insertions, 19 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index cc24323d3045..97912b40c254 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -420,41 +420,53 @@ static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg) | |||
420 | memcpy(gss_msg->databuf, &uid, sizeof(uid)); | 420 | memcpy(gss_msg->databuf, &uid, sizeof(uid)); |
421 | gss_msg->msg.data = gss_msg->databuf; | 421 | gss_msg->msg.data = gss_msg->databuf; |
422 | gss_msg->msg.len = sizeof(uid); | 422 | gss_msg->msg.len = sizeof(uid); |
423 | BUG_ON(sizeof(uid) > UPCALL_BUF_LEN); | 423 | |
424 | BUILD_BUG_ON(sizeof(uid) > sizeof(gss_msg->databuf)); | ||
424 | } | 425 | } |
425 | 426 | ||
426 | static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg, | 427 | static int gss_encode_v1_msg(struct gss_upcall_msg *gss_msg, |
427 | const char *service_name, | 428 | const char *service_name, |
428 | const char *target_name) | 429 | const char *target_name) |
429 | { | 430 | { |
430 | struct gss_api_mech *mech = gss_msg->auth->mech; | 431 | struct gss_api_mech *mech = gss_msg->auth->mech; |
431 | char *p = gss_msg->databuf; | 432 | char *p = gss_msg->databuf; |
432 | int len = 0; | 433 | size_t buflen = sizeof(gss_msg->databuf); |
433 | 434 | int len; | |
434 | gss_msg->msg.len = sprintf(gss_msg->databuf, "mech=%s uid=%d ", | 435 | |
435 | mech->gm_name, | 436 | len = scnprintf(p, buflen, "mech=%s uid=%d ", mech->gm_name, |
436 | from_kuid(&init_user_ns, gss_msg->uid)); | 437 | from_kuid(&init_user_ns, gss_msg->uid)); |
437 | p += gss_msg->msg.len; | 438 | buflen -= len; |
439 | p += len; | ||
440 | gss_msg->msg.len = len; | ||
438 | if (target_name) { | 441 | if (target_name) { |
439 | len = sprintf(p, "target=%s ", target_name); | 442 | len = scnprintf(p, buflen, "target=%s ", target_name); |
443 | buflen -= len; | ||
440 | p += len; | 444 | p += len; |
441 | gss_msg->msg.len += len; | 445 | gss_msg->msg.len += len; |
442 | } | 446 | } |
443 | if (service_name != NULL) { | 447 | if (service_name != NULL) { |
444 | len = sprintf(p, "service=%s ", service_name); | 448 | len = scnprintf(p, buflen, "service=%s ", service_name); |
449 | buflen -= len; | ||
445 | p += len; | 450 | p += len; |
446 | gss_msg->msg.len += len; | 451 | gss_msg->msg.len += len; |
447 | } | 452 | } |
448 | if (mech->gm_upcall_enctypes) { | 453 | if (mech->gm_upcall_enctypes) { |
449 | len = sprintf(p, "enctypes=%s ", mech->gm_upcall_enctypes); | 454 | len = scnprintf(p, buflen, "enctypes=%s ", |
455 | mech->gm_upcall_enctypes); | ||
456 | buflen -= len; | ||
450 | p += len; | 457 | p += len; |
451 | gss_msg->msg.len += len; | 458 | gss_msg->msg.len += len; |
452 | } | 459 | } |
453 | len = sprintf(p, "\n"); | 460 | len = scnprintf(p, buflen, "\n"); |
461 | if (len == 0) | ||
462 | goto out_overflow; | ||
454 | gss_msg->msg.len += len; | 463 | gss_msg->msg.len += len; |
455 | 464 | ||
456 | gss_msg->msg.data = gss_msg->databuf; | 465 | gss_msg->msg.data = gss_msg->databuf; |
457 | BUG_ON(gss_msg->msg.len > UPCALL_BUF_LEN); | 466 | return 0; |
467 | out_overflow: | ||
468 | WARN_ON_ONCE(1); | ||
469 | return -ENOMEM; | ||
458 | } | 470 | } |
459 | 471 | ||
460 | static struct gss_upcall_msg * | 472 | static struct gss_upcall_msg * |
@@ -463,15 +475,15 @@ gss_alloc_msg(struct gss_auth *gss_auth, | |||
463 | { | 475 | { |
464 | struct gss_upcall_msg *gss_msg; | 476 | struct gss_upcall_msg *gss_msg; |
465 | int vers; | 477 | int vers; |
478 | int err = -ENOMEM; | ||
466 | 479 | ||
467 | gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); | 480 | gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); |
468 | if (gss_msg == NULL) | 481 | if (gss_msg == NULL) |
469 | return ERR_PTR(-ENOMEM); | 482 | goto err; |
470 | vers = get_pipe_version(gss_auth->net); | 483 | vers = get_pipe_version(gss_auth->net); |
471 | if (vers < 0) { | 484 | err = vers; |
472 | kfree(gss_msg); | 485 | if (err < 0) |
473 | return ERR_PTR(vers); | 486 | goto err_free_msg; |
474 | } | ||
475 | gss_msg->pipe = gss_auth->gss_pipe[vers]->pipe; | 487 | gss_msg->pipe = gss_auth->gss_pipe[vers]->pipe; |
476 | INIT_LIST_HEAD(&gss_msg->list); | 488 | INIT_LIST_HEAD(&gss_msg->list); |
477 | rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); | 489 | rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); |
@@ -484,9 +496,15 @@ gss_alloc_msg(struct gss_auth *gss_auth, | |||
484 | gss_encode_v0_msg(gss_msg); | 496 | gss_encode_v0_msg(gss_msg); |
485 | break; | 497 | break; |
486 | default: | 498 | default: |
487 | gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name); | 499 | err = gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name); |
500 | if (err) | ||
501 | goto err_free_msg; | ||
488 | }; | 502 | }; |
489 | return gss_msg; | 503 | return gss_msg; |
504 | err_free_msg: | ||
505 | kfree(gss_msg); | ||
506 | err: | ||
507 | return ERR_PTR(err); | ||
490 | } | 508 | } |
491 | 509 | ||
492 | static struct gss_upcall_msg * | 510 | static struct gss_upcall_msg * |