diff options
-rw-r--r-- | buildrun.cxx | 16 | ||||
-rw-r--r-- | runtime/uprobes/Makefile | 12 | ||||
-rw-r--r-- | util.cxx | 43 | ||||
-rw-r--r-- | util.h | 1 |
4 files changed, 62 insertions, 10 deletions
diff --git a/buildrun.cxx b/buildrun.cxx index b6063e36..6774b536 100644 --- a/buildrun.cxx +++ b/buildrun.cxx @@ -277,7 +277,8 @@ verify_uprobes_uptodate (systemtap_session& s) int rc = run_make_cmd(s, make_cmd); if (rc) { clog << "SystemTap's version of uprobes is out of date." << endl; - clog << "As root, run \"make -C " << uprobes_home << "\"." << endl; + clog << "As root, or a member of the 'stap-server' group, run" << endl; + clog << "\"make -C " << uprobes_home << "\"." << endl; } return rc; @@ -322,17 +323,18 @@ uprobes_pass (systemtap_session& s) /* * We need to use the version of uprobes that comes with SystemTap, so * we may need to rebuild uprobes.ko there. Unfortunately, this is - * never a no-op; e.g., the modpost step gets run every time. We don't - * want non-root users modifying uprobes, so we keep the uprobes - * directory writable only by root. But that means a non-root member - * of group stapdev can't run the make even if everything's up to date. + * never a no-op; e.g., the modpost step gets run every time. We + * only want root and members of the 'stap-server' group + * modifying uprobes, so we keep the uprobes directory writable only by + * those users. But that means that other users can't run the make + * even if everything's up to date. * - * So for non-root users, we just use "make -q" with a fake target to + * So for the other users, we just use "make -q" with a fake target to * verify that uprobes doesn't need to be rebuilt. If that's not so, * stap must fail. */ int rc; - if (geteuid() == 0) + if (geteuid() == 0 || egid_in ("stap-server")) rc = make_uprobes(s); else rc = verify_uprobes_uptodate(s); diff --git a/runtime/uprobes/Makefile b/runtime/uprobes/Makefile index bc0fd6a9..e58373af 100644 --- a/runtime/uprobes/Makefile +++ b/runtime/uprobes/Makefile @@ -5,6 +5,10 @@ DEPENDENCIES := $(shell echo uprobes.[ch] uprobes_*.[ch]) DEPENDENCIES += $(shell echo ../uprobes2/uprobes.[ch] ../uprobes2/uprobes_*.[ch]) DEPENDENCIES += Makefile +CLEAN_FILES := $(shell echo *.mod.c *.ko *.o .*.cmd *~ *.sgn) +CLEAN_FILES += Module.markers modules.order Module.symvers +CLEAN_DIRS := .tmp_versions + default: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules if test -f ../../../../bin/stap-sign-module; then \ @@ -14,12 +18,14 @@ default: fi \ done \ fi + chgrp stap-server $(CLEAN_FILES) 2>/dev/null || true + chgrp stap-server $(CLEAN_DIRS) 2>/dev/null || true + chgrp stap-server $(CLEAN_DIRS)/* 2>/dev/null || true # This target is used with "make -q" to see whether a "real" build is needed. uprobes.ko: $(DEPENDENCIES) @echo uprobes.ko is not a valid target. See Makefile. clean: - rm -f *.mod.c *.ko *.o .*.cmd *~ *.sgn - rm -f Module.markers modules.order Module.symvers - rm -rf .tmp_versions + rm -f $(CLEAN_FILES) + rm -rf $(CLEAN_DIRS) @@ -22,6 +22,7 @@ extern "C" { #include <fcntl.h> +#include <grp.h> #include <pwd.h> #include <spawn.h> #include <stdio.h> @@ -188,6 +189,48 @@ remove_file_or_dir (const char *name) return 0; } +// Determine whether the current user is in the given group. +bool +egid_in (const char *gname) +{ + gid_t gid, gidlist[NGROUPS_MAX]; + gid_t target_gid; + int i, ngids; + struct group *group; + + // Lookup the gid for the target group + errno = 0; + group = getgrnam(gname); + + // If we couldn't find the group, then we can't be part of it. + if (group == NULL) + return false; + + target_gid = group->gr_gid; + + // According to the getgroups() man page, getgroups() may not + // return the effective gid, so try to match it first. */ + gid = getegid(); + if (gid == target_gid) + return true; + + // Get the list of the user's groups. + ngids = getgroups(NGROUPS_MAX, gidlist); + if (ngids < 0) { + cerr << "Unable to retrieve group list" << endl; + return false; + } + + for (i = 0; i < ngids; i++) { + // If the user is a member of the target group, then we're done. + if (gidlist[i] == target_gid) + return true; + } + + // The user is not a member of the target group + return false; +} + void tokenize(const string& str, vector<string>& tokens, const string& delimiters = " ") @@ -12,6 +12,7 @@ bool copy_file(const std::string& src, const std::string& dest, bool verbose=false); int create_dir(const char *dir); int remove_file_or_dir(const char *dir); +bool egid_in (const char *gname); void tokenize(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters); std::string find_executable(const std::string& name); |