diff options
-rw-r--r-- | cache.cxx | 24 | ||||
-rw-r--r-- | runtime/staprun/common.c | 1 | ||||
-rw-r--r-- | runtime/staprun/modverify.c | 43 | ||||
-rw-r--r-- | runtime/staprun/modverify.h | 7 | ||||
-rw-r--r-- | runtime/staprun/staprun.c | 18 | ||||
-rw-r--r-- | runtime/staprun/staprun.h | 1 | ||||
-rw-r--r-- | runtime/staprun/staprun_funcs.c | 27 | ||||
-rw-r--r-- | runtime/transport/transport.c | 4 | ||||
-rwxr-xr-x | stap-authorize-server-cert | 2 | ||||
-rwxr-xr-x | stap-authorize-signing-cert | 2 | ||||
-rwxr-xr-x | stap-client | 2 | ||||
-rwxr-xr-x | stap-find-or-start-server | 2 | ||||
-rwxr-xr-x | stap-find-servers | 2 | ||||
-rwxr-xr-x | stap-gen-cert | 2 | ||||
-rwxr-xr-x | stap-server | 2 | ||||
-rwxr-xr-x | stap-serverd | 2 | ||||
-rwxr-xr-x | stap-start-server | 2 | ||||
-rw-r--r-- | testsuite/lib/systemtap.exp | 2 | ||||
-rw-r--r-- | translate.cxx | 19 |
19 files changed, 108 insertions, 56 deletions
@@ -69,7 +69,7 @@ add_to_cache(systemtap_session& s) } #if HAVE_NSS - // This is the name of the cached module signatire. + // This is the name of the cached module signature. string module_signature_dest_path = s.hash_path; module_signature_dest_path += ".sgn"; @@ -133,6 +133,10 @@ get_from_cache(systemtap_session& s) string module_dest_path = s.tmpdir + "/" + s.module_name + ".ko"; string c_src_path = s.hash_path; int fd_stapconf, fd_module, fd_c; +#if HAVE_NSS + string hash_signature_path = s.hash_path + ".sgn"; + int fd_signature; +#endif if (c_src_path.rfind(".ko") == (c_src_path.size() - 3)) c_src_path.resize(c_src_path.size() - 3); @@ -202,6 +206,24 @@ get_from_cache(systemtap_session& s) close(fd_c); return false; } +#if HAVE_NSS + // See if module signature exists. It's not an error if it doesn't. It just + // means that the module is unsigned. + fd_signature = open(hash_signature_path.c_str(), O_RDONLY); + if (fd_signature != -1) { + string signature_dest_path = module_dest_path + ".sgn"; + close(fd_signature); + if (copy_file(hash_signature_path.c_str(), signature_dest_path.c_str()) != 0) + { + cerr << "Copy failed (\"" << hash_signature_path << "\" to \"" + << signature_dest_path << "\"): " << strerror(errno) << endl; + unlink(c_src_path.c_str()); + close(fd_module); + close(fd_c); + return false; + } + } +#endif } // We're done with these file handles. diff --git a/runtime/staprun/common.c b/runtime/staprun/common.c index 26b166c2..6c199616 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 688734c0..d9ccc094 100644 --- a/runtime/staprun/modverify.c +++ b/runtime/staprun/modverify.c @@ -29,6 +29,7 @@ #include <certt.h> #include "nsscommon.h" +#include "modverify.h" static int verify_it (const char *inputName, const char *signatureName, SECKEYPublicKey *pubKey) @@ -48,7 +49,7 @@ verify_it (const char *inputName, const char *signatureName, SECKEYPublicKey *pu { fprintf (stderr, "Unable to obtain information on the signature file %s.\n", signatureName); nssError (); - return -1; + return MODULE_UNTRUSTED; /* Not signed */ } /* Open the signature file. */ @@ -57,7 +58,7 @@ verify_it (const char *inputName, const char *signatureName, SECKEYPublicKey *pu { fprintf (stderr, "Could not open the signature file %s\n.", signatureName); nssError (); - return -1; + return MODULE_CHECK_ERROR; } /* Allocate space to read the signature file. */ @@ -66,7 +67,7 @@ verify_it (const char *inputName, const char *signatureName, SECKEYPublicKey *pu { fprintf (stderr, "Unable to allocate memory for the signature in %s.\n", signatureName); nssError (); - return -1; + return MODULE_CHECK_ERROR; } /* Read the signature. */ @@ -74,18 +75,18 @@ verify_it (const char *inputName, const char *signatureName, SECKEYPublicKey *pu if (numBytes == 0) /* EOF */ { fprintf (stderr, "EOF reading signature file %s.\n", signatureName); - return -1; + return MODULE_CHECK_ERROR; } if (numBytes < 0) { fprintf (stderr, "Error reading signature file %s.\n", signatureName); nssError (); - return -1; + return MODULE_CHECK_ERROR; } if (numBytes != info.size) { fprintf (stderr, "Incomplete data while reading signature file %s.\n", signatureName); - return -1; + return MODULE_CHECK_ERROR; } signature.len = info.size; @@ -97,10 +98,10 @@ verify_it (const char *inputName, const char *signatureName, SECKEYPublicKey *pu SEC_OID_UNKNOWN, NULL, NULL); if (! vfy) { - fprintf (stderr, "Unable to create verification context while verifying %s using the signature in %s.\n", - inputName, signatureName); - nssError (); - return -1; + /* The key does not match the signature. This is not an error. It just means + we are currently trying the wrong certificate/key. i.e. the module + remains untrusted for now. */ + return MODULE_UNTRUSTED; } /* Begin the verification process. */ @@ -110,7 +111,7 @@ verify_it (const char *inputName, const char *signatureName, SECKEYPublicKey *pu fprintf (stderr, "Unable to initialize verification context while verifying %s using the signature in %s.\n", inputName, signatureName); nssError (); - return -1; + return MODULE_CHECK_ERROR; } /* Now read the data and add it to the signature. */ @@ -119,7 +120,7 @@ verify_it (const char *inputName, const char *signatureName, SECKEYPublicKey *pu { fprintf (stderr, "Could not open module file %s.\n", inputName); nssError (); - return -1; + return MODULE_CHECK_ERROR; } for (;;) @@ -132,7 +133,7 @@ verify_it (const char *inputName, const char *signatureName, SECKEYPublicKey *pu { fprintf (stderr, "Error reading module file %s.\n", inputName); nssError (); - return -1; + return MODULE_CHECK_ERROR; } /* Add the data to the signature. */ @@ -141,7 +142,7 @@ verify_it (const char *inputName, const char *signatureName, SECKEYPublicKey *pu { fprintf (stderr, "Error while verifying module file %s.\n", inputName); nssError (); - return -1; + return MODULE_CHECK_ERROR; } } @@ -152,10 +153,10 @@ verify_it (const char *inputName, const char *signatureName, SECKEYPublicKey *pu if (secStatus != SECSuccess) { fprintf (stderr, "Unable to verify signed module %s. It may have been altered since it was created.\n", inputName); nssError (); - return 0; + return MODULE_ALTERED; } - return 1; + return MODULE_OK; } int verify_module (const char *module_name, const char *signature_name) @@ -178,7 +179,7 @@ int verify_module (const char *module_name, const char *signature_name) fprintf (stderr, "Unable to initialize nss library using the database in %s.\n", dbdir); nssError (); - return -1; + return MODULE_CHECK_ERROR; } certList = PK11_ListCerts (PK11CertListAll, NULL); @@ -187,7 +188,7 @@ int verify_module (const char *module_name, const char *signature_name) fprintf (stderr, "Unable to find certificates in the certificate database in %s.\n", dbdir); nssError (); - return -1; + return MODULE_UNTRUSTED; } /* We need to look at each certificate in the database. */ @@ -203,13 +204,13 @@ int verify_module (const char *module_name, const char *signature_name) fprintf (stderr, "Unable to extract public key from the certificate with nickname %s from the certificate database in %s.\n", cert->nickname, dbdir); nssError (); - return -1; + return MODULE_CHECK_ERROR; } /* Verify the file. */ rc = verify_it (module_name, signature_name, pubKey); - if (rc == 1) - break; /* Verified! */ + if (rc == MODULE_OK || rc == MODULE_ALTERED || rc == MODULE_CHECK_ERROR) + break; /* resolved or error */ } /* Shutdown NSS and exit NSPR gracefully. */ diff --git a/runtime/staprun/modverify.h b/runtime/staprun/modverify.h index ad212e2b..9abf62d4 100644 --- a/runtime/staprun/modverify.h +++ b/runtime/staprun/modverify.h @@ -1 +1,8 @@ int verify_module (const char *module_name, const char *signature_name); + +/* return codes for verify_module. */ +#define MODULE_OK 1 +#define MODULE_UNTRUSTED 0 +#define MODULE_CHECK_ERROR -1 +#define MODULE_ALTERED -2 + diff --git a/runtime/staprun/staprun.c b/runtime/staprun/staprun.c index 42b72ff1..917990dc 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 acc533b2..5159f1bd 100644 --- a/runtime/staprun/staprun.h +++ b/runtime/staprun/staprun.h @@ -166,6 +166,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 020bb312..6e72fd72 100644 --- a/runtime/staprun/staprun_funcs.c +++ b/runtime/staprun/staprun_funcs.c @@ -20,6 +20,7 @@ #include <sys/utsname.h> #include <grp.h> #include <pwd.h> +#include <assert.h> extern long init_module(void *, unsigned long, const char *); @@ -225,18 +226,18 @@ check_signature(void) /* Use realpath() to canonicalize the module path. */ if (realpath(modpath, module_realpath) == NULL) { perr("Unable to canonicalize signature path \"%s\"", modpath); - return -1; + return MODULE_CHECK_ERROR; } /* Now add the .sgn suffix to get the signature file name. */ if (strlen (module_realpath) > PATH_MAX - 4) { err("Path \"%s\" is too long.", modpath); - return -1; + return MODULE_CHECK_ERROR; } sprintf (signature_realpath, "%s.sgn", module_realpath); - dbug(2, "verify_module (%s, %s)\n", module_realpath, signature_realpath); rc = verify_module (module_realpath, signature_realpath); + dbug(2, "verify_module returns %d\n", rc); return rc; @@ -419,8 +420,10 @@ check_groups (void) gid = stapusr_gid; } - if (gid != stapusr_gid) + if (gid != stapusr_gid) { + unprivileged_user = 1; return 0; + } } /* At this point the user is only a member of the 'stapusr' @@ -450,6 +453,14 @@ int check_permissions(void) int check_groups_rc; int check_signature_rc = 0; +#if HAVE_NSS + /* Attempt to verify the module against its signature. Return failure + if the module has been tampered with (altered). */ + check_signature_rc = check_signature (); + if (check_signature_rc == MODULE_ALTERED) + return 0; +#endif + /* If we're root, we can do anything. */ if (getuid() == 0) return 1; @@ -459,15 +470,17 @@ int check_permissions(void) if (check_groups_rc == 1) return 1; -#if HAVE_NSS /* 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. */ - check_signature_rc = check_signature (); - if (check_signature_rc == 1) +#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"); diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 762c0a92..1ab49ae2 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -41,6 +41,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); diff --git a/stap-authorize-server-cert b/stap-authorize-server-cert index 058e7ebb..d5f9c2e6 100755 --- a/stap-authorize-server-cert +++ b/stap-authorize-server-cert @@ -11,7 +11,7 @@ # later version. # Initialize the environment -. stap-env +. `dirname $0`/stap-env certfile=$1 certdb=$2 diff --git a/stap-authorize-signing-cert b/stap-authorize-signing-cert index dfcf1a94..429d7fa5 100755 --- a/stap-authorize-signing-cert +++ b/stap-authorize-signing-cert @@ -11,7 +11,7 @@ # later version. # Initialize the environment -. stap-env +. `dirname $0`/stap-env certfile=$1 certdb=$2 diff --git a/stap-client b/stap-client index c8664852..c3afab89 100755 --- a/stap-client +++ b/stap-client @@ -22,7 +22,7 @@ trap 'interrupt' SIGINT trap 'ignore_signal' SIGHUP SIGPIPE # Initialize the environment -. stap-env +. `dirname $0`/stap-env #----------------------------------------------------------------------------- # Helper functions. diff --git a/stap-find-or-start-server b/stap-find-or-start-server index 28fcfa8c..131133ef 100755 --- a/stap-find-or-start-server +++ b/stap-find-or-start-server @@ -18,7 +18,7 @@ # Otherwise, it echoes -1 # Initialize the environment -. stap-env +. `dirname $0`/stap-env # Is there a server available? ${stap_exec_prefix}stap-find-servers >/dev/null 2>&1 && echo 0 && exit 0 diff --git a/stap-find-servers b/stap-find-servers index e0838708..77cd267a 100755 --- a/stap-find-servers +++ b/stap-find-servers @@ -13,7 +13,7 @@ # network. Information about each server found is printed to stdout. # Initialize the environment -. stap-env +. `dirname $0`/stap-env #----------------------------------------------------------------------------- # Helper functions. diff --git a/stap-gen-cert b/stap-gen-cert index bf87b572..940779eb 100755 --- a/stap-gen-cert +++ b/stap-gen-cert @@ -11,7 +11,7 @@ # later version. # Initialize the environment -. stap-env +. `dirname $0`/stap-env # Obtain a password from stdin and echo it. function user_enter_password diff --git a/stap-server b/stap-server index 76130bb1..316cc954 100755 --- a/stap-server +++ b/stap-server @@ -17,7 +17,7 @@ trap 'terminate' SIGTERM SIGINT # Initialize the environment -. stap-env +. `dirname $0`/stap-env #----------------------------------------------------------------------------- # Helper functions. diff --git a/stap-serverd b/stap-serverd index 04ef54c3..16869e89 100755 --- a/stap-serverd +++ b/stap-serverd @@ -17,7 +17,7 @@ trap 'terminate' SIGTERM SIGINT # Initialize the environment -. stap-env +. `dirname $0`/stap-env #----------------------------------------------------------------------------- # Helper functions. diff --git a/stap-start-server b/stap-start-server index bc441545..6471db96 100755 --- a/stap-start-server +++ b/stap-start-server @@ -13,7 +13,7 @@ # process id, if successful. # Initialize the environment -. stap-env +. `dirname $0`/stap-env # start the server ${stap_exec_prefix}stap-serverd "$@" </dev/null >/dev/null 2>&1 & diff --git a/testsuite/lib/systemtap.exp b/testsuite/lib/systemtap.exp index 5311be7b..43116a85 100644 --- a/testsuite/lib/systemtap.exp +++ b/testsuite/lib/systemtap.exp @@ -128,8 +128,10 @@ proc setup_server {} { # The server does not call this instance of 'stap' if {[installtest_p]} then { exec /bin/cp -p [exec which stap-client] $net_path/stap + exec /bin/cp -p [exec which stap-env] $net_path/stap-env } else { exec /bin/cp -p $srcdir/../stap-client $net_path/stap + exec /bin/cp -p $srcdir/../stap-env $net_path/stap-env } set env(PATH) "$net_path:$env(PATH)" diff --git a/translate.cxx b/translate.cxx index 1a86dcd2..95986924 100644 --- a/translate.cxx +++ b/translate.cxx @@ -1097,26 +1097,17 @@ c_unparser::emit_unprivileged_user_check () if (session->unprivileged) return; - // Otherwise, generate code to check the user or group. If the user is not - // root or a member of stapdev or stapusr, then generate an error and - // unload the module. + // Otherwise, generate code to check whether the user is unprivileged. + // If so, then generate an error and indicate that the check has failed. o->newline(); o->newline() << "static int systemtap_unprivileged_user_check (void) {"; -#if 0 - o->newline(1) << "if (_stp_uid == 0)"; - o->newline(1) << "return 0;"; - o->newline(-1) << "stgr = getgrnam(\"stapdev\");"; - o->newline() << "if (stgr != NULL && _stp_gid == stgr->gr_gid)"; - o->newline(1) << "return 0;"; - o->newline(-1) << "stgr = getgrnam(\"stapusr\");"; - o->newline() << "if (stgr != NULL && _stp_gid == stgr->gr_gid)"; + o->newline(1) << "if (! _stp_unprivileged_user)"; o->newline(1) << "return 0;"; + o->newline(-1) << "_stp_error (\"You are attempting to run stap as an ordinary user.\");"; o->newline() << "_stp_error (\"Your module must be compiled using the --unprivileged option.\");"; o->newline() << "return 1;"; -#else - o->newline(1) << "return 0;"; -#endif + o->newline(-1) << "}\n"; } |