forked from Minki/linux
net/ieee802154: fix uninit value bug in dgram_sendmsg
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: Haimin Zhang <tcs_kernel@tencent.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
0727a9a5fb
commit
94160108a7
@ -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)
|
||||
{
|
||||
|
@ -200,8 +200,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)
|
||||
@ -493,7 +494,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)
|
||||
@ -564,8 +566,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;
|
||||
@ -604,6 +607,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;
|
||||
|
||||
@ -612,10 +616,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)
|
||||
return -EISCONN;
|
||||
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);
|
||||
@ -651,16 +665,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;
|
||||
|
Loading…
Reference in New Issue
Block a user