diff options
-rw-r--r-- | buildrun.cxx | 5 | ||||
-rw-r--r-- | cache.cxx | 36 | ||||
-rw-r--r-- | elaborate.cxx | 43 | ||||
-rw-r--r-- | elaborate.h | 4 | ||||
-rw-r--r-- | main.cxx | 154 | ||||
-rw-r--r-- | runtime/staprun/common.c | 1 | ||||
-rw-r--r-- | runtime/staprun/modverify.c | 6 | ||||
-rw-r--r-- | runtime/staprun/staprun.c | 18 | ||||
-rw-r--r-- | runtime/staprun/staprun.h | 1 | ||||
-rw-r--r-- | runtime/staprun/staprun_funcs.c | 29 | ||||
-rw-r--r-- | runtime/transport/transport.c | 4 | ||||
-rw-r--r-- | session.h | 1 | ||||
-rwxr-xr-x[-rw-r--r--] | stap-env | 6 | ||||
-rw-r--r-- | staptree.cxx | 10 | ||||
-rw-r--r-- | staptree.h | 6 | ||||
-rw-r--r-- | systemtap.spec | 2 | ||||
-rw-r--r-- | tapset-been.cxx | 32 | ||||
-rw-r--r-- | tapset-timers.cxx | 91 | ||||
-rw-r--r-- | tapset/logging.stp | 8 | ||||
-rw-r--r-- | tapset/timestamp.stp | 2 | ||||
-rw-r--r-- | tapsets.cxx | 47 | ||||
-rw-r--r-- | testsuite/systemtap.base/optim_arridx.exp | 2 | ||||
-rw-r--r-- | translate.cxx | 7 | ||||
-rw-r--r-- | translate.h | 2 | ||||
-rw-r--r-- | util.cxx | 24 | ||||
-rw-r--r-- | util.h | 2 |
26 files changed, 386 insertions, 157 deletions
diff --git a/buildrun.cxx b/buildrun.cxx index e4b4b7bf..a93b2909 100644 --- a/buildrun.cxx +++ b/buildrun.cxx @@ -231,11 +231,12 @@ compile_pass (systemtap_session& s) rc = run_make_cmd(s, make_cmd); #if HAVE_NSS - // If a certificate database was specified, then try to sign the module. + // If a certificate database was specified, and we're in unprivileged + // mode, then try to sign the module. // Failure to do so is not a fatal error. If the signature is actually needed, // staprun will complain at that time. assert (! s.cert_db_path.empty()); - if (!rc) + if (s.unprivileged && ! rc) sign_module (s); #endif @@ -81,18 +81,20 @@ add_to_cache(systemtap_session& s) string module_signature_src_path = module_src_path; module_signature_src_path += ".sgn"; - STAP_PROBE2(stap, cache__add__nss, module_signature_src_path.c_str(), module_signature_dest_path.c_str()); - - if (s.verbose > 1) - clog << "Copying " << module_signature_src_path << " to " << module_signature_dest_path << endl; - if (copy_file(module_signature_src_path.c_str(), module_signature_dest_path.c_str()) != 0) + if (file_exists (module_signature_src_path)) { - cerr << "Copy failed (\"" << module_signature_src_path << "\" to \"" - << module_signature_dest_path << "\"): " << strerror(errno) << endl; - // NB: this is not so severe as to prevent reuse of the .ko - // already copied. - // - // s.use_cache = false; + STAP_PROBE2(stap, cache__add__nss, module_signature_src_path.c_str(), module_signature_dest_path.c_str()); + if (s.verbose > 1) + clog << "Copying " << module_signature_src_path << " to " << module_signature_dest_path << endl; + if (copy_file(module_signature_src_path.c_str(), module_signature_dest_path.c_str()) != 0) + { + cerr << "Copy failed (\"" << module_signature_src_path << "\" to \"" + << module_signature_dest_path << "\"): " << strerror(errno) << endl; + // NB: this is not so severe as to prevent reuse of the .ko + // already copied. + // + // s.use_cache = false; + } } #endif /* HAVE_NSS */ @@ -372,18 +374,6 @@ clean_cache(systemtap_session& s) } } -// Get the size of a file in bytes -static size_t -get_file_size(const string &path) -{ - struct stat file_info; - - if (stat(path.c_str(), &file_info) == 0) - return file_info.st_size; - else - return 0; -} - //Assign a weight for a particular file. A lower weight // will be removed before a higher weight. //TODO: for now use system mtime... later base a diff --git a/elaborate.cxx b/elaborate.cxx index 9271e847..93500239 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -261,8 +261,9 @@ match_key::globmatch(match_key const & other) const // ------------------------------------------------------------------------ match_node::match_node() - : end(NULL) -{} + : end(NULL), unprivileged_ok (false) +{ +} match_node * match_node::bind(match_key const & k) @@ -304,6 +305,18 @@ match_node::bind_num(string const & k) return bind(match_key(k).with_number()); } +match_node* +match_node::allow_unprivileged (bool b) +{ + unprivileged_ok = b; + return this; +} + +bool +match_node::unprivileged_allowed () const +{ + return unprivileged_ok; +} void match_node::find_and_build (systemtap_session& s, @@ -331,6 +344,14 @@ match_node::find_and_build (systemtap_session& s, param_map[loc->components[i]->functor] = loc->components[i]->arg; // maybe 0 + // Are we compiling for unprivileged users? */ + if (s.unprivileged) + { + // Is this probe point ok for unprivileged users? + if (! unprivileged_allowed ()) + throw semantic_error (string("probe point is not allowed for unprivileged users")); + } + b->build (s, p, loc, param_map, results); } else if (isglob(loc->components[pos]->functor)) // wildcard? @@ -1023,7 +1044,7 @@ semantic_pass_conditions (systemtap_session & sess) expression* e = p->sole_location()->condition; if (e) { - varuse_collecting_visitor vut; + varuse_collecting_visitor vut(sess); e->visit (& vut); if (! vut.written.empty()) @@ -1178,7 +1199,7 @@ void add_global_var_display (systemtap_session& s) // it would clutter up the list of probe points with "end ...". if (s.listing_mode) return; - varuse_collecting_visitor vut; + varuse_collecting_visitor vut(s); for (unsigned i=0; i<s.probes.size(); i++) { s.probes[i]->body->visit (& vut); @@ -1965,7 +1986,7 @@ void semantic_pass_opt1 (systemtap_session& s, bool& relaxed_p) // written nor read. void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p, unsigned iterations) { - varuse_collecting_visitor vut; + varuse_collecting_visitor vut(s); for (unsigned i=0; i<s.probes.size(); i++) { @@ -2162,7 +2183,7 @@ dead_assignment_remover::visit_assignment (assignment* e) break; } - varuse_collecting_visitor lvut; + varuse_collecting_visitor lvut(session); e->left->visit (& lvut); if (lvut.side_effect_free () && !is_global) // XXX: use _wrt() once we track focal_vars { @@ -2195,7 +2216,7 @@ void semantic_pass_opt3 (systemtap_session& s, bool& relaxed_p) // Recompute the varuse data, which will probably match the opt2 // copy of the computation, except for those totally unused // variables that opt2 removed. - varuse_collecting_visitor vut; + varuse_collecting_visitor vut(s); for (unsigned i=0; i<s.probes.size(); i++) s.probes[i]->body->visit (& vut); // includes reachable functions too @@ -2299,7 +2320,7 @@ dead_stmtexpr_remover::visit_if_statement (if_statement *s) { // We may be able to elide this statement, if the condition // expression is side-effect-free. - varuse_collecting_visitor vct; + varuse_collecting_visitor vct(session); s->condition->visit(& vct); if (vct.side_effect_free ()) { @@ -2363,7 +2384,7 @@ dead_stmtexpr_remover::visit_for_loop (for_loop *s) { // We may be able to elide this statement, if the condition // expression is side-effect-free. - varuse_collecting_visitor vct; + varuse_collecting_visitor vct(session); if (s->init) s->init->visit(& vct); s->cond->visit(& vct); if (s->incr) s->incr->visit(& vct); @@ -2400,7 +2421,7 @@ dead_stmtexpr_remover::visit_expr_statement (expr_statement *s) // NB. While we don't share nodes in the parse tree, let's not // deallocate *s anyway, just in case... - varuse_collecting_visitor vut; + varuse_collecting_visitor vut(session); s->value->visit (& vut); if (vut.side_effect_free_wrt (focal_vars)) @@ -2741,7 +2762,7 @@ void_statement_reducer::visit_functioncall (functioncall* e) return; } - varuse_collecting_visitor vut; + varuse_collecting_visitor vut(session); vut.traversed.insert (e->referent); vut.current_function = e->referent; e->referent->body->visit (& vut); diff --git a/elaborate.h b/elaborate.h index d927177b..36439c4f 100644 --- a/elaborate.h +++ b/elaborate.h @@ -236,6 +236,7 @@ match_node typedef std::map<match_key, match_node*>::iterator sub_map_iterator_t; sub_map_t sub; derived_probe_builder* end; + bool unprivileged_ok; public: match_node(); @@ -250,6 +251,9 @@ match_node match_node* bind_str(std::string const & k); match_node* bind_num(std::string const & k); void bind(derived_probe_builder* e); + + match_node* allow_unprivileged (bool b = true); + bool unprivileged_allowed () const; }; // ------------------------------------------------------------------------ @@ -45,6 +45,7 @@ extern "C" { using namespace std; +#define PATH_TBD string("__TBD__") void version () @@ -132,6 +133,8 @@ usage (systemtap_session& s, int exitcode) #ifdef HAVE_LIBSQLITE3 << " -q generate information on tapset coverage" << endl #endif /* HAVE_LIBSQLITE3 */ + << " --unprivileged" << endl + << " restrict usage to features available to unprivileged users" << endl #if 0 /* PR6864: disable temporarily; should merge with -d somehow */ << " --kelf make do with symbol table from vmlinux" << endl << " --kmap[=FILE]" << endl @@ -356,6 +359,90 @@ setup_kernel_release (systemtap_session &s, const char* kstr) { } } +static void +checkOptions (systemtap_session &s) +{ + bool optionsConflict = false; + + if(!s.bulk_mode && !s.merge) + { + cerr << "-M option is valid only for bulk (relayfs) mode." <<endl; + optionsConflict = true; + } + + if(!s.output_file.empty() && s.bulk_mode && !s.merge) + { + cerr << "You can't specify -M, -b and -o options together." <<endl; + optionsConflict = true; + } + + if((s.cmd != "") && (s.target_pid)) + { + cerr << "You can't specify -c and -x options together." <<endl; + optionsConflict = true; + } + + if (s.unprivileged) + { + if (s.guru_mode) + { + cerr << "You can't specify -g and --unprivileged together." << endl; + optionsConflict = true; + } + if (s.include_path.size () > 1) + { + cerr << "You can't specify -I and --unprivileged together." << endl; + optionsConflict = true; + } + if (s.runtime_path != string(PKGDATADIR) + "/runtime") + { + cerr << "You can't use -R to specify an alternate runtime path when --unprivileged is specified." << endl; + optionsConflict = true; + } + if (s.kernel_build_tree.substr(0, 13) != "/lib/modules/") + { + cerr << "You can't use -r to specify a kernel release which is not installed when --unprivileged is specified." << endl; + optionsConflict = true; + } + if (! s.macros.empty ()) + { + cerr << "You can't specify -D and --unprivileged together." << endl; + optionsConflict = true; + } + + if (getenv ("SYSTEMTAP_TAPSET")) + { + cerr << "The environment variable SYSTEMTAP_TAPSET can not be defined when --unprivileged is specified." << endl; + optionsConflict = true; + } + if (getenv ("SYSTEMTAP_RUNTIME")) + { + cerr << "The environment variable SYSTEMTAP_RUNTIME can not be defined when --unprivileged is specified." << endl; + optionsConflict = true; + } + if (getenv ("SYSTEMTAP_DEBUGINFO_PATH")) + { + cerr << "The environment variable SYSTEMTAP_DEBUGINFO_PATH can not be defined when --unprivileged is specified." << endl; + optionsConflict = true; + } + } + + if (!s.kernel_symtab_path.empty()) + { + if (s.consult_symtab) + { + cerr << "You can't specify --kelf and --kmap together." << endl; + optionsConflict = true; + } + s.consult_symtab = true; + if (s.kernel_symtab_path == PATH_TBD) + s.kernel_symtab_path = string("/boot/System.map-") + s.kernel_release; + } + + if (optionsConflict) + usage (s, 1); +} + int main (int argc, char * const argv []) { @@ -406,11 +493,12 @@ main (int argc, char * const argv []) s.ignore_dwarf = false; s.load_only = false; s.skip_badvars = false; + s.unprivileged = false; // Location of our signing certificate. // If we're root, use the database in SYSCONFDIR, otherwise // use the one in our $HOME directory. */ - if (geteuid() == 0) + if (getuid() == 0) s.cert_db_path = SYSCONFDIR "/systemtap/ssl/server"; else s.cert_db_path = getenv("HOME") + string ("/.systemtap/ssl/server"); @@ -460,6 +548,14 @@ main (int argc, char * const argv []) } } + // Location of our signing certificate. + // If we're root, use the database in SYSCONFDIR, otherwise + // use the one in s.data_path. */ + if (geteuid() == 0) + s.cert_db_path = SYSCONFDIR "/systemtap/ssl/server"; + else + s.cert_db_path = s.data_path + "/ssl/server"; + const char* s_tc = getenv ("SYSTEMTAP_COVERAGE"); if (s_tc != NULL) s.tapset_compile_coverage = true; @@ -480,6 +576,7 @@ main (int argc, char * const argv []) #define LONG_OPT_IGNORE_DWARF 4 #define LONG_OPT_VERBOSE_PASS 5 #define LONG_OPT_SKIP_BADVARS 6 +#define LONG_OPT_UNPRIVILEGED 7 // NB: also see find_hash(), usage(), switch stmt below, stap.1 man page static struct option long_options[] = { { "kelf", 0, &long_opt, LONG_OPT_KELF }, @@ -488,6 +585,7 @@ main (int argc, char * const argv []) { "ignore-dwarf", 0, &long_opt, LONG_OPT_IGNORE_DWARF }, { "skip-badvars", 0, &long_opt, LONG_OPT_SKIP_BADVARS }, { "vp", 1, &long_opt, LONG_OPT_VERBOSE_PASS }, + { "unprivileged", 0, &long_opt, LONG_OPT_UNPRIVILEGED }, { NULL, 0, NULL, 0 } }; int grc = getopt_long (argc, argv, "hVMvtp:I:e:o:R:r:m:kgPc:x:D:bs:uqwl:d:L:FS:", @@ -705,7 +803,6 @@ main (int argc, char * const argv []) if (optarg) s.kernel_symtab_path = optarg; else -#define PATH_TBD string("__TBD__") s.kernel_symtab_path = PATH_TBD; break; case LONG_OPT_IGNORE_VMLINUX: @@ -737,6 +834,9 @@ main (int argc, char * const argv []) case LONG_OPT_SKIP_BADVARS: s.skip_badvars = true; break; + case LONG_OPT_UNPRIVILEGED: + s.unprivileged = true; + break; default: cerr << "Internal error parsing command arguments." << endl; usage(s, 1); @@ -749,35 +849,8 @@ main (int argc, char * const argv []) } } - if(!s.bulk_mode && !s.merge) - { - cerr << "-M option is valid only for bulk (relayfs) mode." <<endl; - usage (s, 1); - } - - if(!s.output_file.empty() && s.bulk_mode && !s.merge) - { - cerr << "You can't specify -M, -b and -o options together." <<endl; - usage (s, 1); - } - - if((s.cmd != "") && (s.target_pid)) - { - cerr << "You can't specify -c and -x options together." <<endl; - usage (s, 1); - } - - if (!s.kernel_symtab_path.empty()) - { - if (s.consult_symtab) - { - cerr << "You can't specify --kelf and --kmap together." << endl; - usage (s, 1); - } - s.consult_symtab = true; - if (s.kernel_symtab_path == PATH_TBD) - s.kernel_symtab_path = string("/boot/System.map-") + s.kernel_release; - } + // Check for options conflicts. + checkOptions (s); // Warn in case the target kernel release doesn't match the running one. if (s.last_pass > 4 && @@ -1177,14 +1250,17 @@ main (int argc, char * const argv []) // Save the signature as well. assert (! s.cert_db_path.empty()); module_src_path += ".sgn"; - module_dest_path += ".sgn"; - - if (s.verbose > 1) - clog << "Copying " << module_src_path << " to " - << module_dest_path << endl; - if (copy_file(module_src_path.c_str(), module_dest_path.c_str()) != 0) - cerr << "Copy failed (\"" << module_src_path << "\" to \"" - << module_dest_path << "\"): " << strerror(errno) << endl; + if (file_exists (module_src_path)) + { + module_dest_path += ".sgn"; + + if (s.verbose > 1) + clog << "Copying " << module_src_path << " to " + << module_dest_path << endl; + if (copy_file(module_src_path.c_str(), module_dest_path.c_str()) != 0) + cerr << "Copy failed (\"" << module_src_path << "\" to \"" + << module_dest_path << "\"): " << strerror(errno) << endl; + } #endif } } diff --git a/runtime/staprun/common.c b/runtime/staprun/common.c index afe96606..6a2ac77e 100644 --- a/runtime/staprun/common.c +++ b/runtime/staprun/common.c @@ -30,6 +30,7 @@ int need_uprobes; int daemon_mode; off_t fsize_max; int fnum_max; +int unprivileged_user = 0; /* module variables */ char *modname = NULL; diff --git a/runtime/staprun/modverify.c b/runtime/staprun/modverify.c index b50a69f4..f4b15ac3 100644 --- a/runtime/staprun/modverify.c +++ b/runtime/staprun/modverify.c @@ -203,11 +203,7 @@ verify_it (const char *inputName, const char *signatureName, SECKEYPublicKey *pu /* Get the size of the signature file. */ prStatus = PR_GetFileInfo (signatureName, &info); if (prStatus != PR_SUCCESS || info.type != PR_FILE_FILE || info.size < 0) - { - fprintf (stderr, "Unable to obtain information on the signature file %s.\n", signatureName); - nssError (); - return MODULE_UNTRUSTED; /* Not signed */ - } + return MODULE_UNTRUSTED; /* Not signed */ /* Open the signature file. */ local_file_fd = PR_Open (signatureName, PR_RDONLY, 0); diff --git a/runtime/staprun/staprun.c b/runtime/staprun/staprun.c index 7069cab3..554eecc8 100644 --- a/runtime/staprun/staprun.c +++ b/runtime/staprun/staprun.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * Copyright (C) 2005-2008 Red Hat, Inc. + * Copyright (C) 2005-2009 Red Hat, Inc. * */ @@ -139,11 +139,21 @@ static int enable_uprobes(void) static int insert_stap_module(void) { - char bufsize_option[128]; + char special_options[128]; + char *bufptr = special_options; - if (snprintf_chk(bufsize_option, 128, "_stp_bufsize=%d", buffer_size)) + /* Add the _stp_bufsize option. */ + if (snprintf_chk(bufptr, sizeof (special_options), "_stp_bufsize=%d", buffer_size)) return -1; - return insert_module(modpath, bufsize_option, modoptions); + + /* Add the _stp_unprivileged_user option. */ + bufptr += strlen (bufptr); + if (snprintf_chk(bufptr, + sizeof (special_options) - (bufptr - special_options), + " _stp_unprivileged_user=%d", unprivileged_user)) + return -1; + + return insert_module(modpath, special_options, modoptions); } static int remove_module(const char *name, int verb); diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h index 1c9aece8..0a1ca885 100644 --- a/runtime/staprun/staprun.h +++ b/runtime/staprun/staprun.h @@ -171,6 +171,7 @@ extern int need_uprobes; extern int daemon_mode; extern off_t fsize_max; extern int fnum_max; +extern int unprivileged_user; /* getopt variables */ extern char *optarg; diff --git a/runtime/staprun/staprun_funcs.c b/runtime/staprun/staprun_funcs.c index c19dc3ba..ed7f4fc3 100644 --- a/runtime/staprun/staprun_funcs.c +++ b/runtime/staprun/staprun_funcs.c @@ -404,7 +404,6 @@ check_groups (void) perr("Unable to retrieve group list"); return -1; } - for (i = 0; i < ngids; i++) { /* If the user is a member of 'stapdev', then we're * done, since he can use staprun without any @@ -420,9 +419,10 @@ check_groups (void) if (gidlist[i] == stapusr_gid) gid = stapusr_gid; } - /* Not a member of stapusr? */ - if (gid != stapusr_gid) - return 0; + if (gid != stapusr_gid) { + unprivileged_user = 1; + return 0; + } } /* At this point the user is only a member of the 'stapusr' @@ -441,8 +441,9 @@ check_groups (void) * 1) root can do anything * 2) members of stapdev can do anything * 3) members of stapusr can load modules from /lib/modules/KVER/systemtap + * 4) anyone can load a module which has been signed by a trusted signer * - * It is only an error if all 3 levels of checking fail + * It is only an error if all 4 levels of checking fail * * Returns: -1 on errors, 0 on failure, 1 on success. */ @@ -481,6 +482,17 @@ int check_permissions(void) if (check_groups_rc == 1) return 1; + /* The user is an ordinary user. If the module has been signed with + * a "blessed" certificate and private key, then we will load it for + * anyone. */ +#if HAVE_NSS + if (check_signature_rc == MODULE_OK) + return 1; + assert (check_signature_rc == MODULE_UNTRUSTED || check_signature_rc == MODULE_CHECK_ERROR); +#endif + + /* We are an ordinary user and the module was not signed by a trusted + signer. */ err("ERROR: You are trying to run stap as a normal user.\n" "You should either be root, or be part of either " "group \"stapdev\" or group \"stapusr\".\n"); @@ -488,6 +500,11 @@ int check_permissions(void) err("Your system doesn't seem to have either group.\n"); check_groups_rc = -1; } +#if HAVE_NSS + err("Alternatively, your module must be compiled using the --unprivileged option and signed by a trusted signer.\n" + "For more information, please consult the \"SAFETY AND SECURITY\" section of the \"stap(1)\" manpage\n"); +#endif - return check_groups_rc; + /* Combine the return codes. They are either 0 or -1. */ + return check_groups_rc | check_signature_rc; } diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 1d029e53..ec73f05f 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -59,6 +59,10 @@ static int _stp_bufsize; module_param(_stp_bufsize, int, 0); MODULE_PARM_DESC(_stp_bufsize, "buffer size"); +static int _stp_unprivileged_user; +module_param(_stp_unprivileged_user, int, 1); +MODULE_PARM_DESC(_stp_unprivileged_user, "user is unprivileged"); + /* forward declarations */ static void probe_exit(void); static int probe_start(void); @@ -115,6 +115,7 @@ struct systemtap_session bool tapset_compile_coverage; bool need_uprobes; bool load_only; // flight recorder mode + bool unprivileged; // NB: It is very important for all of the above (and below) fields // to be cleared in the systemtap_session ctor (elaborate.cxx) @@ -25,7 +25,11 @@ stap_avahi_service_tag=_stap._tcp # NSS certificate databases stap_root_ssl_db=$stap_sysconfdir/systemtap/ssl -stap_user_ssl_db=$HOME/.systemtap/ssl +if test "X$SYSTEMTAP_DIR" = "X"; then + stap_user_ssl_db=$HOME/.systemtap/ssl +else + stap_user_ssl_db=$SYSTEMTAP_DIR/ssl +fi if test $EUID = 0; then stap_ssl_db=$stap_root_ssl_db diff --git a/staptree.cxx b/staptree.cxx index 8a589167..aa37b754 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -10,6 +10,7 @@ #include "staptree.h" #include "parse.h" #include "util.h" +#include "session.h" #include <iostream> #include <typeinfo> @@ -1735,6 +1736,14 @@ functioncall_traversing_visitor::visit_functioncall (functioncall* e) void varuse_collecting_visitor::visit_embeddedcode (embeddedcode *s) { + assert (current_function); // only they get embedded code + + // Don't allow embedded C functions in unprivileged mode unless + // they are tagged with /* unprivileged */ + if (session.unprivileged && s->code.find ("/* unprivileged */") == string::npos) + throw semantic_error ("function may not be used when --unprivileged is specified", + current_function->tok); + // We want to elide embedded-C functions when possible. For // example, each $target variable access is expanded to an // embedded-C function call. Yet, for safety reasons, we should @@ -1745,7 +1754,6 @@ varuse_collecting_visitor::visit_embeddedcode (embeddedcode *s) // $target variables as rvalues will have this; lvalues won't. // Also, explicit side-effect-free tapset functions will have this. - assert (current_function); // only they get embedded code if (s->code.find ("/* pure */") != string::npos) return; @@ -23,6 +23,8 @@ extern "C" { } struct token; // parse.h +struct systemtap_session; // session.h + struct semantic_error: public std::runtime_error { const token* tok1; @@ -778,12 +780,14 @@ struct functioncall_traversing_visitor: public traversing_visitor // the elaboration-time optimizer pass. struct varuse_collecting_visitor: public functioncall_traversing_visitor { + systemtap_session& session; std::set<vardecl*> read; std::set<vardecl*> written; bool embedded_seen; expression* current_lvalue; expression* current_lrvalue; - varuse_collecting_visitor(): + varuse_collecting_visitor(systemtap_session& s): + session (s), embedded_seen (false), current_lvalue(0), current_lrvalue(0) {} diff --git a/systemtap.spec b/systemtap.spec index a8e0d9da..eae8a2a2 100644 --- a/systemtap.spec +++ b/systemtap.spec @@ -322,6 +322,8 @@ exit 0 %{_bindir}/stap-client %{_bindir}/stap-env %{_bindir}/stap-find-servers +%{_bindir}/stap-authorize-cert +%{_bindir}/stap-authorize-server-cert %{_bindir}/stap-client-connect %{_mandir}/man8/stap-server.8* diff --git a/tapset-been.cxx b/tapset-been.cxx index d695bdf3..99b59574 100644 --- a/tapset-been.cxx +++ b/tapset-been.cxx @@ -215,14 +215,30 @@ register_tapset_been(systemtap_session& s) { match_node* root = s.pattern_root; - root->bind(TOK_BEGIN)->bind(new be_builder(BEGIN)); - root->bind_num(TOK_BEGIN)->bind(new be_builder(BEGIN)); - root->bind(TOK_END)->bind(new be_builder(END)); - root->bind_num(TOK_END)->bind(new be_builder(END)); - root->bind(TOK_ERROR)->bind(new be_builder(ERROR)); - root->bind_num(TOK_ERROR)->bind(new be_builder(ERROR)); - - root->bind(TOK_NEVER)->bind(new never_builder()); + root->bind(TOK_BEGIN) + ->allow_unprivileged() + ->bind(new be_builder(BEGIN)); + root->bind_num(TOK_BEGIN) + ->allow_unprivileged() + ->bind(new be_builder(BEGIN)); + + root->bind(TOK_END) + ->allow_unprivileged() + ->bind(new be_builder(END)); + root->bind_num(TOK_END) + ->allow_unprivileged() + ->bind(new be_builder(END)); + + root->bind(TOK_ERROR) + ->allow_unprivileged() + ->bind(new be_builder(ERROR)); + root->bind_num(TOK_ERROR) + ->allow_unprivileged() + ->bind(new be_builder(ERROR)); + + root->bind(TOK_NEVER) + ->allow_unprivileged() + ->bind(new never_builder()); } /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ diff --git a/tapset-timers.cxx b/tapset-timers.cxx index 1dc0acac..565a54e8 100644 --- a/tapset-timers.cxx +++ b/tapset-timers.cxx @@ -593,32 +593,71 @@ register_tapset_timers(systemtap_session& s) root = root->bind(TOK_TIMER); - root->bind_num("s")->bind(builder); - root->bind_num("s")->bind_num("randomize")->bind(builder); - root->bind_num("sec")->bind(builder); - root->bind_num("sec")->bind_num("randomize")->bind(builder); - - root->bind_num("ms")->bind(builder); - root->bind_num("ms")->bind_num("randomize")->bind(builder); - root->bind_num("msec")->bind(builder); - root->bind_num("msec")->bind_num("randomize")->bind(builder); - - root->bind_num("us")->bind(builder); - root->bind_num("us")->bind_num("randomize")->bind(builder); - root->bind_num("usec")->bind(builder); - root->bind_num("usec")->bind_num("randomize")->bind(builder); - - root->bind_num("ns")->bind(builder); - root->bind_num("ns")->bind_num("randomize")->bind(builder); - root->bind_num("nsec")->bind(builder); - root->bind_num("nsec")->bind_num("randomize")->bind(builder); - - root->bind_num("jiffies")->bind(builder); - root->bind_num("jiffies")->bind_num("randomize")->bind(builder); - - root->bind_num("hz")->bind(builder); - - root->bind("profile")->bind(builder); + root->bind_num("s") + ->allow_unprivileged() + ->bind(builder); + root->bind_num("s")->bind_num("randomize") + ->allow_unprivileged() + ->bind(builder); + root->bind_num("sec") + ->allow_unprivileged() + ->bind(builder); + root->bind_num("sec")->bind_num("randomize") + ->allow_unprivileged() + ->bind(builder); + + root->bind_num("ms") + ->allow_unprivileged() + ->bind(builder); + root->bind_num("ms")->bind_num("randomize") + ->allow_unprivileged() + ->bind(builder); + root->bind_num("msec") + ->allow_unprivileged() + ->bind(builder); + root->bind_num("msec")->bind_num("randomize") + ->allow_unprivileged() + ->bind(builder); + + root->bind_num("us") + ->allow_unprivileged() + ->bind(builder); + root->bind_num("us")->bind_num("randomize") + ->allow_unprivileged() + ->bind(builder); + root->bind_num("usec") + ->allow_unprivileged() + ->bind(builder); + root->bind_num("usec")->bind_num("randomize") + ->allow_unprivileged() + ->bind(builder); + + root->bind_num("ns") + ->allow_unprivileged() + ->bind(builder); + root->bind_num("ns")->bind_num("randomize") + ->allow_unprivileged() + ->bind(builder); + root->bind_num("nsec") + ->allow_unprivileged() + ->bind(builder); + root->bind_num("nsec")->bind_num("randomize") + ->allow_unprivileged() + ->bind(builder); + + root->bind_num("jiffies") + ->allow_unprivileged() + ->bind(builder); + root->bind_num("jiffies")->bind_num("randomize") + ->allow_unprivileged() + ->bind(builder); + + root->bind_num("hz") + ->allow_unprivileged() + ->bind(builder); + + root->bind("profile") + ->bind(builder); } diff --git a/tapset/logging.stp b/tapset/logging.stp index d2cca612..91f9672b 100644 --- a/tapset/logging.stp +++ b/tapset/logging.stp @@ -8,21 +8,21 @@ // send a string out with a newline // Deprecated. print* functions are much more efficient. -function log (msg:string) %{ +function log (msg:string) %{ /* unprivileged */ _stp_printf ("%s\n", THIS->msg); %} -function warn (msg:string) %{ +function warn (msg:string) %{ /* unprivileged */ _stp_warn ("%s", THIS->msg); %} // NB: exit() does *not* cause immediate return from current function/probe -function exit () %{ +function exit () %{ /* unprivileged */ atomic_set (&session_state, STAP_SESSION_STOPPING); _stp_exit (); %} -function error (msg:string) %{ +function error (msg:string) %{ /* unprivileged */ /* This is an assignment of a local char[] to a global char*. It would normally be just as unsafe as returning a pointer to a local variable from a function. However, the translated diff --git a/tapset/timestamp.stp b/tapset/timestamp.stp index 0b9d350a..1980932a 100644 --- a/tapset/timestamp.stp +++ b/tapset/timestamp.stp @@ -16,7 +16,7 @@ * * Return the processor cycle counter value, or 0 if unavailable. */ -function get_cycles:long () %{ /* pure */ +function get_cycles:long () %{ /* pure */ /* unprivileged */ cycles_t c = get_cycles(); THIS->__retvalue = (int64_t) c; %} diff --git a/tapsets.cxx b/tapsets.cxx index a105526c..b1ca2998 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -359,11 +359,14 @@ struct dwarf_derived_probe: public derived_probe // Pattern registration helpers. static void register_statement_variants(match_node * root, - dwarf_builder * dw); + dwarf_builder * dw, + bool unprivileged_ok_p = false); static void register_function_variants(match_node * root, - dwarf_builder * dw); + dwarf_builder * dw, + bool unprivileged_ok_p = false); static void register_function_and_statement_variants(match_node * root, - dwarf_builder * dw); + dwarf_builder * dw, + bool unprivileged_ok_p = false); static void register_patterns(systemtap_session& s); }; @@ -2463,6 +2466,9 @@ void dwarf_cast_expanding_visitor::filter_special_modules(string& module) void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e) { + if (s.unprivileged) + throw semantic_error("typecasting may not be used when --unprivileged is specified", e->tok); + bool lvalue = is_active_lvalue(e); if (lvalue && !s.guru_mode) throw semantic_error("write to typecast value not permitted", e->tok); @@ -2812,25 +2818,28 @@ dwarf_derived_probe::printargs(std::ostream &o) const void dwarf_derived_probe::register_statement_variants(match_node * root, - dwarf_builder * dw) + dwarf_builder * dw, + bool unprivileged_ok_p) { - root->bind(dw); + root->allow_unprivileged(unprivileged_ok_p)->bind(dw); } void dwarf_derived_probe::register_function_variants(match_node * root, - dwarf_builder * dw) -{ - root->bind(dw); - root->bind(TOK_INLINE)->bind(dw); - root->bind(TOK_CALL)->bind(dw); - root->bind(TOK_RETURN)->bind(dw); - root->bind(TOK_RETURN)->bind_num(TOK_MAXACTIVE)->bind(dw); + dwarf_builder * dw, + bool unprivileged_ok_p) +{ + root->allow_unprivileged(unprivileged_ok_p)->bind(dw); + root->bind(TOK_INLINE)->allow_unprivileged(unprivileged_ok_p)->bind(dw); + root->bind(TOK_CALL)->allow_unprivileged(unprivileged_ok_p)->bind(dw); + root->bind(TOK_RETURN)->allow_unprivileged(unprivileged_ok_p)->bind(dw); + root->bind(TOK_RETURN)->bind_num(TOK_MAXACTIVE)->allow_unprivileged(unprivileged_ok_p)->bind(dw); } void dwarf_derived_probe::register_function_and_statement_variants(match_node * root, - dwarf_builder * dw) + dwarf_builder * dw, + bool unprivileged_ok_p) { // Here we match 4 forms: // @@ -2839,10 +2848,10 @@ dwarf_derived_probe::register_function_and_statement_variants(match_node * root, // .statement("foo") // .statement(0xdeadbeef) - register_function_variants(root->bind_str(TOK_FUNCTION), dw); - register_function_variants(root->bind_num(TOK_FUNCTION), dw); - register_statement_variants(root->bind_str(TOK_STATEMENT), dw); - register_statement_variants(root->bind_num(TOK_STATEMENT), dw); + register_function_variants(root->bind_str(TOK_FUNCTION), dw, unprivileged_ok_p); + register_function_variants(root->bind_num(TOK_FUNCTION), dw, unprivileged_ok_p); + register_statement_variants(root->bind_str(TOK_STATEMENT), dw, unprivileged_ok_p); + register_statement_variants(root->bind_num(TOK_STATEMENT), dw, unprivileged_ok_p); } void @@ -2859,8 +2868,7 @@ dwarf_derived_probe::register_patterns(systemtap_session& s) root->bind(TOK_KERNEL)->bind_num(TOK_STATEMENT)->bind(TOK_ABSOLUTE)->bind(dw); root->bind(TOK_KERNEL)->bind_str(TOK_FUNCTION)->bind_str(TOK_LABEL)->bind(dw); root->bind_str(TOK_PROCESS)->bind_str(TOK_FUNCTION)->bind_str(TOK_LABEL)->bind(dw); - - register_function_and_statement_variants(root->bind_str(TOK_PROCESS), dw); + register_function_and_statement_variants(root->bind_str(TOK_PROCESS), dw, false/*!unprivileged_ok_p*/); root->bind_str(TOK_PROCESS)->bind_str(TOK_MARK)->bind(dw); root->bind_str(TOK_PROCESS)->bind_num(TOK_MARK)->bind(dw); } @@ -6093,7 +6101,6 @@ register_standard_tapsets(systemtap_session & s) register_tapset_timers(s); register_tapset_utrace(s); - // dwarf-based kprobe/uprobe parts dwarf_derived_probe::register_patterns(s); diff --git a/testsuite/systemtap.base/optim_arridx.exp b/testsuite/systemtap.base/optim_arridx.exp index 1f3f4371..c33952a6 100644 --- a/testsuite/systemtap.base/optim_arridx.exp +++ b/testsuite/systemtap.base/optim_arridx.exp @@ -10,7 +10,7 @@ elide_global_a:long elide_global_b:long # functions exit:unknown () -%{ +%{ /* unprivileged */ atomic_set (&session_state, STAP_SESSION_STOPPING); _stp_exit (); %} diff --git a/translate.cxx b/translate.cxx index a26e4085..4a6a10b5 100644 --- a/translate.cxx +++ b/translate.cxx @@ -57,7 +57,8 @@ struct c_unparser: public unparser, public visitor c_unparser (systemtap_session* ss): session (ss), o (ss->op), current_probe(0), current_function (0), - tmpvar_counter (0), label_counter (0) {} + tmpvar_counter (0), label_counter (0), + vcv_needs_global_locks (*ss) {} ~c_unparser () {} void emit_map_type_instantiations (); @@ -1087,7 +1088,6 @@ c_unparser::emit_functionsig (functiondecl* v) } - void c_unparser::emit_module_init () { @@ -1131,6 +1131,7 @@ c_unparser::emit_module_init () o->newline() << "if (_stp_module_check()) rc = -EINVAL;"; o->newline(-1) << "}"; + o->newline() << "if (rc) goto out;"; // initialize gettimeofday (if needed) @@ -1600,7 +1601,7 @@ c_unparser::emit_probe (derived_probe* v) v->emit_probe_local_init(o); // emit all read/write locks for global variables - varuse_collecting_visitor vut; + varuse_collecting_visitor vut(*session); if (v->needs_global_locks ()) { v->body->visit (& vut); diff --git a/translate.h b/translate.h index fdff9521..d1bff678 100644 --- a/translate.h +++ b/translate.h @@ -1,5 +1,5 @@ // -*- C++ -*- -// Copyright (C) 2005 Red Hat Inc. +// Copyright (C) 2005, 2009 Red Hat Inc. // // This file is part of systemtap, and is free software. You can // redistribute it and/or modify it under the terms of the GNU General @@ -52,6 +52,30 @@ get_home_directory(void) } +// Get the size of a file in bytes +size_t +get_file_size(const string &path) +{ + struct stat file_info; + + if (stat(path.c_str(), &file_info) == 0) + return file_info.st_size; + else + return 0; +} + +// Get the size of a file in bytes +bool +file_exists (const string &path) +{ + struct stat file_info; + + if (stat(path.c_str(), &file_info) == 0) + return true; + + return false; +} + // Copy a file. The copy is done via a temporary file and atomic // rename. int @@ -6,6 +6,8 @@ #include <cctype> const char *get_home_directory(void); +size_t get_file_size(const std::string &path); +bool file_exists (const std::string &path); int copy_file(const char *src, const char *dest); int create_dir(const char *dir); int remove_file_or_dir(const char *dir); |