From f98b79158876247b64e49158be6b8c60d8448142 Mon Sep 17 00:00:00 2001 From: Dave Brolley Date: Wed, 14 Sep 2011 14:45:21 -0400 Subject: [PATCH] PR 11441 - continue with unprivileged test suite New test suite, unprivileged_myproc tests that process probes only fire within the user's own process for unprivileged users. Rename unprivileged_all.exp to unprivileged_probes.exp. --- testsuite/systemtap.unprivileged/delayedkill | 5 + testsuite/systemtap.unprivileged/libloop.c | 17 + testsuite/systemtap.unprivileged/loop.c | 46 +++ .../unprivileged_myproc.exp | 330 ++++++++++++++++++ .../unprivileged_probes.exp | 2 +- 5 files changed, 399 insertions(+), 1 deletion(-) create mode 100755 testsuite/systemtap.unprivileged/delayedkill create mode 100644 testsuite/systemtap.unprivileged/libloop.c create mode 100644 testsuite/systemtap.unprivileged/loop.c create mode 100644 testsuite/systemtap.unprivileged/unprivileged_myproc.exp diff --git a/testsuite/systemtap.unprivileged/delayedkill b/testsuite/systemtap.unprivileged/delayedkill new file mode 100755 index 000000000..78ebac453 --- /dev/null +++ b/testsuite/systemtap.unprivileged/delayedkill @@ -0,0 +1,5 @@ +#!/bin/sh + +# Wait for the specified number of seconds, then kill the given pid +sleep $2 +kill $1 diff --git a/testsuite/systemtap.unprivileged/libloop.c b/testsuite/systemtap.unprivileged/libloop.c new file mode 100644 index 000000000..041cf741d --- /dev/null +++ b/testsuite/systemtap.unprivileged/libloop.c @@ -0,0 +1,17 @@ +#include "sys/sdt.h" + +inline int ilibloopfunc (void) { + int i, j = 0; + STAP_PROBE(_test_, ilibloopfunc_enter); + for (i = 0; i < 10; ++i) + j += i; + return j; +} + +int libloopfunc (void) { + int i, j = 0; + STAP_PROBE(_test_, libloopfunc_enter); + for (i = 0; i < 10; ++i) + j += ilibloopfunc (); + return j; +} diff --git a/testsuite/systemtap.unprivileged/loop.c b/testsuite/systemtap.unprivileged/loop.c new file mode 100644 index 000000000..ec028ab6f --- /dev/null +++ b/testsuite/systemtap.unprivileged/loop.c @@ -0,0 +1,46 @@ +#include +#include +#include "sys/sdt.h" + +extern int libloopfunc (void); + +/* Thread entry point */ +void *bar (void *b) { + int i; + int *j = (int *)b; + for (i = 0; i < 10; ++i) + *j += i; + a: + return b; +} + +/* We need an inline function. */ +inline int ibar (void) { + return libloopfunc (); +} + +/* We need a threaded app. */ +inline int tbar (void) { + void *x; + int j = 0; + STAP_PROBE(_test_, main_enter); + pthread_t thread; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_create (& thread, & attr, bar, (void*)& j); + pthread_join (thread, & x); + return j; +} + +main (int argc, char *argv[]) { + int j = 0; + for (;;) { + j += ibar (); + j += tbar (); + /* Don't loop if an argument was passed */ + if (argc > 1) + return 0; + usleep (250000); /* 1/4 second pause. */ + } + return j; +} diff --git a/testsuite/systemtap.unprivileged/unprivileged_myproc.exp b/testsuite/systemtap.unprivileged/unprivileged_myproc.exp new file mode 100644 index 000000000..8d6e0f122 --- /dev/null +++ b/testsuite/systemtap.unprivileged/unprivileged_myproc.exp @@ -0,0 +1,330 @@ +set test "unprivileged myproc" + +set exepath "loop" +set sopath "libloop.so" + +# These probe types should be acceptable for unprivileged users +set valid_probe_types [list \ + "process.begin" \ + "process.end" \ + "process.function(string)" \ + "process.function(number)" \ + "process.function(number).call" \ + "process.function(number).inline" \ + "process.function(number).return" \ + "process.function(string).call" \ + "process.function(string).inline" \ + "process.function(string).label(string)" \ + "process.function(string).return" \ + "process.library(string).function(number)" \ + "process.library(string).function(number).call" \ + "process.library(string).function(number).inline" \ + "process.library(string).function(number).return" \ + "process.library(string).function(string)" \ + "process.library(string).function(string).call" \ + "process.library(string).function(string).inline" \ + "process.library(string).function(string).return" \ + "process.library(string).mark(string)" \ + "process.library(string).provider(string).mark(string)" \ + "process.library(string).statement(number)" \ + "process.library(string).statement(string)" \ + "process.mark(string)" \ + "process.statement(number)" \ + "process.statement(string)" \ + "process.syscall" \ + "process.syscall.return" \ + "process.thread.begin" \ + "process.thread.end" \ + "process(number).begin" \ + "process(number).end" \ + "process(number).statement(number).absolute" \ + "process(number).statement(number).absolute.return" \ + "process(number).syscall" \ + "process(number).syscall.return" \ + "process(number).thread.begin" \ + "process(number).thread.end" \ + "process(string).begin" \ + "process(string).end" \ + "process(string).function(number)" \ + "process(string).function(number).call" \ + "process(string).function(number).inline" \ + "process(string).function(number).return" \ + "process(string).function(string)" \ + "process(string).function(string).call" \ + "process(string).function(string).inline" \ + "process(string).function(string).return" \ + "process(string).library(string).function(number)" \ + "process(string).library(string).function(number).call" \ + "process(string).library(string).function(number).inline" \ + "process(string).library(string).function(number).return" \ + "process(string).library(string).function(string)" \ + "process(string).library(string).function(string).call" \ + "process(string).library(string).function(string).inline" \ + "process(string).library(string).function(string).return" \ + "process(string).library(string).mark(string)" \ + "process(string).library(string).provider(string).mark(string)" \ + "process(string).library(string).statement(number)" \ + "process(string).library(string).statement(string)" \ + "process(string).mark(string)" \ + "process(string).provider(string).mark(string)" \ + "process(string).statement(number)" \ + "process(string).statement(string)" \ + "process(string).syscall" \ + "process(string).syscall.return" \ + "process(string).thread.begin" \ + "process(string).thread.end" \ + "process(string).function(string).label(string)" \ +] + +# Add arguments to a probe type template. +proc add_args { probe_type pid } { + global exepath sopath + + set probe "$probe_type" + + # Replace "hz(number)" with "hz(1000)" + regsub -all "hz\\(number\\)" $probe "hz(1000)" probe + # Replace "ns(number)" with "ns(100000)" + regsub -all "ns\\(number\\)" $probe "ns(100000)" probe + # Replace "nsec(number)" with "nsec(100000)" + regsub -all "nsec\\(number\\)" $probe "nsec(100000)" probe + # Replace "us(number)" with "us(100)" + regsub -all "us\\(number\\)" $probe "us(100)" probe + # Replace "usec(number)" with "usec(100)" + regsub -all "usec\\(number\\)" $probe "usec(100)" probe + # Replace "process(number)" with "process($pid)" + regsub -all "process\\(number\\)" $probe "process($pid)" probe + + # Replace "library(string).function(string).inline" with "library(string).function("ilibloopfunc").inline" + regsub -all "library\\(string\\).function\\(string\\).inline" $probe "library(string).function(\"ilibloopfunc\").inline" probe + + # Replace "function(string).inline" with "function("ibar").inline" + regsub -all "function\\(string\\).inline" $probe "function(\"ibar\").inline" probe + + # Replace "library(string).function(string)" with "library(string.function("libloopfunc")" + regsub -all "library\\(string\\).function\\(string\\)" $probe "library(string).function(\"libloopfunc\")" probe + # Replace "library(string).function(number)" with "library(string).function($addr_of_libloopfunc)" + set addr_of_libloopfunc [exec objdump -d $sopath | awk {// { printf "0x%s\n",$1 }}] + regsub -all "library\\(string\\).function\\(number\\)" $probe "library(string).function($addr_of_libloopfunc)" probe + + # Replace "function(string)" with "function("bar")" + regsub -all "function\\(string\\)" $probe "function(\"bar\")" probe + # Replace "function(number)" with "function($addr_of_bar)" + set addr_of_bar [exec objdump -d $exepath | awk {// { printf "0x%s\n",$1 }}] + regsub -all "function\\(number\\)" $probe "function($addr_of_bar)" probe + + # Replace "label(string)" with "label("a")" + regsub -all "label\\(string\\)" $probe "label(\"a\")" probe + + # Replace "library(string).mark(string)" with "library(string).mark("libloopfunc_enter")" + regsub -all "library\\(string\\).mark\\(string\\)" $probe "library(string).mark(\"libloopfunc_enter\")" probe + # Replace "library(string).provider(string).mark(string)" with "library(string).provider(string).mark("libloopfunc_enter")" + regsub -all "library\\(string\\).provider\\(string\\).mark\\(string\\)" $probe "library(string).provider(string).mark(\"libloopfunc_enter\")" probe + # Replace "mark(string)" with "mark("main_enter")" + regsub -all "mark\\(string\\)" $probe "mark(\"main_enter\")" probe + + # Replace "library(string).statement(number)" with "library(string).statement($addr_of_libloopfunc)" + set addr_of_libloopfunc [exec objdump -d $sopath | awk {// { printf "0x%s\n",$1 }}] + regsub -all "library\\(string\\).statement\\(number\\)" $probe "library(string).statement($addr_of_libloopfunc)" probe + # Replace "library(string).statement(string)" with "library(string).statement("libloopfunc@libloop.c:*")" + regsub -all "library\\(string\\).statement\\(string\\)" $probe "library(string).statement(\"libloopfunc@libloop.c:*\")" probe + + # Replace "statement(number)" with "statement($addr_of_bar)" + set addr_of_bar [exec objdump -d $exepath | awk {// { printf "0x%s\n",$1 }}] + regsub -all "statement\\(number\\)" $probe "statement($addr_of_bar)" probe + # Replace "statement(string)" with "statement("bar@loop.c:*")" + regsub -all "statement\\(string\\)" $probe "statement(\"bar@loop.c:*\")" probe + + # Replace "library(string)" with "library("$sopath")" + regsub -all "library\\(string\\)" $probe "library(\"$sopath\")" probe + + # Replace "provider(string)" with "provider("_test_")" + regsub -all "provider\\(string\\)" $probe "provider(\"_test_\")" probe + + # Replace "(number)" with "(10)" + regsub -all "\\(number\\)" $probe "(10)" probe + # Replace "(string)" with "(\"$exepath\")" + regsub -all "\\(string\\)" $probe "(\"./$exepath\")" probe + + return "$probe" +} + +# Add required extra options according to the probe type. +proc extra_options { probe_type } { + global exepath + + # Add '-c $exepath 1' for process.* probes. + if {[regexp "^process\\." $probe_type]} { + return "-c \"./$exepath 1\"" + } + + return "" +} + +# Test valid probe types +proc test_probes { } { + global valid_probe_types test srcdir subdir tested + + set effective_uid [exec /usr/bin/id -u] + set stap [exec /usr/bin/which stap] + + # These probe types are not valid for unprivileged users, but make sure they aren't reported + # as untested. + set tested(process(number).insn) 1 + set tested(process(number).insn.block) 1 + set tested(process(string).insn) 1 + set tested(process(string).insn.block) 1 + + # Start the test executable in the background + set our_pid [exec ./loop &] + verbose -log "our ./loop pid is $our_pid" + + # If we are not root start another one as root. It will be a failure if any probes fail against + # this instance. + if {$effective_uid != 0} { + # ask for password here, if required ... + as_root { true } + # ... and not here. + exec sudo ./loop & + # Give it a chance to start + sleep 1 + set root_pid [exec ps -fe | awk {/^root.*[^o] \.\/loop/ { print $2 }}] + verbose -log "root's ./loop pid is $root_pid" + } + + foreach probe_type $valid_probe_types { + # There are currently some known and expected failures and some untestable probe types + switch $probe_type { + process.library(string).function(number).inline - + process(string).library(string).function(number).inline - + process.function(number).inline - + process(string).function(number).inline + { + setup_xfail *-*-* + } + process(number).thread.begin - + process(number).thread.end + { + untested "$test: $probe_type" + set tested($probe_type) 1 + continue + } + + } + + # Test the probe type. If successful, the stap rc will be 0. + set probe [add_args $probe_type $our_pid] + set cmd [concat [list $stap --unprivileged -e "probe $probe { if (is_myproc ()) println (\"is myproc\") else println (\"not myproc\"); exit (); }"] [extra_options $probe_type]] + + # If the probe types was 'process(number).end' or 'process(string).end' then set up a + # delayed kill of our test program in order to make the probe fire. + if {[regexp "^process\\(number\\)\\.end" $probe_type] || \ + [regexp "^process\\(string\\)\\.end" $probe_type]} { + exec $srcdir/$subdir/delayedkill $our_pid 5 & + } + + # Run stap. + verbose -log "eval exec $cmd" + set rc [catch {eval exec $cmd} res_stap] + verbose -log "rc == $rc" + verbose -log $res_stap + + # The test passes if it returns 0 and prints "is myproc". + if {$rc == 0 && [regexp ".*is myproc.*" "$res_stap"]} { + pass "$test: $probe_type" + } else { + fail "$test: $probe_type" + } + + # Indicate that this probe type has been tested + set tested($probe_type) 1 + + # If the probe types was 'process(number).end' or 'process(string).end', then our test + # program was killed in order to make the probe fire. Restart it. + if {[regexp "^process\\(number\\)\\.end" $probe_type] || \ + [regexp "^process\\(string\\)\\.end" $probe_type]} { + set our_pid [exec ./loop &] + verbose -log "our ./loop pid is $our_pid" + } + } + + # Kill the the test executable(s) + exec kill $our_pid + if {$effective_uid != 0} { + as_root "kill $root_pid" + } +} + +# Need to build a user shared library. +set libflags [sdt_includes] +set libflags "$libflags additional_flags=-g" +set libflags "$libflags additional_flags=-O" +set libflags "$libflags additional_flags=-Wall" +set libflags "$libflags additional_flags=-Werror" +set libflags "$libflags additional_flags=-I." +set libflags "$libflags additional_flags=-shared" +set libflags "$libflags additional_flags=-fPIC" +set res [target_compile $srcdir/$subdir/libloop.c $sopath executable $libflags ] +if { $res == "" } { + pass "$test library compile" +} else { + fail "$test library compile: $res" + untested "$test Tests" + return +} + +# Need to build a user application +set exeflags "additional_flags=-g" +set exeflags "$exeflags additional_flags=-O" +set exeflags "$exeflags additional_flags=-lpthread" +set exeflags "$exeflags [sdt_includes]" +set exeflags "$exeflags additional_flags=-Wl,-rpath,[pwd]" +set exeflags "$exeflags additional_flags=-L[pwd] additional_flags=-lloop" +set exeflags "$exeflags compiler=gcc" +# ppc64 needs a more restrictive constraint for the probe args +if {[regexp "^(x86_64|i.86)$" $::tcl_platform(machine)] == 0} { +set exeflags "$exeflags additional_flags=-DSTAP_SDT_ARG_CONSTRAINT=nr" +} +set res [target_compile $srcdir/systemtap.unprivileged/loop.c $exepath executable "$exeflags"] +if { $res == "" } { + pass "$test exe compile" +} else { + fail "$test exe compile: $res" + untested "$test Tests" + return +} + +# Obtain a list of all process* probe types from stap +verbose -log "eval exec stap --dump-probe-types | grep ^process" +catch {eval exec stap --dump-probe-types | grep ^process} res_stap +set all_probe_types [split $res_stap "\n"] + +# Initialize each probe type to untested +foreach probe_type $all_probe_types { + verbose -log $probe_type + set tested($probe_type) 0 +} +if {[llength all_probe_types] > 0} { + pass "$test: Obtain list of supported probe types" +} else { + fail "$test: Obtain list of supported probe types" + untested "$test Tests" + return +} + +# Now run the tests +test_probes + +# Generate a failure for each untested probe type +foreach probe_type $all_probe_types { + set status $tested($probe_type) + if {$status != 0} { + pass "$test: tested: $probe_type" + } else { + fail "$test: not tested: $probe_type" + } +} + +# Cleanup +catch {exec rm -f $exepath} +catch {exec rm -f $sopath} diff --git a/testsuite/systemtap.unprivileged/unprivileged_probes.exp b/testsuite/systemtap.unprivileged/unprivileged_probes.exp index 7c3061beb..8100f05da 100644 --- a/testsuite/systemtap.unprivileged/unprivileged_probes.exp +++ b/testsuite/systemtap.unprivileged/unprivileged_probes.exp @@ -1,4 +1,4 @@ -set test unprivilegedall +set test "unprivileged probes" set exepath "foo" set sopath "libfoo.so" -- 2.43.5