Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9d3a2260 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

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: default avatarBruce Fields <bfields@fieldses.org>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 5fccc5b5
Loading
Loading
Loading
Loading
+37 −19
Original line number Diff line number Diff line
@@ -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,
	len = scnprintf(p, buflen, "mech=%s uid=%d ", mech->gm_name,
			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) {
		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 *