diff options
author | Dave Brolley <brolley@redhat.com> | 2009-10-09 11:09:12 -0400 |
---|---|---|
committer | Dave Brolley <brolley@redhat.com> | 2009-10-09 11:09:12 -0400 |
commit | 2865d17a48d055b3aef6e45506292908800cdb21 (patch) | |
tree | 216ef4616108250518e0bd52b5c37a489f2906e0 | |
parent | 47f025139d1c2e75781cdab40dc9195396133754 (diff) | |
download | systemtap-steved-2865d17a48d055b3aef6e45506292908800cdb21.tar.gz systemtap-steved-2865d17a48d055b3aef6e45506292908800cdb21.tar.xz systemtap-steved-2865d17a48d055b3aef6e45506292908800cdb21.zip |
Generate safety net assertions in probe function not authorized for unprivileged users.
2009-10-08 Dave Brolley <brolley@redhat.com>
* elaborate.h (emit_unprivileged_assertion): New virtual method of deriv
ed_probe.
(emit_process_owner_assertion): New static method of derived_probe.
(check_unprivileged): New virtual method of derived_probe_builder.
(match_node::unprivileged_ok): Removed.
(match_node::allow_unprivileged): Removed.
(match_node::unprivileged_allowed): Removed.
* elaborate.cxx (translate.h): #include it.
(emit_unprivileged_assertion): New virtual method of derived_probe.
(emit_process_owner_assertion): New static method of derived_probe.
(check_unprivileged): New virtual method of derived_probe_builder.
(match_node::unprivileged_ok): Removed.
(match_node::allow_unprivileged): Removed.
(match_node::unprivileged_allowed): Removed.
(find_and_build): Don't check for unprivileged restrictions here. Call t
he
builder's check_unprivileged method.
(alias_expansion_builder::check_unprivileged): New virtual method.
* tapset-been.cxx (be_derived_probe::emit_unprivileged_assertion): New v
irtual
method.
(be_builder::check_unprivileged): Likewise.
(never_derived_probe::emit_unprivileged_assertion): Likewise.
(never_builder::check_unprivileged): Likewise.
(register_tapset_been): Don't call allow_unprivileged.
* tapset-itrace.cxx (itrace_derived_probe::emit_unprivileged_assertion):
New virtual
method.
(itrace_builder::check_unprivileged): Likewise.
(register_tapset_itrace): Don't call allow_unprivileged.
* tapset-utrace.cxx (utrace_derived_probe::emit_unprivileged_assertion):
New virtual
method.
(utrace_builder::check_unprivileged): Likewise.
(register_tapset_utrace): Don't call allow_unprivileged.
* tapset-timer.cxx (timer_derived_probe::emit_unprivileged_assertion): N
ew virtual
method.
(timer_builder::check_unprivileged): Likewise.
(register_tapset_timers): Don't call allow_unprivileged.
* tapsets.cxx (uprobe_derived_probe::emit_unprivileged_assertion): New v
irtual
method.
(uprobe_builder::check_unprivileged): Likewise.
(register_standard_tapsets): Don't call allow_unprivileged.
(register_statement_variants): Remove unprivileged_ok_p parameter. Don't
call
allow_unprivileged.
(register_function_variants): Likewise.
(register_function_and_statement_variants): Likewise.
(register_patterns): Don't call allow_unprivileged.
* translate.cxx (emit_probe): Call v->emit_unprivileged_assertion.
-rw-r--r-- | elaborate.cxx | 69 | ||||
-rw-r--r-- | elaborate.h | 14 | ||||
-rw-r--r-- | tapset-been.cxx | 21 | ||||
-rw-r--r-- | tapset-itrace.cxx | 19 | ||||
-rw-r--r-- | tapset-timers.cxx | 40 | ||||
-rw-r--r-- | tapset-utrace.cxx | 27 | ||||
-rw-r--r-- | tapsets.cxx | 62 | ||||
-rw-r--r-- | translate.cxx | 3 |
8 files changed, 164 insertions, 91 deletions
diff --git a/elaborate.cxx b/elaborate.cxx index 01c6e3cd..e8795a6c 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -9,6 +9,7 @@ #include "config.h" #include "elaborate.h" +#include "translate.h" #include "parse.h" #include "tapsets.h" #include "session.h" @@ -132,10 +133,50 @@ derived_probe::sole_location () const } +void +derived_probe::emit_unprivileged_assertion (translator_output* o) +{ + // Emit code which will cause compilation to fail if it is compiled in + // unprivileged mode. + o->newline() << "#ifndef STP_PRIVILEGED"; + o->newline() << "#error Internal Error: Probe "; + probe::printsig (o->line()); + o->line() << " generated in --unprivileged mode"; + o->newline() << "#endif"; +} + + +void +derived_probe::emit_process_owner_assertion (translator_output* o) +{ + // Emit code which will abort should the current target not belong to the + // user in unprivileged mode. + o->newline() << "#ifndef STP_PRIVILEGED"; + o->newline(1) << "if (! is_myproc ()) {"; + o->newline(1) << "snprintf(c->error_buffer, sizeof(c->error_buffer),"; + o->newline() << " \"Internal Error: Process %d does not belong to user %d in probe %s in --unprivileged mode\","; + o->newline() << " current->tgid, _stp_uid, c->probe_point);"; + o->newline() << "c->last_error = c->error_buffer;"; + o->newline() << "goto out;"; + o->newline(-1) << "}"; + o->newline(-1) << "#endif"; +} + // ------------------------------------------------------------------------ // Members of derived_probe_builder +void +derived_probe_builder::check_unprivileged (const systemtap_session & sess, + const literal_map_t & parameters) +{ + // By default, probes are not allowed for unprivileged users. + if (sess.unprivileged) + { + throw semantic_error (string("probe point is not allowed for unprivileged users")); + } +} + bool derived_probe_builder::get_param (std::map<std::string, literal*> const & params, const std::string& key, @@ -261,7 +302,6 @@ match_key::globmatch(match_key const & other) const // ------------------------------------------------------------------------ match_node::match_node() - : unprivileged_ok (false) { } @@ -303,19 +343,6 @@ 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, probe* p, probe_point *loc, unsigned pos, @@ -340,18 +367,11 @@ 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")); - } - // Iterate over all bound builders for (unsigned k=0; k<ends.size(); k++) { derived_probe_builder *b = ends[k]; + b->check_unprivileged (s, param_map); b->build (s, p, loc, param_map, results); } } @@ -573,6 +593,11 @@ alias_expansion_builder } return false; } + + // No action required. The actual probes will be checked when they are + // built. + virtual void check_unprivileged (const systemtap_session & sess, + const literal_map_t & parameters) {} }; diff --git a/elaborate.h b/elaborate.h index cd60b8bb..d41608cb 100644 --- a/elaborate.h +++ b/elaborate.h @@ -146,11 +146,19 @@ struct derived_probe: public probe // From within unparser::emit_probe, emit any extra processing block // for this probe. + virtual void emit_unprivileged_assertion (translator_output*); + // From within unparser::emit_probe, emit any unprivileged mode + // checking for this probe. + public: static void emit_common_header (translator_output* o); // from c_unparser::emit_common_header // XXX: probably can move this stuff to a probe_group::emit_module_decls + static void emit_process_owner_assertion (translator_output*); + // From within unparser::emit_probe, emit a check that the current + // process belongs to the user. + virtual bool needs_global_locks () { return true; } // by default, probes need locks around global variables }; @@ -199,6 +207,8 @@ struct derived_probe_builder probe_point* location, literal_map_t const & parameters, std::vector<derived_probe*> & finished_results) = 0; + virtual void check_unprivileged (const systemtap_session & sess, + const literal_map_t & parameters); virtual ~derived_probe_builder() {} virtual void build_no_more (systemtap_session &) {} @@ -236,7 +246,6 @@ match_node typedef std::map<match_key, match_node*>::iterator sub_map_iterator_t; sub_map_t sub; std::vector<derived_probe_builder*> ends; - bool unprivileged_ok; public: match_node(); @@ -251,9 +260,6 @@ 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; }; // ------------------------------------------------------------------------ diff --git a/tapset-been.cxx b/tapset-been.cxx index 99b59574..002bf66a 100644 --- a/tapset-been.cxx +++ b/tapset-been.cxx @@ -52,6 +52,10 @@ struct be_derived_probe: public derived_probe return a->priority < b->priority; } + // No assertion need be emitted, since these probes are allowed for + // unprivileged users. + void emit_unprivileged_assertion (translator_output*) {} + bool needs_global_locks () { return false; } // begin/end probes don't need locks around global variables, since // they aren't run concurrently with any other probes @@ -86,6 +90,10 @@ struct be_builder: public derived_probe_builder finished_results.push_back (new be_derived_probe(base, location, type, priority)); } + + // No action required. These probes are allowed for unprivileged users. + virtual void check_unprivileged (const systemtap_session & sess, + const literal_map_t & parameters) {} }; @@ -188,6 +196,8 @@ struct never_derived_probe: public derived_probe never_derived_probe (probe* p): derived_probe (p) {} never_derived_probe (probe* p, probe_point* l): derived_probe (p, l) {} void join_group (systemtap_session&) { /* thus no probe_group */ } + void emit_unprivileged_assertion (translator_output*) {} + }; @@ -202,6 +212,10 @@ struct never_builder: public derived_probe_builder { finished_results.push_back(new never_derived_probe(base, location)); } + + // No action required. This probe is allowed for unprivileged users. + virtual void check_unprivileged (const systemtap_session & sess, + const literal_map_t & parameters) {} }; @@ -216,28 +230,21 @@ register_tapset_been(systemtap_session& s) match_node* root = s.pattern_root; 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()); } diff --git a/tapset-itrace.cxx b/tapset-itrace.cxx index 9fc59d42..512a70b0 100644 --- a/tapset-itrace.cxx +++ b/tapset-itrace.cxx @@ -44,6 +44,8 @@ struct itrace_derived_probe: public derived_probe bool hp, string &pn, int64_t pd, int ss ); void join_group (systemtap_session& s); + + void emit_unprivileged_assertion (translator_output*); }; @@ -79,6 +81,15 @@ itrace_derived_probe::itrace_derived_probe (systemtap_session &s, void +itrace_derived_probe::emit_unprivileged_assertion (translator_output* o) +{ + // These probes are allowed for unprivileged users, but only in the + // context of processes which they own. + emit_process_owner_assertion (o); +} + + +void itrace_derived_probe::join_group (systemtap_session& s) { if (! s.itrace_derived_probes) @@ -121,6 +132,10 @@ struct itrace_builder: public derived_probe_builder single_step )); } + + // No action required. These probes are allowed for unprivileged users. + virtual void check_unprivileged (const systemtap_session & sess, + const literal_map_t & parameters) {} }; @@ -300,16 +315,12 @@ register_tapset_itrace(systemtap_session& s) derived_probe_builder *builder = new itrace_builder(); root->bind_str(TOK_PROCESS)->bind(TOK_INSN) - ->allow_unprivileged() ->bind(builder); root->bind_num(TOK_PROCESS)->bind(TOK_INSN) - ->allow_unprivileged() ->bind(builder); root->bind_str(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK) - ->allow_unprivileged() ->bind(builder); root->bind_num(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK) - ->allow_unprivileged() ->bind(builder); } diff --git a/tapset-timers.cxx b/tapset-timers.cxx index 16dcefcb..de57d81a 100644 --- a/tapset-timers.cxx +++ b/tapset-timers.cxx @@ -37,6 +37,10 @@ struct timer_derived_probe: public derived_probe timer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r, bool ms=false); virtual void join_group (systemtap_session& s); + + // No assertion need be emitted, since this probe is allowed for unprivileged + // users. + void emit_unprivileged_assertion (translator_output*) {} }; @@ -204,6 +208,10 @@ struct hrtimer_derived_probe: public derived_probe } void join_group (systemtap_session& s); + + // No assertion need be emitted, since these probes are allowed for + // unprivileged users. + void emit_unprivileged_assertion (translator_output*) {} }; @@ -505,6 +513,9 @@ struct timer_builder: public derived_probe_builder vector<derived_probe *> & finished_results); static void register_patterns(systemtap_session& s); + + virtual void check_unprivileged (const systemtap_session & sess, + const literal_map_t & parameters); }; void @@ -586,6 +597,16 @@ timer_builder::build(systemtap_session & sess, } void +timer_builder::check_unprivileged (const systemtap_session & sess, + const literal_map_t & parameters) +{ + // All timer probes are allowed except for timer.profile + if (has_null_param(parameters, "profile")) + derived_probe_builder::check_unprivileged (sess, parameters); +} + + +void register_tapset_timers(systemtap_session& s) { match_node* root = s.pattern_root; @@ -594,66 +615,47 @@ register_tapset_timers(systemtap_session& s) root = root->bind(TOK_TIMER); 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") diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx index b13dc290..819a2d87 100644 --- a/tapset-utrace.cxx +++ b/tapset-utrace.cxx @@ -60,6 +60,8 @@ struct utrace_derived_probe: public derived_probe bool hp, string &pn, int64_t pd, enum utrace_derived_probe_flags f); void join_group (systemtap_session& s); + + void emit_unprivileged_assertion (translator_output*); }; @@ -195,6 +197,21 @@ utrace_derived_probe::join_group (systemtap_session& s) void +utrace_derived_probe::emit_unprivileged_assertion (translator_output* o) +{ + // Process end probes are allowed for unprivileged users, even if the process + // does not belong to them. They are required to check is_myproc() from within + // their probe script before doing anything "dangerous". + if (flags == UDPF_END) + return; + + // Other process probes are allowed for unprivileged users, but only in the + // context of processes which they own. + emit_process_owner_assertion (o); +} + + +void utrace_var_expanding_visitor::visit_target_symbol_cached (target_symbol* e) { // Get the full name of the target symbol. @@ -624,6 +641,10 @@ struct utrace_builder: public derived_probe_builder has_path, path, pid, flags)); } + + // No action required. These probes are allowed for unprivileged users. + virtual void check_unprivileged (const systemtap_session & sess, + const literal_map_t & parameters) {} }; @@ -1054,22 +1075,16 @@ register_tapset_utrace(systemtap_session& s) for (unsigned i = 0; i < roots.size(); ++i) { roots[i]->bind(TOK_BEGIN) - ->allow_unprivileged() ->bind(builder); roots[i]->bind(TOK_END) - ->allow_unprivileged() ->bind(builder); roots[i]->bind(TOK_THREAD)->bind(TOK_BEGIN) - ->allow_unprivileged() ->bind(builder); roots[i]->bind(TOK_THREAD)->bind(TOK_END) - ->allow_unprivileged() ->bind(builder); roots[i]->bind(TOK_SYSCALL) - ->allow_unprivileged() ->bind(builder); roots[i]->bind(TOK_SYSCALL)->bind(TOK_RETURN) - ->allow_unprivileged() ->bind(builder); } } diff --git a/tapsets.cxx b/tapsets.cxx index 6267f314..88c10f85 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -359,14 +359,11 @@ struct dwarf_derived_probe: public derived_probe // Pattern registration helpers. static void register_statement_variants(match_node * root, - dwarf_builder * dw, - bool unprivileged_ok_p = false); + dwarf_builder * dw); static void register_function_variants(match_node * root, - dwarf_builder * dw, - bool unprivileged_ok_p = false); + dwarf_builder * dw); static void register_function_and_statement_variants(match_node * root, - dwarf_builder * dw, - bool unprivileged_ok_p = false); + dwarf_builder * dw); static void register_patterns(systemtap_session& s); protected: @@ -411,6 +408,8 @@ struct uprobe_derived_probe: public dwarf_derived_probe {} void join_group (systemtap_session& s); + + void emit_unprivileged_assertion (translator_output*); }; struct dwarf_derived_probe_group: public derived_probe_group @@ -2945,28 +2944,25 @@ dwarf_derived_probe::printargs(std::ostream &o) const void dwarf_derived_probe::register_statement_variants(match_node * root, - dwarf_builder * dw, - bool unprivileged_ok_p) + dwarf_builder * dw) { - root->allow_unprivileged(unprivileged_ok_p)->bind(dw); + root->bind(dw); } void dwarf_derived_probe::register_function_variants(match_node * root, - 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); + 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); } void dwarf_derived_probe::register_function_and_statement_variants(match_node * root, - dwarf_builder * dw, - bool unprivileged_ok_p) + dwarf_builder * dw) { // Here we match 4 forms: // @@ -2975,10 +2971,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, 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); + 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); } void @@ -2997,15 +2993,12 @@ dwarf_derived_probe::register_patterns(systemtap_session& s) root->bind(TOK_KERNEL)->bind_str(TOK_FUNCTION)->bind_str(TOK_LABEL) ->bind(dw); - register_function_and_statement_variants(root->bind_str(TOK_PROCESS), dw, true/*unprivileged_ok_p*/); + register_function_and_statement_variants(root->bind_str(TOK_PROCESS), dw); root->bind_str(TOK_PROCESS)->bind_str(TOK_FUNCTION)->bind_str(TOK_LABEL) - ->allow_unprivileged() ->bind(dw); root->bind_str(TOK_PROCESS)->bind_str(TOK_MARK) - ->allow_unprivileged() ->bind(dw); root->bind_str(TOK_PROCESS)->bind_num(TOK_MARK) - ->allow_unprivileged() ->bind(dw); } @@ -4307,6 +4300,15 @@ uprobe_derived_probe::join_group (systemtap_session& s) } +void +uprobe_derived_probe::emit_unprivileged_assertion (translator_output* o) +{ + // These probes are allowed for unprivileged users, but only in the + // context of processes which they own. + emit_process_owner_assertion (o); +} + + struct uprobe_builder: public derived_probe_builder { uprobe_builder() {} @@ -4327,6 +4329,10 @@ struct uprobe_builder: public derived_probe_builder finished_results.push_back(new uprobe_derived_probe(base, location, process, address, rr)); } + + // No action required. These probes are allowed for unprivileged users. + virtual void check_unprivileged (const systemtap_session & sess, + const literal_map_t & parameters) {} }; @@ -6220,11 +6226,9 @@ register_standard_tapsets(systemtap_session & s) // XXX: user-space starter set s.pattern_root->bind_num(TOK_PROCESS) ->bind_num(TOK_STATEMENT)->bind(TOK_ABSOLUTE) - ->allow_unprivileged() ->bind(new uprobe_builder ()); s.pattern_root->bind_num(TOK_PROCESS) ->bind_num(TOK_STATEMENT)->bind(TOK_ABSOLUTE)->bind(TOK_RETURN) - ->allow_unprivileged() ->bind(new uprobe_builder ()); // kernel tracepoint probes diff --git a/translate.cxx b/translate.cxx index a3246d9c..1278a8d5 100644 --- a/translate.cxx +++ b/translate.cxx @@ -1622,6 +1622,9 @@ c_unparser::emit_probe (derived_probe* v) o->newline(1) << "& c->probe_locals." << v->name << ";"; o->newline(-1) << "(void) l;"; // make sure "l" is marked used + // Emit runtime safety net for unprivileged mode. + v->emit_unprivileged_assertion (o); + o->newline() << "#ifdef STP_TIMING"; o->newline() << "c->statp = & time_" << v->basest()->name << ";"; o->newline() << "#endif"; |