Print this page
OS-5549 move bpf filter functions into ip module
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Jerry Jelinek <jerry.jelinek@joyent.com>


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2015 Joyent, Inc. All rights reserved.
  25  */
  26 
  27 #include <sys/types.h>
  28 #include <sys/param.h>
  29 #include <sys/systm.h>
  30 #include <sys/stropts.h>
  31 #include <sys/socket.h>
  32 #include <sys/socketvar.h>
  33 #include <sys/socket_proto.h>
  34 #include <sys/sockio.h>
  35 #include <sys/strsun.h>
  36 #include <sys/kstat.h>
  37 #include <sys/modctl.h>
  38 #include <sys/policy.h>
  39 #include <sys/priv_const.h>
  40 #include <sys/tihdr.h>
  41 #include <sys/zone.h>
  42 #include <sys/time.h>
  43 #include <sys/ethernet.h>
  44 #include <sys/llc1.h>
  45 #include <fs/sockfs/sockcommon.h>
  46 #include <net/if.h>
  47 #include <inet/ip_arp.h>
  48 
  49 #include <sys/dls.h>
  50 #include <sys/mac.h>
  51 #include <sys/mac_client.h>
  52 #include <sys/mac_provider.h>
  53 #include <sys/mac_client_priv.h>

  54 
  55 #include <netpacket/packet.h>
  56 
  57 static void pfp_close(mac_handle_t, mac_client_handle_t);
  58 static int pfp_dl_to_arphrd(int);
  59 static int pfp_getpacket_sockopt(sock_lower_handle_t, int, void *,
  60     socklen_t *);
  61 static int pfp_ifreq_getlinkid(intptr_t, struct ifreq *, datalink_id_t *, int);
  62 static int pfp_lifreq_getlinkid(intptr_t, struct lifreq *, datalink_id_t *,
  63     int);
  64 static int pfp_open_index(int, mac_handle_t *, mac_client_handle_t *,
  65     cred_t *);
  66 static void pfp_packet(void *, mac_resource_handle_t, mblk_t *, boolean_t);
  67 static void pfp_release_bpf(struct pfpsock *);
  68 static int pfp_set_promisc(struct pfpsock *, mac_client_promisc_type_t);
  69 static int pfp_setsocket_sockopt(sock_lower_handle_t, int, const void *,
  70     socklen_t);
  71 static int pfp_setpacket_sockopt(sock_lower_handle_t, int, const void *,
  72     socklen_t);
  73 


 431         if (hdr.mhi_pktsize == 0)
 432                 hdr.mhi_pktsize = msgdsize(mp);
 433 
 434         /*
 435          * If a BPF filter is present, pass the raw packet into that.
 436          * A failed match will result in zero being returned, indicating
 437          * that this socket is not interested in the packet.
 438          */
 439         if (ps->ps_bpf.bf_len != 0) {
 440                 uchar_t *buffer;
 441                 int buflen;
 442 
 443                 buflen = MBLKL(mp);
 444                 if (hdr.mhi_pktsize == buflen) {
 445                         buffer = mp->b_rptr;
 446                 } else {
 447                         buflen = 0;
 448                         buffer = (uchar_t *)mp;
 449                 }
 450                 rw_enter(&ps->ps_bpflock, RW_READER);
 451                 if (bpf_filter(ps->ps_bpf.bf_insns, buffer,
 452                     hdr.mhi_pktsize, buflen) == 0) {
 453                         rw_exit(&ps->ps_bpflock);
 454                         ps->ps_stats.tp_drops++;
 455                         ks_stats.kp_recv_filtered.value.ui64++;
 456                         freemsg(mp);
 457                         return;
 458                 }
 459                 rw_exit(&ps->ps_bpflock);
 460         }
 461 
 462         if (ps->ps_type == SOCK_DGRAM) {
 463                 /*
 464                  * SOCK_DGRAM socket expect a "layer 3" packet, so advance
 465                  * past the link layer header.
 466                  */
 467                 mp->b_rptr += hdr.mhi_hdrsize;
 468                 hdr.mhi_pktsize -= hdr.mhi_hdrsize;
 469         }
 470 
 471         tusz = sizeof (struct T_unitdata_ind) + sizeof (struct sockaddr_ll);


1319                 error = EINVAL;
1320                 break;
1321         }
1322 
1323         return (error);
1324 }
1325 
1326 /*
1327  * There are only two special setsockopt's for SOL_SOCKET with PF_PACKET:
1328  * SO_ATTACH_FILTER and SO_DETACH_FILTER.
1329  *
1330  * Both of these setsockopt values are candidates for being handled by the
1331  * socket layer itself in future, however this requires understanding how
1332  * they would interact with all other sockets.
1333  */
1334 static int
1335 pfp_setsocket_sockopt(sock_lower_handle_t handle, int option_name,
1336     const void *optval, socklen_t optlen)
1337 {
1338         struct bpf_program prog;
1339         struct bpf_insn *fcode;
1340         struct pfpsock *ps;
1341         struct sock_proto_props sopp;
1342         int error = 0;
1343         int size;
1344 
1345         ps = (struct pfpsock *)handle;
1346 
1347         switch (option_name) {
1348         case SO_ATTACH_FILTER :
1349 #ifdef _LP64
1350                 if (optlen == sizeof (struct bpf_program32)) {
1351                         struct bpf_program32 prog32;
1352 
1353                         bcopy(optval, &prog32, sizeof (prog32));
1354                         prog.bf_len = prog32.bf_len;
1355                         prog.bf_insns = (void *)(uint64_t)prog32.bf_insns;
1356                 } else
1357 #endif
1358                 if (optlen == sizeof (struct bpf_program)) {
1359                         bcopy(optval, &prog, sizeof (prog));
1360                 } else if (optlen != sizeof (struct bpf_program)) {
1361                         return (EINVAL);
1362                 }
1363                 if (prog.bf_len > BPF_MAXINSNS)
1364                         return (EINVAL);
1365 
1366                 size = prog.bf_len * sizeof (*prog.bf_insns);
1367                 fcode = kmem_alloc(size, KM_SLEEP);
1368                 if (ddi_copyin(prog.bf_insns, fcode, size, 0) != 0) {
1369                         kmem_free(fcode, size);
1370                         return (EFAULT);
1371                 }
1372 
1373                 if (bpf_validate(fcode, (int)prog.bf_len)) {
1374                         rw_enter(&ps->ps_bpflock, RW_WRITER);
1375                         pfp_release_bpf(ps);
1376                         ps->ps_bpf.bf_insns = fcode;
1377                         ps->ps_bpf.bf_len = size;
1378                         rw_exit(&ps->ps_bpflock);
1379 
1380                         return (0);
1381                 }
1382                 kmem_free(fcode, size);
1383                 error = EINVAL;
1384                 break;
1385 
1386         case SO_DETACH_FILTER :
1387                 pfp_release_bpf(ps);
1388                 break;
1389 
1390         case SO_RCVBUF :
1391                 size = *(int32_t *)optval;
1392                 if (size > sockmod_pfp_rcvbuf_max || size < 0)
1393                         return (ENOBUFS);
1394                 sopp.sopp_flags = SOCKOPT_RCVHIWAT;
1395                 sopp.sopp_rxhiwat = size;
1396                 ps->ps_upcalls->su_set_proto_props(ps->ps_upper, &sopp);




   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2016 Joyent, Inc.
  25  */
  26 
  27 #include <sys/types.h>
  28 #include <sys/param.h>
  29 #include <sys/systm.h>
  30 #include <sys/stropts.h>
  31 #include <sys/socket.h>
  32 #include <sys/socketvar.h>
  33 #include <sys/socket_proto.h>
  34 #include <sys/sockio.h>
  35 #include <sys/strsun.h>
  36 #include <sys/kstat.h>
  37 #include <sys/modctl.h>
  38 #include <sys/policy.h>
  39 #include <sys/priv_const.h>
  40 #include <sys/tihdr.h>
  41 #include <sys/zone.h>
  42 #include <sys/time.h>
  43 #include <sys/ethernet.h>
  44 #include <sys/llc1.h>
  45 #include <fs/sockfs/sockcommon.h>
  46 #include <net/if.h>
  47 #include <inet/ip_arp.h>
  48 
  49 #include <sys/dls.h>
  50 #include <sys/mac.h>
  51 #include <sys/mac_client.h>
  52 #include <sys/mac_provider.h>
  53 #include <sys/mac_client_priv.h>
  54 #include <inet/bpf.h>
  55 
  56 #include <netpacket/packet.h>
  57 
  58 static void pfp_close(mac_handle_t, mac_client_handle_t);
  59 static int pfp_dl_to_arphrd(int);
  60 static int pfp_getpacket_sockopt(sock_lower_handle_t, int, void *,
  61     socklen_t *);
  62 static int pfp_ifreq_getlinkid(intptr_t, struct ifreq *, datalink_id_t *, int);
  63 static int pfp_lifreq_getlinkid(intptr_t, struct lifreq *, datalink_id_t *,
  64     int);
  65 static int pfp_open_index(int, mac_handle_t *, mac_client_handle_t *,
  66     cred_t *);
  67 static void pfp_packet(void *, mac_resource_handle_t, mblk_t *, boolean_t);
  68 static void pfp_release_bpf(struct pfpsock *);
  69 static int pfp_set_promisc(struct pfpsock *, mac_client_promisc_type_t);
  70 static int pfp_setsocket_sockopt(sock_lower_handle_t, int, const void *,
  71     socklen_t);
  72 static int pfp_setpacket_sockopt(sock_lower_handle_t, int, const void *,
  73     socklen_t);
  74 


 432         if (hdr.mhi_pktsize == 0)
 433                 hdr.mhi_pktsize = msgdsize(mp);
 434 
 435         /*
 436          * If a BPF filter is present, pass the raw packet into that.
 437          * A failed match will result in zero being returned, indicating
 438          * that this socket is not interested in the packet.
 439          */
 440         if (ps->ps_bpf.bf_len != 0) {
 441                 uchar_t *buffer;
 442                 int buflen;
 443 
 444                 buflen = MBLKL(mp);
 445                 if (hdr.mhi_pktsize == buflen) {
 446                         buffer = mp->b_rptr;
 447                 } else {
 448                         buflen = 0;
 449                         buffer = (uchar_t *)mp;
 450                 }
 451                 rw_enter(&ps->ps_bpflock, RW_READER);
 452                 if (ip_bpf_filter((ip_bpf_insn_t *)ps->ps_bpf.bf_insns, buffer,
 453                     hdr.mhi_pktsize, buflen) == 0) {
 454                         rw_exit(&ps->ps_bpflock);
 455                         ps->ps_stats.tp_drops++;
 456                         ks_stats.kp_recv_filtered.value.ui64++;
 457                         freemsg(mp);
 458                         return;
 459                 }
 460                 rw_exit(&ps->ps_bpflock);
 461         }
 462 
 463         if (ps->ps_type == SOCK_DGRAM) {
 464                 /*
 465                  * SOCK_DGRAM socket expect a "layer 3" packet, so advance
 466                  * past the link layer header.
 467                  */
 468                 mp->b_rptr += hdr.mhi_hdrsize;
 469                 hdr.mhi_pktsize -= hdr.mhi_hdrsize;
 470         }
 471 
 472         tusz = sizeof (struct T_unitdata_ind) + sizeof (struct sockaddr_ll);


1320                 error = EINVAL;
1321                 break;
1322         }
1323 
1324         return (error);
1325 }
1326 
1327 /*
1328  * There are only two special setsockopt's for SOL_SOCKET with PF_PACKET:
1329  * SO_ATTACH_FILTER and SO_DETACH_FILTER.
1330  *
1331  * Both of these setsockopt values are candidates for being handled by the
1332  * socket layer itself in future, however this requires understanding how
1333  * they would interact with all other sockets.
1334  */
1335 static int
1336 pfp_setsocket_sockopt(sock_lower_handle_t handle, int option_name,
1337     const void *optval, socklen_t optlen)
1338 {
1339         struct bpf_program prog;
1340         ip_bpf_insn_t *fcode;
1341         struct pfpsock *ps;
1342         struct sock_proto_props sopp;
1343         int error = 0;
1344         int size;
1345 
1346         ps = (struct pfpsock *)handle;
1347 
1348         switch (option_name) {
1349         case SO_ATTACH_FILTER :
1350 #ifdef _LP64
1351                 if (optlen == sizeof (struct bpf_program32)) {
1352                         struct bpf_program32 prog32;
1353 
1354                         bcopy(optval, &prog32, sizeof (prog32));
1355                         prog.bf_len = prog32.bf_len;
1356                         prog.bf_insns = (void *)(uint64_t)prog32.bf_insns;
1357                 } else
1358 #endif
1359                 if (optlen == sizeof (struct bpf_program)) {
1360                         bcopy(optval, &prog, sizeof (prog));
1361                 } else if (optlen != sizeof (struct bpf_program)) {
1362                         return (EINVAL);
1363                 }
1364                 if (prog.bf_len > BPF_MAXINSNS)
1365                         return (EINVAL);
1366 
1367                 size = prog.bf_len * sizeof (*prog.bf_insns);
1368                 fcode = kmem_alloc(size, KM_SLEEP);
1369                 if (ddi_copyin(prog.bf_insns, fcode, size, 0) != 0) {
1370                         kmem_free(fcode, size);
1371                         return (EFAULT);
1372                 }
1373 
1374                 if (ip_bpf_validate(fcode, prog.bf_len)) {
1375                         rw_enter(&ps->ps_bpflock, RW_WRITER);
1376                         pfp_release_bpf(ps);
1377                         ps->ps_bpf.bf_insns = (struct bpf_insn *)fcode;
1378                         ps->ps_bpf.bf_len = size;
1379                         rw_exit(&ps->ps_bpflock);
1380 
1381                         return (0);
1382                 }
1383                 kmem_free(fcode, size);
1384                 error = EINVAL;
1385                 break;
1386 
1387         case SO_DETACH_FILTER :
1388                 pfp_release_bpf(ps);
1389                 break;
1390 
1391         case SO_RCVBUF :
1392                 size = *(int32_t *)optval;
1393                 if (size > sockmod_pfp_rcvbuf_max || size < 0)
1394                         return (ENOBUFS);
1395                 sopp.sopp_flags = SOCKOPT_RCVHIWAT;
1396                 sopp.sopp_rxhiwat = size;
1397                 ps->ps_upcalls->su_set_proto_props(ps->ps_upper, &sopp);