lkml.org 
[lkml]   [2010]   [Nov]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: [RFC] lttngtrace available to non-root
    Here is an updated version taking care of /tmp file creation races. Thanks to
    Frank Ch. Eigler for pointing this out.

    A small note: pending a large change in LTTng that will allow arming tracepoints
    on a per-session basis, the current version of the script cannot be run in
    multiple instances concurrently (interaction between the multiple
    ltt-armall/ltt-disarmall). I'm also thinking to use mktemp for the next version
    to create a temporary file rather than the hardcoded file I'm using now. I could
    save the information about the last file name used in the user's home directory.

    Thanks,

    Mathieu

    /*
    * lttngtrace.c
    *
    * lttngtrace starts/stop system wide tracing around program execution.
    *
    * Copyright (c) 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
    *
    * This program is free software; you can redistribute it and/or modify
    * it under the terms of the GNU General Public License as published by
    * the Free Software Foundation; either version 2 of the License, or
    * (at your option) any later version.
    *
    * This program is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    * GNU General Public License for more details.
    *
    * You should have received a copy of the GNU General Public License along
    * with this program; if not, write to the Free Software Foundation, Inc.,
    * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    *
    * This file should be setuid root, and belong to a "tracing" group. Only users
    * part of the tracing group can trace and view the traces gathered.
    */

    #include <errno.h>
    #include <stdio.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
    #include <limits.h>
    #include <dirent.h>
    #include <sys/wait.h>
    #include <sys/stat.h>
    #include <sys/types.h>

    #if DEBUG
    #define printf_dbg(fmt, args...) printf(fmt, args)
    #else
    #define printf_dbg(fmt, ...)
    #endif

    int recunlink(const char *dirname)
    {
    DIR *dir;
    struct dirent *entry;
    char path[PATH_MAX];

    dir = opendir(dirname);
    if (dir == NULL) {
    if (errno == ENOENT)
    return 0;
    perror("Error opendir()");
    return -errno;
    }

    while ((entry = readdir(dir)) != NULL) {
    if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) {
    snprintf(path, (size_t) PATH_MAX, "%s/%s", dirname,
    entry->d_name);
    if (entry->d_type == DT_DIR)
    recunlink(path);
    else
    unlink(path);
    }
    }
    closedir(dir);
    rmdir(dirname);

    return 0;
    }

    int start_tracing(void)
    {
    int ret;

    ret = recunlink("/tmp/autotrace1");
    if (ret)
    return ret;
    ret = unlink("/tmp/autotrace1-pid");
    if (ret)
    return ret;

    /*
    * Create the directory in /tmp to deal with races (refuse if fail).
    * Only allow user and group to read the trace data (to limit
    * information disclosure).
    */
    ret = mkdir("/tmp/autotrace1", S_IRWXU|S_IRWXG);
    if (ret) {
    perror("Trace directory creation race");
    return ret;
    }
    ret = system("ltt-armall > /dev/null");
    if (ret)
    return ret;
    ret = system("lttctl -C -w /tmp/autotrace1 autotrace1 > /dev/null");
    if (ret)
    return ret;
    }

    int stop_tracing(uid_t uid, gid_t egid)
    {
    int ret;

    ret = system("lttctl -D autotrace1 > /dev/null");
    if (ret)
    return ret;
    ret = system("ltt-disarmall > /dev/null");
    if (ret)
    return ret;
    /* Hand the trace back to the user after tracing is over */
    printf("uid: %d egid %d\n", uid, egid);
    ret = chown("/tmp/autotrace1", uid, egid);
    if (ret) {
    perror("chown error");
    return ret;
    }
    }

    int write_child_pid(pid_t pid, uid_t uid, gid_t gid)
    {
    int fd;
    FILE *fp;
    int ret;

    /* Create the file as exclusive to deal with /tmp file creation races */
    fd = open("/tmp/autotrace1-pid", O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
    S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
    fp = fdopen(fd, "w");
    if (!fp) {
    perror("Error writing child pid");
    return -errno;
    }

    fprintf(fp, "%u", (unsigned int) pid);
    ret = fclose(fp);
    if (ret)
    perror("Error in fclose");
    /* Hand pid information file back to user */
    ret = chown("/tmp/autotrace1-pid", uid, gid);
    if (ret)
    perror("chown error");
    return ret;
    }

    int main(int argc, char *argv[])
    {
    uid_t euid, uid;
    gid_t egid, gid;
    pid_t pid;
    int gret = 0, ret = 0;

    if (argc < 2)
    return -ENOENT;

    euid = geteuid();
    uid = getuid();
    egid = getegid();
    gid = geteuid();

    if (euid != 0) {
    printf("%s must be setuid root\n", argv[0]);
    return -EPERM;
    }

    printf_dbg("euid: %d\n", euid);
    printf_dbg("uid: %d\n", uid);
    printf_dbg("egid: %d\n", egid);
    printf_dbg("gid: %d\n", gid);

    ret = start_tracing();
    gret = (gret == 0) ? ret : gret;

    pid = fork();
    if (pid > 0) { /* parent */
    int status;

    pid = wait(&status);
    if (pid == -1)
    gret = (gret == 0) ? -errno : gret;

    ret = stop_tracing(uid, egid);
    gret = (gret == 0) ? ret : gret;
    ret = write_child_pid(pid, uid, egid);
    gret = (gret == 0) ? ret : gret;
    } else if (pid == 0) { /* child */
    /* Drop root euid before executing child program */
    seteuid(uid);
    ret = execvp(argv[1], &argv[1]);
    if (ret)
    perror("Execution error");
    return ret;
    } else { /* error */
    perror("Error in fork");
    return -errno;
    }
    return ret;
    }

    --
    Mathieu Desnoyers
    Operating System Efficiency R&D Consultant
    EfficiOS Inc.
    http://www.efficios.com


    \
     
     \ /
      Last update: 2010-11-20 01:25    [W:0.028 / U:29.908 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site