blob: 812218eb817a5d84afb63db8b4fb37ce759016d5 [file] [log] [blame]
Paul Lawrence7ea40902017-02-14 13:32:23 -08001#!/usr/bin/env python
2# Unit tests for genseccomp.py
3
4import cStringIO
5import textwrap
6import unittest
7
8import genseccomp
9
10class 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 Lawrence89fa81f2017-02-17 10:22:03 -080023 def get_switches(self, arch):
24 return self.get_config(arch)[2]
25
Paul Lawrence7ea40902017-02-14 13:32:23 -080026 def test_get_names(self):
Paul Lawrence3dd3d552017-04-12 10:02:54 -070027 bionic = cStringIO.StringIO(textwrap.dedent("""\
Elliott Hughes2b499042020-02-13 14:21:55 -080028int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) arm,x86
29int fchown:fchown(int, uid_t, gid_t) arm64,x86_64
Paul Lawrence7ea40902017-02-14 13:32:23 -080030 """))
31
Victor Hsiehdbb86702020-06-15 09:29:07 -070032 allowlist = cStringIO.StringIO(textwrap.dedent("""\
Paul Lawrence7ea40902017-02-14 13:32:23 -080033ssize_t read(int, void*, size_t) all
34 """))
35
Paul Lawrence3dd3d552017-04-12 10:02:54 -070036 empty = cStringIO.StringIO(textwrap.dedent("""\
37 """))
38
Victor Hsiehdbb86702020-06-15 09:29:07 -070039 names = genseccomp.get_names([bionic, allowlist, empty], "arm")
Paul Lawrence3dd3d552017-04-12 10:02:54 -070040 bionic.seek(0)
Victor Hsiehdbb86702020-06-15 09:29:07 -070041 allowlist.seek(0)
Paul Lawrence3dd3d552017-04-12 10:02:54 -070042 empty.seek(0)
Victor Hsiehdbb86702020-06-15 09:29:07 -070043 names64 = genseccomp.get_names([bionic, allowlist, empty], "arm64")
Paul Lawrence3dd3d552017-04-12 10:02:54 -070044 bionic.seek(0)
Victor Hsiehdbb86702020-06-15 09:29:07 -070045 allowlist.seek(0)
Paul Lawrence3dd3d552017-04-12 10:02:54 -070046 empty.seek(0)
Paul Lawrence7ea40902017-02-14 13:32:23 -080047
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
Victor Hsiehdbb86702020-06-15 09:29:07 -070055 # Blocklist item must be in bionic
56 blocklist = cStringIO.StringIO(textwrap.dedent("""\
Elliott Hughes2b499042020-02-13 14:21:55 -080057int fchown2:fchown2(int, uid_t, gid_t) arm64,x86_64
Paul Lawrence3dd3d552017-04-12 10:02:54 -070058 """))
59 with self.assertRaises(RuntimeError):
Victor Hsiehdbb86702020-06-15 09:29:07 -070060 genseccomp.get_names([bionic, allowlist, blocklist], "arm")
Paul Lawrence3dd3d552017-04-12 10:02:54 -070061 bionic.seek(0)
Victor Hsiehdbb86702020-06-15 09:29:07 -070062 allowlist.seek(0)
63 blocklist.seek(0)
Paul Lawrence3dd3d552017-04-12 10:02:54 -070064
Victor Hsiehdbb86702020-06-15 09:29:07 -070065 # Test blocklist item is removed
66 blocklist = cStringIO.StringIO(textwrap.dedent("""\
Elliott Hughes2b499042020-02-13 14:21:55 -080067int fchown:fchown(int, uid_t, gid_t) arm64,x86_64
Paul Lawrence3dd3d552017-04-12 10:02:54 -070068 """))
Victor Hsiehdbb86702020-06-15 09:29:07 -070069 names = genseccomp.get_names([bionic, allowlist, blocklist], "arm64")
Paul Lawrence3dd3d552017-04-12 10:02:54 -070070 bionic.seek(0)
Victor Hsiehdbb86702020-06-15 09:29:07 -070071 allowlist.seek(0)
72 blocklist.seek(0)
Paul Lawrence3dd3d552017-04-12 10:02:54 -070073 self.assertIn("read", names)
74 self.assertNotIn("fchown", names)
75
Victor Hsiehdbb86702020-06-15 09:29:07 -070076 # Blocklist item must not be in allowlist
77 allowlist = cStringIO.StringIO(textwrap.dedent("""\
Elliott Hughes2b499042020-02-13 14:21:55 -080078int fchown:fchown(int, uid_t, gid_t) arm64,x86_64
Paul Lawrence3dd3d552017-04-12 10:02:54 -070079 """))
80 with self.assertRaises(RuntimeError):
Victor Hsiehdbb86702020-06-15 09:29:07 -070081 genseccomp.get_names([empty, allowlist, blocklist], "arm")
Paul Lawrence3dd3d552017-04-12 10:02:54 -070082 empty.seek(0)
Victor Hsiehdbb86702020-06-15 09:29:07 -070083 allowlist.seek(0)
84 blocklist.seek(0)
Paul Lawrence3dd3d552017-04-12 10:02:54 -070085
Victor Hsiehdbb86702020-06-15 09:29:07 -070086 # No dups in bionic and allowlist
87 allowlist = cStringIO.StringIO(textwrap.dedent("""\
Elliott Hughes2b499042020-02-13 14:21:55 -080088int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) arm,x86
Paul Lawrence3dd3d552017-04-12 10:02:54 -070089 """))
90 with self.assertRaises(RuntimeError):
Victor Hsiehdbb86702020-06-15 09:29:07 -070091 genseccomp.get_names([bionic, allowlist, empty], "arm")
Paul Lawrence3dd3d552017-04-12 10:02:54 -070092 bionic.seek(0)
Victor Hsiehdbb86702020-06-15 09:29:07 -070093 allowlist.seek(0)
Paul Lawrence3dd3d552017-04-12 10:02:54 -070094 empty.seek(0)
95
Paul Lawrence7ea40902017-02-14 13:32:23 -080096 def test_convert_names_to_NRs(self):
97 self.assertEquals(genseccomp.convert_names_to_NRs(["open"],
Paul Lawrence89fa81f2017-02-17 10:22:03 -080098 self.get_headers("arm"),
99 self.get_switches("arm")),
Paul Lawrence7ea40902017-02-14 13:32:23 -0800100 [("open", 5)])
101
102 self.assertEquals(genseccomp.convert_names_to_NRs(["__ARM_NR_set_tls"],
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800103 self.get_headers("arm"),
104 self.get_switches("arm")),
Paul Lawrence7ea40902017-02-14 13:32:23 -0800105 [('__ARM_NR_set_tls', 983045)])
106
107 self.assertEquals(genseccomp.convert_names_to_NRs(["openat"],
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800108 self.get_headers("arm64"),
109 self.get_switches("arm64")),
Paul Lawrence7ea40902017-02-14 13:32:23 -0800110 [("openat", 56)])
111
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800112 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
Paul Lawrence7ea40902017-02-14 13:32:23 -0800122
123 def test_convert_NRs_to_ranges(self):
124 ranges = genseccomp.convert_NRs_to_ranges([("b", 2), ("a", 1)])
125 self.assertEquals(len(ranges), 1)
126 self.assertEquals(ranges[0].begin, 1)
127 self.assertEquals(ranges[0].end, 3)
128 self.assertItemsEqual(ranges[0].names, ["a", "b"])
129
130 ranges = genseccomp.convert_NRs_to_ranges([("b", 3), ("a", 1)])
131 self.assertEquals(len(ranges), 2)
132 self.assertEquals(ranges[0].begin, 1)
133 self.assertEquals(ranges[0].end, 2)
134 self.assertItemsEqual(ranges[0].names, ["a"])
135 self.assertEquals(ranges[1].begin, 3)
136 self.assertEquals(ranges[1].end, 4)
137 self.assertItemsEqual(ranges[1].names, ["b"])
138
139 def test_convert_to_intermediate_bpf(self):
140 ranges = genseccomp.convert_NRs_to_ranges([("b", 2), ("a", 1)])
141 bpf = genseccomp.convert_to_intermediate_bpf(ranges)
142 self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, {fail}, {allow}), //a|b'])
143
144 ranges = genseccomp.convert_NRs_to_ranges([("b", 3), ("a", 1)])
145 bpf = genseccomp.convert_to_intermediate_bpf(ranges)
146 self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 1, 0),',
147 'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 2, {fail}, {allow}), //a',
148 'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4, {fail}, {allow}), //b'])
149
150 def test_convert_ranges_to_bpf(self):
151 ranges = genseccomp.convert_NRs_to_ranges([("b", 2), ("a", 1)])
152 bpf = genseccomp.convert_ranges_to_bpf(ranges)
Paul Lawrence65b47c92017-03-22 08:03:51 -0700153 self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 1, 0, 2),',
Paul Lawrence7ea40902017-02-14 13:32:23 -0800154 'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 1, 0), //a|b',
155 'BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),'])
156
157 ranges = genseccomp.convert_NRs_to_ranges([("b", 3), ("a", 1)])
158 bpf = genseccomp.convert_ranges_to_bpf(ranges)
Paul Lawrence65b47c92017-03-22 08:03:51 -0700159 self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 1, 0, 4),',
Paul Lawrence7ea40902017-02-14 13:32:23 -0800160 'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 1, 0),',
161 'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 2, 2, 1), //a',
162 'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4, 1, 0), //b',
163 'BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),'])
164
165 def test_convert_bpf_to_output(self):
166 output = genseccomp.convert_bpf_to_output(["line1", "line2"], "arm")
167 expected_output = textwrap.dedent("""\
168 // Autogenerated file - edit at your peril!!
169
170 #include <linux/filter.h>
171 #include <errno.h>
172
Paul Lawrencedfe84342017-02-16 09:24:39 -0800173 #include "seccomp_bpfs.h"
174 const sock_filter arm_filter[] = {
Paul Lawrence7ea40902017-02-14 13:32:23 -0800175 line1
176 line2
177 };
178
179 const size_t arm_filter_size = sizeof(arm_filter) / sizeof(struct sock_filter);
180 """)
181 self.assertEquals(output, expected_output)
182
183 def test_construct_bpf(self):
184 syscalls = cStringIO.StringIO(textwrap.dedent("""\
Elliott Hughes2b499042020-02-13 14:21:55 -0800185 int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) arm,x86
186 int fchown:fchown(int, uid_t, gid_t) arm64,x86_64
Paul Lawrence7ea40902017-02-14 13:32:23 -0800187 """))
188
Victor Hsiehdbb86702020-06-15 09:29:07 -0700189 allowlist = cStringIO.StringIO(textwrap.dedent("""\
Paul Lawrence7ea40902017-02-14 13:32:23 -0800190 ssize_t read(int, void*, size_t) all
191 """))
192
Victor Hsiehdbb86702020-06-15 09:29:07 -0700193 blocklist = cStringIO.StringIO(textwrap.dedent("""\
Paul Lawrence3dd3d552017-04-12 10:02:54 -0700194 """))
195
Victor Hsiehdbb86702020-06-15 09:29:07 -0700196 syscall_files = [syscalls, allowlist, blocklist]
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800197 output = genseccomp.construct_bpf(syscall_files, "arm", self.get_headers("arm"),
198 self.get_switches("arm"))
Paul Lawrence7ea40902017-02-14 13:32:23 -0800199
200 expected_output = textwrap.dedent("""\
201 // Autogenerated file - edit at your peril!!
202
203 #include <linux/filter.h>
204 #include <errno.h>
205
Paul Lawrencedfe84342017-02-16 09:24:39 -0800206 #include "seccomp_bpfs.h"
207 const sock_filter arm_filter[] = {
Paul Lawrence65b47c92017-03-22 08:03:51 -0700208 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 0, 4),
Paul Lawrence7ea40902017-02-14 13:32:23 -0800209 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 140, 1, 0),
210 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4, 2, 1), //read
211 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 141, 1, 0), //_llseek
212 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
213 };
214
215 const size_t arm_filter_size = sizeof(arm_filter) / sizeof(struct sock_filter);
216 """)
217 self.assertEquals(output, expected_output)
218
219
220if __name__ == '__main__':
221 unittest.main()