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

Commit 3c9a75b3 authored by Haimin Zhang's avatar Haimin Zhang Committed by Greg Kroah-Hartman
Browse files

net/ieee802154: fix uninit value bug in dgram_sendmsg



[ Upstream commit 94160108a70c8af17fa1484a37e05181c0e094af ]

There is uninit value bug in dgram_sendmsg function in
net/ieee802154/socket.c when the length of valid data pointed by the
msg->msg_name isn't verified.

We introducing a helper function ieee802154_sockaddr_check_size to
check namelen. First we check there is addr_type in ieee802154_addr_sa.
Then, we check namelen according to addr_type.

Also fixed in raw_bind, dgram_bind, dgram_connect.

Signed-off-by: default avatarHaimin Zhang <tcs_kernel@tencent.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 61be8898
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
@@ -15,6 +15,22 @@
#ifndef IEEE802154_NETDEVICE_H
#define IEEE802154_NETDEVICE_H

#define IEEE802154_REQUIRED_SIZE(struct_type, member) \
	(offsetof(typeof(struct_type), member) + \
	sizeof(((typeof(struct_type) *)(NULL))->member))

#define IEEE802154_ADDR_OFFSET \
	offsetof(typeof(struct sockaddr_ieee802154), addr)

#define IEEE802154_MIN_NAMELEN (IEEE802154_ADDR_OFFSET + \
	IEEE802154_REQUIRED_SIZE(struct ieee802154_addr_sa, addr_type))

#define IEEE802154_NAMELEN_SHORT (IEEE802154_ADDR_OFFSET + \
	IEEE802154_REQUIRED_SIZE(struct ieee802154_addr_sa, short_addr))

#define IEEE802154_NAMELEN_LONG (IEEE802154_ADDR_OFFSET + \
	IEEE802154_REQUIRED_SIZE(struct ieee802154_addr_sa, hwaddr))

#include <net/af_ieee802154.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
@@ -165,6 +181,27 @@ static inline void ieee802154_devaddr_to_raw(void *raw, __le64 addr)
	memcpy(raw, &temp, IEEE802154_ADDR_LEN);
}

static inline int
ieee802154_sockaddr_check_size(struct sockaddr_ieee802154 *daddr, int len)
{
	struct ieee802154_addr_sa *sa;

	sa = &daddr->addr;
	if (len < IEEE802154_MIN_NAMELEN)
		return -EINVAL;
	switch (sa->addr_type) {
	case IEEE802154_ADDR_SHORT:
		if (len < IEEE802154_NAMELEN_SHORT)
			return -EINVAL;
		break;
	case IEEE802154_ADDR_LONG:
		if (len < IEEE802154_NAMELEN_LONG)
			return -EINVAL;
		break;
	}
	return 0;
}

static inline void ieee802154_addr_from_sa(struct ieee802154_addr *a,
					   const struct ieee802154_addr_sa *sa)
{
+23 −19
Original line number Diff line number Diff line
@@ -201,8 +201,9 @@ static int raw_bind(struct sock *sk, struct sockaddr *_uaddr, int len)
	int err = 0;
	struct net_device *dev = NULL;

	if (len < sizeof(*uaddr))
		return -EINVAL;
	err = ieee802154_sockaddr_check_size(uaddr, len);
	if (err < 0)
		return err;

	uaddr = (struct sockaddr_ieee802154 *)_uaddr;
	if (uaddr->family != AF_IEEE802154)
@@ -498,7 +499,8 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)

	ro->bound = 0;

	if (len < sizeof(*addr))
	err = ieee802154_sockaddr_check_size(addr, len);
	if (err < 0)
		goto out;

	if (addr->family != AF_IEEE802154)
@@ -569,8 +571,9 @@ static int dgram_connect(struct sock *sk, struct sockaddr *uaddr,
	struct dgram_sock *ro = dgram_sk(sk);
	int err = 0;

	if (len < sizeof(*addr))
		return -EINVAL;
	err = ieee802154_sockaddr_check_size(addr, len);
	if (err < 0)
		return err;

	if (addr->family != AF_IEEE802154)
		return -EINVAL;
@@ -609,6 +612,7 @@ static int dgram_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
	struct ieee802154_mac_cb *cb;
	struct dgram_sock *ro = dgram_sk(sk);
	struct ieee802154_addr dst_addr;
	DECLARE_SOCKADDR(struct sockaddr_ieee802154*, daddr, msg->msg_name);
	int hlen, tlen;
	int err;

@@ -617,10 +621,20 @@ static int dgram_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
		return -EOPNOTSUPP;
	}

	if (!ro->connected && !msg->msg_name)
		return -EDESTADDRREQ;
	else if (ro->connected && msg->msg_name)
	if (msg->msg_name) {
		if (ro->connected)
			return -EISCONN;
		if (msg->msg_namelen < IEEE802154_MIN_NAMELEN)
			return -EINVAL;
		err = ieee802154_sockaddr_check_size(daddr, msg->msg_namelen);
		if (err < 0)
			return err;
		ieee802154_addr_from_sa(&dst_addr, &daddr->addr);
	} else {
		if (!ro->connected)
			return -EDESTADDRREQ;
		dst_addr = ro->dst_addr;
	}

	if (!ro->bound)
		dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);
@@ -656,16 +670,6 @@ static int dgram_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
	cb = mac_cb_init(skb);
	cb->type = IEEE802154_FC_TYPE_DATA;
	cb->ackreq = ro->want_ack;

	if (msg->msg_name) {
		DECLARE_SOCKADDR(struct sockaddr_ieee802154*,
				 daddr, msg->msg_name);

		ieee802154_addr_from_sa(&dst_addr, &daddr->addr);
	} else {
		dst_addr = ro->dst_addr;
	}

	cb->secen = ro->secen;
	cb->secen_override = ro->secen_override;
	cb->seclevel = ro->seclevel;