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>
This commit is contained in:
Trond Myklebust 2013-10-28 18:18:00 -04:00
parent 5fccc5b52e
commit 9d3a2260f0
1 changed files with 36 additions and 18 deletions

View File

@ -420,41 +420,53 @@ static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg)
memcpy(gss_msg->databuf, &uid, sizeof(uid));
gss_msg->msg.data = gss_msg->databuf;
gss_msg->msg.len = sizeof(uid);
BUG_ON(sizeof(uid) > UPCALL_BUF_LEN);
BUILD_BUG_ON(sizeof(uid) > sizeof(gss_msg->databuf));
}
static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
static int gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
const char *service_name,
const char *target_name)
{
struct gss_api_mech *mech = gss_msg->auth->mech;
char *p = gss_msg->databuf;
int len = 0;
size_t buflen = sizeof(gss_msg->databuf);
int len;
gss_msg->msg.len = sprintf(gss_msg->databuf, "mech=%s uid=%d ",
mech->gm_name,
from_kuid(&init_user_ns, gss_msg->uid));
p += gss_msg->msg.len;
len = scnprintf(p, buflen, "mech=%s uid=%d ", mech->gm_name,
from_kuid(&init_user_ns, gss_msg->uid));
buflen -= len;
p += len;
gss_msg->msg.len = len;
if (target_name) {
len = sprintf(p, "target=%s ", target_name);
len = scnprintf(p, buflen, "target=%s ", target_name);
buflen -= len;
p += len;
gss_msg->msg.len += len;
}
if (service_name != NULL) {
len = sprintf(p, "service=%s ", service_name);
len = scnprintf(p, buflen, "service=%s ", service_name);
buflen -= len;
p += len;
gss_msg->msg.len += len;
}
if (mech->gm_upcall_enctypes) {
len = sprintf(p, "enctypes=%s ", mech->gm_upcall_enctypes);
len = scnprintf(p, buflen, "enctypes=%s ",
mech->gm_upcall_enctypes);
buflen -= len;
p += len;
gss_msg->msg.len += len;
}
len = sprintf(p, "\n");
len = scnprintf(p, buflen, "\n");
if (len == 0)
goto out_overflow;
gss_msg->msg.len += len;
gss_msg->msg.data = gss_msg->databuf;
BUG_ON(gss_msg->msg.len > UPCALL_BUF_LEN);
return 0;
out_overflow:
WARN_ON_ONCE(1);
return -ENOMEM;
}
static struct gss_upcall_msg *
@ -463,15 +475,15 @@ gss_alloc_msg(struct gss_auth *gss_auth,
{
struct gss_upcall_msg *gss_msg;
int vers;
int err = -ENOMEM;
gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS);
if (gss_msg == NULL)
return ERR_PTR(-ENOMEM);
goto err;
vers = get_pipe_version(gss_auth->net);
if (vers < 0) {
kfree(gss_msg);
return ERR_PTR(vers);
}
err = vers;
if (err < 0)
goto err_free_msg;
gss_msg->pipe = gss_auth->gss_pipe[vers]->pipe;
INIT_LIST_HEAD(&gss_msg->list);
rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq");
@ -484,9 +496,15 @@ gss_alloc_msg(struct gss_auth *gss_auth,
gss_encode_v0_msg(gss_msg);
break;
default:
gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name);
err = gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name);
if (err)
goto err_free_msg;
};
return gss_msg;
err_free_msg:
kfree(gss_msg);
err:
return ERR_PTR(err);
}
static struct gss_upcall_msg *