Commit ff5e92c1 authored by Daniel Borkmann's avatar Daniel Borkmann Committed by David S. Miller
Browse files

net: sctp: propagate sysctl errors from proc_do* properly



sysctl handler proc_sctp_do_hmac_alg(), proc_sctp_do_rto_min() and
proc_sctp_do_rto_max() do not properly reflect some error cases
when writing values via sysctl from internal proc functions such
as proc_dointvec() and proc_dostring().

In all these cases we pass the test for write != 0 and partially
do additional work just to notice that additional sanity checks
fail and we return with hard-coded -EINVAL while proc_do*
functions might also return different errors. So fix this up by
simply testing a successful return of proc_do* right after
calling it.

This also allows to propagate its return value onwards to the user.
While touching this, also fix up some minor style issues.

Fixes: 4f3fdf3b ("sctp: add check rto_min and rto_max in sysctl")
Fixes: 3c68198e ("sctp: Make hmac algorithm selection for cookie generation dynamic")
Signed-off-by: default avatarDaniel Borkmann <dborkman@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d36a4f4b
Loading
Loading
Loading
Loading
+23 −20
Original line number Diff line number Diff line
@@ -321,41 +321,40 @@ static int proc_sctp_do_hmac_alg(struct ctl_table *ctl, int write,
				loff_t *ppos)
{
	struct net *net = current->nsproxy->net_ns;
	char tmp[8];
	struct ctl_table tbl;
	int ret;
	int changed = 0;
	bool changed = false;
	char *none = "none";
	char tmp[8];
	int ret;

	memset(&tbl, 0, sizeof(struct ctl_table));

	if (write) {
		tbl.data = tmp;
		tbl.maxlen = 8;
		tbl.maxlen = sizeof(tmp);
	} else {
		tbl.data = net->sctp.sctp_hmac_alg ? : none;
		tbl.maxlen = strlen(tbl.data);
	}
		ret = proc_dostring(&tbl, write, buffer, lenp, ppos);

	if (write) {
	ret = proc_dostring(&tbl, write, buffer, lenp, ppos);
	if (write && ret == 0) {
#ifdef CONFIG_CRYPTO_MD5
		if (!strncmp(tmp, "md5", 3)) {
			net->sctp.sctp_hmac_alg = "md5";
			changed = 1;
			changed = true;
		}
#endif
#ifdef CONFIG_CRYPTO_SHA1
		if (!strncmp(tmp, "sha1", 4)) {
			net->sctp.sctp_hmac_alg = "sha1";
			changed = 1;
			changed = true;
		}
#endif
		if (!strncmp(tmp, "none", 4)) {
			net->sctp.sctp_hmac_alg = NULL;
			changed = 1;
			changed = true;
		}

		if (!changed)
			ret = -EINVAL;
	}
@@ -368,11 +367,10 @@ static int proc_sctp_do_rto_min(struct ctl_table *ctl, int write,
				loff_t *ppos)
{
	struct net *net = current->nsproxy->net_ns;
	int new_value;
	struct ctl_table tbl;
	unsigned int min = *(unsigned int *) ctl->extra1;
	unsigned int max = *(unsigned int *) ctl->extra2;
	int ret;
	struct ctl_table tbl;
	int ret, new_value;

	memset(&tbl, 0, sizeof(struct ctl_table));
	tbl.maxlen = sizeof(unsigned int);
@@ -381,12 +379,15 @@ static int proc_sctp_do_rto_min(struct ctl_table *ctl, int write,
		tbl.data = &new_value;
	else
		tbl.data = &net->sctp.rto_min;

	ret = proc_dointvec(&tbl, write, buffer, lenp, ppos);
	if (write) {
		if (ret || new_value > max || new_value < min)
	if (write && ret == 0) {
		if (new_value > max || new_value < min)
			return -EINVAL;

		net->sctp.rto_min = new_value;
	}

	return ret;
}

@@ -395,11 +396,10 @@ static int proc_sctp_do_rto_max(struct ctl_table *ctl, int write,
				loff_t *ppos)
{
	struct net *net = current->nsproxy->net_ns;
	int new_value;
	struct ctl_table tbl;
	unsigned int min = *(unsigned int *) ctl->extra1;
	unsigned int max = *(unsigned int *) ctl->extra2;
	int ret;
	struct ctl_table tbl;
	int ret, new_value;

	memset(&tbl, 0, sizeof(struct ctl_table));
	tbl.maxlen = sizeof(unsigned int);
@@ -408,12 +408,15 @@ static int proc_sctp_do_rto_max(struct ctl_table *ctl, int write,
		tbl.data = &new_value;
	else
		tbl.data = &net->sctp.rto_max;

	ret = proc_dointvec(&tbl, write, buffer, lenp, ppos);
	if (write) {
		if (ret || new_value > max || new_value < min)
	if (write && ret == 0) {
		if (new_value > max || new_value < min)
			return -EINVAL;

		net->sctp.rto_max = new_value;
	}

	return ret;
}