Blame SOURCES/rhbz1902696.patch

ac42f3
commit e3d03db82853049f65f16dc40c03f3f7f617ffb5
ac42f3
Author: Frank Ch. Eigler <fche@redhat.com>
ac42f3
Date:   Sun Dec 13 21:05:23 2020 -0500
ac42f3
ac42f3
    PR23512: fix staprun/stapio operation via less-than-root privileges
ac42f3
    
ac42f3
    Commit 7615cae790c899bc8a82841c75c8ea9c6fa54df3 for PR26665 introduced
ac42f3
    a regression in handling stapusr/stapdev/stapsys gid invocation of
ac42f3
    staprun/stapio.  This patch simplifies the relevant code in
ac42f3
    staprun/ctl.c, init_ctl_channel(), to rely on openat/etc. to populate
ac42f3
    and use the relay_basedir_fd as much as possible.  Also, we now avoid
ac42f3
    unnecessary use of access(), which was checking against the wrong
ac42f3
    (real rather than effective) uid/gid.
ac42f3
ac42f3
diff --git a/staprun/ctl.c b/staprun/ctl.c
ac42f3
index 4be68af..da3417b 100644
ac42f3
--- a/staprun/ctl.c
ac42f3
+++ b/staprun/ctl.c
ac42f3
@@ -14,111 +14,70 @@
ac42f3
 
ac42f3
 #define CTL_CHANNEL_NAME ".cmd"
ac42f3
 
ac42f3
+
ac42f3
+#ifndef HAVE_OPENAT
ac42f3
+#error "need openat"
ac42f3
+#endif
ac42f3
+
ac42f3
+
ac42f3
+// This function does multiple things:
ac42f3
+//
ac42f3
+// 1) if needed, open the running module's directory (the one that
ac42f3
+//    contains .ctl), stash fd in relay_basedir_fd; this will be
ac42f3
+//    passed to stapio children via -F$fd for privilege passing
ac42f3
+//
ac42f3
+// 2) (re)open the running module's .ctl file, stash fd in the
ac42f3
+//    control_channel global; this will be used all over the place.
ac42f3
+//
ac42f3
+// Return 0 on success.
ac42f3
+//
ac42f3
+// See also PR14245, PR26665, RHBZ1902696 = PR23512
ac42f3
+//
ac42f3
 int init_ctl_channel(const char *name, int verb)
ac42f3
 {
ac42f3
-	char buf[PATH_MAX] = ""; // the .ctl file name
ac42f3
-        char buf2[PATH_MAX] = ""; // other tmp stuff
ac42f3
-	struct statfs st;
ac42f3
-
ac42f3
         (void) verb;
ac42f3
-        if (0) goto out; /* just to defeat gcc warnings */
ac42f3
 
ac42f3
-	/* Before trying to open the control channel, make sure it
ac42f3
-	 * isn't already open. */
ac42f3
-	close_ctl_channel();
ac42f3
+        // Already got them both?
ac42f3
+        if (control_channel >= 0 && relay_basedir_fd >= 0)
ac42f3
+                return 0;
ac42f3
 
ac42f3
-#ifdef HAVE_OPENAT
ac42f3
-        if (relay_basedir_fd >= 0) {
ac42f3
-                strncpy(buf, CTL_CHANNEL_NAME, PATH_MAX - 1);
ac42f3
-                control_channel = openat_cloexec(relay_basedir_fd,
ac42f3
-						 CTL_CHANNEL_NAME, O_RDWR, 0);
ac42f3
-                dbug(2, "Opened %s (%d)\n", CTL_CHANNEL_NAME, control_channel);
ac42f3
+        // Need relay_basedir_fd .... ok try /sys/kernel/debug/systemtap/
ac42f3
+        if (relay_basedir_fd < 0) {
ac42f3
+                char buf[PATH_MAX] = "";
ac42f3
+                struct statfs st;
ac42f3
 
ac42f3
-                /* NB: Extra real-id access check as below */
ac42f3
-                if (faccessat(relay_basedir_fd, CTL_CHANNEL_NAME, R_OK|W_OK, 0) != 0){
ac42f3
-                        close(control_channel);
ac42f3
-                        return -5;
ac42f3
-                }
ac42f3
-                if (control_channel >= 0)
ac42f3
-                        goto out; /* It's OK to bypass the [f]access[at] check below,
ac42f3
-                                     since this would only occur the *second* time 
ac42f3
-                                     staprun tries this gig, or within unprivileged stapio. */
ac42f3
+                if (sprintf_chk(buf, "/sys/kernel/debug/systemtap/%s", name))
ac42f3
+                        return -EINVAL;
ac42f3
+                
ac42f3
+                if (statfs("/sys/kernel/debug", &st) == 0 && (int)st.f_type == (int)DEBUGFS_MAGIC)
ac42f3
+                        relay_basedir_fd = open (buf, O_DIRECTORY | O_RDONLY);                        
ac42f3
         }
ac42f3
-        /* PR14245, NB: we fall through to /sys ... /proc searching,
ac42f3
-           in case the relay_basedir_fd option wasn't given (i.e., for
ac42f3
-           early in staprun), or if errors out for some reason. */
ac42f3
-#endif
ac42f3
-
ac42f3
 
ac42f3
-        // See if we have the .ctl file in debugfs
ac42f3
-        if (sprintf_chk(buf2, "/sys/kernel/debug/systemtap/%s/%s", 
ac42f3
-                        name, CTL_CHANNEL_NAME))
ac42f3
-                return -1;
ac42f3
-	if (statfs("/sys/kernel/debug", &st) == 0 && (int)st.f_type == (int)DEBUGFS_MAGIC &&
ac42f3
-            (access (buf2, W_OK)==0)) {
ac42f3
-                /* PR14245: allow subsequent operations, and if
ac42f3
-                   necessary, staprun->stapio forks, to reuse an fd for 
ac42f3
-                   directory lookups (even if some parent directories have
ac42f3
-                   perms 0700. */
ac42f3
-                strcpy(buf, buf2); // committed
ac42f3
+        // Still need relay_basedir_fd ... ok try /proc/systemtap/
ac42f3
+        if (relay_basedir_fd < 0) {
ac42f3
+                char buf[PATH_MAX] = "";
ac42f3
 
ac42f3
-#ifdef HAVE_OPENAT
ac42f3
-                if (! sprintf_chk(buf2, "/sys/kernel/debug/systemtap/%s", name)) {
ac42f3
-                        relay_basedir_fd = open (buf2, O_DIRECTORY | O_RDONLY);
ac42f3
-                }
ac42f3
-#endif
ac42f3
-        }
ac42f3
-
ac42f3
-        // PR26665: try /proc/systemtap/... also
ac42f3
-        // (STP_TRANSPORT_1 used to use this for other purposes.)
ac42f3
-        if (sprintf_chk(buf2, "/proc/systemtap/%s/%s", 
ac42f3
-                        name, CTL_CHANNEL_NAME))
ac42f3
-                return -1;
ac42f3
-        if (relay_basedir_fd < 0 && (access(buf2, W_OK)==0)) {
ac42f3
-                strcpy(buf, buf2); // committed
ac42f3
+                if (sprintf_chk(buf, "/proc/systemtap/%s", name))
ac42f3
+                        return -EINVAL;
ac42f3
                 
ac42f3
-#ifdef HAVE_OPENAT
ac42f3
-                if (! sprintf_chk(buf2, "/proc/systemtap/%s", name)) {
ac42f3
-                        relay_basedir_fd = open (buf2, O_DIRECTORY | O_RDONLY);
ac42f3
-                }
ac42f3
-#endif
ac42f3
+                relay_basedir_fd = open (buf, O_DIRECTORY | O_RDONLY);                        
ac42f3
         }
ac42f3
 
ac42f3
-        /* At this point, we have buf, which is the full path to the .ctl file,
ac42f3
-           and we may have a relay_basedir_fd, which is useful to pass across
ac42f3
-           staprun->stapio fork/execs. */
ac42f3
-        
ac42f3
-	control_channel = open_cloexec(buf, O_RDWR, 0);
ac42f3
-	dbug(2, "Opened %s (%d)\n", buf, control_channel);
ac42f3
-
ac42f3
-	/* NB: Even if open() succeeded with effective-UID permissions, we
ac42f3
-	 * need the access() check to make sure real-UID permissions are also
ac42f3
-	 * sufficient.  When we run under the setuid staprun, effective and
ac42f3
-	 * real UID may not be the same.  Specifically, we want to prevent 
ac42f3
-         * a local stapusr from trying to attach to a different stapusr's module.
ac42f3
-	 *
ac42f3
-	 * The access() is done *after* open() to avoid any TOCTOU-style race
ac42f3
-	 * condition.  We believe it's probably safe either way, as the file
ac42f3
-	 * we're trying to access connot be modified by a typical user, but
ac42f3
-	 * better safe than sorry.
ac42f3
-	 */
ac42f3
-#ifdef HAVE_OPENAT
ac42f3
-        if (control_channel >= 0 && relay_basedir_fd >= 0) {
ac42f3
-                if (faccessat (relay_basedir_fd, CTL_CHANNEL_NAME, R_OK|W_OK, 0) == 0)
ac42f3
-                        goto out;
ac42f3
-                /* else fall through */
ac42f3
+        // Got relay_basedir_fd, need .ctl
ac42f3
+        if (relay_basedir_fd >= 0) {
ac42f3
+                // verify that the ctl file is accessible to our real uid/gid
ac42f3
+                if (faccessat(relay_basedir_fd, CTL_CHANNEL_NAME, R_OK|W_OK, 0) != 0)
ac42f3
+                        return -EPERM;
ac42f3
+                
ac42f3
+                control_channel = openat_cloexec(relay_basedir_fd,
ac42f3
+						 CTL_CHANNEL_NAME, O_RDWR, 0);
ac42f3
         }
ac42f3
-#endif
ac42f3
-	if (control_channel >= 0 && access(buf, R_OK|W_OK) != 0) {
ac42f3
-		close(control_channel);
ac42f3
-		return -5;
ac42f3
-	}
ac42f3
 
ac42f3
-out:
ac42f3
-	if (control_channel < 0) {
ac42f3
+        // Fell through
ac42f3
+	if (relay_basedir_fd < 0 || control_channel < 0) {
ac42f3
                 err(_("Cannot attach to module %s control channel; not running?\n"),
ac42f3
                     name);
ac42f3
-		return -3;
ac42f3
+                return -EINVAL;
ac42f3
 	}
ac42f3
 	return 0;
ac42f3
 }
ac42f3
ac42f3
commit 1120422c2822be9e00d8d11cab3fb381d2ce0cce
ac42f3
Author: Frank Ch. Eigler <fche@redhat.com>
ac42f3
Date:   Sun Dec 13 21:19:15 2020 -0500
ac42f3
ac42f3
    PR27067 <<< corrected bug# for previous commit
ac42f3
commit cd5b72a538a404011d27d86ff958355ac2c45b8d
ac42f3
Author: Frank Ch. Eigler <fche@redhat.com>
ac42f3
Date:   Sun Jan 24 14:45:54 2021 -0500
ac42f3
ac42f3
    PR27067: set procfs traceNN files' uid/gid too
ac42f3
    
ac42f3
    commit e3d03db828 neglected to include the proper calls to set the
ac42f3
    procfs traceNN files to the correct uid/gid ownership.  With those
ac42f3
    files left as uid/gid=0/0, stapio running with a user with
ac42f3
    stapusr/stapdev privileges couldn't fopenat() those files.  Now they
ac42f3
    can again.  This problem became obvious after commit 4706ab3ca5c0,
ac42f3
    which makes STAP_TRANS_PROCFS the default.
ac42f3
ac42f3
diff --git a/runtime/transport/procfs.c b/runtime/transport/procfs.c
ac42f3
index 97a6e123a..69591a235 100644
ac42f3
--- a/runtime/transport/procfs.c
ac42f3
+++ b/runtime/transport/procfs.c
ac42f3
@@ -336,12 +336,14 @@ __stp_procfs_relay_create_buf_file_callback(const char *filename,
ac42f3
   if (parent != _stp_procfs_module_dir_path.dentry)
ac42f3
     goto out;
ac42f3
   
ac42f3
-  pde = proc_create (filename, 0600,
ac42f3
+  pde = proc_create (filename, 0400,
ac42f3
                      _stp_procfs_module_dir,
ac42f3
                      & relay_procfs_operations);
ac42f3
   if (pde == NULL)
ac42f3
     goto out;
ac42f3
 
ac42f3
+  proc_set_user(pde, KUIDT_INIT(_stp_uid), KGIDT_INIT(_stp_gid));
ac42f3
+  
ac42f3
   rc = snprintf(fullpath, sizeof(fullpath), "/proc/systemtap/%s/%s",
ac42f3
                 THIS_MODULE->name, filename);
ac42f3