From nobody Sat Mar 4 09:12:48 2023 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4PTJym5W7Pz3vmrD; Sat, 4 Mar 2023 09:12:48 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4PTJym4t8Qz3yfR; Sat, 4 Mar 2023 09:12:48 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1677921168; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=d9h5URO4vSn6cwpzgwMXTawk5WvdFMG9mRvazIeH21s=; b=OsbX+SprHnmdrDZanWTMuVpQqzKUulHTh/MCBXqPAVUVt8X3Gb+ChNaykI4nwKTvhRI1ng pw2umS9FLayhYTlZ8A00biqGY7trWzswAGWaveteeKOmC2W+2Zba24HWaXC/H4gDqvonog ngx9fL5MseKwgzhvizEAvJR6ma+GdWYEYnIA43IJKP+VqLXADlxjnPfh3OhTuLaZA0TFnR XZ8LYVYzhqqJjgDb/IK6HD+0Vu6wqgRGTAGsqCULQ1bbiYmiEmBX648GLPOCQI+RotGVKe HnfQkpOdPU/a/ZmWUF0DfcBznbYPLIFY4OezVQgJPs9mfxUuPD3bIY/A1T0pkQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1677921168; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=d9h5URO4vSn6cwpzgwMXTawk5WvdFMG9mRvazIeH21s=; b=YHWyyBA1Q+DMp8mVmWBfjGb2GgQID3OWqPj//7QJ3SJnxywVS5UM8BJbJN7o2fTiqD03LN YBdoJVKHRxvQE+3oDukE3ZAXOW9E+JvjOF59G+ewzA/uOQLppRaPgvTVaXTk8fRxETIC2b lzNOJ2q77B3IFaTy9qf7JUWfkBVBakhL1SINCgExh0tRYi26RdbxMTZ1psUUTzi8E9juRo m4zJjIxpB05aymL3QIui1dokl2o+scLkL8eGGZGn9nWKU6bUH15mJQS6ixeHg+x2CVo9+B PHhPlrGT1gGnEWLZMhQHtjLAf4d+Q4k+9TUz6GX9z50YXrBDhnPQM/9rnLAZrg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1677921168; a=rsa-sha256; cv=none; b=k8aAYYuvR9nB1AVuK9AhrITWFErEZTSUZ6CQpHg1ztGnoHFMo9uecnJQYjVARian4IAzVt 7vwgCDHhZI6yl9MJ+kmB5G2a/Q0dbVKorO5mESx9WolkEBOk+/l6KqHTgv1SipAyp5dkIn /6ZvYw3FEWnRx17Ne+pT3QFHchdBBdEC5jTRIl1GmrlaX7ugW7JIw+RRU2kkVdwx4xI2ST FFV/8v7cwamjfamsCtWgejgjDUl5gm2FNBUN1Y0lp11tJfKNJbn0jaAv3dj0j9ZECR+wOZ mUV31JB/i6cF+gtTujCSqlb0axjRwtJo+6B6+so68gwVBXeDczeV8xeU15ot3Q== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4PTJym3zXXzYq4; Sat, 4 Mar 2023 09:12:48 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 3249Cm1x078913; Sat, 4 Mar 2023 09:12:48 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 3249CmOt078912; Sat, 4 Mar 2023 09:12:48 GMT (envelope-from git) Date: Sat, 4 Mar 2023 09:12:48 GMT Message-Id: <202303040912.3249CmOt078912@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Dmitry Chagin Subject: git: f9b0675b014d - main - linux(4): Refactor socket ioctl path to avoid referencing an unstable interfaces List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: dchagin X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: f9b0675b014d06995e5337b71129fc94bd1cedd0 Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by dchagin: URL: https://cgit.FreeBSD.org/src/commit/?id=f9b0675b014d06995e5337b71129fc94bd1cedd0 commit f9b0675b014d06995e5337b71129fc94bd1cedd0 Author: Dmitry Chagin AuthorDate: 2023-03-04 09:11:38 +0000 Commit: Dmitry Chagin CommitDate: 2023-03-04 09:11:38 +0000 linux(4): Refactor socket ioctl path to avoid referencing an unstable interfaces Split the linux_ioctl_socket() function on two counterparts, where the linux_ioctl_socket_ifreq() intended to use in a code path which requires the struct ifreq manipulation, i.e., translating in/out values of the struct, while the linux_ioctl_socket() function is left as is, it calls sys_ioctl() without touching in/out values. Due to structures ifreq, sockaddr difference between FreeBSD and Linux the linux_ioctl_socket_ifreq() calls kern_ioctl() directly, converting in and out values to FreeBSD and to Linux accordingly. Finally, modify the ifname_linux_to_bsd() to return error code, not an unstable reference to the interface. Reviewed by: melifaro Differential Revision: https://reviews.freebsd.org/D38794 --- sys/compat/linux/linux.c | 4 +- sys/compat/linux/linux_common.h | 3 +- sys/compat/linux/linux_ioctl.c | 310 +++++++++++++++++----------------------- 3 files changed, 132 insertions(+), 185 deletions(-) diff --git a/sys/compat/linux/linux.c b/sys/compat/linux/linux.c index f31a4b5e4f5c..2e6e52f7490c 100644 --- a/sys/compat/linux/linux.c +++ b/sys/compat/linux/linux.c @@ -411,7 +411,7 @@ ifname_linux_to_ifp(struct thread *td, const char *lxname) return (arg.ifp); } -struct ifnet * +int ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname) { struct epoch_tracker et; @@ -424,7 +424,7 @@ ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname) strlcpy(bsdname, if_name(ifp), IFNAMSIZ); NET_EPOCH_EXIT(et); CURVNET_RESTORE(); - return (ifp); + return (ifp != NULL ? 0 : EINVAL); } unsigned short diff --git a/sys/compat/linux/linux_common.h b/sys/compat/linux/linux_common.h index 4b693ccaf868..3392f55672f3 100644 --- a/sys/compat/linux/linux_common.h +++ b/sys/compat/linux/linux_common.h @@ -34,9 +34,8 @@ int ifname_bsd_to_linux_ifp(struct ifnet *, char *, size_t); int ifname_bsd_to_linux_idx(u_int, char *, size_t); int ifname_bsd_to_linux_name(const char *, char *, size_t); struct ifnet *ifname_linux_to_ifp(struct thread *, const char *); +int ifname_linux_to_bsd(struct thread *, const char *, char *); -struct ifnet *ifname_linux_to_bsd(struct thread *td, - const char *lxname, char *bsdname); unsigned short linux_ifflags(struct ifnet *); int linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa); diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c index 9f1fdd3a6671..4c95745e4307 100644 --- a/sys/compat/linux/linux_ioctl.c +++ b/sys/compat/linux/linux_ioctl.c @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -2187,22 +2188,17 @@ linux_ifconf(struct thread *td, struct ifconf *uifc) full = 0; cbs.max_len = maxphys - 1; - CURVNET_SET(TD_TO_VNET(td)); /* handle the 'request buffer size' case */ if ((l_uintptr_t)ifc.ifc_buf == PTROUT(NULL)) { ifc.ifc_len = 0; NET_EPOCH_ENTER(et); if_foreach(linux_ifconf_ifnet_cb, &ifc); NET_EPOCH_EXIT(et); - error = copyout(&ifc, uifc, sizeof(ifc)); - CURVNET_RESTORE(); - return (error); + return (copyout(&ifc, uifc, sizeof(ifc))); } - if (ifc.ifc_len <= 0) { - CURVNET_RESTORE(); + if (ifc.ifc_len <= 0) return (EINVAL); - } again: if (ifc.ifc_len <= cbs.max_len) { @@ -2229,52 +2225,132 @@ again: if (error == 0) error = copyout(&ifc, uifc, sizeof(ifc)); sbuf_delete(sb); - CURVNET_RESTORE(); return (error); } static int -linux_gifflags(struct thread *td, struct ifnet *ifp, struct l_ifreq *ifr) +linux_ioctl_socket_ifreq(struct thread *td, int fd, u_int cmd, + struct l_ifreq *uifr) { - unsigned short flags; - - flags = linux_ifflags(ifp); - - return (copyout(&flags, &ifr->ifr_flags, sizeof(flags))); -} + struct l_ifreq lifr; + struct ifreq bifr; + size_t ifrusiz; + int error, temp_flags; -static int -linux_gifhwaddr(struct ifnet *ifp, struct l_ifreq *ifr) -{ - struct l_sockaddr lsa; - - if (linux_ifhwaddr(ifp, &lsa) != 0) - return (ENOENT); + switch (cmd) { + case LINUX_SIOCGIFINDEX: + cmd = SIOCGIFINDEX; + break; + case LINUX_SIOCGIFFLAGS: + cmd = SIOCGIFFLAGS; + break; + case LINUX_SIOCGIFADDR: + cmd = SIOCGIFADDR; + break; + case LINUX_SIOCSIFADDR: + cmd = SIOCSIFADDR; + break; + case LINUX_SIOCGIFDSTADDR: + cmd = SIOCGIFDSTADDR; + break; + case LINUX_SIOCGIFBRDADDR: + cmd = SIOCGIFBRDADDR; + break; + case LINUX_SIOCGIFNETMASK: + cmd = SIOCGIFNETMASK; + break; + case LINUX_SIOCSIFNETMASK: + cmd = SIOCSIFNETMASK; + break; + case LINUX_SIOCGIFMTU: + cmd = SIOCGIFMTU; + break; + case LINUX_SIOCSIFMTU: + cmd = SIOCSIFMTU; + break; + case LINUX_SIOCGIFHWADDR: + cmd = SIOCGHWADDR; + break; + /* + * XXX This is slightly bogus, but these ioctls are currently + * XXX only used by the aironet (if_an) network driver. + */ + case LINUX_SIOCDEVPRIVATE: + cmd = SIOCGPRIVATE_0; + break; + case LINUX_SIOCDEVPRIVATE+1: + cmd = SIOCGPRIVATE_1; + break; + default: + return (ENOIOCTL); + } - return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof(lsa))); -} + error = copyin(uifr, &lifr, sizeof(lifr)); + if (error != 0) + return (error); + bzero(&bifr, sizeof(bifr)); - /* -* If we fault in bsd_to_linux_ifreq() then we will fault when we call -* the native ioctl(). Thus, we don't really need to check the return -* value of this function. -*/ -static int -bsd_to_linux_ifreq(struct ifreq *arg) -{ - struct ifreq ifr; - size_t ifr_len = sizeof(struct ifreq); - int error; + /* + * The size of Linux enum ifr_ifru is bigger than + * the FreeBSD size due to the struct ifmap. + */ + ifrusiz = (sizeof(lifr) > sizeof(bifr) ? sizeof(bifr) : + sizeof(lifr)) - offsetof(struct l_ifreq, ifr_ifru); + bcopy(&lifr.ifr_ifru, &bifr.ifr_ifru, ifrusiz); - if ((error = copyin(arg, &ifr, ifr_len))) + error = ifname_linux_to_bsd(td, lifr.ifr_name, bifr.ifr_name); + if (error != 0) return (error); - *(u_short *)&ifr.ifr_addr = ifr.ifr_addr.sa_family; + /* Translate in values. */ + switch (cmd) { + case SIOCGIFINDEX: + bifr.ifr_index = lifr.ifr_index; + break; + case SIOCSIFADDR: + case SIOCSIFNETMASK: + bifr.ifr_addr.sa_len = sizeof(struct sockaddr); + bifr.ifr_addr.sa_family = + linux_to_bsd_domain(lifr.ifr_addr.sa_family); + break; + default: + break; + } - error = copyout(&ifr, arg, ifr_len); + error = kern_ioctl(td, fd, cmd, (caddr_t)&bifr); + if (error != 0) + return (error); + bzero(&lifr.ifr_ifru, sizeof(lifr.ifr_ifru)); + + /* Translate out values. */ + switch (cmd) { + case SIOCGIFINDEX: + lifr.ifr_index = bifr.ifr_index; + break; + case SIOCGIFFLAGS: + temp_flags = bifr.ifr_flags | (bifr.ifr_flagshigh << 16); + lifr.ifr_flags = bsd_to_linux_ifflags(temp_flags); + break; + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCGIFDSTADDR: + case SIOCGIFBRDADDR: + case SIOCGIFNETMASK: + bcopy(&bifr.ifr_addr, &lifr.ifr_addr, sizeof(bifr.ifr_addr)); + lifr.ifr_addr.sa_family = + bsd_to_linux_domain(bifr.ifr_addr.sa_family); + break; + case SIOCGHWADDR: + bcopy(&bifr.ifr_addr, &lifr.ifr_hwaddr, sizeof(bifr.ifr_addr)); + lifr.ifr_hwaddr.sa_family = LINUX_ARPHRD_ETHER; + break; + default: + bcopy(&bifr.ifr_ifru, &lifr.ifr_ifru, ifrusiz); + break; + } - return (error); + return (copyout(&lifr, uifr, sizeof(lifr))); } /* @@ -2284,84 +2360,34 @@ bsd_to_linux_ifreq(struct ifreq *arg) static int linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args) { - char lifname[LINUX_IFNAMSIZ], ifname[IFNAMSIZ]; - struct ifnet *ifp; struct file *fp; int error, type; - ifp = NULL; - error = 0; - error = fget(td, args->fd, &cap_ioctl_rights, &fp); if (error != 0) return (error); type = fp->f_type; fdrop(fp, td); + + CURVNET_SET(TD_TO_VNET(td)); + if (type != DTYPE_SOCKET) { /* not a socket - probably a tap / vmnet device */ switch (args->cmd) { case LINUX_SIOCGIFADDR: case LINUX_SIOCSIFADDR: case LINUX_SIOCGIFFLAGS: - return (linux_ioctl_special(td, args)); + error = linux_ioctl_special(td, args); + break; default: - return (ENOIOCTL); + error = ENOIOCTL; + break; } + CURVNET_RESTORE(); + return (error); } - switch (args->cmd & 0xffff) { - case LINUX_FIOGETOWN: - case LINUX_FIOSETOWN: - case LINUX_SIOCADDMULTI: - case LINUX_SIOCATMARK: - case LINUX_SIOCDELMULTI: - case LINUX_SIOCGIFNAME: - case LINUX_SIOCGIFCONF: - case LINUX_SIOCGPGRP: - case LINUX_SIOCSPGRP: - case LINUX_SIOCGIFCOUNT: - /* these ioctls don't take an interface name */ - break; - - case LINUX_SIOCGIFFLAGS: - case LINUX_SIOCGIFADDR: - case LINUX_SIOCSIFADDR: - case LINUX_SIOCGIFDSTADDR: - case LINUX_SIOCGIFBRDADDR: - case LINUX_SIOCGIFNETMASK: - case LINUX_SIOCSIFNETMASK: - case LINUX_SIOCGIFMTU: - case LINUX_SIOCSIFMTU: - case LINUX_SIOCSIFNAME: - case LINUX_SIOCGIFHWADDR: - case LINUX_SIOCSIFHWADDR: - case LINUX_SIOCDEVPRIVATE: - case LINUX_SIOCDEVPRIVATE+1: - case LINUX_SIOCGIFINDEX: - /* copy in the interface name and translate it. */ - error = copyin((void *)args->arg, lifname, LINUX_IFNAMSIZ); - if (error != 0) - return (error); - memset(ifname, 0, sizeof(ifname)); - ifp = ifname_linux_to_bsd(td, lifname, ifname); - if (ifp == NULL) - return (EINVAL); - /* - * We need to copy it back out in case we pass the - * request on to our native ioctl(), which will expect - * the ifreq to be in user space and have the correct - * interface name. - */ - error = copyout(ifname, (void *)args->arg, IFNAMSIZ); - if (error != 0) - return (error); - break; - - default: - return (ENOIOCTL); - } - - switch (args->cmd & 0xffff) { + switch (args->cmd) { case LINUX_FIOSETOWN: args->cmd = FIOSETOWN; error = sys_ioctl(td, (struct ioctl_args *)args); @@ -2397,67 +2423,6 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args) error = linux_ifconf(td, (struct ifconf *)args->arg); break; - case LINUX_SIOCGIFFLAGS: - args->cmd = SIOCGIFFLAGS; - error = linux_gifflags(td, ifp, (struct l_ifreq *)args->arg); - break; - - case LINUX_SIOCGIFADDR: - args->cmd = SIOCGIFADDR; - error = sys_ioctl(td, (struct ioctl_args *)args); - bsd_to_linux_ifreq((struct ifreq *)args->arg); - break; - - case LINUX_SIOCSIFADDR: - /* XXX probably doesn't work, included for completeness */ - args->cmd = SIOCSIFADDR; - error = sys_ioctl(td, (struct ioctl_args *)args); - break; - - case LINUX_SIOCGIFDSTADDR: - args->cmd = SIOCGIFDSTADDR; - error = sys_ioctl(td, (struct ioctl_args *)args); - bsd_to_linux_ifreq((struct ifreq *)args->arg); - break; - - case LINUX_SIOCGIFBRDADDR: - args->cmd = SIOCGIFBRDADDR; - error = sys_ioctl(td, (struct ioctl_args *)args); - bsd_to_linux_ifreq((struct ifreq *)args->arg); - break; - - case LINUX_SIOCGIFNETMASK: - args->cmd = SIOCGIFNETMASK; - error = sys_ioctl(td, (struct ioctl_args *)args); - bsd_to_linux_ifreq((struct ifreq *)args->arg); - break; - - case LINUX_SIOCSIFNETMASK: - error = ENOIOCTL; - break; - - case LINUX_SIOCGIFMTU: - args->cmd = SIOCGIFMTU; - error = sys_ioctl(td, (struct ioctl_args *)args); - break; - - case LINUX_SIOCSIFMTU: - args->cmd = SIOCSIFMTU; - error = sys_ioctl(td, (struct ioctl_args *)args); - break; - - case LINUX_SIOCSIFNAME: - error = ENOIOCTL; - break; - - case LINUX_SIOCGIFHWADDR: - error = linux_gifhwaddr(ifp, (struct l_ifreq *)args->arg); - break; - - case LINUX_SIOCSIFHWADDR: - error = ENOIOCTL; - break; - case LINUX_SIOCADDMULTI: args->cmd = SIOCADDMULTI; error = sys_ioctl(td, (struct ioctl_args *)args); @@ -2468,34 +2433,17 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args) error = sys_ioctl(td, (struct ioctl_args *)args); break; - case LINUX_SIOCGIFINDEX: - args->cmd = SIOCGIFINDEX; - error = sys_ioctl(td, (struct ioctl_args *)args); - break; - case LINUX_SIOCGIFCOUNT: error = 0; break; - /* - * XXX This is slightly bogus, but these ioctls are currently - * XXX only used by the aironet (if_an) network driver. - */ - case LINUX_SIOCDEVPRIVATE: - args->cmd = SIOCGPRIVATE_0; - error = sys_ioctl(td, (struct ioctl_args *)args); - break; - - case LINUX_SIOCDEVPRIVATE+1: - args->cmd = SIOCGPRIVATE_1; - error = sys_ioctl(td, (struct ioctl_args *)args); + default: + error = linux_ioctl_socket_ifreq(td, args->fd, args->cmd, + PTRIN(args->arg)); break; } - if (ifp != NULL) - /* restore the original interface name */ - copyout(lifname, (void *)args->arg, LINUX_IFNAMSIZ); - + CURVNET_RESTORE(); return (error); }