Hello community, here is the log from the commit of package permissions for openSUSE:Factory checked in at 2020-02-13 10:10:50 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/permissions (Old) and /work/SRC/openSUSE:Factory/.permissions.new.26092 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "permissions" Thu Feb 13 10:10:50 2020 rev:130 rq:769971 version:unknown Changes: -------- --- /work/SRC/openSUSE:Factory/permissions/permissions.changes 2019-12-07 15:13:59.239807746 +0100 +++ /work/SRC/openSUSE:Factory/.permissions.new.26092/permissions.changes 2020-02-13 10:10:56.484319996 +0100 @@ -1,0 +2,17 @@ +Tue Feb 04 12:20:43 UTC 2020 - [email protected] + +- Update to version 20200204: + * mariadb: settings for new auth_pam_tool (bsc#1160285) + * chkstat: + - add read-only fallback when /proc is not mounted (bsc#1160764) + - capability handling fixes (bsc#1161779) + - better error message when refusing to fix dir perms (#32) + +------------------------------------------------------------------- +Mon Jan 27 11:58:17 UTC 2020 - [email protected] + +- Update to version 20200127: + * fix paths of ksysguard whitelisting + * fix zero-termination of error message for overly long paths + +------------------------------------------------------------------- Old: ---- permissions-20191205.tar.xz New: ---- permissions-20200204.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ permissions.spec ++++++ --- /var/tmp/diff_new_pack.08lMlz/_old 2020-02-13 10:10:57.008320300 +0100 +++ /var/tmp/diff_new_pack.08lMlz/_new 2020-02-13 10:10:57.012320302 +0100 @@ -1,7 +1,7 @@ # # spec file for package permissions # -# Copyright (c) 2019 SUSE LLC +# Copyright (c) 2020 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -16,7 +16,7 @@ # -%define VERSION 20191205 +%define VERSION 20200204 Name: permissions Version: %{VERSION} ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.08lMlz/_old 2020-02-13 10:10:57.044320321 +0100 +++ /var/tmp/diff_new_pack.08lMlz/_new 2020-02-13 10:10:57.044320321 +0100 @@ -1,4 +1,4 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/openSUSE/permissions.git</param> - <param name="changesrevision">530cade2a85b318e8cb35261f3d2da5223c11af2</param></service></servicedata> \ No newline at end of file + <param name="changesrevision">402e7433e5b8114ea2e591ed6a8eadca8936127d</param></service></servicedata> \ No newline at end of file ++++++ permissions-20191205.tar.xz -> permissions-20200204.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/permissions-20191205/Makefile new/permissions-20200204/Makefile --- old/permissions-20191205/Makefile 2019-12-05 15:28:14.000000000 +0100 +++ new/permissions-20200204/Makefile 2020-02-04 13:19:11.000000000 +0100 @@ -19,6 +19,7 @@ CPPFLAGS += -DFSCAPS_DEFAULT_ENABLED=$(FSCAPS_DEFAULT_ENABLED) all: src/chkstat + @if grep -o -P '\t' src/chkstat.c ; then echo "error: chkstat.c mixes tabs and spaces!" ; touch src/chkstat.c ; exit 1 ; fi ; : install: all @for i in $(bindir) $(man8dir) $(man5dir) $(fillupdir) $(sysconfdir) $(zypp_commit_plugins); \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/permissions-20191205/profiles/permissions.easy new/permissions-20200204/profiles/permissions.easy --- old/permissions-20191205/profiles/permissions.easy 2019-12-05 15:28:14.000000000 +0100 +++ new/permissions-20200204/profiles/permissions.easy 2020-02-04 13:19:11.000000000 +0100 @@ -395,5 +395,11 @@ /var/spool/nagios/ nagios:nagcmd 2775 # ksysguard network helper (bsc#1151190) -/usr/libexec/ksysguard/ksgrd_network_helper root:root 0755 +/usr/lib/libexec/ksysguard/ksgrd_network_helper root:root 0755 +capabilities cap_net_raw=ep +/usr/lib64/libexec/ksysguard/ksgrd_network_helper root:root 0755 + +capabilities cap_net_raw=ep + +# 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 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/permissions-20191205/profiles/permissions.paranoid new/permissions-20200204/profiles/permissions.paranoid --- old/permissions-20191205/profiles/permissions.paranoid 2019-12-05 15:28:14.000000000 +0100 +++ new/permissions-20200204/profiles/permissions.paranoid 2020-02-04 13:19:11.000000000 +0100 @@ -398,4 +398,9 @@ /var/spool/nagios/ nagios:nagcmd 0770 # ksysguard network helper (bsc#1151190) -/usr/libexec/ksysguard/ksgrd_network_helper root:root 0755 +/usr/lib/libexec/ksysguard/ksgrd_network_helper root:root 0755 +/usr/lib64/libexec/ksysguard/ksgrd_network_helper root:root 0755 + +# 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 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/permissions-20191205/profiles/permissions.secure new/permissions-20200204/profiles/permissions.secure --- old/permissions-20191205/profiles/permissions.secure 2019-12-05 15:28:14.000000000 +0100 +++ new/permissions-20200204/profiles/permissions.secure 2020-02-04 13:19:11.000000000 +0100 @@ -434,5 +434,11 @@ /var/spool/nagios/ nagios:nagcmd 2775 # ksysguard network helper (bsc#1151190) -/usr/libexec/ksysguard/ksgrd_network_helper root:root 0755 +/usr/lib/libexec/ksysguard/ksgrd_network_helper root:root 0755 +capabilities cap_net_raw=ep +/usr/lib64/libexec/ksysguard/ksgrd_network_helper root:root 0755 + +capabilities cap_net_raw=ep + +# 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 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/permissions-20191205/src/chkstat.c new/permissions-20200204/src/chkstat.c --- old/permissions-20191205/src/chkstat.c 2019-12-05 15:28:14.000000000 +0100 +++ new/permissions-20200204/src/chkstat.c 2020-02-04 13:19:11.000000000 +0100 @@ -24,6 +24,8 @@ #include <grp.h> #include <sys/types.h> #include <sys/stat.h> +#include <sys/vfs.h> +#include <linux/magic.h> #include <unistd.h> #include <stdlib.h> #include <string.h> @@ -32,6 +34,7 @@ #include <sys/capability.h> #include <fcntl.h> #include <stdbool.h> +#include <sys/param.h> #define BAD_LINE() \ fprintf(stderr, "bad permissions line %s:%d\n", permfiles[i], lcnt) @@ -439,25 +442,59 @@ exit(x); } +enum proc_mount_state { + PROC_MOUNT_STATE_UNKNOWN, + PROC_MOUNT_STATE_AVAIL, + PROC_MOUNT_STATE_UNAVAIL, +}; +static enum proc_mount_state proc_mount_avail = PROC_MOUNT_STATE_UNKNOWN; + +static bool +check_have_proc(void) +{ + if (proc_mount_avail == PROC_MOUNT_STATE_UNKNOWN) + { + char *override = secure_getenv("CHKSTAT_PRETEND_NO_PROC"); + + struct statfs proc; + int r = statfs("/proc", &proc); + if (override == NULL && r == 0 && proc.f_type == PROC_SUPER_MAGIC) + proc_mount_avail = PROC_MOUNT_STATE_AVAIL; + else + proc_mount_avail = PROC_MOUNT_STATE_UNAVAIL; + } + + return proc_mount_avail == PROC_MOUNT_STATE_AVAIL; +} + + + +#define _STRINGIFY(s) #s +#define STRINGIFY(s) _STRINGIFY(s) + +#define PROC_FD_PATH_SIZE (sizeof("/proc/self/fd/") + sizeof(STRINGIFY(INT_MAX))) + + int safe_open(char *path, struct stat *stb, uid_t target_uid, bool *traversed_insecure) { char pathbuf[PATH_MAX]; - char *p; + char *path_rest; int lcnt; int pathfd = -1; struct stat root_st; + bool is_final_path_element = false; *traversed_insecure = false; lcnt = 0; if ((size_t)snprintf(pathbuf, sizeof(pathbuf), "%s", path + rootl) >= sizeof(pathbuf)) goto fail; - p = pathbuf; - do + path_rest = pathbuf; + while (!is_final_path_element) { - *p = '/'; - char *cursor = p + 1; + *path_rest = '/'; + char *cursor = path_rest + 1; if (pathfd == -1) { @@ -476,13 +513,14 @@ memcpy(stb, &root_st, sizeof(*stb)); } - p = strchr(cursor, '/'); - // p is NULL when we reach the final path element - if (p) - *p = 0; + path_rest = strchr(cursor, '/'); + // path_rest is NULL when we reach the final path element + is_final_path_element = path_rest == NULL || strcmp("/", path_rest) == 0; + if (!is_final_path_element) + *path_rest = 0; // multiple consecutive slashes: ignore - if (p && *cursor == '\0') + if (!is_final_path_element && *cursor == '\0') continue; // never move up from the configured root directory (using the stat result from the previous loop iteration) @@ -502,19 +540,21 @@ /* owner of directories must be trusted for setuid/setgid/capabilities as we have no way to verify file contents */ /* for euid != 0 it is also ok if the owner is euid */ - if (stb->st_uid && stb->st_uid != euid && p) + if (stb->st_uid && stb->st_uid != euid && !is_final_path_element) *traversed_insecure = true; // path is in a world-writable directory, or file is world-writable itself. - if (!S_ISLNK(stb->st_mode) && (stb->st_mode & S_IWOTH) && p) + if (!S_ISLNK(stb->st_mode) && (stb->st_mode & S_IWOTH) && !is_final_path_element) *traversed_insecure = true; // if parent directory is not owned by root, the file owner must match the owner of parent if (stb->st_uid && stb->st_uid != target_uid && stb->st_uid != euid) { - if (p) - goto fail_insecure_path; + if (is_final_path_element) + { + fprintf(stderr, "%s: has unexpected owner. refusing to correct due to unknown integrity.\n", path+rootl); + goto fail; + } else - fprintf(stderr, "%s: has unexpected owner. refusing to correct due to unknown integrity.\n", path+rootl); - goto fail; + goto fail_insecure_path; } if (S_ISLNK(stb->st_mode)) @@ -541,17 +581,18 @@ pathfd = -1; } size_t len; - char tmp[sizeof(pathbuf)]; // need a temporary buffer because p points into pathbuf and snprintf doesn't allow the same buffer as source and destination - if (p) - len = (size_t)snprintf(tmp, sizeof(tmp), "%s/%s", linkbuf, p + 1); - else + char tmp[sizeof(pathbuf) - 1]; // need a temporary buffer because path_rest points into pathbuf and snprintf doesn't allow the same buffer as source and destination + if (is_final_path_element) len = (size_t)snprintf(tmp, sizeof(tmp), "%s", linkbuf); - if (len >= sizeof(pathbuf)) + else + len = (size_t)snprintf(tmp, sizeof(tmp), "%s/%s", linkbuf, path_rest + 1); + if (len >= sizeof(tmp)) goto fail; - strcpy(pathbuf, tmp); - p = pathbuf; + // the first byte of path_rest is always set to a slash at the start of the loop, so we offset by one byte + strcpy(pathbuf + 1, tmp); + path_rest = pathbuf; } - } while (p); + } // world-writable file: error out due to unknown file integrity if (S_ISREG(stb->st_mode) && (stb->st_mode & S_IWOTH)) { @@ -563,12 +604,12 @@ fail_insecure_path: { - char linkpath[PATH_MAX]; - char procpath[100]; + char linkpath[PATH_MAX] = "ancestor"; + char procpath[PROC_FD_PATH_SIZE]; snprintf(procpath, sizeof(procpath), "/proc/self/fd/%d", pathfd); ssize_t l = readlink(procpath, linkpath, sizeof(linkpath) - 1); - if (l > 0 && (size_t)l < sizeof(linkpath) - 1) - linkpath[l] = '\0'; + if (l > 0) + linkpath[MIN((size_t)l, sizeof(linkpath) - 1)] = '\0'; fprintf(stderr, "%s: on an insecure path - %s has different non-root owner who could tamper with the file.\n", path+rootl, linkpath); } @@ -578,6 +619,7 @@ return -1; } + /* check /sys/kernel/fscaps, 2.6.39 */ static int check_fscaps_enabled() @@ -980,8 +1022,17 @@ // // So we use path-based operations (yes!) with /proc/self/fd/xxx. (Since safe_open already resolved // all symlinks, 'fd' can't refer to a symlink which we'd have to worry might get followed.) - char fd_path[100]; - snprintf(fd_path, sizeof(fd_path), "/proc/self/fd/%d", fd); + char fd_path_buf[PROC_FD_PATH_SIZE]; + char *fd_path; + if (check_have_proc()) + { + snprintf(fd_path_buf, sizeof(fd_path_buf), "/proc/self/fd/%d", fd); + fd_path = fd_path_buf; + } + else + // fall back to plain path-access for read-only operation. (this much is fine) + // below we make sure that in this case we report errors instead of trying to fix policy violations insecurely + fd_path = e->file; caps = cap_get_file(fd_path); if (!caps) @@ -1033,6 +1084,13 @@ } } + if (do_set && fd_path != fd_path_buf) + { + fprintf(stderr, "ERROR: /proc is not available - unable to fix policy violations.\n"); + errors++; + do_set = false; + } + if (!do_set) printf("%s should be %s:%s %04o", e->file+rootl, e->owner, e->group, e->mode); else @@ -1116,13 +1174,15 @@ fprintf(stderr, "%s: chmod: %s\n", e->file+rootl, strerror(errno)); errors++; } - if (!caps_ok) + // chown and - depending on the file system - chmod clear existing capabilities + // so apply the intended caps even if they were correct previously + if (e->caps || !caps_ok) { if (S_ISREG(stb.st_mode)) { // cap_set_file() tries to be helpful and does a lstat() to check that it isn't called on // a symlink. So we have to open() it (without O_PATH) and use cap_set_fd(). - int cap_fd = open(fd_path, O_NOATIME | O_CLOEXEC); + int cap_fd = open(fd_path, O_NOATIME | O_CLOEXEC | O_RDONLY); if (cap_fd == -1) { fprintf(stderr, "%s: open() for changing capabilities: %s\n", e->file+rootl, strerror(errno)); @@ -1130,8 +1190,12 @@ } else if (cap_set_fd(cap_fd, e->caps)) { - fprintf(stderr, "%s: cap_set_fd: %s\n", e->file+rootl, strerror(errno)); - errors++; + // ignore ENODATA when clearing caps - it just means there were no caps to remove + if (errno != ENODATA || e->caps) + { + fprintf(stderr, "%s: cap_set_fd: %s\n", e->file+rootl, strerror(errno)); + errors++; + } } if (cap_fd != -1) close(cap_fd);
