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:
parent
5fccc5b52e
commit
9d3a2260f0
|
@ -420,41 +420,53 @@ static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg)
|
||||||
memcpy(gss_msg->databuf, &uid, sizeof(uid));
|
memcpy(gss_msg->databuf, &uid, sizeof(uid));
|
||||||
gss_msg->msg.data = gss_msg->databuf;
|
gss_msg->msg.data = gss_msg->databuf;
|
||||||
gss_msg->msg.len = sizeof(uid);
|
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 *service_name,
|
||||||
const char *target_name)
|
const char *target_name)
|
||||||
{
|
{
|
||||||
struct gss_api_mech *mech = gss_msg->auth->mech;
|
struct gss_api_mech *mech = gss_msg->auth->mech;
|
||||||
char *p = gss_msg->databuf;
|
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 ",
|
len = scnprintf(p, buflen, "mech=%s uid=%d ", mech->gm_name,
|
||||||
mech->gm_name,
|
|
||||||
from_kuid(&init_user_ns, gss_msg->uid));
|
from_kuid(&init_user_ns, gss_msg->uid));
|
||||||
p += gss_msg->msg.len;
|
buflen -= len;
|
||||||
|
p += len;
|
||||||
|
gss_msg->msg.len = len;
|
||||||
if (target_name) {
|
if (target_name) {
|
||||||
len = sprintf(p, "target=%s ", target_name);
|
len = scnprintf(p, buflen, "target=%s ", target_name);
|
||||||
|
buflen -= len;
|
||||||
p += len;
|
p += len;
|
||||||
gss_msg->msg.len += len;
|
gss_msg->msg.len += len;
|
||||||
}
|
}
|
||||||
if (service_name != NULL) {
|
if (service_name != NULL) {
|
||||||
len = sprintf(p, "service=%s ", service_name);
|
len = scnprintf(p, buflen, "service=%s ", service_name);
|
||||||
|
buflen -= len;
|
||||||
p += len;
|
p += len;
|
||||||
gss_msg->msg.len += len;
|
gss_msg->msg.len += len;
|
||||||
}
|
}
|
||||||
if (mech->gm_upcall_enctypes) {
|
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;
|
p += len;
|
||||||
gss_msg->msg.len += 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.len += len;
|
||||||
|
|
||||||
gss_msg->msg.data = gss_msg->databuf;
|
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 *
|
static struct gss_upcall_msg *
|
||||||
|
@ -463,15 +475,15 @@ gss_alloc_msg(struct gss_auth *gss_auth,
|
||||||
{
|
{
|
||||||
struct gss_upcall_msg *gss_msg;
|
struct gss_upcall_msg *gss_msg;
|
||||||
int vers;
|
int vers;
|
||||||
|
int err = -ENOMEM;
|
||||||
|
|
||||||
gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS);
|
gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS);
|
||||||
if (gss_msg == NULL)
|
if (gss_msg == NULL)
|
||||||
return ERR_PTR(-ENOMEM);
|
goto err;
|
||||||
vers = get_pipe_version(gss_auth->net);
|
vers = get_pipe_version(gss_auth->net);
|
||||||
if (vers < 0) {
|
err = vers;
|
||||||
kfree(gss_msg);
|
if (err < 0)
|
||||||
return ERR_PTR(vers);
|
goto err_free_msg;
|
||||||
}
|
|
||||||
gss_msg->pipe = gss_auth->gss_pipe[vers]->pipe;
|
gss_msg->pipe = gss_auth->gss_pipe[vers]->pipe;
|
||||||
INIT_LIST_HEAD(&gss_msg->list);
|
INIT_LIST_HEAD(&gss_msg->list);
|
||||||
rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq");
|
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);
|
gss_encode_v0_msg(gss_msg);
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
return gss_msg;
|
||||||
|
err_free_msg:
|
||||||
|
kfree(gss_msg);
|
||||||
|
err:
|
||||||
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct gss_upcall_msg *
|
static struct gss_upcall_msg *
|
||||||
|
|
Loading…
Reference in a new issue