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: syzbot+5cd61039dc9b8bfa6e47@syzkaller.appspotmail.com
Fixes: 6812baabf2
("smc: establish pnet table management")
Cc: <stable@vger.kernel.org> # v4.11+
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
57f6f99fda
Коммит
d49baa7e12
|
@ -245,40 +245,45 @@ out:
|
||||||
static int smc_pnet_fill_entry(struct net *net, struct smc_pnetentry *pnetelem,
|
static int smc_pnet_fill_entry(struct net *net, struct smc_pnetentry *pnetelem,
|
||||||
struct nlattr *tb[])
|
struct nlattr *tb[])
|
||||||
{
|
{
|
||||||
char *string, *ibname = NULL;
|
char *string, *ibname;
|
||||||
int rc = 0;
|
int rc;
|
||||||
|
|
||||||
memset(pnetelem, 0, sizeof(*pnetelem));
|
memset(pnetelem, 0, sizeof(*pnetelem));
|
||||||
INIT_LIST_HEAD(&pnetelem->list);
|
INIT_LIST_HEAD(&pnetelem->list);
|
||||||
if (tb[SMC_PNETID_NAME]) {
|
|
||||||
string = (char *)nla_data(tb[SMC_PNETID_NAME]);
|
rc = -EINVAL;
|
||||||
if (!smc_pnetid_valid(string, pnetelem->pnet_name)) {
|
if (!tb[SMC_PNETID_NAME])
|
||||||
rc = -EINVAL;
|
goto error;
|
||||||
goto error;
|
string = (char *)nla_data(tb[SMC_PNETID_NAME]);
|
||||||
}
|
if (!smc_pnetid_valid(string, pnetelem->pnet_name))
|
||||||
}
|
goto error;
|
||||||
if (tb[SMC_PNETID_ETHNAME]) {
|
|
||||||
string = (char *)nla_data(tb[SMC_PNETID_ETHNAME]);
|
rc = -EINVAL;
|
||||||
pnetelem->ndev = dev_get_by_name(net, string);
|
if (!tb[SMC_PNETID_ETHNAME])
|
||||||
if (!pnetelem->ndev)
|
goto error;
|
||||||
return -ENOENT;
|
rc = -ENOENT;
|
||||||
}
|
string = (char *)nla_data(tb[SMC_PNETID_ETHNAME]);
|
||||||
if (tb[SMC_PNETID_IBNAME]) {
|
pnetelem->ndev = dev_get_by_name(net, string);
|
||||||
ibname = (char *)nla_data(tb[SMC_PNETID_IBNAME]);
|
if (!pnetelem->ndev)
|
||||||
ibname = strim(ibname);
|
goto error;
|
||||||
pnetelem->smcibdev = smc_pnet_find_ib(ibname);
|
|
||||||
if (!pnetelem->smcibdev) {
|
rc = -EINVAL;
|
||||||
rc = -ENOENT;
|
if (!tb[SMC_PNETID_IBNAME])
|
||||||
goto error;
|
goto error;
|
||||||
}
|
rc = -ENOENT;
|
||||||
}
|
ibname = (char *)nla_data(tb[SMC_PNETID_IBNAME]);
|
||||||
if (tb[SMC_PNETID_IBPORT]) {
|
ibname = strim(ibname);
|
||||||
pnetelem->ib_port = nla_get_u8(tb[SMC_PNETID_IBPORT]);
|
pnetelem->smcibdev = smc_pnet_find_ib(ibname);
|
||||||
if (pnetelem->ib_port > SMC_MAX_PORTS) {
|
if (!pnetelem->smcibdev)
|
||||||
rc = -EINVAL;
|
goto error;
|
||||||
goto error;
|
|
||||||
}
|
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;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
@ -307,6 +312,8 @@ static int smc_pnet_get(struct sk_buff *skb, struct genl_info *info)
|
||||||
void *hdr;
|
void *hdr;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
if (!info->attrs[SMC_PNETID_NAME])
|
||||||
|
return -EINVAL;
|
||||||
pnetelem = smc_pnet_find_pnetid(
|
pnetelem = smc_pnet_find_pnetid(
|
||||||
(char *)nla_data(info->attrs[SMC_PNETID_NAME]));
|
(char *)nla_data(info->attrs[SMC_PNETID_NAME]));
|
||||||
if (!pnetelem)
|
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)
|
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(
|
return smc_pnet_remove_by_pnetid(
|
||||||
(char *)nla_data(info->attrs[SMC_PNETID_NAME]));
|
(char *)nla_data(info->attrs[SMC_PNETID_NAME]));
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче