Blame SOURCES/rhbz1902696.patch

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