Commit b831f342 authored by Haimin Zhang's avatar Haimin Zhang Committed by Jialin Zhang
Browse files

net/ieee802154: fix uninit value bug in dgram_sendmsg

stable inclusion
from stable-v5.10.148
commit c1337f8ea8619404b08a5dec837df5643a3fd5c8
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I6D0WL

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=c1337f8ea8619404b08a5dec837df5643a3fd5c8



--------------------------------

[ Upstream commit 94160108 ]

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>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
Reviewed-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent 7e2fc544
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)
@@ -494,7 +495,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)
@@ -565,8 +567,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;
@@ -605,6 +608,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;

@@ -613,10 +617,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);
@@ -652,16 +666,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;