Author: brooks
Date: Sun Apr  8 15:52:32 2018
New Revision: 332281
URL: https://svnweb.freebsd.org/changeset/base/332281

Log:
  MFC r331641, r331644, r332158
  
  r331641:
  Fix access to ifru_buffer on freebsd32.
  
  Make all kernel accesses to ifru_buffer go via access functions
  which take the process ABI into account and use an appropriate union
  to access members in the correct place in struct ifreq.
  
  Reviewed by:  kib
  Obtained from:        CheriBSD
  Sponsored by: DARPA, AFRL
  Differential Revision:        https://reviews.freebsd.org/D14846
  
  r331644:
  Fix a whitespace bug missed in refactoring prior to r331641.
  
  MFC with:     r331641
  
  r332158:
  Remove the thread argument from ifr_buffer_*() accessors.
  
  They are always used in a context where curthread is the correct thread.
  This makes them more similar to the ifr_data_get_ptr() accessor.

Modified:
  stable/11/sys/net/if.c
  stable/11/sys/net/if.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/net/if.c
==============================================================================
--- stable/11/sys/net/if.c      Sun Apr  8 15:35:57 2018        (r332280)
+++ stable/11/sys/net/if.c      Sun Apr  8 15:52:32 2018        (r332281)
@@ -55,6 +55,7 @@
 #include <sys/sockio.h>
 #include <sys/syslog.h>
 #include <sys/sysctl.h>
+#include <sys/sysent.h>
 #include <sys/taskqueue.h>
 #include <sys/domain.h>
 #include <sys/jail.h>
@@ -97,8 +98,50 @@
 #ifdef COMPAT_FREEBSD32
 #include <sys/mount.h>
 #include <compat/freebsd32/freebsd32.h>
+
+struct ifreq_buffer32 {
+       uint32_t        length;         /* (size_t) */
+       uint32_t        buffer;         /* (void *) */
+};
+
+/*
+ * Interface request structure used for socket
+ * ioctl's.  All interface ioctl's must have parameter
+ * definitions which begin with ifr_name.  The
+ * remainder may be interface specific.
+ */
+struct ifreq32 {
+       char    ifr_name[IFNAMSIZ];             /* if name, e.g. "en0" */
+       union {
+               struct sockaddr ifru_addr;
+               struct sockaddr ifru_dstaddr;
+               struct sockaddr ifru_broadaddr;
+               struct ifreq_buffer32 ifru_buffer;
+               short           ifru_flags[2];
+               short           ifru_index;
+               int             ifru_jid;
+               int             ifru_metric;
+               int             ifru_mtu;
+               int             ifru_phys;
+               int             ifru_media;
+               uint32_t        ifru_data;
+               int             ifru_cap[2];
+               u_int           ifru_fib;
+               u_char          ifru_vlan_pcp;
+       } ifr_ifru;
+};
+CTASSERT(sizeof(struct ifreq) == sizeof(struct ifreq32));
+CTASSERT(__offsetof(struct ifreq, ifr_ifru) ==
+    __offsetof(struct ifreq32, ifr_ifru));
 #endif
 
+union ifreq_union {
+       struct ifreq    ifr;
+#ifdef COMPAT_FREEBSD32
+       struct ifreq32  ifr32;
+#endif
+};
+
 SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers");
 SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management");
 
@@ -2302,6 +2345,61 @@ ifunit(const char *name)
        return (ifp);
 }
 
+static void *
+ifr_buffer_get_buffer(void *data)
+{
+       union ifreq_union *ifrup;
+
+       ifrup = data;
+#ifdef COMPAT_FREEBSD32
+       if (SV_CURPROC_FLAG(SV_ILP32))
+               return ((void *)(uintptr_t)
+                   ifrup->ifr32.ifr_ifru.ifru_buffer.buffer);
+#endif
+       return (ifrup->ifr.ifr_ifru.ifru_buffer.buffer);
+}
+
+static void
+ifr_buffer_set_buffer_null(void *data)
+{
+       union ifreq_union *ifrup;
+
+       ifrup = data;
+#ifdef COMPAT_FREEBSD32
+       if (SV_CURPROC_FLAG(SV_ILP32))
+               ifrup->ifr32.ifr_ifru.ifru_buffer.buffer = 0;
+       else
+#endif
+               ifrup->ifr.ifr_ifru.ifru_buffer.buffer = NULL;
+}
+
+static size_t
+ifr_buffer_get_length(void *data)
+{
+       union ifreq_union *ifrup;
+
+       ifrup = data;
+#ifdef COMPAT_FREEBSD32
+       if (SV_CURPROC_FLAG(SV_ILP32))
+               return (ifrup->ifr32.ifr_ifru.ifru_buffer.length);
+#endif
+       return (ifrup->ifr.ifr_ifru.ifru_buffer.length);
+}
+
+static void
+ifr_buffer_set_length(void *data, size_t len)
+{
+       union ifreq_union *ifrup;
+
+       ifrup = data;
+#ifdef COMPAT_FREEBSD32
+       if (SV_CURPROC_FLAG(SV_ILP32))
+               ifrup->ifr32.ifr_ifru.ifru_buffer.length = len;
+       else
+#endif
+               ifrup->ifr.ifr_ifru.ifru_buffer.length = len;
+}
+
 /*
  * Hardware specific interface ioctls.
  */
@@ -2362,12 +2460,12 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data,
                else {
                        /* space for terminating nul */
                        descrlen = strlen(ifp->if_description) + 1;
-                       if (ifr->ifr_buffer.length < descrlen)
-                               ifr->ifr_buffer.buffer = NULL;
+                       if (ifr_buffer_get_length(ifr) < descrlen)
+                               ifr_buffer_set_buffer_null(ifr);
                        else
                                error = copyout(ifp->if_description,
-                                   ifr->ifr_buffer.buffer, descrlen);
-                       ifr->ifr_buffer.length = descrlen;
+                                   ifr_buffer_get_buffer(ifr), descrlen);
+                       ifr_buffer_set_length(ifr, descrlen);
                }
                sx_sunlock(&ifdescr_sx);
                break;
@@ -2383,15 +2481,15 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data,
                 * length parameter is supposed to count the
                 * terminating nul in.
                 */
-               if (ifr->ifr_buffer.length > ifdescr_maxlen)
+               if (ifr_buffer_get_length(ifr) > ifdescr_maxlen)
                        return (ENAMETOOLONG);
-               else if (ifr->ifr_buffer.length == 0)
+               else if (ifr_buffer_get_length(ifr) == 0)
                        descrbuf = NULL;
                else {
-                       descrbuf = malloc(ifr->ifr_buffer.length, M_IFDESCR,
-                           M_WAITOK | M_ZERO);
-                       error = copyin(ifr->ifr_buffer.buffer, descrbuf,
-                           ifr->ifr_buffer.length - 1);
+                       descrbuf = malloc(ifr_buffer_get_length(ifr),
+                           M_IFDESCR, M_WAITOK | M_ZERO);
+                       error = copyin(ifr_buffer_get_buffer(ifr), descrbuf,
+                           ifr_buffer_get_length(ifr) - 1);
                        if (error) {
                                free(descrbuf, M_IFDESCR);
                                break;

Modified: stable/11/sys/net/if.h
==============================================================================
--- stable/11/sys/net/if.h      Sun Apr  8 15:35:57 2018        (r332280)
+++ stable/11/sys/net/if.h      Sun Apr  8 15:52:32 2018        (r332281)
@@ -398,7 +398,9 @@ struct      ifreq {
 #define        ifr_addr        ifr_ifru.ifru_addr      /* address */
 #define        ifr_dstaddr     ifr_ifru.ifru_dstaddr   /* other end of p-to-p 
link */
 #define        ifr_broadaddr   ifr_ifru.ifru_broadaddr /* broadcast address */
+#ifndef _KERNEL
 #define        ifr_buffer      ifr_ifru.ifru_buffer    /* user supplied buffer 
with its length */
+#endif
 #define        ifr_flags       ifr_ifru.ifru_flags[0]  /* flags (low 16 bits) 
*/
 #define        ifr_flagshigh   ifr_ifru.ifru_flags[1]  /* flags (high 16 bits) 
*/
 #define        ifr_jid         ifr_ifru.ifru_jid       /* jail/vnet */
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to