int init_ctl_channel(const char *name, int verb) { char buf[PATH_MAX]; struct statfs st; int old_transport = 0; if (statfs("/sys/kernel/debug", &st) == 0 && (int)st.f_type == (int)DEBUGFS_MAGIC) { if (sprintf_chk(buf, "/sys/kernel/debug/systemtap/%s/.cmd", name)) return -1; } else { old_transport = 1; if (sprintf_chk(buf, "/proc/systemtap/%s/.cmd", name)) return -2; } control_channel = open(buf, O_RDWR); dbug(2, "Opened %s (%d)\n", buf, control_channel); if (control_channel < 0) { if (verb) { if (attach_mod && errno == ENOENT) err("ERROR: Can not attach. Module %s not running.\n", name); else perr("Couldn't open control channel '%s'", buf); } return -3; } if (set_clexec(control_channel) < 0) return -4; return old_transport; }
int init_ctl_channel(const char *name, int verb) { char buf[PATH_MAX]; struct statfs st; int old_transport = 0; if (statfs("/sys/kernel/debug", &st) == 0 && (int)st.f_type == (int)DEBUGFS_MAGIC) { if (sprintf_chk(buf, "/sys/kernel/debug/systemtap/%s/.cmd", name)) return -1; } else { old_transport = 1; if (sprintf_chk(buf, "/proc/systemtap/%s/.cmd", name)) return -2; } control_channel = open(buf, O_RDWR); dbug(2, "Opened %s (%d)\n", buf, control_channel); /* It's actually safe to do this check before the open(), * as the file we're trying to access connot be modified * by a typical user. */ if (access(buf, R_OK|W_OK) != 0){ close(control_channel); return -5; } if (control_channel < 0) { if (verb) { if (attach_mod && errno == ENOENT) err(_("ERROR: Can not attach. Module %s not running.\n"), name); else perr(_("Couldn't open control channel '%s'"), buf); } return -3; } if (set_clexec(control_channel) < 0) return -4; return old_transport; }
static int open_oldoutfile(int fnum, int cpu, int remove_file) { char buf[PATH_MAX]; time_t t; if (outfile_name) { time(&t); if (fnum_max) { if (remove_file) { /* remove oldest file */ if (make_outfile_name(buf, PATH_MAX, fnum - fnum_max, cpu, read_backlog(cpu, fnum - fnum_max), bulkmode) < 0) return -1; remove(buf); /* don't care */ } write_backlog(cpu, fnum, t); } if (make_outfile_name(buf, PATH_MAX, fnum, cpu, t, bulkmode) < 0) return -1; } else if (bulkmode) { if (sprintf_chk(buf, "stpd_cpu%d.%d", cpu, fnum)) return -1; } else { /* stream mode */ percpu_tmpfile[cpu] = stdout; return 0; } if((percpu_tmpfile[cpu] = fopen(buf, "w+")) == NULL) { perr("Couldn't open output file %s", buf); return -1; } out_fd[cpu] = fileno(percpu_tmpfile[cpu]); if (set_clexec(out_fd[cpu]) < 0) { perr("Couldn't clear exec bit of open output file %s", buf); return -1; } return 0; }
/** * open_relayfs_files - open and mmap buffer and open output file. * Returns -1 on unexpected failure, 0 if file not found, 1 on success. */ static int open_relayfs_files(int cpu, const char *relay_filebase, const char *proc_filebase) { size_t total_bufsize; char tmp[PATH_MAX]; memset(&status[cpu], 0, sizeof(struct buf_status)); status[cpu].info.cpu = cpu; if (sprintf_chk(tmp, "%s%d", relay_filebase, cpu)) return -1; dbug(2, "Opening %s.\n", tmp); relay_fd[cpu] = open(tmp, O_RDONLY | O_NONBLOCK); if (relay_fd[cpu] < 0 || set_clexec(relay_fd[cpu]) < 0) { relay_fd[cpu] = 0; return 0; } if (sprintf_chk(tmp, "%s%d", proc_filebase, cpu)) goto err1; dbug(2, "Opening %s.\n", tmp); proc_fd[cpu] = open(tmp, O_RDWR | O_NONBLOCK); if (proc_fd[cpu] < 0) { perr("Couldn't open proc file %s", tmp); goto err1; } if (set_clexec(relay_fd[cpu]) < 0) { relay_fd[cpu] = 0; return -1; } if (fsize_max) { if (init_backlog(cpu) < 0) goto err2; if (open_oldoutfile(0, cpu, 0) < 0) goto err2; goto opened; } if (outfile_name) { /* special case: for testing we sometimes want to * write to /dev/null */ if (strcmp(outfile_name, "/dev/null") == 0) { strcpy(tmp, "/dev/null"); } else { int len; len = stap_strfloctime(tmp, PATH_MAX, outfile_name, time(NULL)); if (len < 0) { err("Invalid FILE name format\n"); goto err2; } if (snprintf_chk(&tmp[len], PATH_MAX - len, "_%d", cpu)) goto err2; } } else { if (sprintf_chk(tmp, "stpd_cpu%d", cpu)) goto err2; } if((percpu_tmpfile[cpu] = fopen(tmp, "w+")) == NULL) { perr("Couldn't open output file %s", tmp); goto err2; } out_fd[cpu] = fileno(percpu_tmpfile[cpu]); if (set_clexec(out_fd[cpu]) < 0) { perr("Couldn't open output file %s", tmp); goto err2; } opened: total_bufsize = subbuf_size * n_subbufs; relay_buffer[cpu] = mmap(NULL, total_bufsize, PROT_READ, MAP_PRIVATE | MAP_POPULATE, relay_fd[cpu], 0); if(relay_buffer[cpu] == MAP_FAILED) { _perr("Couldn't mmap relay file, total_bufsize (%d)" \ "= subbuf_size (%d) * n_subbufs(%d)", (int)total_bufsize, (int)subbuf_size, (int)n_subbufs); goto err3; } return 1; err3: fclose(percpu_tmpfile[cpu]); err2: close (proc_fd[cpu]); err1: close (relay_fd[cpu]); relay_fd[cpu] = 0; return -1; }
int init_ctl_channel(const char *name, int verb) { char buf[PATH_MAX]; struct statfs st; int old_transport = 0; (void) verb; if (0) goto out; /* just to defeat gcc warnings */ /* Before trying to open the control channel, make sure it * isn't already open. */ close_ctl_channel(); #ifdef HAVE_OPENAT if (relay_basedir_fd >= 0) { strncpy(buf, CTL_CHANNEL_NAME, PATH_MAX); control_channel = openat_cloexec(relay_basedir_fd, CTL_CHANNEL_NAME, O_RDWR, 0); dbug(2, "Opened %s (%d)\n", CTL_CHANNEL_NAME, control_channel); /* NB: Extra real-id access check as below */ if (faccessat(relay_basedir_fd, CTL_CHANNEL_NAME, R_OK|W_OK, 0) != 0){ close(control_channel); return -5; } if (control_channel >= 0) goto out; /* It's OK to bypass the [f]access[at] check below, since this would only occur the *second* time staprun tries this gig, or within unprivileged stapio. */ } /* PR14245, NB: we fall through to /sys ... /proc searching, in case the relay_basedir_fd option wasn't given (i.e., for early in staprun), or if errors out for some reason. */ #endif if (statfs("/sys/kernel/debug", &st) == 0 && (int)st.f_type == (int)DEBUGFS_MAGIC) { /* PR14245: allow subsequent operations, and if necessary, staprun->stapio forks, to reuse an fd for directory lookups (even if some parent directories have perms 0700. */ #ifdef HAVE_OPENAT if (! sprintf_chk(buf, "/sys/kernel/debug/systemtap/%s", name)) { relay_basedir_fd = open (buf, O_DIRECTORY | O_RDONLY); /* If this fails, we don't much care; the negative return value will just keep us looking up by name again next time. */ /* NB: we don't plan to close this fd, so that we can pass it across staprun->stapio fork/execs. */ } #endif if (sprintf_chk(buf, "/sys/kernel/debug/systemtap/%s/%s", name, CTL_CHANNEL_NAME)) return -1; } else { old_transport = 1; if (sprintf_chk(buf, "/proc/systemtap/%s/%s", name, CTL_CHANNEL_NAME)) return -2; } control_channel = open_cloexec(buf, O_RDWR, 0); dbug(2, "Opened %s (%d)\n", buf, control_channel); /* NB: Even if open() succeeded with effective-UID permissions, we * need the access() check to make sure real-UID permissions are also * sufficient. When we run under the setuid staprun, effective and * real UID may not be the same. Specifically, we want to prevent * a local stapusr from trying to attach to a different stapusr's module. * * The access() is done *after* open() to avoid any TOCTOU-style race * condition. We believe it's probably safe either way, as the file * we're trying to access connot be modified by a typical user, but * better safe than sorry. */ #ifdef HAVE_OPENAT if (control_channel >= 0 && relay_basedir_fd >= 0) { if (faccessat (relay_basedir_fd, CTL_CHANNEL_NAME, R_OK|W_OK, 0) == 0) goto out; /* else fall through */ } #endif if (control_channel >= 0 && access(buf, R_OK|W_OK) != 0) { close(control_channel); return -5; } out: if (control_channel < 0) { err(_("Cannot attach to module %s control channel; not running?\n"), name); return -3; } return old_transport; }