From b4d6a5fed39c7a3f0aa8e7a156cc7dd465c2984d Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Fri, 27 Aug 2021 11:00:32 -0400 Subject: [PATCH] Set SELinux contexts of dom0-provided kernels This is necessary for qubes to work with SELinux enforcing, and fixes several bugs that appear even when SELinux is not enforcing. Fixes QubesOS/qubes-issues#4278 Fixes QubesOS/qubes-issues#5765 --- genattr.py | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++ kernel.spec.in | 7 +++++ 2 files changed, 92 insertions(+) create mode 100644 genattr.py diff --git a/genattr.py b/genattr.py new file mode 100644 index 00000000..27ecd62c --- /dev/null +++ b/genattr.py @@ -0,0 +1,85 @@ +#!/usr/bin/python3 -- +import subprocess, os, sys, re, tempfile +def main(argv, write_cmd, read_cmd, expected_stdout): + match_re = re.compile(r'\A[A-Za-z0-9._/+,-]+\Z') + write_cmd.write('set_current_time 1\n' + 'ea_set / security.selinux system_u:object_r:modules_dep_t:s0\n') + read_cmd.write('ea_get / security.selinux\n') + expected_stdout.write('debugfs: ea_get / security.selinux\n' + 'security.selinux (34) = "system_u:object_r:modules_dep_t:s0"\n\n') + def bad(e): + raise e + def emit(dirpath, name): + path = os.path.join(dirpath, name) + context = 'modules_object_t' + if path.startswith(argv + '/build'): + context = 'usr_t' + elif dirpath == argv: + if name.startswith('modules.'): + context = 'modules_dep_t' + elif name == 'build': + context = 'usr_t' + context = ':'.join(('system_u', 'object_r', context, 's0')) + write_cmd.write('ea_set /%s security.selinux %s\n' % (path, context)) + read_cmd.write('ea_get /%s security.selinux\n' % (path,)) + expected_stdout.write('''debugfs: ea_get /%s security.selinux +security.selinux (%d) = "%s" + +''' % (path, len(context), context)) + for dirpath, dirnames, filenames in os.walk(argv, onerror=bad, topdown=True): + for i in dirnames: + if not match_re.match(i): + raise ValueError("Invalid directory name %r" % os.path.join(dirpath, i)) + emit(dirpath, i) + for i in filenames: + if not match_re.match(i): + raise ValueError("Invalid filename name %r" % os.path.join(dirpath, i)) + emit(dirpath, i) +if __name__ == '__main__': + os.chdir(sys.argv[1]) + with tempfile.TemporaryDirectory() as d, \ + open(os.path.join(d, 'write_cmd'), 'w') as write_cmd, \ + open(os.path.join(d, 'read_cmd'), 'w') as read_cmd, \ + open(os.path.join(d, 'expected_stdout'), 'w') as expected_stdout, \ + open(os.path.join(d, 'actual_stdout'), 'w') as actual_stdout, \ + open(os.path.join(d, 'clear_timestamps'), 'w') as clear_timestamps: + main(sys.argv[2], write_cmd, read_cmd, expected_stdout) + write_cmd.write(""" +set_super_value mtime 1 +set_super_value lastcheck 1 +set_super_value mkfs_time 1 +set_super_value first_error_time 1 +set_super_value last_error_time 1 +set_current_time 1 +set_super_value wtime 1 +dirty -clean +close +""") + clear_timestamps.write(""" +set_super_value mtime 1 +set_super_value lastcheck 1 +set_super_value mkfs_time 1 +set_super_value first_error_time 1 +set_super_value last_error_time 1 +set_current_time 1 +set_super_value wtime 1 +dirty -clean +close +""") + clear_timestamps.flush() + write_cmd.flush() + read_cmd.flush() + expected_stdout.flush() + subprocess.check_call(('debugfs', '-w', '-f', write_cmd.name, '--', sys.argv[3]), stdout=subprocess.DEVNULL) + subprocess.check_call(('e2fsck', '-pDfE', 'optimize_extents', '--', sys.argv[3])) + if False: # This breaks determinism, sadly + subprocess.check_call(('debugfs', '-w', '-f', clear_timestamps.name, '--', sys.argv[3])) + subprocess.check_call(('resize2fs', '-M', '--', sys.argv[3])) + subprocess.check_call(('e2fsck', '-pDfE', 'optimize_extents', '--', sys.argv[3])) + for i in (0, 0x8000, 0x18000): + subprocess.check_call(('debugfs', '-w', '-f', clear_timestamps.name, '-b4096', '-s' + str(i), '--', sys.argv[3])) + subprocess.check_call(('debugfs', '-f', read_cmd.name, '--', sys.argv[3]), stdout=actual_stdout) + subprocess.check_call(('e2fsck', '-n', '--', sys.argv[3])) + subprocess.check_call(('fallocate', '--dig-holes', '--', sys.argv[3])) + # If the labels weren't set properly, fail the build + subprocess.check_call(('diff', '-u', '--', expected_stdout.name, actual_stdout.name)) diff --git a/kernel.spec.in b/kernel.spec.in index c20c1ce3..07685cfe 100644 --- a/kernel.spec.in +++ b/kernel.spec.in @@ -502,9 +502,16 @@ if [ -n "$SOURCE_DATE_EPOCH" ]; then find %buildroot%vm_install_dir/modules \ -exec touch --no-dereference --date="@${SOURCE_DATE_EPOCH}" {} + fi + PATH="/sbin:$PATH" mkfs.ext3 -d %buildroot%vm_install_dir/modules \ -U dcee2318-92bd-47a5-a15d-e79d1412cdce \ %buildroot%vm_install_dir/modules.img 1024M + +# Set up SELinux labels on the files, so that qubes with SELinux enforcing work +PATH="/sbin:$PATH" python3 ./genattr.py %upstream_version-%plainrel \ + %buildroot%vm_install_dir/modules \ + "$PWD/%buildroot%vm_install_dir/modules.img" || exit + rm -rf %buildroot%vm_install_dir/modules # remove files that will be auto generated by depmod at rpm -i time