Commit d49baa7e authored by Eric Biggers's avatar Eric Biggers Committed by David S. Miller
Browse files

net/smc: check for missing nlattrs in SMC_PNETID messages



It's possible to crash the kernel in several different ways by sending
messages to the SMC_PNETID generic netlink family that are missing the
expected attributes:

- Missing SMC_PNETID_NAME => null pointer dereference when comparing
  names.
- Missing SMC_PNETID_ETHNAME => null pointer dereference accessing
  smc_pnetentry::ndev.
- Missing SMC_PNETID_IBNAME => null pointer dereference accessing
  smc_pnetentry::smcibdev.
- Missing SMC_PNETID_IBPORT => out of bounds array access to
  smc_ib_device::pattr[-1].

Fix it by validating that all expected attributes are present and that
SMC_PNETID_IBPORT is nonzero.

Reported-by: default avatar <syzbot+5cd61039dc9b8bfa6e47@syzkaller.appspotmail.com>
Fixes: 6812baab ("smc: establish pnet table management")
Cc: <stable@vger.kernel.org> # v4.11+
Signed-off-by: default avatarEric Biggers <ebiggers@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 57f6f99f
Loading
Loading
Loading
Loading
+40 −31
Original line number Diff line number Diff line
@@ -245,40 +245,45 @@ out:
static int smc_pnet_fill_entry(struct net *net, struct smc_pnetentry *pnetelem,
			       struct nlattr *tb[])
{
	char *string, *ibname = NULL;
	int rc = 0;
	char *string, *ibname;
	int rc;

	memset(pnetelem, 0, sizeof(*pnetelem));
	INIT_LIST_HEAD(&pnetelem->list);
	if (tb[SMC_PNETID_NAME]) {

	rc = -EINVAL;
	if (!tb[SMC_PNETID_NAME])
		goto error;
	string = (char *)nla_data(tb[SMC_PNETID_NAME]);
		if (!smc_pnetid_valid(string, pnetelem->pnet_name)) {
	if (!smc_pnetid_valid(string, pnetelem->pnet_name))
		goto error;

	rc = -EINVAL;
	if (!tb[SMC_PNETID_ETHNAME])
		goto error;
		}
	}
	if (tb[SMC_PNETID_ETHNAME]) {
	rc = -ENOENT;
	string = (char *)nla_data(tb[SMC_PNETID_ETHNAME]);
	pnetelem->ndev = dev_get_by_name(net, string);
	if (!pnetelem->ndev)
			return -ENOENT;
	}
	if (tb[SMC_PNETID_IBNAME]) {
		goto error;

	rc = -EINVAL;
	if (!tb[SMC_PNETID_IBNAME])
		goto error;
	rc = -ENOENT;
	ibname = (char *)nla_data(tb[SMC_PNETID_IBNAME]);
	ibname = strim(ibname);
	pnetelem->smcibdev = smc_pnet_find_ib(ibname);
		if (!pnetelem->smcibdev) {
			rc = -ENOENT;
	if (!pnetelem->smcibdev)
		goto error;
		}
	}
	if (tb[SMC_PNETID_IBPORT]) {
		pnetelem->ib_port = nla_get_u8(tb[SMC_PNETID_IBPORT]);
		if (pnetelem->ib_port > SMC_MAX_PORTS) {

	rc = -EINVAL;
	if (!tb[SMC_PNETID_IBPORT])
		goto error;
		}
	}
	pnetelem->ib_port = nla_get_u8(tb[SMC_PNETID_IBPORT]);
	if (pnetelem->ib_port < 1 || pnetelem->ib_port > SMC_MAX_PORTS)
		goto error;

	return 0;

error:
@@ -307,6 +312,8 @@ static int smc_pnet_get(struct sk_buff *skb, struct genl_info *info)
	void *hdr;
	int rc;

	if (!info->attrs[SMC_PNETID_NAME])
		return -EINVAL;
	pnetelem = smc_pnet_find_pnetid(
				(char *)nla_data(info->attrs[SMC_PNETID_NAME]));
	if (!pnetelem)
@@ -359,6 +366,8 @@ static int smc_pnet_add(struct sk_buff *skb, struct genl_info *info)

static int smc_pnet_del(struct sk_buff *skb, struct genl_info *info)
{
	if (!info->attrs[SMC_PNETID_NAME])
		return -EINVAL;
	return smc_pnet_remove_by_pnetid(
				(char *)nla_data(info->attrs[SMC_PNETID_NAME]));
}