Re: [PATCH V3] net/ieee802154: fix uninit value bug in dgram_sendmsg

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

just something that we should fix in the future...

On Thu, Sep 8, 2022 at 8:19 AM Haimin Zhang <tcs.kernel@xxxxxxxxx> wrote:
>
> 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@xxxxxxxxxxx>
> ---
>  include/net/ieee802154_netdev.h | 37 +++++++++++++++++++++++++++++
>  net/ieee802154/socket.c         | 42 ++++++++++++++++++---------------
>  2 files changed, 60 insertions(+), 19 deletions(-)
>
> diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
> index d0d188c32..a8994f307 100644
> --- a/include/net/ieee802154_netdev.h
> +++ b/include/net/ieee802154_netdev.h
> @@ -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;
> +       }

There is a missing IEEE802154_ADDR_NONE here. If it's NONE the size is
correct, although all other possible values which are not SHORT, LONG
or NONE, should here end in an -EINVAL as well. In those cases the
size is "undefined" for now.

> +       return 0;
> +}
> +
>  static inline void ieee802154_addr_from_sa(struct ieee802154_addr *a,
>                                            const struct ieee802154_addr_sa *sa)
>  {
> diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c
> index 718fb77bb..7889e1ef7 100644
> --- a/net/ieee802154/socket.c
> +++ b/net/ieee802154/socket.c
> @@ -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;

nitpick, we do this in ieee802154_sockaddr_check_size() as well?

> +               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;

I'm not sure about this change but it looks okay to me.

That's it. I am sorry for the delay... I usually schedule my review
for the weekend if I can't do it then the next weekend...

- Alex




[Index of Archives]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Photo]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux