diff options
author | Dave Brolley <brolley@redhat.com> | 2009-11-09 14:50:52 -0500 |
---|---|---|
committer | Dave Brolley <brolley@redhat.com> | 2009-11-09 14:50:52 -0500 |
commit | 64211010978d0e35c80ec7c119f1986a48f97543 (patch) | |
tree | 4a9d67ed8f7682cf8eb61686709fd69341394e63 /runtime/staprun | |
parent | 5e90af3e298ae39838acedf85f1301806143e920 (diff) | |
download | systemtap-steved-64211010978d0e35c80ec7c119f1986a48f97543.tar.gz systemtap-steved-64211010978d0e35c80ec7c119f1986a48f97543.tar.xz systemtap-steved-64211010978d0e35c80ec7c119f1986a48f97543.zip |
Don't reference global variable modpath in insert_module and its helpers.
This allows insert_module to to be used for loading the signed uprobes.ko
module.
Allow the use of $$parms and $$return in uprobes based probes for
unprivileged users.
Re-add management of module signatures in the cache. Don't know why
it was removed.
Diffstat (limited to 'runtime/staprun')
-rw-r--r-- | runtime/staprun/staprun.c | 10 | ||||
-rw-r--r-- | runtime/staprun/staprun.h | 22 | ||||
-rw-r--r-- | runtime/staprun/staprun_funcs.c | 85 |
3 files changed, 81 insertions, 36 deletions
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 +} |