Hello community, here is the log from the commit of package permissions for openSUSE:Factory checked in at 2020-03-30 22:50:49 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/permissions (Old) and /work/SRC/openSUSE:Factory/.permissions.new.3160 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "permissions" Mon Mar 30 22:50:49 2020 rev:133 rq:787823 version:unknown Changes: -------- --- /work/SRC/openSUSE:Factory/permissions/permissions.changes 2020-03-06 21:23:24.365419871 +0100 +++ /work/SRC/openSUSE:Factory/.permissions.new.3160/permissions.changes 2020-03-30 22:50:52.947755978 +0200 @@ -1,0 +2,15 @@ +Tue Mar 24 12:52:07 UTC 2020 - [email protected] + +- Update to version 20200324: + * whitelist s390-tools setgid bit on log directory (bsc#1167163) + * whitelist WMP (bsc#1161335) + * regtest: improve readability of path variables by using literals + * regtest: adjust test suite to new path locations in /usr/share/permissions + * regtest: only catch explicit FileNotFoundError + * regtest: provide valid home directory in /root + * regtest: mount permissions src repository in /usr/src/permissions + * regtest: move initialialization of TestBase paths into the prepare() function + * chkstat: suppport new --config-root command line option + * fix spelling of icingacmd group + +------------------------------------------------------------------- Old: ---- permissions-20200228.tar.xz New: ---- permissions-20200324.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ permissions.spec ++++++ --- /var/tmp/diff_new_pack.26hX2r/_old 2020-03-30 22:50:53.531756297 +0200 +++ /var/tmp/diff_new_pack.26hX2r/_new 2020-03-30 22:50:53.535756298 +0200 @@ -16,7 +16,7 @@ # -%define VERSION_DATE 20200228 +%define VERSION_DATE 20200324 Name: permissions Version: %{VERSION_DATE}.%{suse_version} ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.26hX2r/_old 2020-03-30 22:50:53.567756316 +0200 +++ /var/tmp/diff_new_pack.26hX2r/_new 2020-03-30 22:50:53.567756316 +0200 @@ -1,4 +1,4 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/openSUSE/permissions.git</param> - <param name="changesrevision">bfa5f7c7437b3fa939b0a88007e2d1cc6de605c9</param></service></servicedata> \ No newline at end of file + <param name="changesrevision">5a8f6ce8743fba27666b634dda7a099e027b2edf</param></service></servicedata> \ No newline at end of file ++++++ permissions-20200228.tar.xz -> permissions-20200324.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/permissions-20200228/profiles/permissions.easy new/permissions-20200324/profiles/permissions.easy --- old/permissions-20200228/profiles/permissions.easy 2020-02-28 09:49:05.000000000 +0100 +++ new/permissions-20200324/profiles/permissions.easy 2020-03-24 12:57:25.000000000 +0100 @@ -351,7 +351,7 @@ +capabilities cap_net_bind_service=ep # icinga2 (bsc#1069410) -/run/icinga2/cmd/ icinga:icingagmd 2750 +/run/icinga2/cmd/ icinga:icingacmd 2750 # fping (bsc#1047921) /usr/sbin/fping root:root 0755 @@ -397,3 +397,9 @@ # mariadb auth_pam_tool (bsc#1160285) /usr/lib/mysql/plugin/auth_pam_tool_dir/auth_pam_tool root:root 4755 /usr/lib64/mysql/plugin/auth_pam_tool_dir/auth_pam_tool root:root 4755 + +# Workload Memory Protection (bsc#1161335) +/usr/lib/sapwmp/sapwmp-capture root:sapsys 4750 + +# s390-tools log directory for ts-shell (bsc#1167163) +/var/log/ts-shell/ root:ts-shell 2770 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/permissions-20200228/profiles/permissions.paranoid new/permissions-20200324/profiles/permissions.paranoid --- old/permissions-20200228/profiles/permissions.paranoid 2020-02-28 09:49:05.000000000 +0100 +++ new/permissions-20200324/profiles/permissions.paranoid 2020-03-24 12:57:25.000000000 +0100 @@ -358,7 +358,7 @@ /usr/lib/gvfs/gvfsd-nfs root:root 0755 # icinga2 (bsc#1069410) -/run/icinga2/cmd/ icinga:icingagmd 0750 +/run/icinga2/cmd/ icinga:icingacmd 0750 # fping (bsc#1047921) /usr/sbin/fping root:root 0755 @@ -400,3 +400,9 @@ # mariadb auth_pam_tool (bsc#1160285) /usr/lib/mysql/plugin/auth_pam_tool_dir/auth_pam_tool root:root 0755 /usr/lib64/mysql/plugin/auth_pam_tool_dir/auth_pam_tool root:root 0755 + +# Workload Memory Protection (bsc#1161335) +/usr/lib/sapwmp/sapwmp-capture root:sapsys 0750 + +# s390-tools log directory for ts-shell (bsc#1167163) +/var/log/ts-shell/ root:ts-shell 0770 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/permissions-20200228/profiles/permissions.secure new/permissions-20200324/profiles/permissions.secure --- old/permissions-20200228/profiles/permissions.secure 2020-02-28 09:49:05.000000000 +0100 +++ new/permissions-20200324/profiles/permissions.secure 2020-03-24 12:57:25.000000000 +0100 @@ -390,7 +390,7 @@ /usr/lib/gvfs/gvfsd-nfs root:root 0755 # icinga2 (bsc#1069410) -/run/icinga2/cmd/ icinga:icingagmd 2750 +/run/icinga2/cmd/ icinga:icingacmd 2750 # fping (bsc#1047921) /usr/sbin/fping root:root 0755 @@ -436,3 +436,9 @@ # mariadb auth_pam_tool (bsc#1160285) /usr/lib/mysql/plugin/auth_pam_tool_dir/auth_pam_tool root:root 4755 /usr/lib64/mysql/plugin/auth_pam_tool_dir/auth_pam_tool root:root 4755 + +# Workload Memory Protection (bsc#1161335) +/usr/lib/sapwmp/sapwmp-capture root:sapsys 4750 + +# s390-tools log directory for ts-shell (bsc#1167163) +/var/log/ts-shell/ root:ts-shell 2770 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/permissions-20200228/src/chkstat.cpp new/permissions-20200324/src/chkstat.cpp --- old/permissions-20200228/src/chkstat.cpp 2020-02-28 09:49:05.000000000 +0100 +++ new/permissions-20200324/src/chkstat.cpp 2020-03-24 12:57:25.000000000 +0100 @@ -37,6 +37,8 @@ #include <fcntl.h> #include <sys/param.h> #include <cassert> +#include <limits.h> +#include <string> #define BAD_LINE() \ fprintf(stderr, "bad permissions line %s:%d\n", permfiles[i], lcnt) @@ -65,6 +67,7 @@ char** permfiles = NULL; size_t npermfiles = 0; char* force_level; +std::string config_root; struct perm* add_permlist(char *file, const char *p_owner, const char *p_group, mode_t mode) @@ -420,16 +423,22 @@ { size_t i; + const auto usr_root = config_root + "/usr/share/permissions"; + const auto etc_root = config_root + "/etc"; + + const auto central_usr_perms = usr_root + "/permissions"; + const auto central_etc_perms = etc_root + "/permissions"; + // 1. central fixed permissions file - if (access("/usr/share/permissions/permissions", R_OK) == 0) + if (access(central_usr_perms.c_str(), R_OK) == 0) { ensure_array((void**)&permfiles, &npermfiles); - permfiles[npermfiles++] = strdup("/usr/share/permissions/permissions"); + permfiles[npermfiles++] = strdup(central_usr_perms.c_str()); } - else if (access("/etc/permissions", R_OK) == 0) + else if (access(central_etc_perms.c_str(), R_OK) == 0) { ensure_array((void**)&permfiles, &npermfiles); - permfiles[npermfiles++] = strdup("/etc/permissions"); + permfiles[npermfiles++] = strdup(central_etc_perms.c_str()); } // 2. central easy, secure paranoid as those are defined by SUSE @@ -439,41 +448,37 @@ || !strcmp(level[i], "secure") || !strcmp(level[i], "paranoid")) { - char fn[4096]; - snprintf(fn, sizeof(fn), "/usr/share/permissions/permissions.%s", level[i]); - if (access(fn, R_OK) == 0) + auto base = std::string("/permissions.") + level[i]; + for( const auto &dir: { usr_root, etc_root } ) { - ensure_array((void**)&permfiles, &npermfiles); - permfiles[npermfiles++] = strdup(fn); - } - else - { - snprintf(fn, sizeof(fn), "/etc/permissions.%s", level[i]); - if (access(fn, R_OK) == 0) + std::string profile = dir + base; + + if (access(profile.c_str(), R_OK) == 0) { ensure_array((void**)&permfiles, &npermfiles); - permfiles[npermfiles++] = strdup(fn); + permfiles[npermfiles++] = strdup(profile.c_str()); + break; } } } } + // 3. package specific permissions - read_permissions_d("/usr/share/permissions/permissions.d"); - read_permissions_d("/etc/permissions.d"); + read_permissions_d((usr_root + "/permissions.d").c_str()); + read_permissions_d((etc_root + "/permissions.d").c_str()); // 4. central permissions files with user defined level incl 'local' for (i = 0; i < nlevel; ++i) { - char fn[4096]; - if (!strcmp(level[i], "easy") || !strcmp(level[i], "secure") || !strcmp(level[i], "paranoid")) continue; - snprintf(fn, sizeof(fn), "/etc/permissions.%s", level[i]); - if (access(fn, R_OK) == 0) + std::string profile = etc_root + "/permissions." + level[i]; + + if (access(profile.c_str(), R_OK) == 0) { ensure_array((void**)&permfiles, &npermfiles); - permfiles[npermfiles++] = strdup(fn); + permfiles[npermfiles++] = strdup(profile.c_str()); } } } @@ -497,6 +502,7 @@ " --examine FILE apply to specified file only\n" " --files FILELIST read list of files to apply from FILELIST\n" " --root DIR check files relative to DIR\n" + " --config-root DIR lookup config files relative to DIR\n" ); exit(x); } @@ -918,6 +924,33 @@ argv++; continue; } + if (!strcmp(opt, "-config-root")) + { + argc--; + argv++; + if (argc == 1) + { + fprintf(stderr, "config-root: argument required\n"); + exit(1); + } + config_root = argv[1]; + if (config_root.empty() || config_root[0] != '/') + { + fprintf(stderr, "config-root: must begin with '/'\n"); + exit(1); + } + // considering NAME_MAX characters left is somewhat arbitrary, but + // staying within these limits should at least allow us to not + // encounter ENAMETOOLONG in typical setups + else if(config_root.length() >= (PATH_MAX - NAME_MAX - 1)) + { + fprintf(stderr, "config-root: prefix is too long\n"); + exit(1); + } + argc--; + argv++; + continue; + } if (*opt == '-') usage(!strcmp(opt, "-h") || !strcmp(opt, "-help") ? 0 : 1); break; @@ -925,13 +958,13 @@ if (systemmode) { - const char file[] = "/etc/sysconfig/security"; - parse_sysconf(file); + const std::string file = config_root + "/etc/sysconfig/security"; + parse_sysconf(file.c_str()); if(do_set == -1) { if (default_set < 0) { - fprintf(stderr, "permissions handling disabled in %s\n", file); + fprintf(stderr, "permissions handling disabled in %s\n", file.c_str()); exit(0); } if (suseconfig && default_set) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/permissions-20200228/tests/regtest.py new/permissions-20200324/tests/regtest.py --- old/permissions-20200228/tests/regtest.py 2020-02-28 09:49:05.000000000 +0100 +++ new/permissions-20200324/tests/regtest.py 2020-03-24 12:57:25.000000000 +0100 @@ -113,7 +113,7 @@ perm_root = os.path.realpath(__file__).split(os.path.sep)[:-2] self.m_permissions_repo = os.path.sep.join(perm_root) - self.m_chkstat_bin = os.path.sep.join([self.m_permissions_repo, "src/chkstat"]) + self.m_chkstat_orig = os.path.sep.join([self.m_permissions_repo, "src/chkstat"]) def printDebug(self, *args, **kwargs): @@ -483,6 +483,12 @@ except subprocess.CalledProcessError: pass + def getChkstatPath(self): + return "/usr/local/bin/chkstat" + + def getChkstatConfigRoot(self): + return "/usr/local" + def setupFakeRoot(self, skip_proc): # simply operate directly in /tmp in a tmpfs, since we're in a @@ -495,12 +501,9 @@ # to own the root filesystem '/', thus let's chroot into /tmp, # where we only bind mount the most important stuff from the # root mount namespace - bind_dirs = ["/bin", "/sbin", "/usr", "/sys", "/dev", "/var"] + bind_dirs = ["/bin", "/sbin", "/usr", "/sys", "/dev", "/var", "/etc"] # add any /lib32/64 symlinks whatever bind_dirs.extend( glob.glob("/lib*") ) - # /etc needs to be copied, we need to be able to write in - # there, to construct fake permissions config files - copy_dirs = ("/etc",) for src in bind_dirs: @@ -514,20 +517,6 @@ else: raise Exception("bad mount src " + src) - for src in copy_dirs: - dst_dir = self.m_fake_root + src - try: - # symlinks here means "copy links as is" - shutil.copytree(src, dst_dir, symlinks = True) - except shutil.Error: - # copying /etc only works partially since - # we're not really root. - # this error contains a list of errors in - # args[0] consisting of (src, dst, error) - # tuples, but "error" is only a string in this - # case, not very helpful for evaluation - pass - # mount a new proc corresponding to our forked pid namespace # unless this is disabled, to test chkstat behaviour without /proc if not skip_proc: @@ -537,19 +526,25 @@ # also bind-mount the permissions repo e.g. useful for # debugging - permissions_repo_dst = self.m_fake_root + "/permissions" + self.mountTmpFS( self.m_fake_root + "/usr/src" ) + permissions_repo_dst = self.m_fake_root + "/usr/src/permissions" os.makedirs(permissions_repo_dst) self.bindMount( self.m_permissions_repo, permissions_repo_dst, ) self.mountTmpFS(self.m_fake_root + "/usr/local") - local_bin = self.m_fake_root + "/usr/local/bin" - os.makedirs(local_bin, exist_ok = True) - local_chkstat = os.path.join(local_bin, "chkstat") + local_bin = self.m_fake_root + self.getChkstatPath() + os.makedirs(os.path.dirname(local_bin), exist_ok = True) # copy the current chkstat into a suitable location of # the fake root FS - shutil.copy(self.m_chkstat_bin, local_chkstat) + shutil.copy(self.m_chkstat_orig, local_bin) + + # make a writeable home available for the user namespace root + # user + root_home = self.m_fake_root + "/root" + os.makedirs(root_home) + self.mountTmpFS(root_home) # finally enter the fake root os.chroot(self.m_fake_root) @@ -557,7 +552,8 @@ os.umask(0o022) # use a defined standard PATH list, include sbin # to make sure we also find admin tools - os.environ["PATH"] = "/bin:/sbin:/usr/bin:/usr/sbin" + os.environ["PATH"] = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin" + os.environ["HOME"] = "/root" os.chdir("/") # setup a tmp directory just in case @@ -588,9 +584,9 @@ def buildChkstat(self): if self.m_args.skip_make: - if not os.path.exists(self.m_chkstat_bin): + if not os.path.exists(self.m_chkstat_orig): print("Couldn't find compiled chkstat binary in", - self.m_chkstat_bin, file = sys.stderr) + self.m_chkstat_orig, file = sys.stderr) sys.exit(2) return @@ -719,13 +715,8 @@ def __init__(self, name, desc): - self.m_sysconfig = "/etc/sysconfig" - self.m_sysconfig_security = self.m_sysconfig + "/security" - self.m_permissions_dir = "/etc/permissions.d" - self.m_permissions_base = "/etc/permissions" self.m_profiles = ("easy", "secure", "paranoid") self.m_local_profile = "local" - self.m_chkstat_bin = "/usr/local/bin/chkstat" self.m_test_name = name self.m_test_desc = desc @@ -738,12 +729,19 @@ self.m_main_test_instance = instance def getProfilePath(self, profile): + base = TestBase.config_root + "/usr/share/permissions/permissions" if not profile: - return self.m_permissions_base - return '.'.join((self.m_permissions_base, profile)) + return base + return '.'.join((base, profile)) + + def getUserProfilePath(self, profile): + base = TestBase.config_root + "/etc/permissions" + if not profile: + return base + return '.'.join((base, profile)) def getPackageProfilePath(self, package, profile): - base = os.path.sep.join((self.m_permissions_dir, package)) + base = TestBase.config_root + "/etc/permissions.d/" + package if not profile: return base @@ -784,11 +782,22 @@ return self.m_test_desc def prepare(self): - if not self.global_init_performed: - # make sure certain dirs exist - os.makedirs(self.m_sysconfig, 0o755, exist_ok = True) - os.makedirs(self.m_permissions_dir, 0o755, exist_ok = True) - self.global_init_performed = True + if not TestBase.global_init_performed: + + TestBase.config_root = self.m_main_test_instance.getChkstatConfigRoot() + TestBase.chkstat = self.m_main_test_instance.getChkstatPath() + + config_root = TestBase.config_root + + # make a convenience symlink to make it feel more + # natural in /usr/local + os.symlink(config_root + "/usr/share", config_root + "/share") + + # make sure base dirs exist + os.makedirs(config_root + "/etc/sysconfig", 0o755, exist_ok = True) + os.makedirs(config_root + "/etc/permissions.d", 0o755, exist_ok = True) + os.makedirs(config_root + "/usr/share/permissions", 0o755, exist_ok = True) + TestBase.global_init_performed = True self.resetConfigs() @@ -799,25 +808,29 @@ def resetConfigs(self): + config_root = TestBase.config_root + sysconfig = config_root + "/etc/sysconfig/security" + central_perms = config_root + "/usr/share/permissions/permissions" + candidates = [ - self.m_sysconfig_security, - self.m_permissions_base, + sysconfig, + central_perms, ] - candidates.append( self.getProfilePath(self.m_local_profile) ) - candidates.extend( glob.glob(self.m_permissions_dir + "/*") ) + candidates.append( self.getUserProfilePath(self.m_local_profile) ) + candidates.extend( glob.glob(config_root + "/etc/permissions.d/*") ) candidates.extend( [self.getProfilePath(profile) for profile in self.m_profiles] ) for cand in candidates: try: os.unlink(cand) - except: + except FileNotFoundError: pass # chkstat expects the base files to exist, otherwise warnings # are emitted - self.createTestFile(self.m_permissions_base, 0o644) - self.createTestFile(self.m_sysconfig_security, 0o644) + self.createTestFile(central_perms, 0o644) + self.createTestFile(sysconfig, 0o644) def addProfileEntries(self, entries): """Adds entries to /etc/permissions.* according to the @@ -830,9 +843,16 @@ } """ + def getAgnosticProfilePath(profile): + + if profile == self.m_local_profile: + return self.getUserProfilePath(profile) + else: + return self.getProfilePath(profile) + for profile, lines in entries.items(): - with open(self.getProfilePath(profile), 'a') as profile_file: + with open(getAgnosticProfilePath(profile), 'a') as profile_file: for line in lines: profile_file.write(line + "\n") @@ -872,7 +892,7 @@ "PERMISSION_FSCAPS": fscaps_val } - with open(self.m_sysconfig_security, 'w') as sec_file: + with open(TestBase.config_root + "/etc/sysconfig/security", 'w') as sec_file: for key, val in items.items(): if not val: @@ -1023,7 +1043,7 @@ if isinstance(args, str): args = [args] - cmdline = [self.m_chkstat_bin] + args + cmdline = [self.chkstat, "--config-root", TestBase.config_root] + args print('#', ' '.join(cmdline)) @@ -1279,9 +1299,9 @@ # this should take precendence over all other entries line = self.buildProfileLine(testdir, local_perms[0]) - global_entries["local"] = [ line ] + global_entries[self.m_local_profile] = [ line ] line = self.buildProfileLine(testfile, local_perms[1]) - pkg_entries["local"] = [ line ] + pkg_entries[self.m_local_profile] = [ line ] self.addProfileEntries(global_entries) self.addPackageProfileEntries(package, pkg_entries)
