• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/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
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("""\
28int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) arm,x86
29int         fchown:fchown(int, uid_t, gid_t)    arm64,x86_64
30    """))
31
32    whitelist = cStringIO.StringIO(textwrap.dedent("""\
33ssize_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("""\
57int         fchown2:fchown2(int, uid_t, gid_t)    arm64,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("""\
67int         fchown:fchown(int, uid_t, gid_t)    arm64,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("""\
78int         fchown:fchown(int, uid_t, gid_t)    arm64,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("""\
88int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) arm,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
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)
153    self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 1, 0, 2),',
154                            '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)
159    self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 1, 0, 4),',
160                            '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
173    #include "seccomp_bpfs.h"
174    const sock_filter arm_filter[] = {
175    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("""\
185    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
187    """))
188
189    whitelist = cStringIO.StringIO(textwrap.dedent("""\
190    ssize_t     read(int, void*, size_t)        all
191    """))
192
193    blacklist = cStringIO.StringIO(textwrap.dedent("""\
194    """))
195
196    syscall_files = [syscalls, whitelist, blacklist]
197    output = genseccomp.construct_bpf(syscall_files, "arm", self.get_headers("arm"),
198                                      self.get_switches("arm"))
199
200    expected_output = textwrap.dedent("""\
201    // Autogenerated file - edit at your peril!!
202
203    #include <linux/filter.h>
204    #include <errno.h>
205
206    #include "seccomp_bpfs.h"
207    const sock_filter arm_filter[] = {
208    BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 0, 4),
209    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()
222