| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * IEEE802154.4 socket interface |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright 2007, 2008 Siemens AG |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License version 2 |
|---|
| 8 | | - * as published by the Free Software Foundation. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | | - * GNU General Public License for more details. |
|---|
| 14 | 6 | * |
|---|
| 15 | 7 | * Written by: |
|---|
| 16 | 8 | * Sergey Lapin <slapin@ossfans.org> |
|---|
| .. | .. |
|---|
| 164 | 156 | struct sock *sk = sock->sk; |
|---|
| 165 | 157 | |
|---|
| 166 | 158 | switch (cmd) { |
|---|
| 167 | | - case SIOCGSTAMP: |
|---|
| 168 | | - return sock_get_timestamp(sk, (struct timeval __user *)arg); |
|---|
| 169 | | - case SIOCGSTAMPNS: |
|---|
| 170 | | - return sock_get_timestampns(sk, (struct timespec __user *)arg); |
|---|
| 171 | 159 | case SIOCGIFADDR: |
|---|
| 172 | 160 | case SIOCSIFADDR: |
|---|
| 173 | 161 | return ieee802154_dev_ioctl(sk, (struct ifreq __user *)arg, |
|---|
| .. | .. |
|---|
| 213 | 201 | int err = 0; |
|---|
| 214 | 202 | struct net_device *dev = NULL; |
|---|
| 215 | 203 | |
|---|
| 216 | | - if (len < sizeof(*uaddr)) |
|---|
| 217 | | - return -EINVAL; |
|---|
| 204 | + err = ieee802154_sockaddr_check_size(uaddr, len); |
|---|
| 205 | + if (err < 0) |
|---|
| 206 | + return err; |
|---|
| 218 | 207 | |
|---|
| 219 | 208 | uaddr = (struct sockaddr_ieee802154 *)_uaddr; |
|---|
| 220 | 209 | if (uaddr->family != AF_IEEE802154) |
|---|
| .. | .. |
|---|
| 282 | 271 | if (size > mtu) { |
|---|
| 283 | 272 | pr_debug("size = %zu, mtu = %u\n", size, mtu); |
|---|
| 284 | 273 | err = -EMSGSIZE; |
|---|
| 274 | + goto out_dev; |
|---|
| 275 | + } |
|---|
| 276 | + if (!size) { |
|---|
| 277 | + err = 0; |
|---|
| 285 | 278 | goto out_dev; |
|---|
| 286 | 279 | } |
|---|
| 287 | 280 | |
|---|
| .. | .. |
|---|
| 394 | 387 | } |
|---|
| 395 | 388 | |
|---|
| 396 | 389 | static int raw_setsockopt(struct sock *sk, int level, int optname, |
|---|
| 397 | | - char __user *optval, unsigned int optlen) |
|---|
| 390 | + sockptr_t optval, unsigned int optlen) |
|---|
| 398 | 391 | { |
|---|
| 399 | 392 | return -EOPNOTSUPP; |
|---|
| 400 | 393 | } |
|---|
| .. | .. |
|---|
| 426 | 419 | .getname = sock_no_getname, |
|---|
| 427 | 420 | .poll = datagram_poll, |
|---|
| 428 | 421 | .ioctl = ieee802154_sock_ioctl, |
|---|
| 422 | + .gettstamp = sock_gettstamp, |
|---|
| 429 | 423 | .listen = sock_no_listen, |
|---|
| 430 | 424 | .shutdown = sock_no_shutdown, |
|---|
| 431 | 425 | .setsockopt = sock_common_setsockopt, |
|---|
| .. | .. |
|---|
| 434 | 428 | .recvmsg = sock_common_recvmsg, |
|---|
| 435 | 429 | .mmap = sock_no_mmap, |
|---|
| 436 | 430 | .sendpage = sock_no_sendpage, |
|---|
| 437 | | -#ifdef CONFIG_COMPAT |
|---|
| 438 | | - .compat_setsockopt = compat_sock_common_setsockopt, |
|---|
| 439 | | - .compat_getsockopt = compat_sock_common_getsockopt, |
|---|
| 440 | | -#endif |
|---|
| 441 | 431 | }; |
|---|
| 442 | 432 | |
|---|
| 443 | 433 | /* DGRAM Sockets (802.15.4 dataframes) */ |
|---|
| .. | .. |
|---|
| 509 | 499 | |
|---|
| 510 | 500 | ro->bound = 0; |
|---|
| 511 | 501 | |
|---|
| 512 | | - if (len < sizeof(*addr)) |
|---|
| 502 | + err = ieee802154_sockaddr_check_size(addr, len); |
|---|
| 503 | + if (err < 0) |
|---|
| 513 | 504 | goto out; |
|---|
| 514 | 505 | |
|---|
| 515 | | - if (addr->family != AF_IEEE802154) |
|---|
| 506 | + if (addr->family != AF_IEEE802154) { |
|---|
| 507 | + err = -EINVAL; |
|---|
| 516 | 508 | goto out; |
|---|
| 509 | + } |
|---|
| 517 | 510 | |
|---|
| 518 | 511 | ieee802154_addr_from_sa(&haddr, &addr->addr); |
|---|
| 519 | 512 | dev = ieee802154_get_dev(sock_net(sk), &haddr); |
|---|
| .. | .. |
|---|
| 580 | 573 | struct dgram_sock *ro = dgram_sk(sk); |
|---|
| 581 | 574 | int err = 0; |
|---|
| 582 | 575 | |
|---|
| 583 | | - if (len < sizeof(*addr)) |
|---|
| 584 | | - return -EINVAL; |
|---|
| 576 | + err = ieee802154_sockaddr_check_size(addr, len); |
|---|
| 577 | + if (err < 0) |
|---|
| 578 | + return err; |
|---|
| 585 | 579 | |
|---|
| 586 | 580 | if (addr->family != AF_IEEE802154) |
|---|
| 587 | 581 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 620 | 614 | struct ieee802154_mac_cb *cb; |
|---|
| 621 | 615 | struct dgram_sock *ro = dgram_sk(sk); |
|---|
| 622 | 616 | struct ieee802154_addr dst_addr; |
|---|
| 617 | + DECLARE_SOCKADDR(struct sockaddr_ieee802154*, daddr, msg->msg_name); |
|---|
| 623 | 618 | int hlen, tlen; |
|---|
| 624 | 619 | int err; |
|---|
| 625 | 620 | |
|---|
| .. | .. |
|---|
| 628 | 623 | return -EOPNOTSUPP; |
|---|
| 629 | 624 | } |
|---|
| 630 | 625 | |
|---|
| 631 | | - if (!ro->connected && !msg->msg_name) |
|---|
| 632 | | - return -EDESTADDRREQ; |
|---|
| 633 | | - else if (ro->connected && msg->msg_name) |
|---|
| 634 | | - return -EISCONN; |
|---|
| 626 | + if (msg->msg_name) { |
|---|
| 627 | + if (ro->connected) |
|---|
| 628 | + return -EISCONN; |
|---|
| 629 | + if (msg->msg_namelen < IEEE802154_MIN_NAMELEN) |
|---|
| 630 | + return -EINVAL; |
|---|
| 631 | + err = ieee802154_sockaddr_check_size(daddr, msg->msg_namelen); |
|---|
| 632 | + if (err < 0) |
|---|
| 633 | + return err; |
|---|
| 634 | + ieee802154_addr_from_sa(&dst_addr, &daddr->addr); |
|---|
| 635 | + } else { |
|---|
| 636 | + if (!ro->connected) |
|---|
| 637 | + return -EDESTADDRREQ; |
|---|
| 638 | + dst_addr = ro->dst_addr; |
|---|
| 639 | + } |
|---|
| 635 | 640 | |
|---|
| 636 | 641 | if (!ro->bound) |
|---|
| 637 | 642 | dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154); |
|---|
| .. | .. |
|---|
| 667 | 672 | cb = mac_cb_init(skb); |
|---|
| 668 | 673 | cb->type = IEEE802154_FC_TYPE_DATA; |
|---|
| 669 | 674 | cb->ackreq = ro->want_ack; |
|---|
| 670 | | - |
|---|
| 671 | | - if (msg->msg_name) { |
|---|
| 672 | | - DECLARE_SOCKADDR(struct sockaddr_ieee802154*, |
|---|
| 673 | | - daddr, msg->msg_name); |
|---|
| 674 | | - |
|---|
| 675 | | - ieee802154_addr_from_sa(&dst_addr, &daddr->addr); |
|---|
| 676 | | - } else { |
|---|
| 677 | | - dst_addr = ro->dst_addr; |
|---|
| 678 | | - } |
|---|
| 679 | | - |
|---|
| 680 | 675 | cb->secen = ro->secen; |
|---|
| 681 | 676 | cb->secen_override = ro->secen_override; |
|---|
| 682 | 677 | cb->seclevel = ro->seclevel; |
|---|
| .. | .. |
|---|
| 887 | 882 | } |
|---|
| 888 | 883 | |
|---|
| 889 | 884 | static int dgram_setsockopt(struct sock *sk, int level, int optname, |
|---|
| 890 | | - char __user *optval, unsigned int optlen) |
|---|
| 885 | + sockptr_t optval, unsigned int optlen) |
|---|
| 891 | 886 | { |
|---|
| 892 | 887 | struct dgram_sock *ro = dgram_sk(sk); |
|---|
| 893 | 888 | struct net *net = sock_net(sk); |
|---|
| .. | .. |
|---|
| 897 | 892 | if (optlen < sizeof(int)) |
|---|
| 898 | 893 | return -EINVAL; |
|---|
| 899 | 894 | |
|---|
| 900 | | - if (get_user(val, (int __user *)optval)) |
|---|
| 895 | + if (copy_from_sockptr(&val, optval, sizeof(int))) |
|---|
| 901 | 896 | return -EFAULT; |
|---|
| 902 | 897 | |
|---|
| 903 | 898 | lock_sock(sk); |
|---|
| .. | .. |
|---|
| 988 | 983 | .getname = sock_no_getname, |
|---|
| 989 | 984 | .poll = datagram_poll, |
|---|
| 990 | 985 | .ioctl = ieee802154_sock_ioctl, |
|---|
| 986 | + .gettstamp = sock_gettstamp, |
|---|
| 991 | 987 | .listen = sock_no_listen, |
|---|
| 992 | 988 | .shutdown = sock_no_shutdown, |
|---|
| 993 | 989 | .setsockopt = sock_common_setsockopt, |
|---|
| .. | .. |
|---|
| 996 | 992 | .recvmsg = sock_common_recvmsg, |
|---|
| 997 | 993 | .mmap = sock_no_mmap, |
|---|
| 998 | 994 | .sendpage = sock_no_sendpage, |
|---|
| 999 | | -#ifdef CONFIG_COMPAT |
|---|
| 1000 | | - .compat_setsockopt = compat_sock_common_setsockopt, |
|---|
| 1001 | | - .compat_getsockopt = compat_sock_common_getsockopt, |
|---|
| 1002 | | -#endif |
|---|
| 1003 | 995 | }; |
|---|
| 1004 | 996 | |
|---|
| 1005 | 997 | static void ieee802154_sock_destruct(struct sock *sk) |
|---|
| .. | .. |
|---|
| 1110 | 1102 | |
|---|
| 1111 | 1103 | static int __init af_ieee802154_init(void) |
|---|
| 1112 | 1104 | { |
|---|
| 1113 | | - int rc = -EINVAL; |
|---|
| 1105 | + int rc; |
|---|
| 1114 | 1106 | |
|---|
| 1115 | 1107 | rc = proto_register(&ieee802154_raw_prot, 1); |
|---|
| 1116 | 1108 | if (rc) |
|---|