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