summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Brolley <brolley@redhat.com>2010-01-15 10:57:08 -0500
committerDave Brolley <brolley@redhat.com>2010-01-15 10:57:08 -0500
commitceeefadd6874e3d315669a87ec0d05a0ce1f7094 (patch)
treefad469e3f31212afee4d1fb6aa6833b48e1724b7
parent3f78f0208e1bfe8061d1898418882b5e2756f8a2 (diff)
parent86f99ad8206574dc6400d48563db58341cb50f52 (diff)
downloadsystemtap-steved-ceeefadd6874e3d315669a87ec0d05a0ce1f7094.tar.gz
systemtap-steved-ceeefadd6874e3d315669a87ec0d05a0ce1f7094.tar.xz
systemtap-steved-ceeefadd6874e3d315669a87ec0d05a0ce1f7094.zip
Merge branch 'master' of ssh://sources.redhat.com/git/systemtap
Conflicts: stap-client
-rw-r--r--Makefile.am2
-rw-r--r--Makefile.in2
-rw-r--r--main.cxx11
-rw-r--r--runtime/stack.c3
-rw-r--r--runtime/staprun/modverify.c10
-rw-r--r--runtime/uprobes-common.c15
-rw-r--r--runtime/uprobes-common.h1
-rwxr-xr-xstap-client26
-rw-r--r--stap-server-connect.c499
-rwxr-xr-xstap-server-request512
-rwxr-xr-xstap-serverd2
-rw-r--r--tapsets.cxx1
-rw-r--r--testsuite/systemtap.server/client_args.exp4
13 files changed, 456 insertions, 632 deletions
diff --git a/Makefile.am b/Makefile.am
index 3c2ddbe1..a7603fb2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -43,7 +43,7 @@ if BUILD_SERVER
man_MANS += stap-client.8 stap-server.8 stap-authorize-server-cert.8
pkglibexec_PROGRAMS += stap-client-connect stap-server-connect
bin_SCRIPTS += stap-client stap-server stap-authorize-server-cert
-pkglibexec_SCRIPTS += stap-serverd stap-server-request stap-find-servers \
+pkglibexec_SCRIPTS += stap-serverd stap-find-servers \
stap-start-server stap-find-or-start-server stap-stop-server
endif
endif
diff --git a/Makefile.in b/Makefile.in
index 016162ab..e655f8a2 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -47,7 +47,7 @@ pkglibexec_PROGRAMS = stapio$(EXEEXT) $(am__EXEEXT_2) $(am__EXEEXT_3)
@BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@am__append_8 = stap-client.8 stap-server.8 stap-authorize-server-cert.8
@BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@am__append_9 = stap-client-connect stap-server-connect
@BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@am__append_10 = stap-client stap-server stap-authorize-server-cert
-@BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@am__append_11 = stap-serverd stap-server-request stap-find-servers \
+@BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@am__append_11 = stap-serverd stap-find-servers \
@BUILD_SERVER_TRUE@@BUILD_TRANSLATOR_TRUE@@HAVE_NSS_TRUE@ stap-start-server stap-find-or-start-server stap-stop-server
@BUILD_TRANSLATOR_FALSE@stap_DEPENDENCIES =
diff --git a/main.cxx b/main.cxx
index 4a845620..cbedd6e4 100644
--- a/main.cxx
+++ b/main.cxx
@@ -1,5 +1,5 @@
// systemtap translator/driver
-// Copyright (C) 2005-2009 Red Hat Inc.
+// Copyright (C) 2005-2010 Red Hat Inc.
// Copyright (C) 2005 IBM Corp.
// Copyright (C) 2006 Intel Corporation.
//
@@ -877,6 +877,8 @@ main (int argc, char * const argv [])
break;
case LONG_OPT_UNPRIVILEGED:
s.unprivileged = true;
+ /* NB: for server security, it is essential that once this flag is
+ set, no future flag be able to unset it. */
break;
case LONG_OPT_CLIENT_OPTIONS:
client_options = true;
@@ -895,6 +897,10 @@ main (int argc, char * const argv [])
// Check for options conflicts.
+ if (client_options && s.last_pass > 4)
+ {
+ s.last_pass = 4; /* Quietly downgrade. Server passed through -p5 naively. */
+ }
if (client_options && s.unprivileged && ! client_options_disallowed.empty ())
{
cerr << "You can't specify " << client_options_disallowed << " when --unprivileged is specified." << endl;
@@ -921,7 +927,6 @@ main (int argc, char * const argv [])
if (s.kernel_symtab_path == PATH_TBD)
s.kernel_symtab_path = string("/boot/System.map-") + s.kernel_release;
}
-
// Warn in case the target kernel release doesn't match the running one.
if (s.last_pass > 4 &&
(string(buf.release) != s.kernel_release ||
@@ -1369,6 +1374,8 @@ pass_5:
else
{
if (s.keep_tmpdir)
+ // NB: the format of this message needs to match the expectations
+ // of stap-server-connect.c.
clog << "Keeping temporary directory \"" << s.tmpdir << "\"" << endl;
else
{
diff --git a/runtime/stack.c b/runtime/stack.c
index 7dfeb76a..0e537a8e 100644
--- a/runtime/stack.c
+++ b/runtime/stack.c
@@ -212,7 +212,8 @@ void _stp_stack_print_tsk(struct task_struct *tsk, int verbose, int levels)
for (i = 0; i < maxLevels; ++i) {
if (backtrace[i] == 0 || backtrace[i] == ULONG_MAX)
break;
- _stp_printf("%lx ", backtrace[i]);
+ _stp_symbol_print(backtrace[i]);
+ _stp_print_char('\n');
}
#endif
}
diff --git a/runtime/staprun/modverify.c b/runtime/staprun/modverify.c
index a17bb2ec..5d442393 100644
--- a/runtime/staprun/modverify.c
+++ b/runtime/staprun/modverify.c
@@ -272,12 +272,18 @@ int verify_module (const char *signatureName, const char* module_name,
/* Verify the permissions of the certificate database and its files. */
if (! check_cert_db_permissions (dbdir))
- return MODULE_UNTRUSTED;
+ {
+ if (verbose>1) fprintf (stderr, "Certificate db %s permissions too loose\n", dbdir);
+ return MODULE_UNTRUSTED;
+ }
/* Get the size of the signature file. */
prStatus = PR_GetFileInfo (signatureName, &info);
if (prStatus != PR_SUCCESS || info.type != PR_FILE_FILE || info.size < 0)
- return MODULE_UNTRUSTED; /* Not signed */
+ {
+ if (verbose>1) fprintf (stderr, "Signature file %s not found\n", signatureName);
+ return MODULE_UNTRUSTED; /* Not signed */
+ }
/* Open the signature file. */
local_file_fd = PR_Open (signatureName, PR_RDONLY, 0);
diff --git a/runtime/uprobes-common.c b/runtime/uprobes-common.c
index b0273ba4..58e3a05f 100644
--- a/runtime/uprobes-common.c
+++ b/runtime/uprobes-common.c
@@ -286,4 +286,19 @@ static int stap_uprobe_munmap_found (struct stap_task_finder_target *tgt, struct
return stap_uprobe_change_minus (tsk, addr, length, stf);
}
+/* The task_finder_callback we use for ET_DYN targets.
+ This just forces an unmap of everything as the process exits.
+ (PR11151) */
+static int stap_uprobe_process_munmap (struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {
+ const struct stap_uprobe_tf *stf = container_of(tgt, struct stap_uprobe_tf, finder);
+ if (! process_p) return 0; /* ignore threads */
+ #ifdef DEBUG_TASK_FINDER_VMA
+ _stp_dbug (__FUNCTION__,__LINE__, "%cproc pid %d stf %p %p path %s\n", register_p?'+':'-', tsk->tgid, tgt, stf, stf->pathname);
+ #endif
+ /* Covering 0->TASK_SIZE means "unmap everything" */
+ if (!register_p)
+ return stap_uprobe_change_minus (tsk, 0, TASK_SIZE, stf);
+ return 0;
+}
+
#endif /* _UPROBE_COMMON_C_ */
diff --git a/runtime/uprobes-common.h b/runtime/uprobes-common.h
index 68741f4d..990b473a 100644
--- a/runtime/uprobes-common.h
+++ b/runtime/uprobes-common.h
@@ -33,5 +33,6 @@ struct stap_uprobe_spec {
static int stap_uprobe_process_found (struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p);
static int stap_uprobe_mmap_found (struct stap_task_finder_target *tgt, struct task_struct *tsk, char *path, unsigned long addr, unsigned long length, unsigned long offset, unsigned long vm_flags);
static int stap_uprobe_munmap_found (struct stap_task_finder_target *tgt, struct task_struct *tsk, unsigned long addr, unsigned long length);
+static int stap_uprobe_process_munmap (struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p);
#endif /* _UPROBE_COMMON_H_ */
diff --git a/stap-client b/stap-client
index 4cb44b18..64452159 100755
--- a/stap-client
+++ b/stap-client
@@ -260,7 +260,7 @@ function parse_options {
else
local_name="-"
fi
- echo "script/$local_name" > "$tmpdir_client/argv$script_file_argc"
+ echo -n "script/$local_name" > "$tmpdir_client/argv$script_file_argc"
fi
# Processing based on final options settings
@@ -500,17 +500,6 @@ function unpack_response {
unzip -d $tmpdir_server $zip_server > /dev/null || \
fatal "Cannot unpack server response, $zip_server"
- # Check the contents of the expanded directory. It should contain a
- # single directory whose name matches $stap_tmpdir_prefix_server.??????
- local num_files=`ls $tmpdir_server | wc -l`
- test $num_files = 1 || \
- fatal "Wrong number of files in server's temp directory"
- test -d $tmpdir_server/$stap_tmpdir_prefix_server.?????? || \
- fatal "`ls $tmpdir_server` does not match the expected name or is not a directory"
- # Move the contents of the directory down one level.
- mv $tmpdir_server/$stap_tmpdir_prefix_server.??????/* $tmpdir_server
- rm -fr $tmpdir_server/$stap_tmpdir_prefix_server.??????
-
# Check the contents of the directory. It should contain:
# 1) a file called stdout
# 2) a file called stderr
@@ -526,7 +515,8 @@ function unpack_response {
test -f $tmpdir_server/rc || \
fatal "`pwd`/$tmpdir_server/rc does not exist or is not a regular file"
- # See if there is a systemtap temp directory
+ # See if there is a systemtap temp directory. There should be at least an empty one.
+ # ls -l $tmpdir_server
tmpdir_stap=`cd $tmpdir_server && ls | grep stap......\$ 2>/dev/null`
if test "X$tmpdir_stap" != "X"; then
test -d $tmpdir_server/$tmpdir_stap || \
@@ -549,6 +539,16 @@ function unpack_response {
test $EUID = 0 && chown $EUID:$EUID $tmpdir_stap
fi
fi
+
+ if test $keep_temps = 0; then
+ # Remove the output line due to the synthetic server-side -k
+ sed -i "/^Keeping temporary directory.*/ d" $tmpdir_server/stderr
+ fi
+
+ if test $p_phase = 5; then
+ # Remove the output line due to the synthetic server-side -p4
+ sed -i "/^.*\.ko$/ d" $tmpdir_server/stdout
+ fi
}
# function: find_and_connect_to_server
diff --git a/stap-server-connect.c b/stap-server-connect.c
index cf0e5a65..bbf5ade7 100644
--- a/stap-server-connect.c
+++ b/stap-server-connect.c
@@ -1,9 +1,9 @@
/*
SSL server program listens on a port, accepts client connection, reads
- the data into a temporary file, calls the systemtap server script and
- then transmits the resulting fileback to the client.
+ the data into a temporary file, calls the systemtap translator and
+ then transmits the resulting file back to the client.
- Copyright (C) 2008, 2009 Red Hat Inc.
+ Copyright (C) 2008-2010 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 Public
@@ -23,7 +23,16 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <errno.h>
+#include <spawn.h>
+#include <fcntl.h>
+#include <glob.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <wordexp.h>
+#include <sys/param.h>
#include <ssl.h>
#include <nspr.h>
@@ -31,19 +40,21 @@
#include <nss.h>
#include <pk11func.h>
+#include "config.h"
#include "nsscommon.h"
-#define READ_BUFFER_SIZE (60 * 1024)
/* Global variables */
static char *password = NULL;
static CERTCertificate *cert = NULL;
static SECKEYPrivateKey *privKey = NULL;
static char *dbdir = NULL;
-static char requestFileName[] = "/tmp/stap.server.client.zip.XXXXXX";
-static char responseDirName[] = "/tmp/stap.server.XXXXXX";
-static char responseZipName[] = "/tmp/stap.server.XXXXXX.zip.XXXXXX";
-static const char *stapOptions = "";
+static const char *stapOptions = "";
+
+
+static PRStatus spawn_and_wait (char **argv,
+ const char* fd0, const char* fd1, const char* fd2, const char *pwd);
+
static void
Usage(const char *progName)
@@ -72,24 +83,27 @@ exitErr(char *function)
exit(1);
}
+
+
+
/* Function: readDataFromSocket()
*
* Purpose: Read data from the socket into a temporary file.
*
*/
-static SECStatus
-readDataFromSocket(PRFileDesc *sslSocket)
+static SECStatus readDataFromSocket(PRFileDesc *sslSocket, const char *requestFileName)
{
PRFileDesc *local_file_fd;
PRFileInfo info;
PRInt32 numBytesRead;
PRInt32 numBytesWritten;
PRInt32 totalBytes;
+#define READ_BUFFER_SIZE 4096
char buffer[READ_BUFFER_SIZE];
/* Open the output file. */
local_file_fd = PR_Open(requestFileName, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
- PR_IRUSR | PR_IWUSR | PR_IRGRP | PR_IWGRP | PR_IROTH);
+ PR_IRUSR | PR_IWUSR);
if (local_file_fd == NULL)
{
fprintf (stderr, "could not open output file %s\n", requestFileName);
@@ -97,6 +111,7 @@ readDataFromSocket(PRFileDesc *sslSocket)
}
/* Read the number of bytes to be received. */
+ /* XXX: impose a limit to prevent disk space consumption DoS */
numBytesRead = PR_Read(sslSocket, & info.size, sizeof (info.size));
if (numBytesRead == 0) /* EOF */
{
@@ -123,10 +138,11 @@ readDataFromSocket(PRFileDesc *sslSocket)
/* Write to stdout */
numBytesWritten = PR_Write(local_file_fd, buffer, numBytesRead);
- if (numBytesWritten < 0)
- fprintf (stderr, "could not write to output file %s\n", requestFileName);
- if (numBytesWritten != numBytesRead)
- fprintf (stderr, "could not write to output file %s\n", requestFileName);
+ if (numBytesWritten < 0 || (numBytesWritten != numBytesRead))
+ {
+ fprintf (stderr, "could not write to output file %s\n", requestFileName);
+ break;
+ }
#if DEBUG
fprintf(stderr, "***** Connection read %d bytes.\n", numBytesRead);
#if 0
@@ -317,27 +333,15 @@ authenticateSocket(PRFileDesc *sslSocket, PRBool requireCert)
*
*/
static SECStatus
-writeDataToSocket(PRFileDesc *sslSocket)
+writeDataToSocket(PRFileDesc *sslSocket, const char *responseFileName)
{
int numBytes;
PRFileDesc *local_file_fd;
- PRFileInfo info;
- PRStatus prStatus;
- /* Try to open the local file named.
- * If successful, then write it to the client.
- */
- prStatus = PR_GetFileInfo(responseZipName, &info);
- if (prStatus != PR_SUCCESS || info.type != PR_FILE_FILE || info.size < 0)
- {
- fprintf (stderr, "Input file %s not found\n", responseZipName);
- return SECFailure;
- }
-
- local_file_fd = PR_Open(responseZipName, PR_RDONLY, 0);
+ local_file_fd = PR_Open(responseFileName, PR_RDONLY, 0);
if (local_file_fd == NULL)
{
- fprintf (stderr, "Could not open input file %s\n", responseZipName);
+ fprintf (stderr, "Could not open input file %s\n", responseFileName);
return SECFailure;
}
@@ -357,7 +361,7 @@ writeDataToSocket(PRFileDesc *sslSocket)
#if DEBUG
/* Transmitted bytes successfully. */
fprintf(stderr, "PR_TransmitFile wrote %d bytes from %s\n",
- numBytes, responseZipName);
+ numBytes, responseFileName);
#endif
PR_Close(local_file_fd);
@@ -365,10 +369,303 @@ writeDataToSocket(PRFileDesc *sslSocket)
return SECSuccess;
}
+
+/* Run the translator on the data in the request directory, and produce output
+ in the given output directory. */
+static void handleRequest (const char* requestDirName, const char* responseDirName)
+{
+ char stapstdout[PATH_MAX];
+ char stapstderr[PATH_MAX];
+ char staprc[PATH_MAX];
+#define MAXSTAPARGC 1000 /* sorry, too lazy to dynamically allocate */
+ char* stapargv[MAXSTAPARGC];
+ int stapargc=0;
+ int rc;
+ wordexp_t words;
+ int i;
+ FILE* f;
+ int unprivileged = 0;
+ int stapargv_freestart = 0;
+
+ stapargv[stapargc++]= STAP_PREFIX "/bin/stap";
+
+ /* Transcribe stapOptions. We use plain wordexp(3), since these
+ options are coming from the local trusted user, so malicious
+ content is not a concern. */
+
+ rc = wordexp (stapOptions, & words, WRDE_NOCMD|WRDE_UNDEF);
+ if (rc)
+ {
+ errWarn("cannot parse -s stap options");
+ return;
+ }
+ if (words.we_wordc+10 >= MAXSTAPARGC) /* 10: padding for literal entries */
+ {
+ errWarn("too many -s options; MAXSTAPARGC");
+ return;
+ }
+
+ for (i=0; i<words.we_wordc; i++)
+ stapargv[stapargc++] = words.we_wordv[i];
+
+ stapargv[stapargc++] = "-k"; /* Need to keep temp files in order to package them up again. */
+
+ /* Process the saved command line arguments. Avoid quoting/unquoting errors by
+ transcribing literally. */
+ stapargv[stapargc++] = "--client-options";
+ stapargv_freestart = stapargc;
+
+ for (i=1 ; ; i++)
+ {
+ char stapargfile[PATH_MAX];
+ FILE* argfile;
+ struct stat st;
+ char *arg;
+
+ if (stapargc >= MAXSTAPARGC)
+ {
+ errWarn("too many stap options; MAXSTAPARGC");
+ return;
+ }
+
+ snprintf (stapargfile, PATH_MAX, "%s/argv%d", requestDirName, i);
+
+ rc = stat(stapargfile, & st);
+ if (rc) break;
+
+ arg = malloc (st.st_size+1);
+ if (!arg)
+ {
+ errWarn("stap arg malloc");
+ return;
+ }
+
+ argfile = fopen(stapargfile, "r");
+ if (! argfile)
+ {
+ errWarn("stap arg fopen");
+ return;
+ }
+
+ rc = fread(arg, 1, st.st_size, argfile);
+ if (rc != st.st_size)
+ {
+ errWarn("stap arg fread");
+ return;
+ }
+
+ arg[st.st_size] = '\0';
+ stapargv[stapargc++] = arg; /* freed later */
+ fclose (argfile);
+ }
+
+ snprintf (stapstdout, PATH_MAX, "%s/stdout", responseDirName);
+ snprintf (stapstderr, PATH_MAX, "%s/stderr", responseDirName);
+
+ stapargv[stapargc] = NULL; /* spawn_and_wait expects NULL termination */
+
+ /* Check for the unprivileged flag; we need this so that we can decide to sign the module. */
+ for (i=0; i<stapargc; i++)
+ if (strcmp (stapargv[i], "--unprivileged") == 0)
+ unprivileged=1;
+ /* NB: but it's not that easy! What if an attacker passes
+ --unprivileged as some sort of argument-parameter, so that the
+ translator does not interpret it as an --unprivileged mode flag,
+ but something else? Then it could generate unrestrained modules,
+ but silly we might still sign it, and let the attacker get away
+ with murder. And yet we don't want to fully getopt-parse the
+ args here for duplication of effort.
+
+ So let's do a hack: forcefully add --unprivileged to stapargv[]
+ near the front in this case, something which a later option
+ cannot undo. */
+ if (unprivileged)
+ {
+ if (stapargc+1 >= MAXSTAPARGC)
+ {
+ errWarn("too many stap options; MAXSTAPARGC");
+ return;
+ }
+
+ /* Shift all stapargv[] entries up one, including the NULL. */
+ for (i=stapargc; i>=1; i--)
+ stapargv[i+1]=stapargv[i];
+ stapargv_freestart ++; /* adjust for shift */
+
+ stapargv[1]="--unprivileged"; /* better not be resettable by later option */
+ }
+
+ /* All ready, let's run the translator! */
+ rc = spawn_and_wait (stapargv, "/dev/null", stapstdout, stapstderr, requestDirName);
+
+ /* Save the RC */
+ snprintf (staprc, PATH_MAX, "%s/rc", responseDirName);
+ f = fopen(staprc, "w");
+ if (f)
+ {
+ /* best effort basis */
+ fprintf(f, "%d", rc);
+ fclose(f);
+ }
+
+ /* Parse output to extract the -k-saved temprary directory.
+ XXX: bletch. */
+ f = fopen(stapstderr, "r");
+ if (!f)
+ {
+ errWarn("stap stderr open");
+ return;
+ }
+
+ while (1)
+ {
+ char line[PATH_MAX];
+ char *l = fgets(line, PATH_MAX, f); /* NB: normally includes \n at end */
+ if (!l) break;
+ char key[]="Keeping temporary directory \"";
+
+ /* Look for line from main.cxx: s.keep_tmpdir */
+ if (strncmp(l, key, strlen(key)) == 0 &&
+ l[strlen(l)-2] == '"') /* "\n */
+ {
+ /* Move this directory under responseDirName. We don't have to
+ preserve the exact stapXXXXXX suffix part, since stap-client
+ will accept anything ("stap......" regexp), and rewrite it
+ to a client-local string.
+
+ We don't just symlink because then we'd have to
+ remember to delete it later anyhow. */
+ char *mvargv[10];
+ char *orig_staptmpdir = & l[strlen(key)];
+ char new_staptmpdir[PATH_MAX];
+
+ orig_staptmpdir[strlen(orig_staptmpdir)-2] = '\0'; /* Kill the closing "\n */
+ snprintf(new_staptmpdir, PATH_MAX, "%s/stap000000", responseDirName);
+ mvargv[0]="mv";
+ mvargv[1]=orig_staptmpdir;
+ mvargv[2]=new_staptmpdir;
+ mvargv[3]=NULL;
+ rc = spawn_and_wait (mvargv, NULL, NULL, NULL, NULL);
+ if (rc != PR_SUCCESS)
+ errWarn("stap tmpdir move");
+
+ /* In unprivileged mode, if we have a module built, we need to
+ sign the sucker. */
+ if (unprivileged)
+ {
+ glob_t globber;
+ char pattern[PATH_MAX];
+ snprintf (pattern,PATH_MAX,"%s/*.ko", new_staptmpdir);
+ rc = glob (pattern, GLOB_ERR, NULL, &globber);
+ if (rc)
+ errWarn("stap tmpdir .ko glob");
+ else if (globber.gl_pathc != 1)
+ errWarn("stap tmpdir too many .ko globs");
+ else
+ {
+ char *signargv [10];
+ signargv[0] = STAP_PREFIX "/libexec/systemtap/stap-sign-module";
+ signargv[1] = globber.gl_pathv[0];
+ signargv[2] = dbdir;
+ signargv[3] = NULL;
+ rc = spawn_and_wait (signargv, NULL, NULL, NULL, NULL);
+ if (rc != PR_SUCCESS)
+ errWarn("stap-sign-module");
+ }
+ }
+ }
+
+ /* XXX: What about uprobes.ko? */
+ }
+
+ /* Free up all the arg string copies. Note that the first few were alloc'd
+ by wordexp(), which wordfree() frees; others were hand-set to literal strings. */
+ for (i= stapargv_freestart; i<stapargc; i++)
+ free (stapargv[i]);
+ wordfree (& words);
+
+ /* Sorry about the inconvenience. C string/file processing is such a pleasure. */
+}
+
+
+/* A frontend for posix_spawnp that waits for the child process and
+ returns overall success or failure. */
+static PRStatus spawn_and_wait (char ** argv,
+ const char* fd0, const char* fd1, const char* fd2, const char *pwd)
+{
+ pid_t pid;
+ int rc;
+ int status;
+ extern char** environ;
+ posix_spawn_file_actions_t actions;
+ int dotfd = -1;
+
+#define CHECKRC(msg) do { if (rc) { errWarn(msg); return PR_FAILURE; } } while (0)
+
+ rc = posix_spawn_file_actions_init (& actions);
+ CHECKRC ("spawn file actions ctor");
+ if (fd0) {
+ rc = posix_spawn_file_actions_addopen(& actions, 0, fd0, O_RDONLY, 0600);
+ CHECKRC ("spawn file actions fd0");
+ }
+ if (fd1) {
+ rc = posix_spawn_file_actions_addopen(& actions, 1, fd1, O_WRONLY|O_CREAT, 0600);
+ CHECKRC ("spawn file actions fd1");
+ }
+ if (fd2) {
+ rc = posix_spawn_file_actions_addopen(& actions, 2, fd2, O_WRONLY|O_CREAT, 0600);
+ CHECKRC ("spawn file actions fd2");
+ }
+
+ /* change temporarily to a directory if requested */
+ if (pwd)
+ {
+ dotfd = open (".", O_RDONLY);
+ if (dotfd < 0)
+ {
+ errWarn ("spawn getcwd");
+ return PR_FAILURE;
+ }
+
+ rc = chdir (pwd);
+ CHECKRC ("spawn chdir");
+ }
+
+ rc = posix_spawnp (& pid, argv[0], & actions, NULL, argv, environ);
+ /* NB: don't react to rc!=0 right away; need to chdir back first. */
+
+ if (pwd && dotfd >= 0)
+ {
+ int subrc;
+ subrc = fchdir (dotfd);
+ subrc |= close (dotfd);
+ if (subrc)
+ errWarn("spawn unchdir");
+ }
+
+ CHECKRC ("spawn");
+
+ rc = waitpid (pid, &status, 0);
+ if ((rc!=pid) || !WIFEXITED(status))
+ {
+ errWarn ("waitpid");
+ return PR_FAILURE;
+ }
+
+ rc = posix_spawn_file_actions_destroy (&actions);
+ CHECKRC ("spawn file actions dtor");
+
+ return WEXITSTATUS(status) ? PR_FAILURE : PR_SUCCESS;
+#undef CHECKRC
+}
+
+
+
/* Function: int handle_connection()
*
- * Purpose: Handle a connection to a socket.
- *
+ * Purpose: Handle a connection to a socket. Copy in request zip
+ * file, process it, copy out response. Temporary directories are
+ * created & destroyed here.
*/
static SECStatus
handle_connection(PRFileDesc *tcpSocket)
@@ -377,11 +674,16 @@ handle_connection(PRFileDesc *tcpSocket)
SECStatus secStatus = SECFailure;
PRStatus prStatus;
PRSocketOptionData socketOption;
- PRFileInfo info;
- char *cmdline;
- char *stap_server_prefix;
int rc;
char *rc1;
+ char tmpdir[PATH_MAX];
+ char requestFileName[PATH_MAX];
+ char requestDirName[PATH_MAX];
+ char responseDirName[PATH_MAX];
+ char responseFileName[PATH_MAX];
+ char *argv[10]; /* we use fewer than these in all the posix_spawn's below. */
+
+ tmpdir[0]='\0'; /* prevent cleanup-time /bin/rm of uninitialized directory */
/* Make sure the socket is blocking. */
socketOption.option = PR_SockOpt_Nonblocking;
@@ -410,50 +712,49 @@ handle_connection(PRFileDesc *tcpSocket)
goto cleanup;
}
- /* Create a temporary files and directories. */
- memcpy (requestFileName + sizeof (requestFileName) - 1 - 6, "XXXXXX", 6);
- rc = mkstemp(requestFileName);
- if (rc == -1)
+ snprintf(tmpdir, PATH_MAX, "%s/stap-server.XXXXXX", getenv("TMPDIR") ?: "/tmp");
+ rc1 = mkdtemp(tmpdir);
+ if (! rc1)
{
- fprintf (stderr, "Could not create temporary file %s\n", requestFileName);
+ fprintf (stderr, "Could not create temporary directory %s\n", tmpdir);
perror ("");
secStatus = SECFailure;
+ tmpdir[0]=0; /* prevent /bin/rm */
goto cleanup;
}
- memcpy (responseDirName + sizeof (responseDirName) - 1 - 6, "XXXXXX", 6);
- rc1 = mkdtemp(responseDirName);
- if (! rc1)
+ /* Create a temporary files names and directories. */
+ snprintf (requestFileName, PATH_MAX, "%s/request.zip", tmpdir);
+
+ snprintf (requestDirName, PATH_MAX, "%s/request", tmpdir);
+ rc = mkdir(requestDirName, 0700);
+ if (rc)
{
- fprintf (stderr, "Could not create temporary directory %s\n", responseDirName);
+ fprintf (stderr, "Could not create temporary directory %s\n", requestDirName);
perror ("");
secStatus = SECFailure;
goto cleanup;
}
- memcpy (responseZipName, responseDirName, sizeof (responseDirName) - 1);
- memcpy (responseZipName + sizeof (responseZipName) - 1 - 6, "XXXXXX", 6);
- rc = mkstemp(responseZipName);
- if (rc == -1)
+ snprintf (responseDirName, PATH_MAX, "%s/response", tmpdir);
+ rc = mkdir(responseDirName, 0700);
+ if (rc)
{
- fprintf (stderr, "Could not create temporary file %s\n", responseZipName);
+ fprintf (stderr, "Could not create temporary directory %s\n", responseDirName);
perror ("");
secStatus = SECFailure;
-
- /* Remove this so that the other temp files will get removed in cleanup. */
- prStatus = PR_RmDir (responseDirName);
- if (prStatus != PR_SUCCESS)
- errWarn ("PR_RmDir");
goto cleanup;
}
+ snprintf (responseFileName, PATH_MAX, "%s/response.zip", tmpdir);
+
/* Read data from the socket.
* If the user is requesting/requiring authentication, authenticate
* the socket. */
#if DEBUG
fprintf(stdout, "\nReading data from socket...\n\n");
#endif
- secStatus = readDataFromSocket(sslSocket);
+ secStatus = readDataFromSocket(sslSocket, requestFileName);
if (secStatus != SECSuccess)
goto cleanup;
@@ -467,32 +768,42 @@ handle_connection(PRFileDesc *tcpSocket)
}
#endif
- /* Call the stap-server-request script. */
- stap_server_prefix = getenv("SYSTEMTAP_SERVER_SCRIPTS") ?: PKGLIBDIR;
- cmdline = PORT_Alloc(strlen (stap_server_prefix) + sizeof ("/stap-server-request") + 1 +
- sizeof (requestFileName) + 1 +
- sizeof (responseDirName) + 1 +
- sizeof (responseZipName) + 1 +
- strlen (dbdir) + 1 +
- 1 + strlen (stapOptions) + 1 +
- 1);
- if (! cmdline) {
- errWarn ("PORT_Alloc");
- secStatus = SECFailure;
- goto cleanup;
- }
-
- sprintf (cmdline, "%s/stap-server-request %s %s %s %s '%s'", stap_server_prefix,
- requestFileName, responseDirName, responseZipName, dbdir,
- stapOptions);
- rc = system (cmdline);
-
- PR_Free (cmdline);
+ /* Unzip the request. */
+ argv[0]="unzip";
+ argv[1]="-d";
+ argv[2]=requestDirName;
+ argv[3]=requestFileName;
+ rc = spawn_and_wait(argv, NULL, NULL, NULL, NULL);
+ if (rc != PR_SUCCESS)
+ {
+ errWarn ("request unzip");
+ secStatus = SECFailure;
+ goto cleanup;
+ }
+ /* Handle the request zip file. An error therein should still result
+ in a response zip file (containing stderr etc.) so we don't have to
+ have a result code here. */
+ handleRequest(requestDirName, responseDirName);
+
+ /* Zip the response. */
+ argv[0]="zip";
+ argv[1]="-r";
+ argv[2]=responseFileName;
+ argv[3]=".";
+ argv[4]=NULL;
+ rc = spawn_and_wait(argv, NULL, NULL, NULL, responseDirName);
+ if (rc != PR_SUCCESS)
+ {
+ errWarn ("response zip");
+ secStatus = SECFailure;
+ goto cleanup;
+ }
+
#if DEBUG
fprintf(stdout, "\nWriting data to socket...\n\n");
#endif
- secStatus = writeDataToSocket(sslSocket);
+ secStatus = writeDataToSocket(sslSocket, responseFileName);
cleanup:
/* Close down the socket. */
@@ -500,17 +811,16 @@ cleanup:
if (prStatus != PR_SUCCESS)
errWarn("PR_Close");
- /* Attempt to remove temporary files, unless the temporary directory was
- not deleted by the server script. */
- prStatus = PR_GetFileInfo(responseDirName, &info);
- if (prStatus != PR_SUCCESS)
+ if (tmpdir[0])
{
- prStatus = PR_Delete (requestFileName);
- if (prStatus != PR_SUCCESS)
- errWarn ("PR_Delete");
- prStatus = PR_Delete (responseZipName);
- if (prStatus != PR_SUCCESS)
- errWarn ("PR_Delete");
+ /* Remove the whole tmpdir and all that lies beneath. */
+ argv[0]="rm";
+ argv[1]="-r";
+ argv[2]=tmpdir;
+ argv[3]=NULL;
+ rc = spawn_and_wait(argv, NULL, NULL, NULL, NULL);
+ if (rc != PR_SUCCESS)
+ errWarn ("tmpdir cleanup");
}
return secStatus;
@@ -554,6 +864,9 @@ accept_connection(PRFileDesc *listenSocket)
addr.inet.port);
fflush (stdout);
+ /* XXX: alarm() or somesuch to set a timeout. */
+ /* XXX: fork() or somesuch to handle concurrent requests. */
+
/* Accepted the connection, now handle it. */
/*result =*/ handle_connection (tcpSocket);
@@ -564,16 +877,6 @@ accept_connection(PRFileDesc *listenSocket)
(addr.inet.ip >> 24) & 0xff,
addr.inet.port);
fflush (stdout);
-
-#if 0 /* Not necessary */
- if (result != SECSuccess)
- {
- prStatus = PR_Close(tcpSocket);
- if (prStatus != PR_SUCCESS)
- exitErr("PR_Close");
- break;
- }
-#endif
}
#if DEBUG
diff --git a/stap-server-request b/stap-server-request
deleted file mode 100755
index d1731895..00000000
--- a/stap-server-request
+++ /dev/null
@@ -1,512 +0,0 @@
-#!/bin/bash
-
-# Compile server for systemtap
-#
-# Copyright (C) 2008, 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
-# Public License (GPL); either version 2, or (at your option) any
-# later version.
-
-# This script unpacks the tar file provided on stdin and uses the information
-# contained in the unpacked tree to build the requested systemtap kernel module.
-# This module is then written to stdout.
-
-# Catch ctrl-c and other termination signals
-trap 'terminate' SIGTERM SIGINT
-
-# Initialize the environment
-. ${PKGLIBEXECDIR}stap-env
-
-#-----------------------------------------------------------------------------
-# Helper functions.
-#-----------------------------------------------------------------------------
-# function: initialization
-function initialization {
- # Initialization
- stap_rc=0
- wd=`pwd`
-
- # Default options settings
- p_phase=5
- keep_temps=0
- unprivileged=0
- stap_options=
-
- zip_client=$1
- tmpdir_server=$2
- zip_server=$3
- ssl_db=$4
- server_options="$5"
-
- # This script is not intended to be called directly, so if the arguments
- # aren't specified correctly, just exit with non-zero
- test "X$tmpdir_server" != "X" || exit 2
- test -d $tmpdir_server || exit 3
- tmpdir_env=`dirname $tmpdir_server`
-
- # Response file name.
- test "X$zip_server" != "X" || exit 4
- # Make sure the specified .zip file exists.
- test -f $zip_server || exit 5
-
- # Request file name.
- test "X$zip_client" != "X" || exit 6
- test -f $zip_client || exit 7
-
- # Where is the ssl certificate/key database?
- test "X$ssl_db" != "X" || exit 8
- test -d $ssl_db || exit 9
- nss_pw=$ssl_db/pw
- test -f $nss_pw || exit 10
-
- # What are the options that the server was started with?
- eval parse_options "$server_options"
-
- nss_cert=stap-server
-
- touch $tmpdir_server/stdout
- touch $tmpdir_server/stderr
-}
-
-# function: unpack_request
-#
-# Unpack the zip file received from the client and make the contents
-# available for use when running 'stap'
-function unpack_request {
- cd $tmpdir_server
-
- # Unpack the zip file.
- unzip $zip_client > /dev/null || \
- fatal "Cannot unpack zip archive $zip_client"
-
- # Identify the client's request tree. The zip file should have expanded
- # into a single directory named to match $stap_tmpdir_prefix_client.??????
- # which should now be the only item in the current directory.
- test "`ls | wc -l`" = 3 || \
- fatal "Wrong number of files after expansion of client's zip file"
-
- tmpdir_client=`ls | grep $stap_tmpdir_prefix_client.......\$`
-
- test "X$tmpdir_client" != "X" || \
- fatal "Client zip file did not expand as expected"
-
- # Move the client's temp directory to a local temp location
- local local_tmpdir_client=`mktemp -dt $stap_tmpdir_prefix_server.client.XXXXXX` || \
- fatal "Cannot create temporary client request directory " $local_tmpdir_client
- mv $tmpdir_client/* $local_tmpdir_client
- rm -fr $tmpdir_client
- tmpdir_client=$local_tmpdir_client
-}
-
-# function: check_request
-#
-# Examine the contents of the request to make sure that they are valid.
-function check_request {
- # Work in the temporary directory provided by the client
- cd $tmpdir_client
-
- # Add the necessary info from files in our temporary directory.
- cmdline=`read_data_file cmdline`
- test "X$cmdline" != "X" || exit 1
-
- eval parse_options "$cmdline"
-
- client_sysinfo=`read_data_file sysinfo`
- test "X$client_sysinfo" != "X" || exit 1
-
- check_compatibility "$client_sysinfo" "`server_sysinfo`"
-}
-
-# function server_sysinfo
-#
-# Generate the server's sysinfo and echo it to stdout
-function server_sysinfo {
- if test "X$sysinfo_server" = "X"; then
- # Add some info from uname
- sysinfo_server="`uname -r` `stap_get_arch`"
- fi
- echo "$sysinfo_server"
-}
-
-# function check_compaibility SYSINFO1 SYSINFO2
-#
-# Make sure that systemtap as described by SYSINFO1 and SYSINFO2 are compaible
-function check_compatibility {
- # Compatibility is irrelevant. The client can choose any server
- # it sees fit
- return
-}
-
-# function: read_data_file PREFIX
-#
-# Find a file whose name is '$1' and whose first line
-# contents are '$1: .*'. Read and echo the data.
-function read_data_file {
- test -f $1 || \
- fatal "Data file $1 not found"
-
- # Open the file
- exec 3< $1
-
- # Verify the first line of the file.
- read <&3
- line="$REPLY"
- data=`expr "$line" : "$1: \\\(.*\\\)"`
- if test "X$data" = "X"; then
- fatal "Data in file $1 is incorrect"
- return
- fi
-
- # Close the file
- exec 3<&-
-
- # Now read the entire file.
- cat $1 | sed "s/$1: //"
-}
-
-# function: parse_options [ STAP-OPTIONS ]
-#
-# Examine the command line. We need not do much checking, but we do need to
-# parse all options in order to discover the ones we're interested in.
-function parse_options {
- # We need to know in advance if --unprivileged was specified.
- all_options=" ""$@"" "
- token=`expr "$all_options" : '.* \(--unprivileged\) .*'`
- if test "X$token" = "X--unprivileged"; then
- unprivileged=1
- fi
-
- while test $# != 0
- do
- advance_p=0
- dash_seen=0
-
- # Start of a new token.
- first_token=$1
-
- # Process the option.
- until test $advance_p != 0
- do
- # Identify the next option
- first_char=`expr "$first_token" : '\(.\).*'`
- if test $dash_seen = 0; then
- if test "$first_char" = "-"; then
- if test "$first_token" != "-"; then
- # It's not a lone dash, so it's an option.
- # Is it a long option (i.e. --option)?
- second_char=`expr "$first_token" : '.\(.\).*'`
- if test "X$second_char" = "X-"; then
- advance_p=$(($advance_p + 1))
- stap_options="$stap_options $first_token"
- break
- fi
- # It's not a lone dash, or a long option, so it's a short option string.
- # Remove the dash.
- first_token=`expr "$first_token" : '-\(.*\)'`
- dash_seen=1
- first_char=`expr "$first_token" : '\(.\).*'`
- fi
- fi
- if test $dash_seen = 0; then
- # The dash has not been seen. This is either the script file
- # name or an arument to be passed to the probe module.
- # If this is the first time, and -e has not been specified,
- # then it could be the name of the script file.
- if test "X$e_script" = "X" -a "X$script_file" = "X"; then
- script_file="$first_token"
- fi
- if test "$first_char" != "'"; then
- stap_options="$stap_options '$first_token'"
- else
- stap_options="$stap_options $first_token"
- fi
- advance_p=$(($advance_p + 1))
- break
- fi
- fi
-
- # We are at the start of an option. Look at the first character.
- case $first_char in
- a)
- get_arg $first_token $2
- if test $unprivileged = 1; then
- fatal "You can't specify -$first_char and --unprivileged together."
- else
- stap_options="$stap_options -$first_char $stap_arg"
- fi
- ;;
- B)
- get_arg $first_token $2
- if test $unprivileged = 1; then
- fatal "You can't specify -$first_char and --unprivileged together."
- else
- stap_options="$stap_options -$first_char $stap_arg"
- fi
- ;;
- d)
- get_arg $first_token $2
- stap_options="$stap_options -$first_char $stap_arg"
- ;;
- D)
- get_arg $first_token $2
- if test $unprivileged = 1; then
- fatal "You can't specify -$first_char and --unprivileged together."
- else
- stap_options="$stap_options -$first_char $stap_arg"
- fi
- ;;
- e)
- get_arg $first_token "$2"
- stap_options="$stap_options -$first_char '$stap_arg'"
- process_e "$stap_arg"
- ;;
- I)
- get_arg $first_token $2
- if test $unprivileged = 1; then
- fatal "You can't specify -$first_char and --unprivileged together."
- else
- stap_options="$stap_options -$first_char $stap_arg"
- fi
- ;;
- k)
- keep_temps=1
- ;;
- l)
- get_arg $first_token $2
- stap_options="$stap_options -$first_char $stap_arg"
- process_p 2
- ;;
- L)
- get_arg $first_token $2
- stap_options="$stap_options -$first_char $stap_arg"
- process_p 2
- ;;
- m)
- get_arg $first_token $2
- if test $unprivileged = 1; then
- fatal "You can't specify -$first_char and --unprivileged together."
- else
- stap_options="$stap_options -$first_char $stap_arg"
- fi
- ;;
- o)
- get_arg $first_token $2
- stap_options="$stap_options -$first_char $stap_arg"
- ;;
- p)
- get_arg $first_token $2
- process_p $stap_arg
- ;;
- r)
- get_arg $first_token $2
- if test $unprivileged = 1; then
- fatal "You can't specify -$first_char and --unprivileged together."
- else
- stap_options="$stap_options -$first_char $stap_arg"
- fi
- ;;
- R)
- get_arg $first_token $2
- if test $unprivileged = 1; then
- fatal "You can't specify -$first_char and --unprivileged together."
- else
- stap_options="$stap_options -$first_char $stap_arg"
- fi
- ;;
- s)
- get_arg $first_token $2
- stap_options="$stap_options -$first_char $stap_arg"
- ;;
- S)
- get_arg $first_token $2
- stap_options="$stap_options -$first_char $stap_arg"
- ;;
- x)
- get_arg $first_token $2
- stap_options="$stap_options -$first_char $stap_arg"
- ;;
- *)
- # An unknown flag. Ignore it.
- ;;
- esac
-
- if test $advance_p = 0; then
- # Just another flag character. Consume it.
- stap_options="$stap_options -$first_char"
- first_token=`expr "$first_token" : '.\(.*\)'`
- if test "X$first_token" = "X"; then
- advance_p=$(($advance_p + 1))
- fi
- fi
- done
-
- # Consume the arguments we just processed.
- while test $advance_p != 0
- do
- shift
- advance_p=$(($advance_p - 1))
- done
- done
-}
-
-# function: get_arg FIRSTWORD SECONDWORD
-#
-# Collect an argument to the given option
-function get_arg {
- # Remove first character. Advance to the next token, if the first one
- # is exhausted.
- local first=`expr "$1" : '.\(.*\)'`
- if test "X$first" = "X"; then
- shift
- advance_p=$(($advance_p + 1))
- first=$1
- fi
- stap_arg="$first"
- advance_p=$(($advance_p + 1))
-}
-
-# function: process_e ARGUMENT
-#
-# Process the -e flag.
-function process_e {
- if test "X$e_script" = "X"; then
- e_script="$1"
- script_file=
- fi
-}
-
-# function: process_p ARGUMENT
-#
-# Process the -p flag.
-function process_p {
- if test $1 -ge 1 -a $1 -le 5; then
- p_phase=$1
- fi
-}
-
-# function: call_stap
-#
-# Call 'stap' with the options provided. Don't run past phase 4.
-function call_stap {
- # Invoke systemtap.
- # Use -k so we can return results to the client
- # Limit to -p4. i.e. don't run the module
- cd $tmpdir_client
- if test $p_phase -gt 4; then
- server_p_phase=4
- else
- server_p_phase=$p_phase
- fi
-
- eval ${stap_exec_prefix}stap "$stap_options" -k -p $server_p_phase \
- >> $tmpdir_server/stdout \
- 2>> $tmpdir_server/stderr
-
- stap_rc=$?
-}
-
-# function: create_response
-#
-# Add information to the server's temp directory representing the response
-# to the client.
-function create_response {
- cd $tmpdir_server
-
- # Get the name of the stap temp directory, which was kept, from stderr.
- tmpdir_line=`cat stderr | grep "Keeping temp"`
- tmpdir_stap=`expr "$tmpdir_line" : '.*"\(.*\)".*'`
-
- # Remove the message about keeping the stap temp directory from stderr, unless
- # the user did request to keep it.
- if test "X$tmpdir_stap" != "X"; then
- if test $keep_temps != 1; then
- sed -i "/^Keeping temp/d" stderr
- fi
-
- # Add the contents of the stap temp directory to the server output directory
- ln -s $tmpdir_stap `basename $tmpdir_stap`
-
- # Sign the resulting module if --unprivileged was specified.
- if test $unprivileged = 1 -a $p_phase -ge 4 -a $stap_rc = 0; then
- modname=$tmpdir_stap/`grep -m1 '^.*\.ko$' stdout`
- if test "X$modname" != "X"; then
- ${stap_pkglibexecdir}stap-sign-module $modname $ssl_db
- fi
- fi
- fi
-
- # If the user specified -p5, remove the name of the kernel module from stdout.
- if test $p_phase = 5; then
- sed -i '/\.ko$/d' stdout
- fi
-
- # The return status of the stap command.
- echo -n $stap_rc > rc
-}
-
-# function: package_response
-#
-# Package the server's temp directory into a form suitable for sending to the
-# client.
-function package_response {
- cd $tmpdir_env
-
- # Compress the server's temporary directory into a .zip archive.
- (rm $zip_server && zip -r $zip_server `basename $tmpdir_server` > /dev/null)
- return $?
-}
-
-# function: fatal [ MESSAGE ]
-#
-# Fatal error
-# Prints its arguments to stderr and exits
-function fatal {
- echo "$0: ERROR:" "$@" >> $tmpdir_server/stderr
- echo -n 1 > $tmpdir_server/rc
- package_response
- cleanup
- exit 1
-}
-
-# Non fatal error
-# Prints its arguments to stderr but does not exit
-function error {
- echo "$0: ERROR:" "$@" >> $tmpdir_server/stderr
-}
-
-# function cleanup
-#
-# Cleanup work files unless asked to keep them.
-function cleanup {
- # Clean up.
- cd $tmpdir_env
- if test $keep_temps != 1; then
- rm -fr $tmpdir_server
- rm -fr $tmpdir_client
- rm -fr $tmpdir_stap
- fi
-}
-
-# function: terminate
-#
-# Terminate gracefully.
-function terminate {
- # Clean up
- cleanup
- exit 1
-}
-
-#-----------------------------------------------------------------------------
-# Beginning of main line execution.
-#-----------------------------------------------------------------------------
-initialization "$@"
-unpack_request
-check_request
-call_stap
-create_response
-package_response
-cleanup
-
-exit 0
diff --git a/stap-serverd b/stap-serverd
index f3df884d..4d8a10ce 100755
--- a/stap-serverd
+++ b/stap-serverd
@@ -38,6 +38,8 @@ function initialization {
# Parse the arguments
parse_options "$@"
+ echo ===== compile server pid $$ started >> $logfile
+
# What port will we listen on?
test "X$port" = "X" && port=$((1024+$RANDOM%64000))
while netstat -atn | awk '{print $4}' | cut -f2 -d: | egrep -q "^$port\$";
diff --git a/tapsets.cxx b/tapsets.cxx
index 7835b39a..071f92db 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -4632,6 +4632,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->line() << " .procname=\"" << p->path << "\", ";
s.op->line() << " .mmap_callback=&stap_uprobe_mmap_found, ";
s.op->line() << " .munmap_callback=&stap_uprobe_munmap_found, ";
+ s.op->line() << " .callback=&stap_uprobe_process_munmap,";
}
s.op->line() << " },";
diff --git a/testsuite/systemtap.server/client_args.exp b/testsuite/systemtap.server/client_args.exp
index 348f8cea..f41b91cb 100644
--- a/testsuite/systemtap.server/client_args.exp
+++ b/testsuite/systemtap.server/client_args.exp
@@ -1,11 +1,11 @@
-set test "Valid Server Client Arguments"
+set test "Invalid Server Client Arguments"
# Test that stap on the server side will correctly accept/reject certain
# arguments in unprivileged mode.
set test_file $srcdir/systemtap.server/test.stp
# Test invalid combinations.
-set error_regexp ".*You can't specify (-\[aBDImRr\], )*-\[aBDImRr\] when --unprivileged is specified.*"
+set error_regexp ".*You can't specify .* when --unprivileged is specified.*"
set invalid_options [list \
"--unprivileged --client-options -a i386" \