| Paul Lawrence | 7ea4090 | 2017-02-14 13:32:23 -0800 | [diff] [blame] | 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 |  | 
| Paul Lawrence | 89fa81f | 2017-02-17 10:22:03 -0800 | [diff] [blame] | 23 | def get_switches(self, arch): | 
|  | 24 | return self.get_config(arch)[2] | 
|  | 25 |  | 
| Paul Lawrence | 7ea4090 | 2017-02-14 13:32:23 -0800 | [diff] [blame] | 26 | def test_get_names(self): | 
| Paul Lawrence | 3dd3d55 | 2017-04-12 10:02:54 -0700 | [diff] [blame] | 27 | bionic = cStringIO.StringIO(textwrap.dedent("""\ | 
| Paul Lawrence | 7ea4090 | 2017-02-14 13:32:23 -0800 | [diff] [blame] | 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 |  | 
| Paul Lawrence | 3dd3d55 | 2017-04-12 10:02:54 -0700 | [diff] [blame] | 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) | 
| Paul Lawrence | 7ea4090 | 2017-02-14 13:32:23 -0800 | [diff] [blame] | 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 |  | 
| Paul Lawrence | 3dd3d55 | 2017-04-12 10:02:54 -0700 | [diff] [blame] | 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 |  | 
| Paul Lawrence | 7ea4090 | 2017-02-14 13:32:23 -0800 | [diff] [blame] | 96 | def test_convert_names_to_NRs(self): | 
|  | 97 | self.assertEquals(genseccomp.convert_names_to_NRs(["open"], | 
| Paul Lawrence | 89fa81f | 2017-02-17 10:22:03 -0800 | [diff] [blame] | 98 | self.get_headers("arm"), | 
|  | 99 | self.get_switches("arm")), | 
| Paul Lawrence | 7ea4090 | 2017-02-14 13:32:23 -0800 | [diff] [blame] | 100 | [("open", 5)]) | 
|  | 101 |  | 
|  | 102 | self.assertEquals(genseccomp.convert_names_to_NRs(["__ARM_NR_set_tls"], | 
| Paul Lawrence | 89fa81f | 2017-02-17 10:22:03 -0800 | [diff] [blame] | 103 | self.get_headers("arm"), | 
|  | 104 | self.get_switches("arm")), | 
| Paul Lawrence | 7ea4090 | 2017-02-14 13:32:23 -0800 | [diff] [blame] | 105 | [('__ARM_NR_set_tls', 983045)]) | 
|  | 106 |  | 
|  | 107 | self.assertEquals(genseccomp.convert_names_to_NRs(["openat"], | 
| Paul Lawrence | 89fa81f | 2017-02-17 10:22:03 -0800 | [diff] [blame] | 108 | self.get_headers("arm64"), | 
|  | 109 | self.get_switches("arm64")), | 
| Paul Lawrence | 7ea4090 | 2017-02-14 13:32:23 -0800 | [diff] [blame] | 110 | [("openat", 56)]) | 
|  | 111 |  | 
| Paul Lawrence | 89fa81f | 2017-02-17 10:22:03 -0800 | [diff] [blame] | 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 |  | 
| Paul Lawrence | 7ea4090 | 2017-02-14 13:32:23 -0800 | [diff] [blame] | 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) | 
| Paul Lawrence | 65b47c9 | 2017-03-22 08:03:51 -0700 | [diff] [blame] | 163 | self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 1, 0, 2),', | 
| Paul Lawrence | 7ea4090 | 2017-02-14 13:32:23 -0800 | [diff] [blame] | 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) | 
| Paul Lawrence | 65b47c9 | 2017-03-22 08:03:51 -0700 | [diff] [blame] | 169 | self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 1, 0, 4),', | 
| Paul Lawrence | 7ea4090 | 2017-02-14 13:32:23 -0800 | [diff] [blame] | 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 |  | 
| Paul Lawrence | dfe8434 | 2017-02-16 09:24:39 -0800 | [diff] [blame] | 183 | #include "seccomp_bpfs.h" | 
|  | 184 | const sock_filter arm_filter[] = { | 
| Paul Lawrence | 7ea4090 | 2017-02-14 13:32:23 -0800 | [diff] [blame] | 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 |  | 
| Paul Lawrence | 3dd3d55 | 2017-04-12 10:02:54 -0700 | [diff] [blame] | 203 | blacklist = cStringIO.StringIO(textwrap.dedent("""\ | 
|  | 204 | """)) | 
|  | 205 |  | 
|  | 206 | syscall_files = [syscalls, whitelist, blacklist] | 
| Paul Lawrence | 89fa81f | 2017-02-17 10:22:03 -0800 | [diff] [blame] | 207 | output = genseccomp.construct_bpf(syscall_files, "arm", self.get_headers("arm"), | 
|  | 208 | self.get_switches("arm")) | 
| Paul Lawrence | 7ea4090 | 2017-02-14 13:32:23 -0800 | [diff] [blame] | 209 |  | 
|  | 210 | expected_output = textwrap.dedent("""\ | 
|  | 211 | // Autogenerated file - edit at your peril!! | 
|  | 212 |  | 
|  | 213 | #include <linux/filter.h> | 
|  | 214 | #include <errno.h> | 
|  | 215 |  | 
| Paul Lawrence | dfe8434 | 2017-02-16 09:24:39 -0800 | [diff] [blame] | 216 | #include "seccomp_bpfs.h" | 
|  | 217 | const sock_filter arm_filter[] = { | 
| Paul Lawrence | 65b47c9 | 2017-03-22 08:03:51 -0700 | [diff] [blame] | 218 | BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 0, 4), | 
| Paul Lawrence | 7ea4090 | 2017-02-14 13:32:23 -0800 | [diff] [blame] | 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() |