Home | History | Annotate | Download | only in tools
      1 #!/usr/bin/env python
      2 # Unit tests for genseccomp.py
      3 
      4 import cStringIO
      5 import textwrap
      6 import unittest
      7 
      8 import genseccomp
      9 
     10 class TestGenseccomp(unittest.TestCase):
     11   def setUp(self):
     12     genseccomp.set_dir()
     13 
     14   def get_config(self, arch):
     15     for i in genseccomp.POLICY_CONFIGS:
     16       if i[0] == arch:
     17         return i
     18     self.fail("No such architecture")
     19 
     20   def get_headers(self, arch):
     21     return self.get_config(arch)[1]
     22 
     23   def get_switches(self, arch):
     24     return self.get_config(arch)[2]
     25 
     26   def test_get_names(self):
     27     bionic = cStringIO.StringIO(textwrap.dedent("""\
     28 int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) arm,mips,x86
     29 int         fchown:fchown(int, uid_t, gid_t)    arm64,mips,mips64,x86_64
     30     """))
     31 
     32     whitelist = cStringIO.StringIO(textwrap.dedent("""\
     33 ssize_t     read(int, void*, size_t)        all
     34     """))
     35 
     36     empty = cStringIO.StringIO(textwrap.dedent("""\
     37     """))
     38 
     39     names = genseccomp.get_names([bionic, whitelist, empty], "arm")
     40     bionic.seek(0)
     41     whitelist.seek(0)
     42     empty.seek(0)
     43     names64 = genseccomp.get_names([bionic, whitelist, empty], "arm64")
     44     bionic.seek(0)
     45     whitelist.seek(0)
     46     empty.seek(0)
     47 
     48     self.assertIn("fchown", names64)
     49     self.assertNotIn("fchown", names)
     50     self.assertIn("_llseek", names)
     51     self.assertNotIn("_llseek", names64)
     52     self.assertIn("read", names)
     53     self.assertIn("read", names64)
     54 
     55     # Blacklist item must be in bionic
     56     blacklist = cStringIO.StringIO(textwrap.dedent("""\
     57 int         fchown2:fchown2(int, uid_t, gid_t)    arm64,mips,mips64,x86_64
     58     """))
     59     with self.assertRaises(RuntimeError):
     60       genseccomp.get_names([bionic, whitelist, blacklist], "arm")
     61     bionic.seek(0)
     62     whitelist.seek(0)
     63     blacklist.seek(0)
     64 
     65     # Test blacklist item is removed
     66     blacklist = cStringIO.StringIO(textwrap.dedent("""\
     67 int         fchown:fchown(int, uid_t, gid_t)    arm64,mips,mips64,x86_64
     68     """))
     69     names = genseccomp.get_names([bionic, whitelist, blacklist], "arm64")
     70     bionic.seek(0)
     71     whitelist.seek(0)
     72     blacklist.seek(0)
     73     self.assertIn("read", names)
     74     self.assertNotIn("fchown", names)
     75 
     76     # Blacklist item must not be in whitelist
     77     whitelist = cStringIO.StringIO(textwrap.dedent("""\
     78 int         fchown:fchown(int, uid_t, gid_t)    arm64,mips,mips64,x86_64
     79     """))
     80     with self.assertRaises(RuntimeError):
     81       genseccomp.get_names([empty, whitelist, blacklist], "arm")
     82     empty.seek(0)
     83     whitelist.seek(0)
     84     blacklist.seek(0)
     85 
     86     # No dups in bionic and whitelist
     87     whitelist = cStringIO.StringIO(textwrap.dedent("""\
     88 int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) arm,mips,x86
     89     """))
     90     with self.assertRaises(RuntimeError):
     91       genseccomp.get_names([bionic, whitelist, empty], "arm")
     92     bionic.seek(0)
     93     whitelist.seek(0)
     94     empty.seek(0)
     95 
     96   def test_convert_names_to_NRs(self):
     97     self.assertEquals(genseccomp.convert_names_to_NRs(["open"],
     98                                                       self.get_headers("arm"),
     99                                                       self.get_switches("arm")),
    100                       [("open", 5)])
    101 
    102     self.assertEquals(genseccomp.convert_names_to_NRs(["__ARM_NR_set_tls"],
    103                                                       self.get_headers("arm"),
    104                                                       self.get_switches("arm")),
    105                       [('__ARM_NR_set_tls', 983045)])
    106 
    107     self.assertEquals(genseccomp.convert_names_to_NRs(["openat"],
    108                                                       self.get_headers("arm64"),
    109                                                       self.get_switches("arm64")),
    110                       [("openat", 56)])
    111 
    112     self.assertEquals(genseccomp.convert_names_to_NRs(["openat"],
    113                                                       self.get_headers("x86"),
    114                                                       self.get_switches("x86")),
    115                       [("openat", 295)])
    116 
    117     self.assertEquals(genseccomp.convert_names_to_NRs(["openat"],
    118                                                       self.get_headers("x86_64"),
    119                                                       self.get_switches("x86_64")),
    120                       [("openat", 257)])
    121 
    122     self.assertEquals(genseccomp.convert_names_to_NRs(["openat"],
    123                                                       self.get_headers("mips"),
    124                                                       self.get_switches("mips")),
    125                       [("openat", 4288)])
    126 
    127     self.assertEquals(genseccomp.convert_names_to_NRs(["openat"],
    128                                                       self.get_headers("mips64"),
    129                                                       self.get_switches("mips64")),
    130                       [("openat", 5247)])
    131 
    132 
    133   def test_convert_NRs_to_ranges(self):
    134     ranges = genseccomp.convert_NRs_to_ranges([("b", 2), ("a", 1)])
    135     self.assertEquals(len(ranges), 1)
    136     self.assertEquals(ranges[0].begin, 1)
    137     self.assertEquals(ranges[0].end, 3)
    138     self.assertItemsEqual(ranges[0].names, ["a", "b"])
    139 
    140     ranges = genseccomp.convert_NRs_to_ranges([("b", 3), ("a", 1)])
    141     self.assertEquals(len(ranges), 2)
    142     self.assertEquals(ranges[0].begin, 1)
    143     self.assertEquals(ranges[0].end, 2)
    144     self.assertItemsEqual(ranges[0].names, ["a"])
    145     self.assertEquals(ranges[1].begin, 3)
    146     self.assertEquals(ranges[1].end, 4)
    147     self.assertItemsEqual(ranges[1].names, ["b"])
    148 
    149   def test_convert_to_intermediate_bpf(self):
    150     ranges = genseccomp.convert_NRs_to_ranges([("b", 2), ("a", 1)])
    151     bpf = genseccomp.convert_to_intermediate_bpf(ranges)
    152     self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, {fail}, {allow}), //a|b'])
    153 
    154     ranges = genseccomp.convert_NRs_to_ranges([("b", 3), ("a", 1)])
    155     bpf = genseccomp.convert_to_intermediate_bpf(ranges)
    156     self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 1, 0),',
    157                             'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 2, {fail}, {allow}), //a',
    158                             'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4, {fail}, {allow}), //b'])
    159 
    160   def test_convert_ranges_to_bpf(self):
    161     ranges = genseccomp.convert_NRs_to_ranges([("b", 2), ("a", 1)])
    162     bpf = genseccomp.convert_ranges_to_bpf(ranges)
    163     self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 1, 0, 2),',
    164                             'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 1, 0), //a|b',
    165                             'BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),'])
    166 
    167     ranges = genseccomp.convert_NRs_to_ranges([("b", 3), ("a", 1)])
    168     bpf = genseccomp.convert_ranges_to_bpf(ranges)
    169     self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 1, 0, 4),',
    170                             'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 1, 0),',
    171                             'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 2, 2, 1), //a',
    172                             'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4, 1, 0), //b',
    173                             'BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),'])
    174 
    175   def test_convert_bpf_to_output(self):
    176     output = genseccomp.convert_bpf_to_output(["line1", "line2"], "arm")
    177     expected_output = textwrap.dedent("""\
    178     // Autogenerated file - edit at your peril!!
    179 
    180     #include <linux/filter.h>
    181     #include <errno.h>
    182 
    183     #include "seccomp_bpfs.h"
    184     const sock_filter arm_filter[] = {
    185     line1
    186     line2
    187     };
    188 
    189     const size_t arm_filter_size = sizeof(arm_filter) / sizeof(struct sock_filter);
    190     """)
    191     self.assertEquals(output, expected_output)
    192 
    193   def test_construct_bpf(self):
    194     syscalls = cStringIO.StringIO(textwrap.dedent("""\
    195     int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) arm,mips,x86
    196     int         fchown:fchown(int, uid_t, gid_t)    arm64,mips,mips64,x86_64
    197     """))
    198 
    199     whitelist = cStringIO.StringIO(textwrap.dedent("""\
    200     ssize_t     read(int, void*, size_t)        all
    201     """))
    202 
    203     blacklist = cStringIO.StringIO(textwrap.dedent("""\
    204     """))
    205 
    206     syscall_files = [syscalls, whitelist, blacklist]
    207     output = genseccomp.construct_bpf(syscall_files, "arm", self.get_headers("arm"),
    208                                       self.get_switches("arm"))
    209 
    210     expected_output = textwrap.dedent("""\
    211     // Autogenerated file - edit at your peril!!
    212 
    213     #include <linux/filter.h>
    214     #include <errno.h>
    215 
    216     #include "seccomp_bpfs.h"
    217     const sock_filter arm_filter[] = {
    218     BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 0, 4),
    219     BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 140, 1, 0),
    220     BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4, 2, 1), //read
    221     BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 141, 1, 0), //_llseek
    222     BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
    223     };
    224 
    225     const size_t arm_filter_size = sizeof(arm_filter) / sizeof(struct sock_filter);
    226     """)
    227     self.assertEquals(output, expected_output)
    228 
    229 
    230 if __name__ == '__main__':
    231   unittest.main()
    232