summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cache.cxx7
-rw-r--r--runtime/staprun/staprun.c10
-rw-r--r--runtime/staprun/staprun.h22
-rw-r--r--runtime/staprun/staprun_funcs.c85
-rw-r--r--tapsets.cxx30
5 files changed, 118 insertions, 36 deletions
diff --git a/cache.cxx b/cache.cxx
index 8a6553ff..29c20d0d 100644
--- a/cache.cxx
+++ b/cache.cxx
@@ -68,6 +68,9 @@ add_to_cache(systemtap_session& s)
s.use_cache = false;
return;
}
+ // Copy the signature file, if any. It is not an error if this fails.
+ if (file_exists (module_src_path + ".sgn"))
+ copy_file(module_src_path + ".sgn", s.hash_path + ".sgn", verbose);
string c_dest_path = s.hash_path;
if (c_dest_path.rfind(".ko") == (c_dest_path.size() - 3))
@@ -155,6 +158,10 @@ get_from_cache(systemtap_session& s)
close(fd_c);
return false;
}
+ // Copy the module signature file, if any.
+ // It is not an error if this fails.
+ if (file_exists (s.hash_path + ".sgn"))
+ copy_file(s.hash_path + ".sgn", module_dest_path + ".sgn");
}
// We're done with these file handles.
diff --git a/runtime/staprun/staprun.c b/runtime/staprun/staprun.c
index c5651d9a..078be4cf 100644
--- a/runtime/staprun/staprun.c
+++ b/runtime/staprun/staprun.c
@@ -129,14 +129,12 @@ static int enable_uprobes(void)
if (run_as(0, 0, 0, argv[0], argv) == 0)
return 0;
+ /* This module may be signed, so use insert_module to load it. */
snprintf (runtimeko, sizeof(runtimeko), "%s/uprobes/uprobes.ko",
(getenv("SYSTEMTAP_RUNTIME") ?: PKGDATADIR "/runtime"));
dbug(2, "Inserting uprobes module from SystemTap runtime %s.\n", runtimeko);
- i = 0;
- argv[i++] = "/sbin/insmod";
- argv[i++] = runtimeko;
- argv[i] = NULL;
- if (run_as(0, 0, 0, argv[0], argv) == 0)
+ argv[0] = NULL;
+ if (insert_module(runtimeko, NULL, argv, assert_uprobes_module_permissions) == 0)
return 0;
return 1; /* failure */
@@ -150,7 +148,7 @@ static int insert_stap_module(void)
if (snprintf_chk(special_options, sizeof (special_options), "_stp_bufsize=%d", buffer_size))
return -1;
- return insert_module(modpath, special_options, modoptions);
+ return insert_module(modpath, special_options, modoptions, assert_stap_module_permissions);
}
static int remove_module(const char *name, int verb);
diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h
index 9cdbc861..91761bde 100644
--- a/runtime/staprun/staprun.h
+++ b/runtime/staprun/staprun.h
@@ -131,8 +131,28 @@ time_t read_backlog(int cpu, int fnum);
/* staprun_funcs.c */
void setup_staprun_signals(void);
const char *moderror(int err);
+
+/* insert_module helper functions. */
+typedef void (*assert_permissions_func) (
+ const char *module_path __attribute__ ((unused)),
+ const void *module_data __attribute__ ((unused)),
+ off_t module_size __attribute__ ((unused))
+);
+
+void assert_stap_module_permissions (
+ const char *module_path __attribute__ ((unused)),
+ const void *module_data __attribute__ ((unused)),
+ off_t module_size __attribute__ ((unused))
+);
+
+void assert_uprobes_module_permissions (
+ const char *module_path __attribute__ ((unused)),
+ const void *module_data __attribute__ ((unused)),
+ off_t module_size __attribute__ ((unused))
+);
int insert_module(const char *path, const char *special_options,
- char **options);
+ char **options, assert_permissions_func apf);
+
int mountfs(void);
void start_symbol_thread(void);
void stop_symbol_thread(void);
diff --git a/runtime/staprun/staprun_funcs.c b/runtime/staprun/staprun_funcs.c
index aef8a2da..47ad6a19 100644
--- a/runtime/staprun/staprun_funcs.c
+++ b/runtime/staprun/staprun_funcs.c
@@ -23,7 +23,6 @@
#include <assert.h>
extern long init_module(void *, unsigned long, const char *);
-static void assert_permissions(const void *, off_t);
/* Module errors get translated. */
const char *moderror(int err)
@@ -42,8 +41,12 @@ const char *moderror(int err)
}
}
-int insert_module(const char *path, const char *special_options, char **options)
-{
+int insert_module(
+ const char *path,
+ const char *special_options,
+ char **options,
+ assert_permissions_func assert_permissions
+) {
int i;
long ret;
void *file;
@@ -74,23 +77,23 @@ int insert_module(const char *path, const char *special_options, char **options)
dbug(2, "module options: %s\n", opts);
/* Use realpath() to canonicalize the module path. */
- if (realpath(modpath, module_realpath) == NULL) {
- perr("Unable to canonicalize path \"%s\"", modpath);
+ if (realpath(path, module_realpath) == NULL) {
+ perr("Unable to canonicalize path \"%s\"", path);
return -1;
}
- /* Overwrite the modpath with the canonicalized one, to defeat
+ /* Overwrite the path with the canonicalized one, to defeat
a possible race between path and signature checking below and,
somewhat later, module loading. */
- modpath = strdup (module_realpath);
- if (modpath == NULL) {
+ path = strdup (module_realpath);
+ if (path == NULL) {
_perr("allocating memory failed");
exit (1);
}
/* Open the module file. Work with the open file descriptor from this
point on to avoid TOCTOU problems. */
- fd = open(modpath, O_RDONLY);
+ fd = open(path, O_RDONLY);
if (fd < 0) {
perr("Error opening '%s'", path);
return -1;
@@ -114,8 +117,7 @@ int insert_module(const char *path, const char *special_options, char **options)
/* Check whether this module can be loaded by the current user.
* check_permissions will exit(-1) if permissions are insufficient*/
- assert_permissions (file, sbuf.st_size);
-
+ assert_permissions (path, file, sbuf.st_size);
STAP_PROBE1(staprun, insert__module, path);
/* Actually insert the module */
@@ -239,20 +241,20 @@ int mountfs(void)
* Returns: -1 on errors, 0 on failure, 1 on success.
*/
static int
-check_signature(const void *module_data, off_t module_size)
+check_signature(const char *path, const void *module_data, off_t module_size)
{
char signature_realpath[PATH_MAX];
int rc;
- dbug(2, "checking signature for %s\n", modpath);
+ dbug(2, "checking signature for %s\n", path);
/* Add the .sgn suffix to the canonicalized module path to get the signature
file path. */
- if (strlen (modpath) >= PATH_MAX - 4) {
- err("Path \"%s.sgn\" is too long.", modpath);
+ if (strlen (path) >= PATH_MAX - 4) {
+ err("Path \"%s.sgn\" is too long.", path);
return -1;
}
- sprintf (signature_realpath, "%s.sgn", modpath);
+ sprintf (signature_realpath, "%s.sgn", path);
rc = verify_module (signature_realpath, module_data, module_size);
@@ -270,7 +272,7 @@ check_signature(const void *module_data, off_t module_size)
* Returns: -1 on errors, 0 on failure, 1 on success.
*/
static int
-check_path(void)
+check_path(const char *module_path)
{
char staplib_dir_path[PATH_MAX];
char staplib_dir_realpath[PATH_MAX];
@@ -330,18 +332,18 @@ check_path(void)
if (strlen(staplib_dir_realpath) < (PATH_MAX - 1))
strcat(staplib_dir_realpath, "/");
else {
- err("Path \"%s\" is too long.", modpath);
+ err("Path \"%s\" is too long.", staplib_dir_realpath);
return -1;
}
/* Now we've got two canonicalized paths. Make sure
- * modpath starts with staplib_dir_realpath. */
- if (strncmp(staplib_dir_realpath, modpath,
+ * path starts with staplib_dir_realpath. */
+ if (strncmp(staplib_dir_realpath, module_path,
strlen(staplib_dir_realpath)) != 0) {
err("ERROR: Members of the \"stapusr\" group can only use modules within\n"
" the \"%s\" directory.\n"
" Module \"%s\" does not exist within that directory.\n",
- staplib_dir_path, modpath);
+ staplib_dir_path, module_path);
return 0;
}
return 1;
@@ -359,7 +361,7 @@ check_path(void)
* 1 on success
*/
static int
-check_groups (void)
+check_groups (const char *module_path)
{
gid_t gid, gidlist[NGROUPS_MAX];
gid_t stapdev_gid, stapusr_gid;
@@ -430,7 +432,7 @@ check_groups (void)
* group. Members of the 'stapusr' group can only use modules
* in /lib/modules/KVER/systemtap. Make sure the module path
* is in that directory. */
- return check_path();
+ return check_path (module_path);
}
/*
@@ -445,10 +447,9 @@ check_groups (void)
* 4) anyone can load a module which has been signed by a trusted signer
*
* It is only an error if all 4 levels of checking fail
- *
- * Returns: -1 on errors, 0 on failure, 1 on success.
*/
-void assert_permissions(
+void assert_stap_module_permissions(
+ const char *module_path __attribute__ ((unused)),
const void *module_data __attribute__ ((unused)),
off_t module_size __attribute__ ((unused))
) {
@@ -457,7 +458,7 @@ void assert_permissions(
#if HAVE_NSS
/* Attempt to verify the module against its signature. Return failure
if the module has been tampered with (altered). */
- int check_signature_rc = check_signature (module_data, module_size);
+ int check_signature_rc = check_signature (module_path, module_data, module_size);
if (check_signature_rc == MODULE_ALTERED)
exit(-1);
#endif
@@ -480,7 +481,7 @@ void assert_permissions(
}
/* Check permissions for group membership. */
- check_groups_rc = check_groups ();
+ check_groups_rc = check_groups (module_path);
if (check_groups_rc == 1)
return;
@@ -507,6 +508,32 @@ void assert_permissions(
"For more information, please consult the \"SAFETY AND SECURITY\" section of the \"stap(1)\" manpage\n");
#endif
- /* Combine the return codes. They are either 0 or -1. */
exit(-1);
}
+
+/*
+ * For the uprobes.ko module, if we have NSS, then
+ * check the signature. Otherwise go ahead and load it.
+ */
+void assert_uprobes_module_permissions(
+ const char *module_path __attribute__ ((unused)),
+ const void *module_data __attribute__ ((unused)),
+ off_t module_size __attribute__ ((unused))
+) {
+#if HAVE_NSS
+ /* Attempt to verify the module against its signature. Return failure
+ if the module has been tampered with (altered). */
+ int rc = check_signature (module_path, module_data, module_size);
+ if (rc == MODULE_ALTERED)
+ exit(-1);
+ if (rc == MODULE_OK)
+ return;
+ assert (rc == MODULE_UNTRUSTED || rc == MODULE_CHECK_ERROR);
+ err("Signature verification failed for module %s.\n", module_path);
+ if (rc == MODULE_UNTRUSTED) {
+ err("Run '" BINDIR "/stap-sign-module %s' as root and/or\n", module_path);
+ err("run '" BINDIR "/stap-authorize-signing-cert %s' as root\n",
+ SYSCONFDIR "/systemtap/ssl/server/stap.cert");
+ }
+#endif
+}
diff --git a/tapsets.cxx b/tapsets.cxx
index e0346c69..2a893c95 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -358,6 +358,9 @@ struct dwarf_derived_probe: public derived_probe
void emit_probe_local_init(translator_output * o);
void getargs(std::set<std::string> &arg_set) const;
+ void emit_unprivileged_assertion (translator_output*);
+ void print_dupe_stamp(ostream& o);
+
// Pattern registration helpers.
static void register_statement_variants(match_node * root,
dwarf_builder * dw);
@@ -672,6 +675,11 @@ struct dwarf_builder: public derived_probe_builder
probe_point * location,
literal_map_t const & parameters,
vector<derived_probe *> & finished_results);
+
+ // No action required. These probes are allowed for unprivileged users.
+ // as process owners.
+ virtual void check_unprivileged (const systemtap_session & sess,
+ const literal_map_t & parameters) {}
};
@@ -2307,6 +2315,8 @@ dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e)
if (! lvalue)
ec->code += "/* pure */";
+
+ ec->code += "/* unprivileged */";
}
catch (const semantic_error& er)
{
@@ -2962,6 +2972,24 @@ dwarf_derived_probe::getargs(std::set<std::string> &arg_set) const
void
+dwarf_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
+dwarf_derived_probe::print_dupe_stamp(ostream& o)
+{
+ // These probes are allowed for unprivileged users, but only in the
+ // context of processes which they own.
+ print_dupe_stamp_unprivileged_process_owner (o);
+}
+
+
+void
dwarf_derived_probe::register_statement_variants(match_node * root,
dwarf_builder * dw)
{
@@ -5581,6 +5609,8 @@ tracepoint_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
else
ec->code += "/* pure */";
+ ec->code += "/* unprivileged */";
+
dw.sess.functions[fdecl->name] = fdecl;
// Synthesize a functioncall.