tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: bridge sioc[gs]drvspec operations incompatible with COMPAT_NETBSD32
Hi Matt
On 2015-05-30 01:02, Matt Thomas wrote:
The use of SIOC[GS]DRVSPEC to copyin or copyout other structures which
have pointers/size_t/u_long makes them very hard to deal with in
COMPAT_NETBSD32.
The simplest solution is to eliminate the use of the ifbifconf and
ifbaconf structures in userland and have BRDGGIFS and BRDGRTS use the
ifdrv struct members ifd_len and ifb_data directly for their needs.
The netbsd32 compat code already deals with this so this just requires
a small change to if_bridge{.c,var.h}. I also converted ifbareq to
use fixed types in the diff.
Make brconfig to deal with the new method actually makes brconfig
simplier.
There is the problem of missing compat code for the old ifbareq but
I’m not sure if it’s really required.
Comments?
Thanks for working on this!
I took your patch and adjusted it some more:
* Added a check in the kernel if we have a function in the command
table as the ipfilter stuff is optional and I think the table
will now always grow beyond it.
* added an extra parameter to do_cmd in brconfig.c so we can
get the returned length from the ioctl. This allows us to know
if we need a bigger buffer or not.
Seems to be working fine now, at least for setup.
Will be able to plug another interface in once PPPoE works to actually
test it with though.
While in brconfig, I notice that the kernel returns the length needed
if the buffer is too small, but brconfig just does old length *2 and
tries again. Is it worthwile fixing this to grow a buffer of what
the kernel actually wants?
Comments on this welcome!
Roy
Index: sys/net/if_bridge.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_bridge.c,v
retrieving revision 1.98
diff -u -r1.98 if_bridge.c
--- sys/net/if_bridge.c 16 Apr 2015 08:54:15 -0000 1.98
+++ sys/net/if_bridge.c 31 May 2015 09:40:09 -0000
@@ -143,6 +143,10 @@
#include <netinet/ip_carp.h>
#endif
+__CTASSERT(sizeof(struct ifbifconf) == sizeof(struct ifbaconf));
+__CTASSERT(offsetof(struct ifbifconf, ifbic_len) == offsetof(struct ifbaconf, ifbac_len));
+__CTASSERT(offsetof(struct ifbifconf, ifbic_buf) == offsetof(struct ifbaconf, ifbac_buf));
+
/*
* Maximum number of addresses to cache.
*/
@@ -306,6 +310,8 @@
#define BC_F_COPYIN 0x01 /* copy arguments in */
#define BC_F_COPYOUT 0x02 /* copy arguments out */
#define BC_F_SUSER 0x04 /* do super-user check */
+#define BC_F_XLATEIN 0x08 /* xlate arguments in */
+#define BC_F_XLATEOUT 0x10 /* xlate arguments out */
static const struct bridge_control bridge_control_table[] = {
[BRDGADD] = {bridge_ioctl_add, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER},
@@ -317,8 +323,8 @@
[BRDGSCACHE] = {bridge_ioctl_scache, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER},
[BRDGGCACHE] = {bridge_ioctl_gcache, sizeof(struct ifbrparam), BC_F_COPYOUT},
-[BRDGGIFS] = {bridge_ioctl_gifs, sizeof(struct ifbifconf), BC_F_COPYIN|BC_F_COPYOUT},
-[BRDGRTS] = {bridge_ioctl_rts, sizeof(struct ifbaconf), BC_F_COPYIN|BC_F_COPYOUT},
+[OBRDGGIFS] = {bridge_ioctl_gifs, sizeof(struct ifbifconf), BC_F_COPYIN|BC_F_COPYOUT},
+[OBRDGRTS] = {bridge_ioctl_rts, sizeof(struct ifbaconf), BC_F_COPYIN|BC_F_COPYOUT},
[BRDGSADDR] = {bridge_ioctl_saddr, sizeof(struct ifbareq), BC_F_COPYIN|BC_F_SUSER},
@@ -348,7 +354,10 @@
[BRDGGFILT] = {bridge_ioctl_gfilt, sizeof(struct ifbrparam), BC_F_COPYOUT},
[BRDGSFILT] = {bridge_ioctl_sfilt, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER},
#endif /* BRIDGE_IPF */
+[BRDGGIFS] = {bridge_ioctl_gifs, sizeof(struct ifbifconf), BC_F_XLATEIN|BC_F_XLATEOUT},
+[BRDGRTS] = {bridge_ioctl_rts, sizeof(struct ifbaconf), BC_F_XLATEIN|BC_F_XLATEOUT},
};
+
static const int bridge_control_table_size = __arraycount(bridge_control_table);
static LIST_HEAD(, bridge_softc) bridge_list;
@@ -627,6 +636,12 @@
}
bc = &bridge_control_table[ifd->ifd_cmd];
+ /* Some commands are optionally included, so check
+ * there is actually a function to call. */
+ if (bc->bc_func == NULL) {
+ error = ENOTSUP;
+ return error;
+ }
/* We only care about BC_F_SUSER at this point. */
if ((bc->bc_flags & BC_F_SUSER) == 0)
@@ -651,20 +666,21 @@
case SIOCSDRVSPEC:
KASSERT(bc != NULL);
if (cmd == SIOCGDRVSPEC &&
- (bc->bc_flags & BC_F_COPYOUT) == 0) {
+ (bc->bc_flags & (BC_F_COPYOUT|BC_F_XLATEOUT)) == 0) {
error = EINVAL;
break;
}
else if (cmd == SIOCSDRVSPEC &&
- (bc->bc_flags & BC_F_COPYOUT) != 0) {
+ (bc->bc_flags & (BC_F_COPYOUT|BC_F_XLATEOUT)) != 0) {
error = EINVAL;
break;
}
/* BC_F_SUSER is checked above, before splnet(). */
- if (ifd->ifd_len != bc->bc_argsize ||
- ifd->ifd_len > sizeof(args)) {
+ if ((bc->bc_flags & (BC_F_XLATEIN|BC_F_XLATEOUT)) == 0
+ && (ifd->ifd_len != bc->bc_argsize
+ || ifd->ifd_len > sizeof(args))) {
error = EINVAL;
break;
}
@@ -674,15 +690,21 @@
error = copyin(ifd->ifd_data, &args, ifd->ifd_len);
if (error)
break;
+ } else if (bc->bc_flags & BC_F_XLATEIN) {
+ args.ifbifconf.ifbic_len = ifd->ifd_len;
+ args.ifbifconf.ifbic_buf = ifd->ifd_data;
}
error = (*bc->bc_func)(sc, &args);
if (error)
break;
- if (bc->bc_flags & BC_F_COPYOUT)
+ if (bc->bc_flags & BC_F_COPYOUT) {
error = copyout(&args, ifd->ifd_data, ifd->ifd_len);
-
+ } else if (bc->bc_flags & BC_F_XLATEOUT) {
+ ifd->ifd_len = args.ifbifconf.ifbic_len;
+ ifd->ifd_data = args.ifbifconf.ifbic_buf;
+ }
break;
case SIOCSIFFLAGS:
Index: sys/net/if_bridgevar.h
===================================================================
RCS file: /cvsroot/src/sys/net/if_bridgevar.h,v
retrieving revision 1.23
diff -u -r1.23 if_bridgevar.h
--- sys/net/if_bridgevar.h 16 Jan 2015 10:36:14 -0000 1.23
+++ sys/net/if_bridgevar.h 31 May 2015 09:40:09 -0000
@@ -90,8 +90,8 @@
#define BRDGSIFFLGS 3 /* set member if flags (ifbreq) */
#define BRDGSCACHE 4 /* set cache size (ifbrparam) */
#define BRDGGCACHE 5 /* get cache size (ifbrparam) */
-#define BRDGGIFS 6 /* get member list (ifbifconf) */
-#define BRDGRTS 7 /* get address list (ifbaconf) */
+#define OBRDGGIFS 6 /* get member list (ifbifconf) */
+#define OBRDGRTS 7 /* get address list (ifbaconf) */
#define BRDGSADDR 8 /* set static address (ifbareq) */
#define BRDGSTO 9 /* set cache timeout (ifbrparam) */
#define BRDGGTO 10 /* get cache timeout (ifbrparam) */
@@ -111,6 +111,9 @@
#define BRDGGFILT 23 /* get filter flags (ifbrparam) */
#define BRDGSFILT 24 /* set filter flags (ifbrparam) */
+#define BRDGGIFS 25 /* get member list */
+#define BRDGRTS 26 /* get address list */
+
/*
* Generic bridge control request.
*/
@@ -163,8 +166,7 @@
*/
struct ifbareq {
char ifba_ifsname[IFNAMSIZ]; /* member if name */
- /*XXX: time_t */
- long ifba_expire; /* address expire time */
+ time_t ifba_expire; /* address expire time */
uint8_t ifba_flags; /* address flags */
uint8_t ifba_dst[ETHER_ADDR_LEN];/* destination address */
};
Index: sbin/brconfig/brconfig.c
===================================================================
RCS file: /cvsroot/src/sbin/brconfig/brconfig.c,v
retrieving revision 1.16
diff -u -r1.16 brconfig.c
--- sbin/brconfig/brconfig.c 28 May 2015 20:14:00 -0000 1.16
+++ sbin/brconfig/brconfig.c 31 May 2015 09:40:09 -0000
@@ -141,7 +141,9 @@
static void show_interfaces(int, const char *, const char *);
static void show_addresses(int, const char *, const char *);
static int get_val(const char *, u_long *);
-static int do_cmd(int, const char *, u_long, void *, size_t, int);
+#define do_cmd(sock, ifname, cmd, buf, buflen, set) \
+ do_cmdl((sock), (ifname), (cmd), (buf), (buflen), NULL, (set))
+static int do_cmdl(int, const char *, u_long, void *, size_t, size_t*, int);
static void do_ifflag(int, const char *, int, int);
static void do_bridgeflag(int, const char *, const char *, int, int);
@@ -418,26 +420,26 @@
"forwarding",
"blocking",
};
- struct ifbifconf bifc;
struct ifbreq *req;
char *inbuf = NULL, *ninbuf;
- uint32_t i, len = 8192;
+ size_t i, len = 8192, olen;
for (;;) {
ninbuf = realloc(inbuf, len);
if (ninbuf == NULL)
err(1, "unable to allocate interface buffer");
- bifc.ifbic_len = len;
- bifc.ifbic_buf = inbuf = ninbuf;
- if (do_cmd(sock, bridge, BRDGGIFS, &bifc, sizeof(bifc), 0) < 0)
+ inbuf = ninbuf;
+ if (do_cmdl(sock, bridge, BRDGGIFS, inbuf, len, &olen, 0) < 0)
err(1, "unable to get interface list");
- if ((bifc.ifbic_len + sizeof(*req)) < len)
+ if (olen <= len)
break;
len *= 2;
}
- for (i = 0; i < bifc.ifbic_len / sizeof(*req); i++) {
- req = bifc.ifbic_req + i;
+ for (i = 0, req = (struct ifbreq *)inbuf;
+ i < olen / sizeof(*req);
+ i++, req++)
+ {
printf("%s%s ", prefix, req->ifbr_ifsname);
printb("flags", req->ifbr_ifsflags, IFBIFBITS);
printf("\n");
@@ -462,31 +464,31 @@
static void
show_addresses(int sock, const char *bridge, const char *prefix)
{
- struct ifbaconf ifbac;
struct ifbareq *ifba;
char *inbuf = NULL, *ninbuf;
- uint32_t i, len = 8192;
+ size_t i, len = 8192, olen;
struct ether_addr ea;
for (;;) {
ninbuf = realloc(inbuf, len);
if (ninbuf == NULL)
err(1, "unable to allocate address buffer");
- ifbac.ifbac_len = len;
- ifbac.ifbac_buf = inbuf = ninbuf;
- if (do_cmd(sock, bridge, BRDGRTS, &ifbac, sizeof(ifbac), 0) < 0)
+ inbuf = ninbuf;
+ if (do_cmdl(sock, bridge, BRDGRTS, inbuf, len, &olen, 0) < 0)
err(1, "unable to get address cache");
- if ((ifbac.ifbac_len + sizeof(*ifba)) < len)
+ if (olen <= len)
break;
len *= 2;
}
- for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) {
- ifba = ifbac.ifbac_req + i;
+ for (i = 0, ifba = (struct ifbareq *)inbuf;
+ i < olen / sizeof(*ifba);
+ i++, ifba++)
+ {
memcpy(ea.ether_addr_octet, ifba->ifba_dst,
sizeof(ea.ether_addr_octet));
- printf("%s%s %s %ld ", prefix, ether_ntoa(&ea),
- ifba->ifba_ifsname, ifba->ifba_expire);
+ printf("%s%s %s %lld ", prefix, ether_ntoa(&ea),
+ ifba->ifba_ifsname, (long long)ifba->ifba_expire);
printb("flags", ifba->ifba_flags, IFBAFBITS);
printf("\n");
}
@@ -510,10 +512,11 @@
}
static int
-do_cmd(int sock, const char *bridge, u_long op, void *arg, size_t argsize,
- int set)
+do_cmdl(int sock, const char *bridge, u_long op, void *arg, size_t argsize,
+ size_t *outsize, int set)
{
struct ifdrv ifd;
+ int r;
memset(&ifd, 0, sizeof(ifd));
@@ -522,7 +525,11 @@
ifd.ifd_len = argsize;
ifd.ifd_data = arg;
- return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
+ r = ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd);
+ if (outsize != NULL && r >= 0)
+ *outsize = ifd.ifd_len;
+
+ return r;
}
static void
Home |
Main Index |
Thread Index |
Old Index