[ltt-dev] [RFC] lttngtrace available to non-root
Mathieu Desnoyers
mathieu.desnoyers at efficios.com
Fri Nov 19 17:21:12 EST 2010
Hello!
I just coded a lttngtrace.c program that can spawn a thread from a non-root
user. The idea is to have "lttngtrace" setuid root, executable only by the
"tracing" group. Within lttngtrace, I set the euid and egid back to the original
caller user before executing the command.
I plan to integrate this with the UST userspace tracer as soon as Nils comes
back from vacation and release a new version.
Comments are welcome,
Thanks,
Mathieu
/*
* lttngtrace.c
*
* lttngtrace starts/stop system wide tracing around program execution.
*
* Copyright (c) 2010 Mathieu Desnoyers <mathieu.desnoyers at 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.
*/
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <dirent.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;
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(void)
{
int ret;
ret = system("lttctl -D autotrace1 > /dev/null");
if (ret)
return ret;
ret = system("ltt-disarmall > /dev/null");
if (ret)
return ret;
}
int write_child_pid(pid_t pid)
{
FILE *fp;
fp = fopen("/tmp/autotrace1-pid", "w");
if (!fp) {
perror("Error writing child pid");
return -errno;
}
fprintf(fp, "%u", (unsigned int) pid);
return fclose(fp);
}
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();
gret = (gret == 0) ? ret : gret;
ret = write_child_pid(pid);
gret = (gret == 0) ? ret : gret;
} else if (pid == 0) { /* child */
seteuid(uid);
setegid(gid);
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
More information about the lttng-dev
mailing list