From 6fa7bd6e70f8f6d783395399c92a9a13d24ce997 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Fri, 5 Sep 2008 13:02:37 -0400 Subject: remove capability logic It was only barely beneficial anyway, since some crucial capabilities were never permanently dropped. --- runtime/staprun/cap.c | 166 -------------------------------------------------- 1 file changed, 166 deletions(-) delete mode 100644 runtime/staprun/cap.c diff --git a/runtime/staprun/cap.c b/runtime/staprun/cap.c deleted file mode 100644 index 6ac6701f..00000000 --- a/runtime/staprun/cap.c +++ /dev/null @@ -1,166 +0,0 @@ -/* -*- linux-c -*- - * - * cap.c - staprun capabilities functions - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * 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) 2007 Red Hat, Inc. - * - */ - -#include "staprun.h" -#include - -static int _stp_no_caps = 0; - -/* like perror, but exits */ -#define ferror(msg) { \ - _perr(msg); \ - exit(1); \ - } \ - -/* - * init_cap() sets up the initial capabilities for staprun. Then - * it calls prctl( PR_SET_KEEPCAPS) to arrrange to keep these capabilities - * even when not running as root. Next it resets the real, effective, and - * saved uid and gid back to the normal user. - * - * There are two sets of capabilities we are concerned with; permitted - * and effective. The permitted capabilities are all the capabilities - * that this process is ever permitted to have. They are defined in init_cap() - * and may be permanently removed with drop_cap(). - * - * Effective capabilities are the capabilities from the permitted set - * that are currently enabled. A good practice would be to only enable - * capabilities when necessary and to delete or drop them as soon as possible. - * - * Capabilities we might use include: - * - * CAP_SYS_MODULE - insert and remove kernel modules - * CAP_SYS_ADMIN - misc, including mounting and unmounting - * CAP_SYS_NICE - setpriority() - * CAP_SETUID - allows setuid - * CAP_SETGID - allows setgid - * CAP_CHOWN - allows chown - */ - -void init_cap(void) -{ - cap_t caps = cap_init(); - cap_value_t capv[] = { CAP_SYS_MODULE, CAP_SYS_ADMIN, CAP_SYS_NICE, CAP_SETUID, CAP_SETGID, CAP_DAC_OVERRIDE }; - const int numcaps = sizeof(capv) / sizeof(capv[0]); - uid_t uid = getuid(); - gid_t gid = getgid(); - - cap_clear(caps); - if (caps == NULL) - ferror("cap_init"); - - if (cap_set_flag(caps, CAP_PERMITTED, numcaps, capv, CAP_SET) < 0) - ferror("cap_set_flag"); - - if (cap_set_proc(caps) < 0) { - dbug(1, "Setting capabilities failed. Capabilities disabled.\n"); - _stp_no_caps = 1; - return; - } - - cap_free(caps); - - if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) - ferror("prctl"); - - if (setresuid(uid, uid, uid) < 0) - ferror("setresuid"); - - if (setresgid(gid, gid, gid) < 0) - ferror("setresgid"); -} - -void print_cap(char *text) -{ - int p; - cap_t caps = cap_get_proc(); - uid_t uid, euid, suid; - gid_t gid, egid, sgid; - - if (caps == NULL) { - perr("cap_get_proc"); - return; - } - - getresuid(&uid, &euid, &suid); - getresgid(&gid, &egid, &sgid); - - printf("***** %s\n", text); - - if ((p = prctl(PR_GET_KEEPCAPS, 0, 0, 0, 0)) < 0) - perr("Couldn't get PR_SET_KEEPCAPS flag value"); - else - printf("KEEPCAPS: %d\n", p); - - printf("uid: %d, euid: %d, suid: %d\ngid: %d. egid: %d, sgid: %d\n", uid, euid, suid, gid, egid, sgid); - printf("Caps: %s\n", cap_to_text(caps, NULL)); - cap_free(caps); - printf("*****\n\n"); -} - -/* drop_cap() permanently removes a capability from the permitted set. There is - * no way to recover the capability after this. You do not need to remove - * it from the effective set before calling this. - */ -void drop_cap(cap_value_t cap) -{ - if (_stp_no_caps == 0) { - cap_t caps = cap_get_proc(); - if (caps == NULL) - ferror("cap_get_proc failed"); - if (cap_set_flag(caps, CAP_PERMITTED, 1, &cap, CAP_CLEAR) < 0) - ferror("Could not clear effective capabilities"); - if (cap_set_proc(caps) < 0) - ferror("Could not apply capability set"); - cap_free(caps); - } -} - -/* add_cap() adds a permitted capability to the effective set. */ -void add_cap(cap_value_t cap) -{ - if (_stp_no_caps == 0) { - cap_t caps = cap_get_proc(); - if (caps == NULL) - ferror("cap_get_proc failed"); - if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_SET) < 0) - ferror("Could not set effective capabilities"); - if (cap_set_proc(caps) < 0) - ferror("Could not apply capability set"); - cap_free(caps); - } -} - -/* del_cap() deletes a permitted capability from the effective set. */ -void del_cap(cap_value_t cap) -{ - if (_stp_no_caps == 0) { - cap_t caps = cap_get_proc(); - if (caps == NULL) - ferror("cap_get_proc failed"); - if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_CLEAR) < 0) - ferror("Could not clear effective capabilities"); - if (cap_set_proc(caps) < 0) - ferror("Could not apply capability set"); - cap_free(caps); - } -} -- cgit From 337cd273963410c9a1fa46b10287e72c146df054 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Fri, 5 Sep 2008 13:02:56 -0400 Subject: remove capabilities logic, cont'd --- ChangeLog | 11 +- Makefile.am | 14 ++- Makefile.in | 30 ++--- configure | 238 +--------------------------------------- configure.ac | 13 --- doc/Makefile.in | 1 - runtime/staprun/ChangeLog | 8 ++ runtime/staprun/staprun.c | 106 +++++++++--------- runtime/staprun/staprun.h | 20 +--- runtime/staprun/staprun_funcs.c | 30 ++--- systemtap.spec | 1 - 11 files changed, 98 insertions(+), 374 deletions(-) diff --git a/ChangeLog b/ChangeLog index 04fa2a6c..ab8dd190 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,13 @@ +2008-09-05 Frank Ch. Eigler + + * configure.ac, Makefile.am, systemtap.spec: Don't look for libcap. + * configure, Makefile.in: Regenerated. + 2008-09-05 Wenji Huang - PR 6731. - * main.cxx (usage,main,printscript): Improve listing mode with "-L". - * stap.1.in, stapex.5.in: Document it. + PR 6731. + * main.cxx (usage,main,printscript): Improve listing mode with "-L". + * stap.1.in, stapex.5.in: Document it. 2008-09-04 Frank Ch. Eigler diff --git a/Makefile.am b/Makefile.am index fe0fc408..c1bcd11e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -68,6 +68,8 @@ staprun_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@ stapio_CPPFLAGS = $(AM_CPPFLAGS) stapio_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@ + +PHONIES = if BUILD_ELFUTILS stap_CPPFLAGS += -Iinclude-elfutils stap_LDFLAGS += -Llib-elfutils -Wl,-rpath-link,lib-elfutils \ @@ -85,7 +87,7 @@ stamp-elfutils: config.status stap_DEPENDENCIES = lib-elfutils/libdw.so lib-elfutils/libdw.so: stamp-elfutils ; -.PHONY: install-elfutils +PHONIES += install-elfutils install-elfutils: mkdir -p $(DESTDIR)$(pkglibdir) for file in lib-elfutils/*.so* lib-elfutils/${PACKAGE_NAME}/*.so*; do \ @@ -95,12 +97,11 @@ install-exec-local: install-elfutils endif staprun_SOURCES = runtime/staprun/staprun.c runtime/staprun/staprun_funcs.c\ - runtime/staprun/ctl.c runtime/staprun/common.c \ - runtime/staprun/cap.c + runtime/staprun/ctl.c runtime/staprun/common.c staprun_CPPFLAGS = $(AM_CPPFLAGS) staprun_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) -DSINGLE_THREADED -staprun_LDADD = @PROCFLAGS@ @cap_LIBS@ +staprun_LDADD = @PROCFLAGS@ stapio_SOURCES = runtime/staprun/stapio.c \ runtime/staprun/mainloop.c runtime/staprun/common.c \ @@ -234,7 +235,10 @@ installcheck: # --define "with_bundled_elfutils 1" --define "elfutils_version 0.135" RPMBUILDFLAGS= -.PHONY: dist-gzip +PHONIES += dist-gzip + +.PHONY: $(PHONIES) + dist-gzip: cd $(srcdir); git status | grep working.directory.clean || (echo "You should commit your changes before 'make rpm'.") (cd $(srcdir); git archive --prefix=systemtap-$(VERSION)/ --format=tar HEAD) | gzip > systemtap-$(VERSION).tar.gz diff --git a/Makefile.in b/Makefile.in index ebd158dc..ff10a31d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -41,6 +41,7 @@ bin_PROGRAMS = stap$(EXEEXT) staprun$(EXEEXT) @BUILD_ELFUTILS_TRUE@am__append_3 = stamp-elfutils @BUILD_ELFUTILS_TRUE@am__append_4 = stamp-elfutils @BUILD_ELFUTILS_FALSE@stap_DEPENDENCIES = +@BUILD_ELFUTILS_TRUE@am__append_5 = install-elfutils pkglibexec_PROGRAMS = stapio$(EXEEXT) noinst_PROGRAMS = loc2c-test$(EXEEXT) subdir = . @@ -111,7 +112,7 @@ stapio_LINK = $(CCLD) $(stapio_CFLAGS) $(CFLAGS) $(stapio_LDFLAGS) \ $(LDFLAGS) -o $@ am_staprun_OBJECTS = staprun-staprun.$(OBJEXT) \ staprun-staprun_funcs.$(OBJEXT) staprun-ctl.$(OBJEXT) \ - staprun-common.$(OBJEXT) staprun-cap.$(OBJEXT) + staprun-common.$(OBJEXT) staprun_OBJECTS = $(am_staprun_OBJECTS) staprun_DEPENDENCIES = staprun_LINK = $(CCLD) $(staprun_CFLAGS) $(CFLAGS) $(staprun_LDFLAGS) \ @@ -217,7 +218,6 @@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ -cap_LIBS = @cap_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ @@ -286,14 +286,14 @@ stap_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@ $(am__append_2) staprun_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@ stapio_CPPFLAGS = $(AM_CPPFLAGS) stapio_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@ +PHONIES = $(am__append_5) dist-gzip @BUILD_ELFUTILS_TRUE@stap_DEPENDENCIES = lib-elfutils/libdw.so staprun_SOURCES = runtime/staprun/staprun.c runtime/staprun/staprun_funcs.c\ - runtime/staprun/ctl.c runtime/staprun/common.c \ - runtime/staprun/cap.c + runtime/staprun/ctl.c runtime/staprun/common.c staprun_CPPFLAGS = $(AM_CPPFLAGS) staprun_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) -DSINGLE_THREADED -staprun_LDADD = @PROCFLAGS@ @cap_LIBS@ +staprun_LDADD = @PROCFLAGS@ stapio_SOURCES = runtime/staprun/stapio.c \ runtime/staprun/mainloop.c runtime/staprun/common.c \ runtime/staprun/ctl.c \ @@ -523,7 +523,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stapio-relay.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stapio-relay_old.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stapio-stapio.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-cap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-common.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-ctl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-staprun.Po@am__quote@ @@ -739,20 +738,6 @@ staprun-common.obj: runtime/staprun/common.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -c -o staprun-common.obj `if test -f 'runtime/staprun/common.c'; then $(CYGPATH_W) 'runtime/staprun/common.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/common.c'; fi` -staprun-cap.o: runtime/staprun/cap.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -MT staprun-cap.o -MD -MP -MF $(DEPDIR)/staprun-cap.Tpo -c -o staprun-cap.o `test -f 'runtime/staprun/cap.c' || echo '$(srcdir)/'`runtime/staprun/cap.c -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/staprun-cap.Tpo $(DEPDIR)/staprun-cap.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/cap.c' object='staprun-cap.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -c -o staprun-cap.o `test -f 'runtime/staprun/cap.c' || echo '$(srcdir)/'`runtime/staprun/cap.c - -staprun-cap.obj: runtime/staprun/cap.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -MT staprun-cap.obj -MD -MP -MF $(DEPDIR)/staprun-cap.Tpo -c -o staprun-cap.obj `if test -f 'runtime/staprun/cap.c'; then $(CYGPATH_W) 'runtime/staprun/cap.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/cap.c'; fi` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/staprun-cap.Tpo $(DEPDIR)/staprun-cap.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/cap.c' object='staprun-cap.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -c -o staprun-cap.obj `if test -f 'runtime/staprun/cap.c'; then $(CYGPATH_W) 'runtime/staprun/cap.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/cap.c'; fi` - .cxx.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @@ -1358,8 +1343,6 @@ cscope: @BUILD_ELFUTILS_TRUE@ done @BUILD_ELFUTILS_TRUE@ touch $@ @BUILD_ELFUTILS_TRUE@lib-elfutils/libdw.so: stamp-elfutils ; - -@BUILD_ELFUTILS_TRUE@.PHONY: install-elfutils @BUILD_ELFUTILS_TRUE@install-elfutils: @BUILD_ELFUTILS_TRUE@ mkdir -p $(DESTDIR)$(pkglibdir) @BUILD_ELFUTILS_TRUE@ for file in lib-elfutils/*.so* lib-elfutils/${PACKAGE_NAME}/*.so*; do \ @@ -1456,7 +1439,8 @@ installcheck: fi; $(MAKE) -C testsuite installcheck RUNTESTFLAGS="$(RUNTESTFLAGS)" -.PHONY: dist-gzip +.PHONY: $(PHONIES) + dist-gzip: cd $(srcdir); git status | grep working.directory.clean || (echo "You should commit your changes before 'make rpm'.") (cd $(srcdir); git archive --prefix=systemtap-$(VERSION)/ --format=tar HEAD) | gzip > systemtap-$(VERSION).tar.gz diff --git a/configure b/configure index 71413615..5f5c4c03 100755 --- a/configure +++ b/configure @@ -722,7 +722,6 @@ elfutils_abs_srcdir stap_LIBS DATE PROCFLAGS -cap_LIBS CXXCPP subdirs LIBOBJS @@ -6426,156 +6425,6 @@ else fi - -for ac_header in sys/capability.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - { echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -else - # Is the header compilable? -{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 -echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_header_compiler=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_compiler=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -echo "${ECHO_T}$ac_header_compiler" >&6; } - -# Is the header present? -{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 -echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <$ac_header> -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - ac_header_preproc=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_preproc=no -fi - -rm -f conftest.err conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -echo "${ECHO_T}$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 -echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 -echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 -echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 -echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 -echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 -echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - ( cat <<\_ASBOX -## ------------------------------------------- ## -## Report this to systemtap@sources.redhat.com ## -## ------------------------------------------- ## -_ASBOX - ) | sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac -{ echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - eval "$as_ac_Header=\$ac_header_preproc" -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } - -fi -if test `eval echo '${'$as_ac_Header'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -else - { { echo "$as_me:$LINENO: error: cannot find required libcap header (libcap-devel may need to be installed)" >&5 -echo "$as_me: error: cannot find required libcap header (libcap-devel may need to be installed)" >&2;} - { (exit 1); exit 1; }; } -fi - -done - - build_elfutils=no # Check whether --with-elfutils was given. @@ -6717,90 +6566,6 @@ x86_64) PROCFLAGS=-m64 ;; esac -# -lcap is used for staprun, so PROCFLAGS comes in to play -SAVE_LIBS="$LIBS" -SAVE_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS $PROCFLAGS" - -{ echo "$as_me:$LINENO: checking for cap_init in -lcap" >&5 -echo $ECHO_N "checking for cap_init in -lcap... $ECHO_C" >&6; } -if test "${ac_cv_lib_cap_cap_init+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lcap $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char cap_init (); -int -main () -{ -return cap_init (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - ac_cv_lib_cap_cap_init=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_cap_cap_init=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ echo "$as_me:$LINENO: result: $ac_cv_lib_cap_cap_init" >&5 -echo "${ECHO_T}$ac_cv_lib_cap_cap_init" >&6; } -if test $ac_cv_lib_cap_cap_init = yes; then - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBCAP 1 -_ACEOF - - LIBS="-lcap $LIBS" - -else - { { echo "$as_me:$LINENO: error: need $PROCFLAGS -lcap" >&5 -echo "$as_me: error: need $PROCFLAGS -lcap" >&2;} - { (exit 1); exit 1; }; } -fi - -cap_LIBS="$LIBS" - -LIBS="$SAVE_LIBS" -CFLAGS="$SAVE_CFLAGS" - # Use tr1/unordered_map if available ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' @@ -8048,14 +7813,13 @@ elfutils_abs_srcdir!$elfutils_abs_srcdir$ac_delim stap_LIBS!$stap_LIBS$ac_delim DATE!$DATE$ac_delim PROCFLAGS!$PROCFLAGS$ac_delim -cap_LIBS!$cap_LIBS$ac_delim CXXCPP!$CXXCPP$ac_delim subdirs!$subdirs$ac_delim LIBOBJS!$LIBOBJS$ac_delim LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 16; then + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 15; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 diff --git a/configure.ac b/configure.ac index 123ac657..294fabe1 100644 --- a/configure.ac +++ b/configure.ac @@ -161,9 +161,6 @@ if test "$enable_docs" == "yes"; then fi AM_CONDITIONAL([BUILD_DOCS], [test "x${have_latex}${have_dvips}${have_ps2pdf}${have_latex2html}" == "xyesyesyesyes" -a "$enable_docs" != "no"]) -AC_CHECK_HEADERS([sys/capability.h], , - [AC_MSG_ERROR([cannot find required libcap header (libcap-devel may need to be installed)])]) - dnl Handle elfutils. If '--with-elfutils=DIR' wasn't specified, used dnl the system's elfutils. build_elfutils=no @@ -215,16 +212,6 @@ x86_64) PROCFLAGS=-m64 ;; esac AC_SUBST([PROCFLAGS]) -# -lcap is used for staprun, so PROCFLAGS comes in to play -SAVE_LIBS="$LIBS" -SAVE_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS $PROCFLAGS" -AC_CHECK_LIB(cap, cap_init, [], [AC_MSG_ERROR(need $PROCFLAGS -lcap)]) -cap_LIBS="$LIBS" -AC_SUBST(cap_LIBS) -LIBS="$SAVE_LIBS" -CFLAGS="$SAVE_CFLAGS" - # Use tr1/unordered_map if available AC_LANG_PUSH(C++) AC_CHECK_HEADERS([tr1/unordered_map]) diff --git a/doc/Makefile.in b/doc/Makefile.in index 47b6d85b..aed03ee2 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -111,7 +111,6 @@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ -cap_LIBS = @cap_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ diff --git a/runtime/staprun/ChangeLog b/runtime/staprun/ChangeLog index a4f47880..8b7a116d 100644 --- a/runtime/staprun/ChangeLog +++ b/runtime/staprun/ChangeLog @@ -1,3 +1,11 @@ +2008-09-05 Frank Ch. Eigler + + * staprun.c (run_as): Teach it to exec too. Update callers. + Always do set[ug]id as dictated. + * staprun.h (do_cap): Remove. Update all callers. + * staprun_funcs.c: Ditto. + * cap.c: Removed. Update headers. + 2008-07-10 Frank Ch. Eigler PR 6736. diff --git a/runtime/staprun/staprun.c b/runtime/staprun/staprun.c index 664b75ee..f8a08876 100644 --- a/runtime/staprun/staprun.c +++ b/runtime/staprun/staprun.c @@ -1,6 +1,6 @@ /* -*- linux-c -*- * - * staprun.c - SystemTap module loader + * staprun.c - SystemTap module loader * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,14 +34,14 @@ extern long delete_module(const char *, unsigned int); int send_relocations (); -static int run_as(uid_t uid, gid_t gid, const char *path, char *const argv[]) +static int run_as(int exec_p, uid_t uid, gid_t gid, const char *path, char *const argv[]) { pid_t pid; int rstatus; if (verbose >= 2) { int i = 0; - err("execing: "); + err(exec_p ? "execing: ": "spawning: "); while (argv[i]) { err("%s ", argv[i]); i++; @@ -49,36 +49,43 @@ static int run_as(uid_t uid, gid_t gid, const char *path, char *const argv[]) err("\n"); } - if ((pid = fork()) < 0) { - _perr("fork"); - return -1; - } else if (pid == 0) { - /* Make sure we run as the full user. If we're - * switching to a non-root user, this won't allow - * that process to switch back to root (since the - * original process is setuid). */ - if (uid != getuid()) { - if (do_cap(CAP_SETGID, setresgid, gid, gid, gid) < 0) { - _perr("setresgid"); - exit(1); - } - if (do_cap(CAP_SETUID, setresuid, uid, uid, uid) < 0) { - _perr("setresuid"); - exit(1); - } - } + if (exec_p) + pid = 0; + else + pid = fork(); + + if (pid < 0) + { + _perr("fork"); + return -1; + } + + if (pid == 0) /* child process, or exec_p */ + { + /* Make sure we run as the full user. If we're + * switching to a non-root user, this won't allow + * that process to switch back to root (since the + * original process is setuid). */ + if (setresgid (gid, gid, gid) < 0) { + _perr("setresgid"); + exit(1); + } + if (setresuid (uid, uid, uid) < 0) { + _perr("setresuid"); + exit(1); + } - /* Actually run the command. */ - if (execv(path, argv) < 0) - perror(path); - _exit(1); - } + /* Actually run the command. */ + if (execv(path, argv) < 0) + perror(path); + _exit(1); + } if (waitpid(pid, &rstatus, 0) < 0) - return -1; + return -1; if (WIFEXITED(rstatus)) - return WEXITSTATUS(rstatus); + return WEXITSTATUS(rstatus); return -1; } @@ -104,14 +111,13 @@ static int enable_uprobes(void) argv[i++] = "unregister_uprobe"; argv[i++] = "/proc/kallsyms"; argv[i] = NULL; - if (run_as(uid, gid, argv[0], argv) == 0) + if (run_as(0, uid, gid, argv[0], argv) == 0) return 0; /* * TODO: If user can't setresuid to root here, staprun will exit. * Is there a situation where that would fail but the subsequent - * attempt to use CAP_SYS_MODULE privileges (in insert_module()) - * would succeed? + * attempt to insert_module() would succeed? */ dbug(2, "Inserting uprobes module from /lib/modules, if any.\n"); i = 0; @@ -119,7 +125,7 @@ static int enable_uprobes(void) argv[i++] = "-q"; argv[i++] = "uprobes"; argv[i] = NULL; - if (run_as(0, 0, argv[0], argv) == 0) + if (run_as(0, 0, 0, argv[0], argv) == 0) return 0; dbug(2, "Inserting uprobes module from SystemTap runtime.\n"); @@ -169,9 +175,9 @@ static int remove_module(const char *name, int verb) } /* Call init_ctl_channel() which actually attempts an open() - * of the control channel. This is better than using access() because + * of the control channel. This is better than using access() because * an open on an already open channel will fail, preventing us from attempting - * to remove an in-use module. + * to remove an in-use module. */ if (init_ctl_channel(name, 0) < 0) { if (verb) @@ -186,7 +192,7 @@ static int remove_module(const char *name, int verb) if (setpriority(PRIO_PROCESS, 0, 0) < 0) _perr("setpriority"); - ret = do_cap(CAP_SYS_MODULE, delete_module, name, 0); + ret = delete_module (name, 0); if (ret != 0) { err("Error removing module '%s': %s.\n", name, strerror(errno)); return 1; @@ -203,9 +209,6 @@ int init_staprun(void) if (mountfs() < 0) return -1; - /* We're done with CAP_SYS_ADMIN. */ - drop_cap(CAP_SYS_ADMIN); - if (delete_mod) exit(remove_module(modname, 1)); else if (!attach_mod) { @@ -269,25 +272,14 @@ int main(int argc, char **argv) exit(1); } - init_cap(); - if (check_permissions() != 1) usage(argv[0]); - /* now bump the priority */ - rc = do_cap(CAP_SYS_NICE, setpriority, PRIO_PROCESS, 0, -10); - /* failure is not fatal in this case */ - if (rc < 0) - _perr("setpriority"); - - /* We're done with CAP_SYS_NICE. */ - drop_cap(CAP_SYS_NICE); - if (init_staprun()) exit(1); argv[0] = PKGLIBDIR "/stapio"; - if (execv(argv[0], argv) < 0) { + if (run_as (1, getuid(), getgid(), argv[0], argv) < 0) { perror(argv[0]); goto err; } @@ -337,7 +329,7 @@ int send_relocation_kernel () FILE* kallsyms = fopen ("/proc/kallsyms", "r"); if (kallsyms == NULL) { - perror("cannot open /proc/kallsyms"); + perror("cannot open /proc/kallsyms"); // ... and the kernel module will almost certainly fail to initialize. } else @@ -404,18 +396,18 @@ void send_relocation_modules () module_section_file = globbuf.gl_pathv[i]; - /* Tokenize the file name. + /* Tokenize the file name. Sample gl_pathv[]: /sys/modules/zlib_deflate/sections/.text Pieces: ^^^^^^^^^^^^ ^^^^^ */ - section_name = rindex (module_section_file, '/'); + section_name = rindex (module_section_file, '/'); if (! section_name) continue; section_name ++; if (!strcmp (section_name, ".")) continue; if (!strcmp (section_name, "..")) continue; - - module_name = index (module_section_file, '/'); + + module_name = index (module_section_file, '/'); if (! module_name) continue; module_name ++; module_name = index (module_name, '/'); @@ -436,7 +428,7 @@ void send_relocation_modules () /* Now we destructively modify the string, but by now the file is open so we won't need the full name again. */ *module_name_end = '\0'; - + send_a_relocation (module_name, section_name, section_address); } @@ -454,7 +446,7 @@ void send_relocation_modules () same time that a probeworthy module is being unloaded. */ } } - + globfree (& globbuf); } diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h index 0a35fee6..2014ce5b 100644 --- a/runtime/staprun/staprun.h +++ b/runtime/staprun/staprun.h @@ -33,7 +33,6 @@ #include #include #include -#include #define dbug(level, args...) {if (verbose>=level) {fprintf(stderr,"%s:%s:%d ",__name__,__FUNCTION__, __LINE__); fprintf(stderr,args);}} @@ -58,17 +57,6 @@ extern char *__name__; fprintf(stderr, ": %s\n", strerror(_errno)); \ } while (0) #define overflow_error() _err("Internal buffer overflow. Please file a bug report.\n") - -#define do_cap(cap,func,args...) ({ \ - int _rc, _saved_errno; \ - add_cap(cap); \ - _rc = func(args); \ - _saved_errno = errno; \ - del_cap(cap); \ - errno = _saved_errno; \ - _rc; \ - }) \ - /* Error checking version of sprintf() - returns 1 if overflow error */ #define sprintf_chk(str, args...) ({ \ @@ -123,12 +111,6 @@ void close_relayfs(void); int init_oldrelayfs(void); void close_oldrelayfs(int); void setup_signals(void); -/* cap.c */ -void print_cap(char *text); -void init_cap(void); -void add_cap(cap_value_t cap); -void del_cap(cap_value_t cap); -void drop_cap(cap_value_t cap); /* staprun_funcs.c */ void setup_staprun_signals(void); const char *moderror(int err); @@ -147,7 +129,7 @@ void setup_signals(void); int set_clexec(int fd); /* - * variables + * variables */ extern int control_channel; extern int ncpus; diff --git a/runtime/staprun/staprun_funcs.c b/runtime/staprun/staprun_funcs.c index c1cb92b7..8fa95e45 100644 --- a/runtime/staprun/staprun_funcs.c +++ b/runtime/staprun/staprun_funcs.c @@ -43,7 +43,7 @@ int insert_module(const char *path, const char *special_options, char **options) char *opts; int fd, saved_errno; struct stat sbuf; - + dbug(2, "inserting module\n"); if (special_options) @@ -71,7 +71,7 @@ int insert_module(const char *path, const char *special_options, char **options) perr("Error opening '%s'", path); return -1; } - + /* Now that the file is open, figure out how big it is. */ if (fstat(fd, &sbuf) < 0) { _perr("Error stat'ing '%s'", path); @@ -87,9 +87,9 @@ int insert_module(const char *path, const char *special_options, char **options) free(opts); return -1; } - + /* Actually insert the module */ - ret = do_cap(CAP_SYS_MODULE, init_module, file, sbuf.st_size, opts); + ret = init_module(file, sbuf.st_size, opts); saved_errno = errno; /* Cleanup. */ @@ -99,7 +99,7 @@ int insert_module(const char *path, const char *special_options, char **options) if (ret != 0) { err("Error inserting module '%s': %s\n", path, moderror(saved_errno)); - return -1; + return -1; } return 0; } @@ -120,8 +120,7 @@ int mountfs(void) rc = stat(DEBUGFSDIR, &sb); if (rc == 0 && S_ISDIR(sb.st_mode)) { /* If we can mount the debugfs dir correctly, we're done. */ - rc = do_cap(CAP_SYS_ADMIN, mount, "debugfs", DEBUGFSDIR, - "debugfs", 0, NULL); + rc = mount ("debugfs", DEBUGFSDIR, "debugfs", 0, NULL); if (rc == 0) return 0; /* If we got ENODEV, that means that debugfs isn't @@ -132,7 +131,7 @@ int mountfs(void) return -1; } } - + /* DEBUGFSDIR couldn't be mounted. So, try RELAYFSDIR. */ /* If the relayfs dir is already mounted correctly, we're done. */ @@ -159,11 +158,12 @@ int mountfs(void) /* To ensure the directory gets created with the * proper group, we'll have to temporarily switch to * root. */ - if (do_cap(CAP_SETUID, setuid, 0) < 0) { + /* XXX: Why not just chown() the thing? */ + if (setuid (0) < 0) { _perr("Couldn't change user while creating %s", RELAYFSDIR); return -1; } - if (do_cap(CAP_SETGID, setgid, 0) < 0) { + if (setgid (0) < 0) { _perr("Couldn't change group while creating %s", RELAYFSDIR); return -1; } @@ -174,11 +174,11 @@ int mountfs(void) saved_errno = errno; /* Restore everything we changed. */ - if (do_cap(CAP_SETGID, setgid, gid) < 0) { + if (setgid (gid) < 0) { _perr("Couldn't restore group while creating %s", RELAYFSDIR); return -1; } - if (do_cap(CAP_SETUID, setuid, uid) < 0) { + if (setuid (uid) < 0) { _perr("Couldn't restore user while creating %s", RELAYFSDIR); return -1; } @@ -192,7 +192,7 @@ int mountfs(void) } /* Now that we're sure the directory exists, try mounting RELAYFSDIR. */ - if (do_cap(CAP_SYS_ADMIN, mount, "relayfs", RELAYFSDIR, "relayfs", 0, NULL) < 0) { + if (mount ("relayfs", RELAYFSDIR, "relayfs", 0, NULL) < 0) { perr("Couldn't mount %s", RELAYFSDIR); return -1; } @@ -262,13 +262,13 @@ check_path(void) " Unable to canonicalize that directory", staplib_dir_path); return -1; } - + /* Use realpath() to canonicalize the module path. */ if (realpath(modpath, module_realpath) == NULL) { perr("Unable to canonicalize path \"%s\"", modpath); return -1; } - + /* To make sure the user can't specify something like * /lib/modules/`uname -r`/systemtapmod.ko, put a '/' on the * end of staplib_dir_realpath. */ diff --git a/systemtap.spec b/systemtap.spec index 4bbd9f37..e9050d77 100644 --- a/systemtap.spec +++ b/systemtap.spec @@ -18,7 +18,6 @@ Source: ftp://sourceware.org/pub/%{name}/releases/%{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Requires: kernel >= 2.6.9-11 -BuildRequires: libcap-devel %if %{with_sqlite} BuildRequires: sqlite-devel Requires: sqlite -- cgit From 40be866ffcfc21a15836643cc7c2437ed5c91e8f Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Fri, 5 Sep 2008 14:49:04 -0400 Subject: PR4255: uprobes test case --- testsuite/ChangeLog | 5 +++++ testsuite/systemtap.base/uprobes.exp | 36 ++++++++++++++++++++++++++++++++++++ testsuite/systemtap.base/uprobes.stp | 3 +++ 3 files changed, 44 insertions(+) create mode 100644 testsuite/systemtap.base/uprobes.exp create mode 100755 testsuite/systemtap.base/uprobes.stp diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index 9ca00077..ff907094 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2008-09-05 Frank Ch. Eigler + + PR 4255. + * systemtap.base/uprobes.{exp,stp}: New file. + 2008-09-05 Wenji Huang * systemtap.base/cmd_parse.stp: Add test for "-L" option. diff --git a/testsuite/systemtap.base/uprobes.exp b/testsuite/systemtap.base/uprobes.exp new file mode 100644 index 00000000..a0ae3e76 --- /dev/null +++ b/testsuite/systemtap.base/uprobes.exp @@ -0,0 +1,36 @@ + + +set test uprobes + +# Compile a little C program to use as the user-space probing victim +set path "jennie.c" +set fp [open $path "w"] +puts $fp "int main (int argc, char *argv[])" +puts $fp "{" +puts $fp "if (argc > 1) main (argc - 1, argv);" +puts $fp "}" +close $fp + +# too easy +if [file exists $path] then { pass "$test prep" } else { fail "$test prep" } + +catch {exec gcc -g -o jennie jennie.c} err +if {$err == "" && [file exists jennie]} then { pass "$test compile" } else { pass "$test compile" } + +set rc [stap_run_batch $srcdir/$subdir/uprobes.stp] +if {$rc == 0} then { pass "$test -p4" } else { fail "$test -p4" } + +if {! [installtest_p]} { untested "$test -p5"; return } + +spawn sudo stap -v $srcdir/$subdir/uprobes.stp -c "./jennie 1 2 3 4" +set ok 0 +expect { + -re {^Pass[^\r\n]*\r\n} { exp_continue } + -re {^process[^\r\n]*jennie[^\r\n]*main[^\r\n]*call[^\r\n]*\r\n} { incr ok; exp_continue } + -re {^process[^\r\n]*jennie[^\r\n]*main[^\r\n]*return[^\r\n]*\r\n} { incr ok; exp_continue } + -timeout 30 + timeout { } + eof { } +} +if {$ok == 10} then { pass "$test -p5" } else { fail "$test -p5 ($ok)" } +catch {wait; close} diff --git a/testsuite/systemtap.base/uprobes.stp b/testsuite/systemtap.base/uprobes.stp new file mode 100755 index 00000000..957cbe16 --- /dev/null +++ b/testsuite/systemtap.base/uprobes.stp @@ -0,0 +1,3 @@ +#! stap -p4 +probe process("./jennie").function("main").call { log (pp() . " " . $$parms) } +probe process("./jennie").function("main").return { log (pp() . " " . $$return) } -- cgit From e071e49b06c2fe9e20c15ec3719cbaa60ae4afe1 Mon Sep 17 00:00:00 2001 From: Stan Cox Date: Fri, 5 Sep 2008 19:00:17 -0400 Subject: Handle scalar statistics. --- ChangeLog | 4 ++++ elaborate.cxx | 33 +++++++++++++++++++++++++-------- testsuite/ChangeLog | 5 +++++ testsuite/systemtap.base/global_end.exp | 3 ++- testsuite/systemtap.base/global_end.stp | 7 ++++++- 5 files changed, 42 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index ab8dd190..10a72cef 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2008-09-05 Stan Cox + + * elaborate.cxx (add_global_var_display): Handle scalar statistics. + 2008-09-05 Frank Ch. Eigler * configure.ac, Makefile.am, systemtap.spec: Don't look for libcap. diff --git a/elaborate.cxx b/elaborate.cxx index 44b6e24f..3dfc7183 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -1194,15 +1194,35 @@ void add_global_var_display (systemtap_session& s) if (l->index_types.size() == 0) // Scalar { - if (l->type == pe_string) + if (l->type == pe_stats) + pf->raw_components += " @count=%#x @min=%#x @max=%#x @sum=%#x @avg=%#x\\n"; + else if (l->type == pe_string) pf->raw_components += "=\"%#s\"\\n"; else pf->raw_components += "=%#x\\n"; - pf->args.push_back(g_sym); pf->components = print_format::string_to_components(pf->raw_components); expr_statement* feb = new expr_statement; feb->value = pf; feb->tok = print_tok; + if (l->type == pe_stats) + { + struct stat_op* so [5]; + const stat_component_type stypes[] = {sc_count, sc_min, sc_max, sc_sum, sc_average}; + + for (unsigned si = 0; + si < (sizeof(so)/sizeof(struct stat_op*)); + si++) + { + so[si]= new stat_op; + so[si]->ctype = stypes[si]; + so[si]->type = pe_long; + so[si]->stat = g_sym; + so[si]->tok = l->tok; + pf->args.push_back(so[si]); + } + } + else + pf->args.push_back(g_sym); b->statements.push_back(feb); } else // Array @@ -1265,6 +1285,8 @@ void add_global_var_display (systemtap_session& s) { struct stat_op* so [5]; const stat_component_type stypes[] = {sc_count, sc_min, sc_max, sc_sum, sc_average}; + + ai->type = pe_stats; for (unsigned si = 0; si < (sizeof(so)/sizeof(struct stat_op*)); si++) @@ -1274,13 +1296,8 @@ void add_global_var_display (systemtap_session& s) so[si]->type = pe_long; so[si]->stat = ai; so[si]->tok = l->tok; + pf->args.push_back(so[si]); } - - ai->type = pe_stats; - for (unsigned si = 0; - si < (sizeof(so)/sizeof(struct stat_op*)); - si++) - pf->args.push_back(so[si]); } else pf->args.push_back(ai); diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index ff907094..82435044 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2008-09-05 Stan Cox + + * systemtap.base/global_end.stp: Also check scalar statistics. + * systemtap.base/global_end.exp: Likeewise. + 2008-09-05 Frank Ch. Eigler PR 4255. diff --git a/testsuite/systemtap.base/global_end.exp b/testsuite/systemtap.base/global_end.exp index d066cf9d..cd5c6f83 100644 --- a/testsuite/systemtap.base/global_end.exp +++ b/testsuite/systemtap.base/global_end.exp @@ -18,8 +18,9 @@ expect { -re {iota."two".="twelve"} { incr ok; exp_continue } -re {epsilon."one",1. @count=0x4 @min=0x1 @max=0x4 @sum=0xa @avg=0x2} { incr ok; exp_continue } -re {epsilon."two",2. @count=0x4 @min=0xa @max=0x28 @sum=0x64 @avg=0x19} { incr ok; exp_continue } + -re {phi @count=0x4 @min=0x1 @max=0x4 @sum=0xa @avg=0x2} { incr ok; exp_continue } timeout { fail "$test (timeout)" } eof { } } wait -if {$ok == 10} { pass "$test ($ok)" } { fail "$test ($ok)" } +if {$ok == 11} { pass "$test ($ok)" } { fail "$test ($ok)" } diff --git a/testsuite/systemtap.base/global_end.stp b/testsuite/systemtap.base/global_end.stp index b26b7c03..876eac8c 100644 --- a/testsuite/systemtap.base/global_end.stp +++ b/testsuite/systemtap.base/global_end.stp @@ -1,4 +1,4 @@ -global alpha, beta, gamma, iota, epsilon +global alpha, beta, gamma, iota, epsilon, phi probe begin { gamma = "abcdefghijklmnopqrstuvwxyz" @@ -16,6 +16,11 @@ probe begin { beta["two",1] = 3 beta["two",2] = 4 + phi <<< 1 + phi <<< 2 + phi <<< 3 + phi <<< 4 + epsilon["one",1] <<< 1 epsilon["one",1] <<< 2 epsilon["one",1] <<< 3 -- cgit From e56e51c92847a328a713e56eb6796a25cf6eb3e2 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Fri, 5 Sep 2008 23:18:24 -0400 Subject: task_finder <-> target_pid coupling; staprun/target_cmd fork under ptrace control --- runtime/staprun/mainloop.c | 626 ++++++++++++++++++++++++--------------------- runtime/task_finder.c | 9 +- tapsets.cxx | 5 +- 3 files changed, 339 insertions(+), 301 deletions(-) diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c index a7b919cb..e0f48ebc 100644 --- a/runtime/staprun/mainloop.c +++ b/runtime/staprun/mainloop.c @@ -12,6 +12,7 @@ #include "staprun.h" #include +#include /* globals */ int ncpus; @@ -22,172 +23,193 @@ static int use_old_transport = 0; static void *signal_thread(void *arg) { - sigset_t *s = (sigset_t *) arg; - int signum, rc, btype = STP_EXIT; - - while (1) { - if (sigwait(s, &signum) < 0) { - _perr("sigwait"); - continue; - } - dbug(2, "sigproc %d (%s)\n", signum, strsignal(signum)); - if (signum == SIGQUIT) - cleanup_and_exit(1); - else if (signum == SIGINT || signum == SIGHUP || signum == SIGTERM) { - // send STP_EXIT - rc = write(control_channel, &btype, sizeof(btype)); - break; - } - } - return NULL; + sigset_t *s = (sigset_t *) arg; + int signum, rc, btype = STP_EXIT; + + while (1) { + if (sigwait(s, &signum) < 0) { + _perr("sigwait"); + continue; + } + dbug(2, "sigproc %d (%s)\n", signum, strsignal(signum)); + if (signum == SIGQUIT) + cleanup_and_exit(1); + else if (signum == SIGINT || signum == SIGHUP || signum == SIGTERM) { + // send STP_EXIT + rc = write(control_channel, &btype, sizeof(btype)); + break; + } + } + return NULL; } static void chld_proc(int signum) { - int32_t rc, btype = STP_EXIT; - dbug(2, "chld_proc %d (%s)\n", signum, strsignal(signum)); - pid_t pid = waitpid(-1, NULL, WNOHANG); - if (pid != target_pid) - return; - // send STP_EXIT - rc = write(control_channel, &btype, sizeof(btype)); + int32_t rc, btype = STP_EXIT; + dbug(2, "chld_proc %d (%s)\n", signum, strsignal(signum)); + pid_t pid = waitpid(-1, NULL, WNOHANG); + if (pid != target_pid) + return; + // send STP_EXIT + rc = write(control_channel, &btype, sizeof(btype)); } static void setup_main_signals(void) { - pthread_t tid; - struct sigaction sa; - sigset_t *s = malloc(sizeof(*s)); - if (!s) { - _perr("malloc failed"); - exit(1); - } - sigfillset(s); - pthread_sigmask(SIG_SETMASK, s, NULL); - memset(&sa, 0, sizeof(sa)); - sigfillset(&sa.sa_mask); - sa.sa_handler = SIG_IGN; - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGHUP, &sa, NULL); - sigaction(SIGQUIT, &sa, NULL); - - sa.sa_handler = chld_proc; - sigaction(SIGCHLD, &sa, NULL); - - sigemptyset(s); - sigaddset(s, SIGINT); - sigaddset(s, SIGTERM); - sigaddset(s, SIGHUP); - sigaddset(s, SIGQUIT); - pthread_sigmask(SIG_SETMASK, s, NULL); - if (pthread_create(&tid, NULL, signal_thread, s) < 0) { - _perr("failed to create thread"); - exit(1); - } + pthread_t tid; + struct sigaction sa; + sigset_t *s = malloc(sizeof(*s)); + if (!s) { + _perr("malloc failed"); + exit(1); + } + sigfillset(s); + pthread_sigmask(SIG_SETMASK, s, NULL); + memset(&sa, 0, sizeof(sa)); + sigfillset(&sa.sa_mask); + sa.sa_handler = SIG_IGN; + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + + sa.sa_handler = chld_proc; + sigaction(SIGCHLD, &sa, NULL); + + sigemptyset(s); + sigaddset(s, SIGINT); + sigaddset(s, SIGTERM); + sigaddset(s, SIGHUP); + sigaddset(s, SIGQUIT); + pthread_sigmask(SIG_SETMASK, s, NULL); + if (pthread_create(&tid, NULL, signal_thread, s) < 0) { + _perr("failed to create thread"); + exit(1); + } } -/* - * start_cmd forks the command given on the command line - * with the "-c" option. It will not exec that command - * until it received signal SIGUSR1. We do it this way because - * we must have the pid of the forked command so it can be set to - * the module and made available internally as _stp_target. - * SIGUSR1 is sent from stp_main_loop() below when it receives - * STP_START from the module. +/* + * start_cmd forks the command given on the command line with the "-c" + * option. It will wait just at the cusp of the exec until we get the + * signal from the kernel to let it run. We do it this way because we + * must have the pid of the forked command so it can be set to the + * module and made available internally as _stp_target. PTRACE_DETACH + * is sent from stp_main_loop() below when it receives STP_START from + * the module. */ void start_cmd(void) { - pid_t pid; - sigset_t usrset; - struct sigaction a; - - sigemptyset(&usrset); - sigaddset(&usrset, SIGUSR1); - pthread_sigmask(SIG_BLOCK, &usrset, NULL); - - /* if we are execing a target cmd, ignore ^C in stapio */ - /* and let the target cmd get it. */ - sigemptyset(&a.sa_mask); - a.sa_flags = 0; - a.sa_handler = SIG_IGN; - sigaction(SIGINT, &a, NULL); - - dbug(1, "execing target_cmd %s\n", target_cmd); - if ((pid = fork()) < 0) { - _perr("fork"); - exit(1); - } else if (pid == 0) { - int signum; - - a.sa_handler = SIG_DFL; - sigaction(SIGINT, &a, NULL); - - /* commands we fork need to run at normal priority */ - setpriority(PRIO_PROCESS, 0, 0); - - /* wait here until signaled */ - sigwait(&usrset, &signum); - - if (execl("/bin/sh", "sh", "-c", target_cmd, NULL) < 0) - perror(target_cmd); - _exit(1); - } - target_pid = pid; + pid_t pid; + struct sigaction a; + + /* if we are execing a target cmd, ignore ^C in stapio */ + /* and let the target cmd get it. */ + sigemptyset(&a.sa_mask); + a.sa_flags = 0; + a.sa_handler = SIG_IGN; + sigaction(SIGINT, &a, NULL); + + dbug(1, "execing target_cmd %s\n", target_cmd); + if ((pid = fork()) < 0) { + _perr("fork"); + exit(1); + } else if (pid == 0) { + /* We're in the target process. Let's start the execve of target_cmd, */ + int rc; + + a.sa_handler = SIG_DFL; + sigaction(SIGINT, &a, NULL); + + rc = ptrace (PTRACE_TRACEME, 0, 0, 0); + if (rc < 0) perror ("ptrace me"); + + if (execl("/bin/sh", "sh", "-c", target_cmd, NULL) < 0) + perror(target_cmd); + _exit(1); + } else { + /* We're back in the parent. Since we forked a sh -c, we need to wait until + the shell itself has been exec'd (one SIGTRAP via ptrace), and then again + until the (first?) target command has been. */ + int status; + target_pid = pid; + waitpid (target_pid, &status, 0); + if (WIFSTOPPED (status)) + { + /* OK, we got the first exec. Let the shell start. */ + int rc = ptrace (PTRACE_CONT, target_pid, 0, 0); + if (rc < 0) perror ("ptrace continue"); + /* Now we wait until the shell has evaluated the command line, + and is about to exec the child process(es). */ + waitpid (target_pid, &status, 0); + /* That's it. The child process has either died, or is just + about to exec the real command. We can sit back and relax; + once we get our STP_START message, we will PTRACE_DETACH + and let it run free. */ + } + else + { + /* Who knows, maybe the shell failed to exec; maybe we're OOM; + whatever. We should get a SIGCHLD before too long and wind + up the session. */ + _perr ("unexpected status %d from sh -c %s", status, target_cmd); + } + } + + } -/** +/** * system_cmd() executes system commands in response * to an STP_SYSTEM message from the module. These * messages are sent by the system() systemtap function. */ void system_cmd(char *cmd) { - pid_t pid; - - dbug(2, "system %s\n", cmd); - if ((pid = fork()) < 0) { - _perr("fork"); - } else if (pid == 0) { - setpriority(PRIO_PROCESS, 0, 0); - if (execl("/bin/sh", "sh", "-c", cmd, NULL) < 0) - perr("%s", cmd); - _exit(1); - } + pid_t pid; + + dbug(2, "system %s\n", cmd); + if ((pid = fork()) < 0) { + _perr("fork"); + } else if (pid == 0) { + setpriority(PRIO_PROCESS, 0, 0); + if (execl("/bin/sh", "sh", "-c", cmd, NULL) < 0) + perr("%s", cmd); + _exit(1); + } } /* This is only used in the old relayfs code */ static void read_buffer_info(void) { - char buf[PATH_MAX]; - struct statfs st; - int fd, len, ret; - - if (!use_old_transport) - return; - - if (statfs("/sys/kernel/debug", &st) == 0 && (int)st.f_type == (int)DEBUGFS_MAGIC) - return; - - if (sprintf_chk(buf, "/proc/systemtap/%s/bufsize", modname)) - return; - fd = open(buf, O_RDONLY); - if (fd < 0) - return; - - len = read(fd, buf, sizeof(buf)); - if (len <= 0) { - perr("Couldn't read bufsize"); - close(fd); - return; - } - ret = sscanf(buf, "%u,%u", &n_subbufs, &subbuf_size); - if (ret != 2) - perr("Couldn't read bufsize"); - - dbug(2, "n_subbufs= %u, size=%u\n", n_subbufs, subbuf_size); - close(fd); - return; + char buf[PATH_MAX]; + struct statfs st; + int fd, len, ret; + + if (!use_old_transport) + return; + + if (statfs("/sys/kernel/debug", &st) == 0 && (int)st.f_type == (int)DEBUGFS_MAGIC) + return; + + if (sprintf_chk(buf, "/proc/systemtap/%s/bufsize", modname)) + return; + fd = open(buf, O_RDONLY); + if (fd < 0) + return; + + len = read(fd, buf, sizeof(buf)); + if (len <= 0) { + perr("Couldn't read bufsize"); + close(fd); + return; + } + ret = sscanf(buf, "%u,%u", &n_subbufs, &subbuf_size); + if (ret != 2) + perr("Couldn't read bufsize"); + + dbug(2, "n_subbufs= %u, size=%u\n", n_subbufs, subbuf_size); + close(fd); + return; } /** @@ -198,79 +220,79 @@ static void read_buffer_info(void) */ int init_stapio(void) { - dbug(2, "init_stapio\n"); - - /* create control channel */ - use_old_transport = init_ctl_channel(modname, 1); - if (use_old_transport < 0) { - err("Failed to initialize control channel.\n"); - return -1; - } - read_buffer_info(); - - if (attach_mod) { - dbug(2, "Attaching\n"); - if (use_old_transport) { - if (init_oldrelayfs() < 0) { - close_ctl_channel(); - return -1; - } - } else { - if (init_relayfs() < 0) { - close_ctl_channel(); - return -1; - } - } - return 0; - } - - /* fork target_cmd if requested. */ - /* It will not actually exec until signalled. */ - if (target_cmd) - start_cmd(); - - return 0; + dbug(2, "init_stapio\n"); + + /* create control channel */ + use_old_transport = init_ctl_channel(modname, 1); + if (use_old_transport < 0) { + err("Failed to initialize control channel.\n"); + return -1; + } + read_buffer_info(); + + if (attach_mod) { + dbug(2, "Attaching\n"); + if (use_old_transport) { + if (init_oldrelayfs() < 0) { + close_ctl_channel(); + return -1; + } + } else { + if (init_relayfs() < 0) { + close_ctl_channel(); + return -1; + } + } + return 0; + } + + /* fork target_cmd if requested. */ + /* It will not actually exec until signalled. */ + if (target_cmd) + start_cmd(); + + return 0; } /* cleanup_and_exit() closed channels, frees memory, * removes the module (if necessary) and exits. */ void cleanup_and_exit(int detach) { - pid_t err; - static int exiting = 0; - - if (exiting) - return; - exiting = 1; - - setup_main_signals(); - - dbug(1, "detach=%d\n", detach); - - /* what about child processes? we will wait for them here. */ - err = waitpid(-1, NULL, WNOHANG); - if (err >= 0) - err("\nWaiting for processes to exit\n"); - while (wait(NULL) > 0) ; - - if (use_old_transport) - close_oldrelayfs(detach); - else - close_relayfs(); - - dbug(1, "closing control channel\n"); - close_ctl_channel(); - - if (detach) { - err("\nDisconnecting from systemtap module.\n" "To reconnect, type \"staprun -A %s\"\n", modname); - } else { - dbug(2, "removing %s\n", modname); - if (execl(BINDIR "/staprun", "staprun", "-d", modname, NULL) < 0) { - perror(modname); - _exit(1); - } - } - _exit(0); + pid_t err; + static int exiting = 0; + + if (exiting) + return; + exiting = 1; + + setup_main_signals(); + + dbug(1, "detach=%d\n", detach); + + /* what about child processes? we will wait for them here. */ + err = waitpid(-1, NULL, WNOHANG); + if (err >= 0) + err("\nWaiting for processes to exit\n"); + while (wait(NULL) > 0) ; + + if (use_old_transport) + close_oldrelayfs(detach); + else + close_relayfs(); + + dbug(1, "closing control channel\n"); + close_ctl_channel(); + + if (detach) { + err("\nDisconnecting from systemtap module.\n" "To reconnect, type \"staprun -A %s\"\n", modname); + } else { + dbug(2, "removing %s\n", modname); + if (execl(BINDIR "/staprun", "staprun", "-d", modname, NULL) < 0) { + perror(modname); + _exit(1); + } + } + _exit(0); } /** @@ -279,97 +301,105 @@ void cleanup_and_exit(int detach) int stp_main_loop(void) { - ssize_t nb; - void *data; - uint32_t type; - FILE *ofp = stdout; - char recvbuf[8196]; - - setvbuf(ofp, (char *)NULL, _IOLBF, 0); - setup_main_signals(); - dbug(2, "in main loop\n"); - - send_request(STP_READY, NULL, 0); - - /* handle messages from control channel */ - while (1) { - nb = read(control_channel, recvbuf, sizeof(recvbuf)); - dbug(2, "nb=%d\n", (int)nb); - if (nb <= 0) { - if (errno != EINTR) - _perr("Unexpected EOF in read (nb=%ld)", (long)nb); - continue; - } - - type = *(uint32_t *) recvbuf; - data = (void *)(recvbuf + sizeof(uint32_t)); - nb -= sizeof(uint32_t); - - switch (type) { + ssize_t nb; + void *data; + uint32_t type; + FILE *ofp = stdout; + char recvbuf[8196]; + + setvbuf(ofp, (char *)NULL, _IOLBF, 0); + setup_main_signals(); + dbug(2, "in main loop\n"); + + send_request(STP_READY, NULL, 0); + + /* handle messages from control channel */ + while (1) { + nb = read(control_channel, recvbuf, sizeof(recvbuf)); + dbug(2, "nb=%d\n", (int)nb); + if (nb <= 0) { + if (errno != EINTR) + _perr("Unexpected EOF in read (nb=%ld)", (long)nb); + continue; + } + + type = *(uint32_t *) recvbuf; + data = (void *)(recvbuf + sizeof(uint32_t)); + nb -= sizeof(uint32_t); + + switch (type) { #ifdef STP_OLD_TRANSPORT - case STP_REALTIME_DATA: - { - ssize_t bw = write(out_fd[0], data, nb); - if (bw >= 0 && bw != nb) { - nb = nb - bw; - bw = write(out_fd[0], data, nb); - } - if (bw != nb) { - _perr("write error (nb=%ld)", (long)nb); - cleanup_and_exit(0); - } - break; - } + case STP_REALTIME_DATA: + { + ssize_t bw = write(out_fd[0], data, nb); + if (bw >= 0 && bw != nb) { + nb = nb - bw; + bw = write(out_fd[0], data, nb); + } + if (bw != nb) { + _perr("write error (nb=%ld)", (long)nb); + cleanup_and_exit(0); + } + break; + } #endif - case STP_OOB_DATA: - fputs((char *)data, stderr); - break; - case STP_EXIT: - { - /* module asks us to unload it and exit */ - dbug(2, "got STP_EXIT\n"); - cleanup_and_exit(0); - break; - } - case STP_START: - { - struct _stp_msg_start *t = (struct _stp_msg_start *)data; - dbug(2, "probe_start() returned %d\n", t->res); - if (t->res < 0) { - if (target_cmd) - kill(target_pid, SIGKILL); - cleanup_and_exit(0); - } else if (target_cmd) - kill(target_pid, SIGUSR1); - break; - } - case STP_SYSTEM: - { - struct _stp_msg_cmd *c = (struct _stp_msg_cmd *)data; - dbug(2, "STP_SYSTEM: %s\n", c->cmd); - system_cmd(c->cmd); - break; - } - case STP_TRANSPORT: - { - struct _stp_msg_start ts; - if (use_old_transport) { - if (init_oldrelayfs() < 0) - cleanup_and_exit(0); - } else { - if (init_relayfs() < 0) - cleanup_and_exit(0); - } - ts.target = target_pid; - send_request(STP_START, &ts, sizeof(ts)); - if (load_only) - cleanup_and_exit(1); - break; - } - default: - err("WARNING: ignored message of type %d\n", (type)); - } - } - fclose(ofp); - return 0; + case STP_OOB_DATA: + fputs((char *)data, stderr); + break; + case STP_EXIT: + { + /* module asks us to unload it and exit */ + dbug(2, "got STP_EXIT\n"); + cleanup_and_exit(0); + break; + } + case STP_START: + { + struct _stp_msg_start *t = (struct _stp_msg_start *)data; + dbug(2, "probe_start() returned %d\n", t->res); + if (t->res < 0) { + if (target_cmd) + kill(target_pid, SIGKILL); + cleanup_and_exit(0); + } else if (target_cmd) { + int rc = ptrace (PTRACE_DETACH, target_pid, 0, 0); + if (rc < 0) + { + perror ("ptrace detach"); + if (target_cmd) + kill(target_pid, SIGKILL); + cleanup_and_exit(0); + } + } + break; + } + case STP_SYSTEM: + { + struct _stp_msg_cmd *c = (struct _stp_msg_cmd *)data; + dbug(2, "STP_SYSTEM: %s\n", c->cmd); + system_cmd(c->cmd); + break; + } + case STP_TRANSPORT: + { + struct _stp_msg_start ts; + if (use_old_transport) { + if (init_oldrelayfs() < 0) + cleanup_and_exit(0); + } else { + if (init_relayfs() < 0) + cleanup_and_exit(0); + } + ts.target = target_pid; + send_request(STP_START, &ts, sizeof(ts)); + if (load_only) + cleanup_and_exit(1); + break; + } + default: + err("WARNING: ignored message of type %d\n", (type)); + } + } + fclose(ofp); + return 0; } diff --git a/runtime/task_finder.c b/runtime/task_finder.c index 9c0dd55b..2d4eed15 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -360,7 +360,7 @@ __stp_get_mm_path(struct mm_struct *mm, char *buf, int buflen) | UTRACE_EVENT(EXEC) \ | UTRACE_EVENT(DEATH)) -/* +/* * __STP_TASK_BASE_EVENTS: base events for stap_task_finder_target's * without a vm_callback * @@ -460,7 +460,7 @@ __stp_utrace_attach_match_filename(struct task_struct *tsk, else if (tgt->pid != 0) continue; /* Notice that "pid == 0" (which means to probe all - * threads) falls through. */ + * threads) falls through. */ list_for_each(cb_node, &tgt->callback_list_head) { struct stap_task_finder_target *cb_tgt; @@ -1138,6 +1138,11 @@ stap_start_task_finder(void) size_t mmpathlen; struct list_head *tgt_node; + /* Skip over processes other than that specified with + stap -c or -x. */ + if (_stp_target && tsk->tgid != _stp_target) + continue; + rc = stap_utrace_attach(tsk, &__stp_utrace_task_finder_ops, 0, __STP_TASK_FINDER_EVENTS); if (rc == EPERM) { diff --git a/tapsets.cxx b/tapsets.cxx index 4fa53a88..240af469 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -5868,8 +5868,11 @@ utrace_derived_probe::utrace_derived_probe (systemtap_session &s, vector comps; if (hp) comps.push_back (new probe_point::component(TOK_PROCESS, new literal_string(path))); - else + else if (pid != 0) comps.push_back (new probe_point::component(TOK_PROCESS, new literal_number(pid))); + else + comps.push_back (new probe_point::component(TOK_PROCESS)); + switch (flags) { case UDPF_THREAD_BEGIN: -- cgit From a80aa597e9d6fa3443a8f5a1c049422f909c85bb Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Sat, 6 Sep 2008 10:09:02 -0400 Subject: "stap -c" cleanup part 2 - use wordexp / execvp instead of "sh -c" to execute cmd string --- runtime/staprun/mainloop.c | 58 ++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c index e0f48ebc..6fc061ae 100644 --- a/runtime/staprun/mainloop.c +++ b/runtime/staprun/mainloop.c @@ -13,6 +13,8 @@ #include "staprun.h" #include #include +#include + /* globals */ int ncpus; @@ -109,53 +111,52 @@ void start_cmd(void) a.sa_handler = SIG_IGN; sigaction(SIGINT, &a, NULL); - dbug(1, "execing target_cmd %s\n", target_cmd); if ((pid = fork()) < 0) { _perr("fork"); exit(1); } else if (pid == 0) { /* We're in the target process. Let's start the execve of target_cmd, */ int rc; + wordexp_t words; a.sa_handler = SIG_DFL; sigaction(SIGINT, &a, NULL); + /* Formerly, we just execl'd(sh,-c,$target_cmd). But this does't + work well if target_cmd is a shell builtin. We really want to + probe a new child process, not a mishmash of shell-interpreted + stuff. */ + rc = wordexp (target_cmd, & words, WRDE_NOCMD); + if (rc != 0) { _perr ("wordexp parsing error"); _exit (1); } + if (words.we_wordc < 1) { _perr ("empty target_cmd"); _exit (1); } + rc = ptrace (PTRACE_TRACEME, 0, 0, 0); if (rc < 0) perror ("ptrace me"); - if (execl("/bin/sh", "sh", "-c", target_cmd, NULL) < 0) +#if 0 + dbug(1, "blocking briefly\n"); + raise (SIGCONT); /* Harmless; just passes control to parent. */ +#endif + + dbug(1, "execing target_cmd %s\n", target_cmd); + + /* Note that execvp() is not a direct system call; it does a $PATH + search in glibc. We would like to filter out these dummy syscalls + from the utrace events seen by scripts. */ + if (execvp (words.we_wordv[0], words.we_wordv) < 0) perror(target_cmd); + + /* (There is no need to wordfree() words; they are or will be gone.) */ + _exit(1); } else { - /* We're back in the parent. Since we forked a sh -c, we need to wait until - the shell itself has been exec'd (one SIGTRAP via ptrace), and then again - until the (first?) target command has been. */ - int status; + /* We're in the parent. The child will parse target_cmd and execv() + the result. It will be stopped thereabouts and send us a SIGTRAP. */ target_pid = pid; + int status; waitpid (target_pid, &status, 0); - if (WIFSTOPPED (status)) - { - /* OK, we got the first exec. Let the shell start. */ - int rc = ptrace (PTRACE_CONT, target_pid, 0, 0); - if (rc < 0) perror ("ptrace continue"); - /* Now we wait until the shell has evaluated the command line, - and is about to exec the child process(es). */ - waitpid (target_pid, &status, 0); - /* That's it. The child process has either died, or is just - about to exec the real command. We can sit back and relax; - once we get our STP_START message, we will PTRACE_DETACH - and let it run free. */ - } - else - { - /* Who knows, maybe the shell failed to exec; maybe we're OOM; - whatever. We should get a SIGCHLD before too long and wind - up the session. */ - _perr ("unexpected status %d from sh -c %s", status, target_cmd); - } + dbug(1, "waited for target_cmd %s pid %d status %x\n", target_cmd, target_pid, (unsigned) status); } - - } /** @@ -362,6 +363,7 @@ int stp_main_loop(void) kill(target_pid, SIGKILL); cleanup_and_exit(0); } else if (target_cmd) { + dbug(1, "detaching pid %d\n", target_pid); int rc = ptrace (PTRACE_DETACH, target_pid, 0, 0); if (rc < 0) { -- cgit From cec7293bd301b4737da7abe8d1b70b9689fd3f00 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Sat, 6 Sep 2008 10:25:28 -0400 Subject: PR6445: documentation, mopping up --- ChangeLog | 5 ++++ NEWS | 12 +++++++++ runtime/ChangeLog | 7 +++++ runtime/staprun/ChangeLog | 5 ++++ testsuite/ChangeLog | 5 ++++ testsuite/systemtap.base/cmd_parse.exp | 48 ++++++++++++++-------------------- 6 files changed, 54 insertions(+), 28 deletions(-) diff --git a/ChangeLog b/ChangeLog index 10a72cef..741c4ad0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2008-09-06 Frank Ch. Eigler + + * tapsets.cxx (utrace_derived_probe ctor): Handle + process.* probe point reverse engineering (pid- and path-less). + 2008-09-05 Stan Cox * elaborate.cxx (add_global_var_display): Handle scalar statistics. diff --git a/NEWS b/NEWS index 5036cebb..ab035593 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,17 @@ * What's new +- Target process mode (stap -c CMD or -x PID) now implicitly restricts all + "process.*" probes to the given child process. (It does not effect + kernel.* or other probe types.) The CMD string is now executed directly, + rather than via a /bin/sh -c subshell. + + % stap -e 'probe process.syscall, process.end { + printf("%s %d %s\n", execname(), pid(), pp())}'\ + -c ls + ls 2323 process.syscall + ls 2323 process.syscall + ls 2323 process.end + - Probe listing mode is improved: "-L" lists available script-level variables % stap -L 'syscall.*open*' diff --git a/runtime/ChangeLog b/runtime/ChangeLog index e02c5f0b..8f20ed11 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,10 @@ +2008-09-06 Frank Ch. Eigler + + PR 6445 + * task_finder.c (stap_start_task_finder): When _stp_target + is set (stap -c or -x mode), restrict initial utrace attach + iteration to target process only. + 2008-09-01 Frank Ch. Eigler * task_finder.c: Move CONFIG_UTRACE assertion here. diff --git a/runtime/staprun/ChangeLog b/runtime/staprun/ChangeLog index 8b7a116d..21e02e47 100644 --- a/runtime/staprun/ChangeLog +++ b/runtime/staprun/ChangeLog @@ -1,3 +1,8 @@ +2008-09-06 Frank Ch. Eigler + + * mainloop.c (start_cmd): Rewrite to use wordexp/execvp/ptrace. + (stp_main_loop): Use ptrace detach to resume target process. + 2008-09-05 Frank Ch. Eigler * staprun.c (run_as): Teach it to exec too. Update callers. diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index 82435044..045772a3 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2008-09-06 Frank Ch. Eigler + + * systemtap.base/cmd_parse.exp: Adapt to sh-c-less "stap -c" + execution. + 2008-09-05 Stan Cox * systemtap.base/global_end.stp: Also check scalar statistics. diff --git a/testsuite/systemtap.base/cmd_parse.exp b/testsuite/systemtap.base/cmd_parse.exp index c37d358f..733881a1 100644 --- a/testsuite/systemtap.base/cmd_parse.exp +++ b/testsuite/systemtap.base/cmd_parse.exp @@ -5,76 +5,68 @@ if {![installtest_p]} { return } -# stap -c 'echo "hello world"' -e 'probe begin {}' -spawn stap -c {echo "hello world"} -e {probe begin {}} +spawn stap -c {echo "hello world"} -we {probe begin {}} expect { -timeout 60 "hello world" {pass "cmd_parse1"} timeout {fail "cmd_parse1: unexpected timeout"} eof {fail "cmd_parse1: unexpected EOF"} } -wait +wait;close -# stap -c 'echo "hello "\"world\"' -e 'probe begin {}' -spawn stap -c {echo "hello "\"world\"} -e {probe begin {}} +spawn stap -c {echo "hello "\"world\"} -we {probe begin {}} expect { -timeout 60 "hello \"world\"" {pass "cmd_parse2"} timeout {fail "cmd_parse2: unexpected timeout"} eof {fail "cmd_parse2: unexpected EOF"} } -wait +wait;close -#stap -c '(a="hello world"; echo $a)' -e 'probe begin {}' -spawn stap -c {(a="hello world"; echo $a)} -e {probe begin {}} +spawn stap -c {sh -c '(a="hello world"; echo $a)'} -we {probe begin {}} expect { -timeout 60 "hello world" {pass "cmd_parse3"} timeout {fail "cmd_parse3: unexpected timeout"} eof {fail "cmd_parse3: unexpected EOF"} } -wait +wait;close -#stap -c '(a="hello "\"world\"; echo $a)' -e 'probe begin {}' -spawn stap -c {(a="hello "\"world\"; echo $a)} -e {probe begin {}} +spawn stap -c {sh -c '(a="hello "\"world\"; echo $a)'} -we {probe begin {}} expect { -timeout 60 "hello \"world\"" {pass "cmd_parse4"} timeout {fail "cmd_parse4: unexpected timeout"} eof {fail "cmd_parse4: unexpected EOF"} } -wait +wait;close -#stap -c '(a="hello "world; echo $a)' -e 'probe begin {}' -spawn stap -c {(a="hello "world; echo $a)} -e {probe begin {}} +spawn stap -c {sh -c '(a="hello "world; echo $a)'} -we {probe begin {}} expect { -timeout 60 "hello world" {pass "cmd_parse5"} timeout {fail "cmd_parse5: unexpected timeout"} eof {fail "cmd_parse5: unexpected EOF"} } -wait +wait;close -#stap -c '(((a=42+7)); echo "The answer is $a")' -e 'probe begin {}' -# NB: not ((a=42+7)) - must not assume bash -spawn stap -c {(a=49; echo "The answer is $a")} -e {probe begin {}} +spawn stap -c {bash -c '((a=42+7)); echo "The answer is $a"'} -we {probe begin {}} expect { -timeout 60 "The answer is 49" {pass "cmd_parse6"} timeout {fail "cmd_parse6: unexpected timeout"} eof {fail "cmd_parse6: unexpected EOF"} } -wait +wait;close -#stap -c '(echo "Hello World" 1>&2) > /dev/null' -e 'probe begin {}' -spawn stap -c {(echo "Hello World" 1>&2) > /dev/null} -e {probe begin {}} +spawn stap -c {sh -c '(echo "Hello World" 1>&2) > /dev/null'} -we {probe begin {}} expect { -timeout 60 "Hello World" {pass "cmd_parse7"} timeout {fail "cmd_parse7: unexpected timeout"} eof {fail "cmd_parse7: unexpected EOF"} } -wait +wait;close spawn stap -l {vm.*} expect { @@ -83,7 +75,7 @@ expect { timeout {fail "cmd_parse8: unexpected timeout"} eof {fail "cmd_parse8: unexpected EOF"} } -wait +wait;close spawn stap -e {probe begin { printf("%d %s\n", argc, argv[$1]) exit() }} 1 expect { @@ -92,7 +84,7 @@ expect { timeout { fail "cmd_parse9 timeout" } eof { fail "cmd_parse9 eof" } } -wait +wait;close spawn stap -e {probe begin { printf("%d %s\n", argc, argv[$1]) exit() }} 5 a b c d expect { @@ -101,7 +93,7 @@ expect { timeout { fail "cmd_parse10 timeout" } eof { fail "cmd_parse10 eof" } } -wait +wait;close spawn stap -e {probe begin { printf("%d %s\n", argc, argv[$1]) exit() }} 10 a b c d expect { @@ -110,7 +102,7 @@ expect { timeout { fail "cmd_parse11 timeout" } eof { fail "cmd_parse11 eof" } } -wait +wait;close spawn stap -e {probe begin { printf("%d %s\n", argc, argv[0]) exit() }} expect { @@ -119,7 +111,7 @@ expect { timeout { fail "cmd_parse12 timeout" } eof { fail "cmd_parse12 eof" } } -wait +wait;close spawn stap -L syscall.a* expect { @@ -128,4 +120,4 @@ expect { timeout {fail "cmd_parse13: unexpected timeout"} eof {fail "cmd_parse13: unexpected EOF"} } -wait +wait;close -- cgit From 98f007e6f2c276b1e2faaca1bd7a2460cec17c3a Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Sat, 6 Sep 2008 10:53:19 -0400 Subject: PR6871: temporarily weaken the uprobe test since $$parms are unreliable --- testsuite/systemtap.base/uprobes.stp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testsuite/systemtap.base/uprobes.stp b/testsuite/systemtap.base/uprobes.stp index 957cbe16..d7efb586 100755 --- a/testsuite/systemtap.base/uprobes.stp +++ b/testsuite/systemtap.base/uprobes.stp @@ -1,3 +1,3 @@ #! stap -p4 -probe process("./jennie").function("main").call { log (pp() . " " . $$parms) } -probe process("./jennie").function("main").return { log (pp() . " " . $$return) } +probe process("./jennie").function("main").call { log(pp()." "/*.$$parms*/) } +probe process("./jennie").function("main").return { log(pp()." "/*.$$return*/) } -- cgit From 02a929d10b4cc68ef46d85af8d055ac0fcad3a71 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Sun, 7 Sep 2008 18:14:44 -0400 Subject: x86-32 blacklist extension (rhel5 testing based) --- ChangeLog | 4 ++++ tapsets.cxx | 2 ++ 2 files changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index 741c4ad0..09f661ae 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2008-09-07 Frank Ch. Eigler + + * tapsets.cxx (build_blacklist): Add some x86 raw port-io spots. + 2008-09-06 Frank Ch. Eigler * tapsets.cxx (utrace_derived_probe ctor): Handle diff --git a/tapsets.cxx b/tapsets.cxx index 240af469..64fa9d34 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -2919,6 +2919,8 @@ dwarf_query::build_blacklist() blfile += "kernel/kprobes.c"; // first alternative, no "|" blfile += "|arch/.*/kernel/kprobes.c"; + blfile += "|include/asm/io.h"; + blfile += "|drivers/ide/ide-iops.c"; // XXX: it would be nice if these blacklisted functions were pulled // in dynamically, instead of being statically defined here. -- cgit From 82f426c231754da7c58ddbeca29c3e36baa0b291 Mon Sep 17 00:00:00 2001 From: ddomingo Date: Mon, 8 Sep 2008 14:29:23 +1000 Subject: added content for Ch1 and 2, to add more later --- .../en-US/Introduction.xml | 33 ++++++++++++++---- .../en-US/SystemTap_Beginners_Guide.ent | 3 +- .../en-US/Understanding_How_SystemTap_Works.xml | 40 ++++++++++++++++++++-- 3 files changed, 66 insertions(+), 10 deletions(-) diff --git a/doc/SystemTap_Beginners_Guide/en-US/Introduction.xml b/doc/SystemTap_Beginners_Guide/en-US/Introduction.xml index 9285d0ae..f60ab2f3 100644 --- a/doc/SystemTap_Beginners_Guide/en-US/Introduction.xml +++ b/doc/SystemTap_Beginners_Guide/en-US/Introduction.xml @@ -5,15 +5,36 @@ Introduction - A short introduction on SystemTap_Beginners_Guide + SystemTap is a tracing and probing tool that provides users deep technical insight into what the operating system (particularly, the kernel) is doing at any given time. It provides information similar to the output of tools like netstat, ps, top, and iostat; however, SystemTap is designed to provide information that is more "granular" in nature. - + + For system administrators, SystemTap can be used as a performance monitoring tool for &PROD;. It is most useful when other similar tools cannot precisely pinpoint a bottleneck in the system, requiring a deep analysis of kernel activity. In the same manner, application developers can also use SystemTap to monitor, in finer detail, how their application behaves. + + + +
Goals - TBD - + The goal of SystemTap is to provide infrastructure to monitor the running Linux kernel for detailed analysis. This can assist in identifying the underlying cause of a performance or functional problem. + + Without SystemTap, monitoring the activity of a running kernel would require a tedious instrument, recompile, install, and reboot sequence. SystemTap is designed to eliminate this, allowing you to gather the same information by simply running its suite of tools against specific tapsets or SystemTap scripts. + + However, SystemTap was initially designed for users with intermediate to advanced knowledge of the kernel. This could present a steep learning curve for administrators or developers whose knowledge of the Linux kernel is little to none. + + In line with that, the main goal of the SystemTap Beginner's Guide is two-fold: + + + To introduce users to SystemTap, familiarize them with its architecture, and provide setup instructions for all kernel types. + + To provide pre-written SystemTap scripts for monitoring and forensic tasks, along with instructions on how to analyze their output. + + above, Short description on the underlying goals of SystemTap_Beginners_Guide, what we want to teach users. - +
Usage @@ -25,7 +46,7 @@
SystemTap Versus Other Monitoring Tools - Short summary; when is SystemTap suitable vs other popular monitoring tools (e.g. top, Oprofile, /proc) + ** Short summary; when is SystemTap suitable vs other popular monitoring tools (e.g. top, Oprofile, /proc) diff --git a/doc/SystemTap_Beginners_Guide/en-US/SystemTap_Beginners_Guide.ent b/doc/SystemTap_Beginners_Guide/en-US/SystemTap_Beginners_Guide.ent index 46bb6c06..994cf1a4 100644 --- a/doc/SystemTap_Beginners_Guide/en-US/SystemTap_Beginners_Guide.ent +++ b/doc/SystemTap_Beginners_Guide/en-US/SystemTap_Beginners_Guide.ent @@ -1,3 +1,4 @@ - \ No newline at end of file + + \ No newline at end of file diff --git a/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml b/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml index b3a1cbed..3194dba0 100644 --- a/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml +++ b/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml @@ -8,18 +8,52 @@ Short summary; probes, handlers, events + SystemTap allows users to write and reuse simple scripts to deeply examine the activities of a running Linux system. These scripts can be designed to extract data, filter it, and summarize it quickly (and safely), enabling the diagnosis of complex performance (or even functional) problems. + + The essential idea behind a SystemTap script is to name events, and to give them handlers. When SystemTap runs the script, SystemTap monitors for the event; once the event occurs, the Linux kernel then runs the handler as a quick sub-routine, then resumes. + + There are several kind of events; entering/exiting a function, timer expiration, session termination, etc. A handler is a series of script language statements that specify the work to be done whenever the event occurs. This work normally includes extracting data from the event context, storing them into internal variables, or printing results. +
Architecture - add diagram, describe architecture, enumerate common tools + ** add diagram, describe architecture, enumerate common tools -
+ + + ** architecture diagram must be simpler, if at all included + + + + ** add design advantages? e.g. "building kmods on-the-fly allows safer execution of script etc etc" + + + + test + + + A SystemTap session begins when you run a SystemTap script. This session occurs in the following fashion: + + + SystemTap Session + SystemTap first translates the script to C, running the system C compiler to create a kernel module from it. + + SystemTap then loads the module, then enables all the probed events by "hooking" those events into the kernel. + + As the events occur, their corresponding handlers are executed. + + Once the SystemTap session is terminated, the hooked events are disconnected from the kernel; afterwards, the kernel module is unloaded. + + +This sequence is driver from a single command-line program: stap. This program is SystemTap's main front-end tool. For more information about stap, refer to man stap (once SystemTap is set up on your machine). + +
SystemTap Scripts - definition, significance, structure, very basic examples, reference to later chapter (how to read library of preset SystemTap scripts in this book, using them) + ** definition, significance, structure, very basic examples, reference to later chapter (how to read library of preset SystemTap scripts in this book, using them)
-- cgit From e36b5fc35d4033d5718eb8e101968b79d0360202 Mon Sep 17 00:00:00 2001 From: ddomingo Date: Mon, 8 Sep 2008 14:42:17 +1000 Subject: remove test tag --- .../en-US/Understanding_How_SystemTap_Works.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml b/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml index 3194dba0..e418f561 100644 --- a/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml +++ b/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml @@ -26,10 +26,6 @@ ** add design advantages? e.g. "building kmods on-the-fly allows safer execution of script etc etc" - - - - test A SystemTap session begins when you run a SystemTap script. This session occurs in the following fashion: -- cgit From e6342ff8c11bbed1d2058507b918cf3c140e1322 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Mon, 8 Sep 2008 16:14:03 +0200 Subject: PR1288: runtime functions for avoiding certain addresses --- runtime/ChangeLog | 8 ++ runtime/addr-map.c | 181 +++++++++++++++++++++++++++++++++++++ runtime/loc2c-runtime.h | 230 ++++++++++++++++++++++++++++-------------------- runtime/runtime.h | 1 + 4 files changed, 326 insertions(+), 94 deletions(-) create mode 100644 runtime/addr-map.c diff --git a/runtime/ChangeLog b/runtime/ChangeLog index 8f20ed11..eb091d01 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,11 @@ +2008-09-08 Tim Moore + + PR 1288 + * addr-map.c: New file with functions for looking up addresses + * loc2c-runtime.h (deref, store_deref): Use lookup_bad_addr to + avoid dereferencing known dangerous addresses. + * runtime.h: Include addr-map.c. + 2008-09-06 Frank Ch. Eigler PR 6445 diff --git a/runtime/addr-map.c b/runtime/addr-map.c new file mode 100644 index 00000000..8231b57f --- /dev/null +++ b/runtime/addr-map.c @@ -0,0 +1,181 @@ +/* -*- linux-c -*- + * Map of addresses to disallow. + * Copyright (C) 2005-2008 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. + */ + +#ifndef _ADDR_MAP_C_ +#define _ADDR_MAP_C_ 1 + +/** @file addr-map + * @brief Implements functions used by the deref macro to blacklist + * certain addresses. + */ + +struct addr_map_entry +{ + unsigned long min; + unsigned long max; +}; + +struct addr_map +{ + size_t size; + struct addr_map_entry entries[0]; +}; + +static DEFINE_SPINLOCK(addr_map_lock); + +struct addr_map* blackmap; + +/* Find address of entry where we can insert a new one. */ +static size_t +upper_bound(unsigned long addr, struct addr_map* map) +{ + size_t start = 0; + size_t end = map->size; + struct addr_map_entry *entry = 0; + + if (end == 0) + return 0; + do + { + size_t new_idx; + if (addr < map->entries[start].min) + return start; + if (addr >= map->entries[end-1].max) + return end; + new_idx = (end + start) / 2; + entry = &map->entries[new_idx]; + if (addr < entry->min) + end = new_idx; + else + start = new_idx + 1; + } while (end != start); + return entry - &map->entries[0]; +} + +static struct addr_map_entry* +lookup_addr_aux(unsigned long addr, struct addr_map* map) +{ + size_t start = 0; + size_t end; + if (!map) + return 0; + end = map->size; + if (map->size == 0) + return 0; + + do + { + int entry_idx; + struct addr_map_entry *entry = 0; + if (addr < map->entries[start].min || addr >= map->entries[end - 1].max) + return 0; + entry_idx = (end + start) / 2; + entry = &map->entries[entry_idx]; + if (entry->min <= addr && entry->max > addr) + return entry; + if (addr < entry->min) + end = entry_idx; + else + start = entry_idx + 1; + } while (start < end); + return 0; +} + +int +lookup_bad_addr(unsigned long addr) +{ + struct addr_map_entry* result = 0; + spin_lock(&addr_map_lock); + result = lookup_addr_aux(addr, blackmap); + spin_unlock(&addr_map_lock); + if (result) + return 1; + else + return 0; +} + + +int +add_bad_addr_entry(unsigned long min_addr, unsigned long max_addr, + struct addr_map_entry** existing_min, + struct addr_map_entry** existing_max) +{ + struct addr_map* new_map = 0; + struct addr_map* old_map = 0; + struct addr_map_entry* min_entry = 0; + struct addr_map_entry* max_entry = 0; + struct addr_map_entry* new_entry = 0; + size_t existing = 0; + + while (1) + { + size_t old_size; + spin_lock(&addr_map_lock); + old_map = blackmap; + if (!blackmap) + { + existing = 0; + old_size = 0; + } + else + { + min_entry = lookup_addr_aux(min_addr, blackmap); + max_entry = lookup_addr_aux(max_addr, blackmap); + if (min_entry || max_entry) + { + if (existing_min) + *existing_min = min_entry; + if (existing_max) + *existing_max = max_entry; + spin_unlock(&addr_map_lock); + return 1; + } + existing = upper_bound(min_addr, old_map); + old_size = old_map->size; + } + spin_unlock(&addr_map_lock); + new_map = kmalloc(sizeof(*new_map) + + sizeof(*new_entry) * (old_size + 1), + GFP_KERNEL); + if (!new_map) + return -ENOMEM; + spin_lock(&addr_map_lock); + if (blackmap != old_map) + { + kfree(new_map); + spin_unlock(&addr_map_lock); + continue; + } + new_entry = &new_map->entries[existing]; + new_entry->min = min_addr; + new_entry->max = max_addr; + if (old_map) + { + memcpy(&new_map->entries, old_map->entries, + existing * sizeof(*new_entry)); + if (old_map->size > existing) + memcpy(new_entry + 1, &old_map->entries[existing + 1], + (old_map->size - existing) * sizeof(*new_entry)); + } + new_map->size = blackmap->size + 1; + blackmap = new_map; + spin_unlock(&addr_map_lock); + if (old_map) + kfree(old_map); + return 0; + } +} + +void +delete_bad_addr_entry(struct addr_map_entry* entry) +{ +} + +#endif diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h index 1247da51..0af19edc 100644 --- a/runtime/loc2c-runtime.h +++ b/runtime/loc2c-runtime.h @@ -201,6 +201,8 @@ #define deref(size, addr) ({ \ intptr_t _i; \ + if (lookup_bad_addr((unsigned long)addr)) \ + __deref_bad(); \ switch (size) { \ case 1: _i = kread((u8 *)(addr)); break; \ case 2: _i = kread((u16 *)(addr)); break; \ @@ -213,6 +215,8 @@ }) #define store_deref(size, addr, value) ({ \ + if (lookup_bad_addr((unsigned long)addr)) \ + __store_deref_bad(); \ switch (size) { \ case 1: kwrite((u8 *)(addr), (value)); break; \ case 2: kwrite((u16 *)(addr), (value)); break; \ @@ -234,30 +238,36 @@ extern void __store_deref_bad(void); int _bad = 0; \ u8 _b; u16 _w; u32 _l; \ intptr_t _v; \ - switch (size) \ - { \ - case 1: __get_user_asm(_b,addr,_bad,"b","b","=q",1); _v = _b; break; \ - case 2: __get_user_asm(_w,addr,_bad,"w","w","=r",1); _v = _w; break; \ - case 4: __get_user_asm(_l,addr,_bad,"l","","=r",1); _v = _l; break; \ - default: _v = __get_user_bad(); \ - } \ - if (_bad) \ - DEREF_FAULT(addr); \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) \ + { \ + case 1: __get_user_asm(_b,addr,_bad,"b","b","=q",1); _v = _b; break; \ + case 2: __get_user_asm(_w,addr,_bad,"w","w","=r",1); _v = _w; break; \ + case 4: __get_user_asm(_l,addr,_bad,"l","","=r",1); _v = _l; break; \ + default: _v = __get_user_bad(); \ + } \ + if (_bad) \ + DEREF_FAULT(addr); \ _v; \ }) #define store_deref(size, addr, value) \ ({ \ int _bad = 0; \ - switch (size) \ - { \ - case 1: __put_user_asm(((u8)(value)),addr,_bad,"b","b","iq",1); break; \ - case 2: __put_user_asm(((u16)(value)),addr,_bad,"w","w","ir",1); break; \ - case 4: __put_user_asm(((u32)(value)),addr,_bad,"l","k","ir",1); break; \ - default: __put_user_bad(); \ - } \ - if (_bad) \ - STORE_DEREF_FAULT(addr); \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) \ + { \ + case 1: __put_user_asm(((u8)(value)),addr,_bad,"b","b","iq",1); break;\ + case 2: __put_user_asm(((u16)(value)),addr,_bad,"w","w","ir",1); break;\ + case 4: __put_user_asm(((u32)(value)),addr,_bad,"l","k","ir",1); break;\ + default: __put_user_bad(); \ + } \ + if (_bad) \ + STORE_DEREF_FAULT(addr); \ }) @@ -268,14 +278,17 @@ extern void __store_deref_bad(void); int _bad = 0; \ u8 _b; u16 _w; u32 _l; u64 _q; \ intptr_t _v; \ - switch (size) \ - { \ - case 1: __get_user_asm(_b,addr,_bad,"b","b","=q",1); _v = _b; break; \ - case 2: __get_user_asm(_w,addr,_bad,"w","w","=r",1); _v = _w; break; \ - case 4: __get_user_asm(_l,addr,_bad,"l","","=r",1); _v = _l; break; \ - case 8: __get_user_asm(_q,addr,_bad,"q","","=r",1); _v = _q; break; \ - default: _v = __get_user_bad(); \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) \ + { \ + case 1: __get_user_asm(_b,addr,_bad,"b","b","=q",1); _v = _b; break; \ + case 2: __get_user_asm(_w,addr,_bad,"w","w","=r",1); _v = _w; break; \ + case 4: __get_user_asm(_l,addr,_bad,"l","","=r",1); _v = _l; break; \ + case 8: __get_user_asm(_q,addr,_bad,"q","","=r",1); _v = _q; break; \ + default: _v = __get_user_bad(); \ + } \ if (_bad) \ DEREF_FAULT(addr); \ _v; \ @@ -284,14 +297,17 @@ extern void __store_deref_bad(void); #define store_deref(size, addr, value) \ ({ \ int _bad = 0; \ - switch (size) \ - { \ - case 1: __put_user_asm(((u8)(value)),addr,_bad,"b","b","iq",1); break; \ - case 2: __put_user_asm(((u16)(value)),addr,_bad,"w","w","ir",1); break; \ - case 4: __put_user_asm(((u32)(value)),addr,_bad,"l","k","ir",1); break; \ - case 8: __put_user_asm(((u64)(value)),addr,_bad,"q","","Zr",1); break; \ - default: __put_user_bad(); \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) \ + { \ + case 1: __put_user_asm(((u8)(value)),addr,_bad,"b","b","iq",1); break; \ + case 2: __put_user_asm(((u16)(value)),addr,_bad,"w","w","ir",1); break;\ + case 4: __put_user_asm(((u32)(value)),addr,_bad,"l","k","ir",1); break;\ + case 8: __put_user_asm(((u64)(value)),addr,_bad,"q","","Zr",1); break; \ + default: __put_user_bad(); \ + } \ if (_bad) \ STORE_DEREF_FAULT(addr); \ }) @@ -301,13 +317,16 @@ extern void __store_deref_bad(void); ({ \ int _bad = 0; \ intptr_t _v=0; \ - switch (size){ \ - case 1: __get_user_size(_v, addr, 1, _bad); break; \ - case 2: __get_user_size(_v, addr, 2, _bad); break; \ - case 4: __get_user_size(_v, addr, 4, _bad); break; \ - case 8: __get_user_size(_v, addr, 8, _bad); break; \ - default: __get_user_unknown(); break; \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size){ \ + case 1: __get_user_size(_v, addr, 1, _bad); break; \ + case 2: __get_user_size(_v, addr, 2, _bad); break; \ + case 4: __get_user_size(_v, addr, 4, _bad); break; \ + case 8: __get_user_size(_v, addr, 8, _bad); break; \ + default: __get_user_unknown(); break; \ + } \ if (_bad) \ DEREF_FAULT(addr); \ _v; \ @@ -316,13 +335,16 @@ extern void __store_deref_bad(void); #define store_deref(size, addr, value) \ ({ \ int _bad=0; \ - switch (size){ \ - case 1: __put_user_size(value, addr, 1, _bad); break; \ - case 2: __put_user_size(value, addr, 2, _bad); break; \ - case 4: __put_user_size(value, addr, 4, _bad); break; \ - case 8: __put_user_size(value, addr, 8, _bad); break; \ - default: __put_user_unknown(); break; \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size){ \ + case 1: __put_user_size(value, addr, 1, _bad); break; \ + case 2: __put_user_size(value, addr, 2, _bad); break; \ + case 4: __put_user_size(value, addr, 4, _bad); break; \ + case 8: __put_user_size(value, addr, 8, _bad); break; \ + default: __put_user_unknown(); break; \ + } \ if (_bad) \ STORE_DEREF_FAULT(addr); \ }) @@ -373,30 +395,36 @@ extern void __store_deref_bad(void); ({ \ int _bad = 0; \ intptr_t _v; \ - switch (size) \ - { \ - case 1: __stp_get_user_asm(_v,addr,_bad,"lbz"); break; \ - case 2: __stp_get_user_asm(_v,addr,_bad,"lhz"); break; \ - case 4: __stp_get_user_asm(_v,addr,_bad,"lwz"); break; \ - case 8: __stp_get_user_asm(_v,addr,_bad,"ld"); break; \ - default: _v = __get_user_bad(); \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) \ + { \ + case 1: __stp_get_user_asm(_v,addr,_bad,"lbz"); break; \ + case 2: __stp_get_user_asm(_v,addr,_bad,"lhz"); break; \ + case 4: __stp_get_user_asm(_v,addr,_bad,"lwz"); break; \ + case 8: __stp_get_user_asm(_v,addr,_bad,"ld"); break; \ + default: _v = __get_user_bad(); \ + } \ if (_bad) \ - DEREF_FAULT(addr); \ + DEREF_FAULT(addr); \ _v; \ }) #define store_deref(size, addr, value) \ ({ \ int _bad = 0; \ - switch (size) \ - { \ - case 1: __stp_put_user_asm(((u8)(value)),addr,_bad,"stb"); break; \ - case 2: __stp_put_user_asm(((u16)(value)),addr,_bad,"sth"); break; \ - case 4: __stp_put_user_asm(((u32)(value)),addr,_bad,"stw"); break; \ - case 8: __stp_put_user_asm(((u64)(value)),addr,_bad, "std"); break; \ - default: __put_user_bad(); \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) \ + { \ + case 1: __stp_put_user_asm(((u8)(value)),addr,_bad,"stb"); break; \ + case 2: __stp_put_user_asm(((u16)(value)),addr,_bad,"sth"); break; \ + case 4: __stp_put_user_asm(((u32)(value)),addr,_bad,"stw"); break; \ + case 8: __stp_put_user_asm(((u64)(value)),addr,_bad, "std"); break; \ + default: __put_user_bad(); \ + } \ if (_bad) \ STORE_DEREF_FAULT(addr); \ }) @@ -541,12 +569,15 @@ extern void __store_deref_bad(void); ({ \ int _bad = 0; \ intptr_t _v=0; \ - switch (size){ \ - case 1: __stp_get_user_asm_byte(_v, addr, _bad); break; \ - case 2: __stp_get_user_asm_half(_v, addr, _bad); break; \ - case 4: __stp_get_user_asm_word(_v, addr, _bad); break; \ - default: __get_user_bad(); break; \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size){ \ + case 1: __stp_get_user_asm_byte(_v, addr, _bad); break; \ + case 2: __stp_get_user_asm_half(_v, addr, _bad); break; \ + case 4: __stp_get_user_asm_word(_v, addr, _bad); break; \ + default: __get_user_bad(); break; \ + } \ if (_bad) \ DEREF_FAULT(addr); \ _v; \ @@ -555,13 +586,16 @@ extern void __store_deref_bad(void); #define store_deref(size, addr, value) \ ({ \ int _bad=0; \ - switch (size){ \ - case 1: __stp_put_user_asm_byte(value, addr, _bad); break; \ - case 2: __stp_put_user_asm_half(value, addr, _bad); break; \ - case 4: __stp_put_user_asm_word(value, addr, _bad); break; \ - case 8: __stp_put_user_asm_dword(value, addr, _bad); break; \ - default: __put_user_bad(); break; \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size){ \ + case 1: __stp_put_user_asm_byte(value, addr, _bad); break; \ + case 2: __stp_put_user_asm_half(value, addr, _bad); break; \ + case 4: __stp_put_user_asm_word(value, addr, _bad); break; \ + case 8: __stp_put_user_asm_dword(value, addr, _bad); break; \ + default: __put_user_bad(); break; \ + } \ if (_bad) \ STORE_DEREF_FAULT(addr); \ }) @@ -624,28 +658,31 @@ extern void __store_deref_bad(void); u8 _b; u16 _w; u32 _l; u64 _q; \ int _bad = 0; \ intptr_t _v = 0; \ - switch (size) { \ - case 1: { \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) { \ + case 1: { \ __stp_get_asm(_b, addr, _bad, 1); \ _v = _b; \ break; \ - }; \ - case 2: { \ + }; \ + case 2: { \ __stp_get_asm(_w, addr, _bad, 2); \ _v = _w; \ break; \ - }; \ - case 4: { \ + }; \ + case 4: { \ __stp_get_asm(_l, addr, _bad, 4); \ _v = _l; \ break; \ - }; \ - case 8: { \ + }; \ + case 8: { \ __stp_get_asm(_q, addr, _bad, 8); \ _v = _q; \ break; \ - }; \ - default: \ + }; \ + default: \ _bad = -EFAULT; \ } \ if (_bad) \ @@ -657,12 +694,17 @@ extern void __store_deref_bad(void); ({ \ int _bad = 0; \ int i; \ - for(i=0;i>((size-i-1)*8)&0xff), \ - (u64)addr+i,_bad); \ - if (_bad) \ - STORE_DEREF_FAULT(addr); \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + for(i=0;i>((size-i-1)*8)&0xff), \ + (u64)addr+i,_bad); \ + if (_bad) \ + break; \ + } \ + if (_bad) \ + STORE_DEREF_FAULT(addr); \ }) diff --git a/runtime/runtime.h b/runtime/runtime.h index 2711f531..fd0cac9e 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -88,6 +88,7 @@ static struct #ifdef STP_PERFMON #include "perf.c" #endif +#include "addr-map.c" /* Support functions for int64_t module parameters. */ int param_set_int64_t(const char *val, struct kernel_param *kp) -- cgit