blob: 6b87574998c307f421a795a1ff93b5870d8d9563 [file] [log] [blame]
Brad Bishopc342db32019-05-15 21:57:59 -04001import unittest
2import re
3import os
4import string
5from oeqa.runtime.case import OERuntimeTestCase
6from oeqa.core.decorator.depends import OETestDepends
7from oeqa.runtime.decorator.package import OEHasPackage
8from oeqa.core.decorator.data import skipIfNotFeature
9
10MAX_LABEL_LEN = 255
11LABEL = "a" * MAX_LABEL_LEN
12
13class SmackBasicTest(OERuntimeTestCase):
14 ''' base smack test '''
15
16 @classmethod
17 def setUpClass(cls):
Brad Bishopc342db32019-05-15 21:57:59 -040018 cls.current_label = ""
19 cls.uid = 1000
Andrew Geissler615f2f12022-07-15 14:00:58 -050020 status, output = cls.tc.target.run("grep smack /proc/mounts | awk '{print $2}'")
21 cls.smack_path = output
Brad Bishopc342db32019-05-15 21:57:59 -040022
23 @skipIfNotFeature('smack',
24 'Test requires smack to be in DISTRO_FEATURES')
25 @OEHasPackage(['smack-test'])
26 @OETestDepends(['ssh.SSHTest.test_ssh'])
27 def test_smack_basic(self):
Brad Bishopc342db32019-05-15 21:57:59 -040028 status,output = self.target.run("cat /proc/self/attr/current")
29 self.current_label = output.strip()
30
Brad Bishopc342db32019-05-15 21:57:59 -040031 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
32 def test_add_access_label(self):
33 ''' Test if chsmack can correctly set a SMACK label '''
34 filename = "/tmp/test_access_label"
35 self.target.run("touch %s" %filename)
36 status, output = self.target.run("chsmack -a %s %s" %(LABEL, filename))
37 self.assertEqual(
38 status, 0,
39 "Cannot set smack access label. "
40 "Status and output: %d %s" %(status, output))
41 status, output = self.target.run("chsmack %s" %filename)
42 self.target.run("rm %s" %filename)
Andrew Geissler615f2f12022-07-15 14:00:58 -050043 m = re.search('(access=")\S+(?=")', output)
Brad Bishopc342db32019-05-15 21:57:59 -040044 if m is None:
45 self.fail("Did not find access attribute")
46 else:
Andrew Geissler615f2f12022-07-15 14:00:58 -050047 label_retrieved = re.split("access=\"", output)[1][:-1]
Brad Bishopc342db32019-05-15 21:57:59 -040048 self.assertEqual(
49 LABEL, label_retrieved,
50 "label not set correctly. expected and gotten: "
51 "%s %s" %(LABEL,label_retrieved))
52
53
Brad Bishopc342db32019-05-15 21:57:59 -040054 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
55 def test_add_exec_label(self):
56 '''Test if chsmack can correctly set a SMACK Exec label'''
57 filename = "/tmp/test_exec_label"
58 self.target.run("touch %s" %filename)
59 status, output = self.target.run("chsmack -e %s %s" %(LABEL, filename))
60 self.assertEqual(
61 status, 0,
62 "Cannot set smack exec label. "
63 "Status and output: %d %s" %(status, output))
64 status, output = self.target.run("chsmack %s" %filename)
65 self.target.run("rm %s" %filename)
Andrew Geissler615f2f12022-07-15 14:00:58 -050066 m= re.search('(execute=")\S+(?=")', output)
Brad Bishopc342db32019-05-15 21:57:59 -040067 if m is None:
68 self.fail("Did not find execute attribute")
69 else:
Andrew Geissler615f2f12022-07-15 14:00:58 -050070 label_retrieved = re.split("execute=\"", output)[1][:-1]
Brad Bishopc342db32019-05-15 21:57:59 -040071 self.assertEqual(
72 LABEL, label_retrieved,
73 "label not set correctly. expected and gotten: " +
74 "%s %s" %(LABEL,label_retrieved))
75
76
Brad Bishopc342db32019-05-15 21:57:59 -040077 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
78 def test_add_mmap_label(self):
79 '''Test if chsmack can correctly set a SMACK mmap label'''
80 filename = "/tmp/test_exec_label"
81 self.target.run("touch %s" %filename)
82 status, output = self.target.run("chsmack -m %s %s" %(LABEL, filename))
83 self.assertEqual(
84 status, 0,
85 "Cannot set smack mmap label. "
86 "Status and output: %d %s" %(status, output))
87 status, output = self.target.run("chsmack %s" %filename)
88 self.target.run("rm %s" %filename)
Andrew Geissler615f2f12022-07-15 14:00:58 -050089 m = re.search('(mmap=")\S+(?=")', output)
Brad Bishopc342db32019-05-15 21:57:59 -040090 if m is None:
91 self.fail("Did not find mmap attribute")
92 else:
Andrew Geissler615f2f12022-07-15 14:00:58 -050093 label_retrieved = re.split("mmap=\"", output)[1][:-1]
Brad Bishopc342db32019-05-15 21:57:59 -040094 self.assertEqual(
95 LABEL, label_retrieved,
96 "label not set correctly. expected and gotten: " +
97 "%s %s" %(LABEL,label_retrieved))
98
99
Brad Bishopc342db32019-05-15 21:57:59 -0400100 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
101 def test_add_transmutable(self):
102 '''Test if chsmack can correctly set a SMACK transmutable mode'''
103
104 directory = "~/test_transmutable"
105 self.target.run("mkdir -p %s" %directory)
106 status, output = self.target.run("chsmack -t %s" %directory)
107 self.assertEqual(status, 0, "Cannot set smack transmutable. "
108 "Status and output: %d %s" %(status, output))
109 status, output = self.target.run("chsmack %s" %directory)
110 self.target.run("rmdir %s" %directory)
Andrew Geissler615f2f12022-07-15 14:00:58 -0500111 m = re.search('(transmute=")\S+(?=")', output)
Brad Bishopc342db32019-05-15 21:57:59 -0400112 if m is None:
113 self.fail("Did not find transmute attribute")
114 else:
Andrew Geissler615f2f12022-07-15 14:00:58 -0500115 label_retrieved = re.split("transmute=\"", output)[1][:-1]
Brad Bishopc342db32019-05-15 21:57:59 -0400116 self.assertEqual(
117 "TRUE", label_retrieved,
118 "label not set correctly. expected and gotten: " +
119 "%s %s" %(LABEL,label_retrieved))
120
121
Brad Bishopc342db32019-05-15 21:57:59 -0400122 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
123 def test_privileged_change_self_label(self):
124 '''Test if privileged process (with CAP_MAC_ADMIN privilege)
125 can change its label.
126 '''
127
128 labelf = "/proc/self/attr/current"
Andrew Geissler615f2f12022-07-15 14:00:58 -0500129 command = "/bin/sh -c 'echo PRIVILEGED >%s'; cat %s" %(labelf, labelf)
Brad Bishopc342db32019-05-15 21:57:59 -0400130
131 status, output = self.target.run(
Andrew Geissler615f2f12022-07-15 14:00:58 -0500132 "/usr/sbin/notroot.py 0 %s %s" %(self.current_label, command))
Brad Bishopc342db32019-05-15 21:57:59 -0400133
134 self.assertIn("PRIVILEGED", output,
135 "Privilege process did not change label.Output: %s" %output)
136
Brad Bishopc342db32019-05-15 21:57:59 -0400137 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
138 def test_unprivileged_change_self_label(self):
139 '''Test if unprivileged process (without CAP_MAC_ADMIN privilege)
140 cannot change its label'''
141
142 command = "/bin/sh -c 'echo %s >/proc/self/attr/current'" %LABEL
143 status, output = self.target.run(
Andrew Geissler615f2f12022-07-15 14:00:58 -0500144 "/usr/sbin/notroot.py %d %s %s"
Brad Bishopc342db32019-05-15 21:57:59 -0400145 %(self.uid, self.current_label, command) +
146 " 2>&1 | grep 'Operation not permitted'" )
147
148 self.assertEqual(
149 status, 0,
150 "Unprivileged process should not be able to change its label")
151
152
Brad Bishopc342db32019-05-15 21:57:59 -0400153 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
154 def test_unprivileged_change_file_label(self):
155 '''Test if unprivileged process cannot change file labels'''
156
157 status, chsmack = self.target.run("which chsmack")
158 status, touch = self.target.run("which touch")
159 filename = "/tmp/test_unprivileged_change_file_label"
160
161 self.target.run("touch %s" % filename)
Andrew Geissler615f2f12022-07-15 14:00:58 -0500162 self.target.run("/usr/sbin/notroot.py %d %s" %(self.uid, self.current_label))
Brad Bishopc342db32019-05-15 21:57:59 -0400163 status, output = self.target.run(
Andrew Geissler615f2f12022-07-15 14:00:58 -0500164 "/usr/sbin/notroot.py " +
Brad Bishopc342db32019-05-15 21:57:59 -0400165 "%d unprivileged %s -a %s %s 2>&1 " %(self.uid, chsmack, LABEL, filename) +
166 "| grep 'Operation not permitted'" )
167
168 self.target.run("rm %s" % filename)
169 self.assertEqual( status, 0, "Unprivileged process changed label for %s" %filename)
170
Brad Bishopc342db32019-05-15 21:57:59 -0400171 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
172 def test_load_smack_rule(self):
173 '''Test if new smack access rules can be loaded'''
174
175 # old 23 character format requires special spaces formatting
176 # 12345678901234567890123456789012345678901234567890123
177 ruleA="TheOne TheOther rwxat"
178 ruleB="TheOne TheOther r----"
179 clean="TheOne TheOther -----"
180 modeA = "rwxat"
181 modeB = "r"
182
183 status, output = self.target.run('echo -n "%s" > %s/load' %(ruleA, self.smack_path))
184 status, output = self.target.run( 'cat %s/load | grep "^TheOne" | grep " TheOther "' %self.smack_path)
185 self.assertEqual(status, 0, "Rule A was not added")
186 mode = list(filter(bool, output.split(" ")))[2].strip()
187 self.assertEqual( mode, modeA, "Mode A was not set correctly; mode: %s" %mode)
188
189 status, output = self.target.run( 'echo -n "%s" > %s/load' %(ruleB, self.smack_path))
190 status, output = self.target.run( 'cat %s/load | grep "^TheOne" | grep " TheOther "' %self.smack_path)
191 mode = list(filter(bool, output.split(" ")))[2].strip()
192 self.assertEqual( mode, modeB, "Mode B was not set correctly; mode: %s" %mode)
193
194 self.target.run('echo -n "%s" > %s/load' %(clean, self.smack_path))
195
196
Brad Bishopc342db32019-05-15 21:57:59 -0400197 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
198 def test_smack_onlycap(self):
199 '''Test if smack onlycap label can be set
200
201 test needs to change the running label of the current process,
202 so whole test takes places on image
203 '''
204 status, output = self.target.run("sh /usr/sbin/test_smack_onlycap.sh")
205 self.assertEqual(status, 0, output)
206
Brad Bishopc342db32019-05-15 21:57:59 -0400207
208 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
209 def test_smack_netlabel(self):
210
211 test_label="191.191.191.191 TheOne"
212 expected_label="191.191.191.191/32 TheOne"
213
214 status, output = self.target.run( "echo -n '%s' > %s/netlabel" %(test_label, self.smack_path))
215 self.assertEqual( status, 0, "Netlabel /32 could not be set. Output: %s" %output)
216
217 status, output = self.target.run("cat %s/netlabel" %self.smack_path)
218 self.assertIn( expected_label, output, "Did not find expected label in output: %s" %output)
219
220 test_label="253.253.253.0/24 TheOther"
221 status, output = self.target.run( "echo -n '%s' > %s/netlabel" %(test_label, self.smack_path))
222 self.assertEqual( status, 0, "Netlabel /24 could not be set. Output: %s" %output)
223
224 status, output = self.target.run("cat %s/netlabel" %self.smack_path)
225 self.assertIn(
226 test_label, output,
227 "Did not find expected label in output: %s" %output)
228
Brad Bishopc342db32019-05-15 21:57:59 -0400229
230 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
231 def test_smack_cipso(self):
232 '''Test if smack cipso rules can be set'''
233 # 12345678901234567890123456789012345678901234567890123456
234 ruleA="TheOneA 2 0 "
235 ruleB="TheOneB 3 1 55 "
236 ruleC="TheOneC 4 2 17 33 "
237
238 status, output = self.target.run(
239 "echo -n '%s' > %s/cipso" %(ruleA, self.smack_path))
240 self.assertEqual(status, 0,
241 "Could not set cipso label A. Ouput: %s" %output)
242
243 status, output = self.target.run(
244 "cat %s/cipso | grep '^TheOneA'" %self.smack_path)
245 self.assertEqual(status, 0, "Cipso rule A was not set")
246 self.assertIn(" 2", output, "Rule A was not set correctly")
247
248 status, output = self.target.run(
249 "echo -n '%s' > %s/cipso" %(ruleB, self.smack_path))
250 self.assertEqual(status, 0,
251 "Could not set cipso label B. Ouput: %s" %output)
252
253 status, output = self.target.run(
254 "cat %s/cipso | grep '^TheOneB'" %self.smack_path)
255 self.assertEqual(status, 0, "Cipso rule B was not set")
256 self.assertIn("/55", output, "Rule B was not set correctly")
257
258 status, output = self.target.run(
259 "echo -n '%s' > %s/cipso" %(ruleC, self.smack_path))
260 self.assertEqual(
261 status, 0,
262 "Could not set cipso label C. Ouput: %s" %output)
263
264 status, output = self.target.run(
265 "cat %s/cipso | grep '^TheOneC'" %self.smack_path)
266 self.assertEqual(status, 0, "Cipso rule C was not set")
267 self.assertIn("/17,33", output, "Rule C was not set correctly")
268
Brad Bishopc342db32019-05-15 21:57:59 -0400269
270 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
271 def test_smack_direct(self):
272 status, initial_direct = self.target.run(
273 "cat %s/direct" %self.smack_path)
274
275 test_direct="17"
276 status, output = self.target.run(
277 "echo '%s' > %s/direct" %(test_direct, self.smack_path))
278 self.assertEqual(status, 0 ,
279 "Could not set smack direct. Output: %s" %output)
280 status, new_direct = self.target.run("cat %s/direct" %self.smack_path)
281 # initial label before checking
282 status, output = self.target.run(
283 "echo '%s' > %s/direct" %(initial_direct, self.smack_path))
284 self.assertEqual(
285 test_direct, new_direct.strip(),
286 "Smack direct label does not match.")
287
288
Brad Bishopc342db32019-05-15 21:57:59 -0400289 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
290 def test_smack_ambient(self):
291 test_ambient = "test_ambient"
292 status, initial_ambient = self.target.run("cat %s/ambient" %self.smack_path)
293 status, output = self.target.run(
294 "echo '%s' > %s/ambient" %(test_ambient, self.smack_path))
295 self.assertEqual(status, 0,
296 "Could not set smack ambient. Output: %s" %output)
297
298 status, output = self.target.run("cat %s/ambient" %self.smack_path)
299 # Filter '\x00', which is sometimes added to the ambient label
300 new_ambient = ''.join(filter(lambda x: x in string.printable, output))
301 initial_ambient = ''.join(filter(lambda x: x in string.printable, initial_ambient))
302 status, output = self.target.run(
303 "echo '%s' > %s/ambient" %(initial_ambient, self.smack_path))
304 self.assertEqual(
305 test_ambient, new_ambient.strip(),
306 "Ambient label does not match")
307
308
Brad Bishopc342db32019-05-15 21:57:59 -0400309 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
310 def test_smackload(self):
311 '''Test if smackload command works'''
312 rule="testobject testsubject rwx"
313
314 status, output = self.target.run("echo -n '%s' > /tmp/rules" %rule)
315 status, output = self.target.run("smackload /tmp/rules")
316 self.assertEqual( status, 0, "Smackload failed to load rule. Output: %s" %output)
317
318 status, output = self.target.run( "cat %s/load | grep '%s'" %(self.smack_path, rule))
319 self.assertEqual(status, 0, "Smackload rule was loaded correctly")
320
321
Brad Bishopc342db32019-05-15 21:57:59 -0400322 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
323 def test_smackcipso(self):
324 '''Test if smackcipso command works'''
325 # 12345678901234567890123456789012345678901234567890123456
326 rule="cipsolabel 2 2 "
327
328 status, output = self.target.run("echo '%s' | smackcipso" %rule)
329 self.assertEqual( status, 0, "Smackcipso failed to load rule. Output: %s" %output)
330
331 status, output = self.target.run(
332 "cat %s/cipso | grep 'cipsolabel'" %self.smack_path)
333 self.assertEqual(status, 0, "smackcipso rule was loaded correctly")
334 self.assertIn( "2/2", output, "Rule was not set correctly. Got: %s" %output)
335
336
Brad Bishopc342db32019-05-15 21:57:59 -0400337 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
338 def test_smack_enforce_file_access(self):
339 '''Test if smack file access is enforced (rwx)
340
341 test needs to change the running label of the current process,
342 so whole test takes places on image
343 '''
344 status, output = self.target.run("sh /usr/sbin/smack_test_file_access.sh")
345 self.assertEqual(status, 0, output)
346
347
Brad Bishopc342db32019-05-15 21:57:59 -0400348 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
Brad Bishopc342db32019-05-15 21:57:59 -0400349 def test_smack_transmute_dir(self):
350 '''Test if smack transmute attribute works
351
352 test needs to change the running label of the current process,
353 so whole test takes places on image
354 '''
355 test_dir = "/tmp/smack_transmute_dir"
356 label="transmute_label"
357 status, initial_label = self.target.run("cat /proc/self/attr/current")
358
359 self.target.run("mkdir -p %s" % test_dir)
360 self.target.run("chsmack -a %s %s" % (label, test_dir))
361 self.target.run("chsmack -t %s" % test_dir)
362 self.target.run("echo -n '%s %s rwxat' | smackload" %(initial_label, label) )
363
364 self.target.run("touch %s/test" % test_dir)
365 status, output = self.target.run("chsmack %s/test" % test_dir)
366 self.assertIn( 'access="%s"' %label, output,
367 "Did not get expected label. Output: %s" % output)
368
369
Brad Bishopc342db32019-05-15 21:57:59 -0400370 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
371 def test_smack_tcp_sockets(self):
372 '''Test if smack is enforced on tcp sockets
373
374 whole test takes places on image, depends on tcp_server/tcp_client'''
375
376 status, output = self.target.run("sh /usr/sbin/test_smack_tcp_sockets.sh")
377 self.assertEqual(status, 0, output)
378
379
Brad Bishopc342db32019-05-15 21:57:59 -0400380 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
381 def test_smack_udp_sockets(self):
382 '''Test if smack is enforced on udp sockets
383
384 whole test takes places on image, depends on udp_server/udp_client'''
385
386 status, output = self.target.run("sh /usr/sbin/test_smack_udp_sockets.sh")
387 self.assertEqual(status, 0, output)
388
389
Brad Bishopc342db32019-05-15 21:57:59 -0400390 @OETestDepends(['smack.SmackBasicTest.test_smack_basic'])
391 def test_smack_labels(self):
392 '''Check for correct Smack labels.'''
393 expected = '''
394/tmp/ access="*"
395/etc/ access="System::Shared" transmute="TRUE"
396/etc/passwd access="System::Shared"
397/etc/terminfo access="System::Shared" transmute="TRUE"
398/etc/skel/ access="System::Shared" transmute="TRUE"
399/etc/skel/.profile access="System::Shared"
400/var/log/ access="System::Log" transmute="TRUE"
401/var/tmp/ access="*"
402'''
403 files = ' '.join([x.split()[0] for x in expected.split('\n') if x])
404 files_wildcard = ' '.join([x + '/*' for x in files.split()])
405 # Auxiliary information.
406 status, output = self.target.run(
407 'set -x; mount; ls -l -d %s; find %s | xargs ls -d -l; find %s | xargs chsmack' % (
408 ' '.join([x.rstrip('/') for x in files.split()]), files, files
409 )
410 )
411 msg = "File status:\n" + output
412 status, output = self.target.run('chsmack %s' % files)
413 self.assertEqual(
414 status, 0, msg="status and output: %s and %s\n%s" % (status,output, msg))
415 self.longMessage = True
416 self.maxDiff = None
417 self.assertEqual(output.strip().split('\n'), expected.strip().split('\n'), msg=msg)