Home | History | Annotate | Download | only in security_ProtocolFamilies
      1 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import logging
      6 import socket
      7 
      8 from autotest_lib.client.bin import test, utils
      9 from autotest_lib.client.common_lib import error
     10 
     11 
     12 # From <bits/socket.h> on Linux 3.2, EGLIBC 2.15.
     13 PROTOCOL_FAMILIES_STR = """
     14 #define PF_UNSPEC       0       /* Unspecified.  */
     15 #define PF_LOCAL        1       /* Local to host (pipes and file-domain).  */
     16 #define PF_UNIX         1       /* POSIX name for PF_LOCAL.  */
     17 #define PF_FILE         1       /* Another non-standard name for PF_LOCAL.  */
     18 #define PF_INET         2       /* IP protocol family.  */
     19 #define PF_AX25         3       /* Amateur Radio AX.25.  */
     20 #define PF_IPX          4       /* Novell Internet Protocol.  */
     21 #define PF_APPLETALK    5       /* Appletalk DDP.  */
     22 #define PF_NETROM       6       /* Amateur radio NetROM.  */
     23 #define PF_BRIDGE       7       /* Multiprotocol bridge.  */
     24 #define PF_ATMPVC       8       /* ATM PVCs.  */
     25 #define PF_X25          9       /* Reserved for X.25 project.  */
     26 #define PF_INET6        10      /* IP version 6.  */
     27 #define PF_ROSE         11      /* Amateur Radio X.25 PLP.  */
     28 #define PF_DECnet       12      /* Reserved for DECnet project.  */
     29 #define PF_NETBEUI      13      /* Reserved for 802.2LLC project.  */
     30 #define PF_SECURITY     14      /* Security callback pseudo AF.  */
     31 #define PF_KEY          15      /* PF_KEY key management API.  */
     32 #define PF_NETLINK      16
     33 #define PF_ROUTE        16      /* Alias to emulate 4.4BSD.  */
     34 #define PF_PACKET       17      /* Packet family.  */
     35 #define PF_ASH          18      /* Ash.  */
     36 #define PF_ECONET       19      /* Acorn Econet.  */
     37 #define PF_ATMSVC       20      /* ATM SVCs.  */
     38 #define PF_RDS          21      /* RDS sockets.  */
     39 #define PF_SNA          22      /* Linux SNA Project */
     40 #define PF_IRDA         23      /* IRDA sockets.  */
     41 #define PF_PPPOX        24      /* PPPoX sockets.  */
     42 #define PF_WANPIPE      25      /* Wanpipe API sockets.  */
     43 #define PF_LLC          26      /* Linux LLC.  */
     44 #define PF_CAN          29      /* Controller Area Network.  */
     45 #define PF_TIPC         30      /* TIPC sockets.  */
     46 #define PF_BLUETOOTH    31      /* Bluetooth sockets.  */
     47 #define PF_IUCV         32      /* IUCV sockets.  */
     48 #define PF_RXRPC        33      /* RxRPC sockets.  */
     49 #define PF_ISDN         34      /* mISDN sockets.  */
     50 #define PF_PHONET       35      /* Phonet sockets.  */
     51 #define PF_IEEE802154   36      /* IEEE 802.15.4 sockets.  */
     52 #define PF_CAIF         37      /* CAIF sockets.  */
     53 #define PF_ALG          38      /* Algorithm sockets.  */
     54 #define PF_NFC          39      /* NFC sockets.  */
     55 #define PF_MAX          40      /* For now...  */
     56 """
     57 
     58 PROTOCOL_FAMILIES = dict([(int(line.split()[2]), line.split()[1])
     59                           for line
     60                           in PROTOCOL_FAMILIES_STR.strip().splitlines()])
     61 
     62 SOCKET_TYPES = [socket.SOCK_STREAM, socket.SOCK_DGRAM, socket.SOCK_RAW,
     63                 socket.SOCK_RDM, socket.SOCK_SEQPACKET]
     64 
     65 
     66 class security_ProtocolFamilies(test.test):
     67     version = 1
     68     PF_BASELINE = ["PF_FILE", "PF_PACKET", "PF_INET", "PF_INET6", "PF_ROUTE",
     69                    "PF_LOCAL", "PF_NETLINK", "PF_UNIX", "PF_BLUETOOTH", "PF_ALG"]
     70     PER_BOARD = {}
     71 
     72 
     73     def pf_name(self, pfn):
     74         protocol_family = ""
     75 
     76         if pfn in PROTOCOL_FAMILIES:
     77             protocol_family = PROTOCOL_FAMILIES[pfn]
     78         else:
     79             protocol_family = "PF %d (unknown)" % pfn
     80 
     81         return protocol_family
     82 
     83 
     84     def is_protocol_family_available(self, pfn):
     85         """Tries to create a socket with protocol family number |pfn|
     86         and every possible socket type.
     87         Returns |True| if any socket can be created, |False| otherwise.
     88         """
     89 
     90         available = False
     91 
     92         for socket_type in SOCKET_TYPES:
     93             try:
     94                 socket.socket(pfn, socket_type)
     95                 available = True
     96                 logging.info("%s available with socket type %d" %
     97                              (self.pf_name(pfn), socket_type))
     98                 break
     99             except socket.error:
    100                 pass
    101 
    102         return available
    103 
    104 
    105     def run_once(self):
    106         """Tries to create a socket with every possible combination of
    107         protocol family and socket type.
    108         Fails if it can create a socket for one or more protocol families
    109         not in the baseline.
    110         """
    111 
    112         unexpected_protocol_families = []
    113 
    114         # Protocol families currently go up to 40, but this way we make sure
    115         # to catch new families that might get added to the kernel.
    116         for pfn in range(256):
    117             pf_available = self.is_protocol_family_available(pfn)
    118             protocol_family = self.pf_name(pfn)
    119 
    120             if pf_available:
    121                 # If PF is in baseline, continue.
    122                 if protocol_family in self.PF_BASELINE:
    123                     continue
    124 
    125                 # Check the board-specific whitelist.
    126                 current_board = utils.get_current_board()
    127                 board_pfs = self.PER_BOARD.get(current_board, None)
    128                 if not board_pfs or protocol_family not in board_pfs:
    129                     unexpected_protocol_families.append(protocol_family)
    130 
    131         if len(unexpected_protocol_families) > 0:
    132             failure_string = "Unexpected protocol families available: "
    133             failure_string += ", ".join(unexpected_protocol_families)
    134             logging.error(failure_string)
    135             raise error.TestFail(failure_string)
    136