From ab8d12806d3d1e1dcc6a7acc9e7654f263e95a57 Mon Sep 17 00:00:00 2001 From: michalbiesek Date: Tue, 6 Sep 2022 00:14:11 +0200 Subject: [PATCH] (#1096) Detect AppScope library state in the application - check the state of application if was unscoped/scoped/loaded - provide a dummy mapping for the loaded state Closes #1096 --- cli/cmd/ps.go | 1 + cli/run/attach.go | 6 +-- cli/run/start.go | 2 +- cli/util/proc.go | 72 ++++++++++++++++--------- cli/util/proc_test.go | 16 +++--- os/linux/Makefile | 1 + os/linux/aarch64.mk | 2 +- os/linux/x86_64.mk | 2 +- src/libstate.c | 82 +++++++++++++++++++++++++++++ src/libstate.h | 10 ++++ src/runtimecfg.h | 2 +- src/wrap.c | 41 +++++++++------ test/execute.sh | 1 + test/libstatetest.c | 120 ++++++++++++++++++++++++++++++++++++++++++ 14 files changed, 302 insertions(+), 56 deletions(-) create mode 100644 src/libstate.c create mode 100644 src/libstate.h create mode 100644 test/libstatetest.c diff --git a/cli/cmd/ps.go b/cli/cmd/ps.go index fbf06db5e..1d4b95ac8 100644 --- a/cli/cmd/ps.go +++ b/cli/cmd/ps.go @@ -38,6 +38,7 @@ var psCmd = &cobra.Command{ {Name: "Pid", Field: "pid"}, {Name: "User", Field: "user"}, {Name: "Command", Field: "command"}, + {Name: "State", Field: "scoped"}, }, procs) }, } diff --git a/cli/run/attach.go b/cli/run/attach.go index a00eb6fa4..4a2989bf1 100644 --- a/cli/run/attach.go +++ b/cli/run/attach.go @@ -74,8 +74,8 @@ func (rc *Config) Attach(args []string) error { return errPidMissing } // Check PID is not already being scoped - if util.PidScoped(pid) { - return errAlreadyScope + if util.PidScopeState(pid) == util.Scoped { + util.ErrAndExit("Attach failed. This process is already being scoped") } // Create ldscope if err := createLdscope(); err != nil { @@ -115,7 +115,7 @@ func choosePid(procs util.Processes) (int, error) { {Name: "ID", Field: "id"}, {Name: "Pid", Field: "pid"}, {Name: "User", Field: "user"}, - {Name: "Scoped", Field: "scoped"}, + {Name: "State", Field: "scoped"}, {Name: "Command", Field: "command"}, }, procs) fmt.Println("Select an ID from the list:") diff --git a/cli/run/start.go b/cli/run/start.go index 74ea03ea9..2f9872564 100644 --- a/cli/run/start.go +++ b/cli/run/start.go @@ -139,7 +139,7 @@ func startAttach(allowProc allowProcConfig) error { } for pid, scopeState := range pidsToAttach { - if scopeState { + if scopeState == util.Scoped { log.Info(). Str("pid", strconv.Itoa(pid)). Msgf("Attach Failed. Process: %v is already scoped.", pid) diff --git a/cli/util/proc.go b/cli/util/proc.go index 873bf9507..91d542bfb 100644 --- a/cli/util/proc.go +++ b/cli/util/proc.go @@ -12,17 +12,30 @@ import ( linuxproc "github.com/c9s/goprocinfo/linux" ) +type ScopeState int + +const ( + Unscoped ScopeState = iota + Scoped + Loaded + Unknown +) + +func (ss ScopeState) String() string { + return []string{"Unscoped", "Scoped", "Loaded", "Unknown"}[ss] +} + // Process is a unix process type Process struct { - ID int `json:"id"` - Pid int `json:"pid"` - User string `json:"user"` - Scoped bool `json:"scoped"` - Command string `json:"command"` + ID int `json:"id"` + Pid int `json:"pid"` + User string `json:"user"` + ScopeStatus ScopeState `json:"scoped"` + Command string `json:"command"` } // PidScopeMap is a map of Pid and Scope state -type PidScopeMapState map[int]bool +type PidScopeMapState map[int]ScopeState // Processes is an array of Process type Processes []Process @@ -85,7 +98,7 @@ func pidScopeMapSearch(inputArg string, sF searchFun) (PidScopeMapState, error) } if sF(pid, inputArg) { - pidMap[pid] = PidScoped(pid) + pidMap[pid] = PidScopeState(pid) } } @@ -149,11 +162,11 @@ func ProcessesByName(name string) (Processes, error) { // Add process if there is a name match if strings.Contains(command, name) { processes = append(processes, Process{ - ID: i, - Pid: pid, - User: userName, - Scoped: PidScoped(pid), - Command: cmdLine, + ID: i, + Pid: pid, + User: userName, + ScopeStatus: PidScopeState(pid), + Command: cmdLine, }) i++ } @@ -200,15 +213,15 @@ func ProcessesScoped() (Processes, error) { continue } - // Add process if is is scoped - scoped := PidScoped(pid) - if scoped { + // Add process if is is scoped or loaded + scopeState := PidScopeState(pid) + if scopeState == Scoped || scopeState == Loaded { processes = append(processes, Process{ - ID: i, - Pid: pid, - User: userName, - Scoped: scoped, - Command: cmdLine, + ID: i, + Pid: pid, + User: userName, + ScopeStatus: scopeState, + Command: cmdLine, }) i++ } @@ -234,11 +247,11 @@ func PidUser(pid int) (string, error) { return user.Username, nil } -// PidScoped checks if a process specified by PID is being scoped -func PidScoped(pid int) bool { +// PidScopeState retrieve Scope state of a process specified by PID +func PidScopeState(pid int) ScopeState { pidMapFile, err := ioutil.ReadFile(fmt.Sprintf("/proc/%v/maps", pid)) if err != nil { - return false + return Unknown } // Look for libscope in map @@ -246,12 +259,19 @@ func PidScoped(pid int) bool { if strings.Contains(pidMap, "libscope") { command, err := PidCommand(pid) if err != nil { - return false + return Unknown + } + + if command == "ldscopedyn" { + return Unscoped } - return command != "ldscopedyn" + if strings.Contains(pidMap, "scope_loaded") { + return Loaded + } + return Scoped } - return false + return Unscoped } // PidCommand gets the command used to start the process specified by PID diff --git a/cli/util/proc_test.go b/cli/util/proc_test.go index f7c326573..07d6abe46 100644 --- a/cli/util/proc_test.go +++ b/cli/util/proc_test.go @@ -20,11 +20,11 @@ func TestProcessesByName(t *testing.T) { user, _ := user.Current() exp := Processes{ Process{ - ID: 1, - Pid: os.Getpid(), - User: user.Username, - Command: strings.Join(os.Args[:], " "), - Scoped: false, + ID: 1, + Pid: os.Getpid(), + User: user.Username, + Command: strings.Join(os.Args[:], " "), + ScopeStatus: Unscoped, }, } assert.Equal(t, exp, result) @@ -42,7 +42,7 @@ func TestPidScopeMapByProcessName(t *testing.T) { assert.NoError(t, err) assert.Len(t, pidMap, 1) assert.Contains(t, pidMap, os.Getpid()) - assert.Equal(t, pidMap[os.Getpid()], false) + assert.Equal(t, pidMap[os.Getpid()], Unscoped) } // TestPidScopeMapByProcessName @@ -70,7 +70,7 @@ func TestPidScopeMapByCmdLine(t *testing.T) { assert.NoError(t, err) assert.Len(t, pidMap, 1) assert.Contains(t, pidMap, os.Getpid()) - assert.Equal(t, pidMap[os.Getpid()], false) + assert.Equal(t, pidMap[os.Getpid()], Unscoped) } // TestPidScopeMapByCmdLineCharShorter @@ -86,7 +86,7 @@ func TestPidScopeMapByCmdLineCharShorter(t *testing.T) { assert.NoError(t, err) assert.Len(t, pidMap, 1) assert.Contains(t, pidMap, os.Getpid()) - assert.Equal(t, pidMap[os.Getpid()], false) + assert.Equal(t, pidMap[os.Getpid()], Unscoped) } // TestPidUser diff --git a/os/linux/Makefile b/os/linux/Makefile index 127d8433c..98e3294a5 100644 --- a/os/linux/Makefile +++ b/os/linux/Makefile @@ -106,6 +106,7 @@ coretest: $(C_FILES) $(YAML_AR) $(JSON_AR) $(TEST_LIB) $(CC) $(TEST_CFLAGS) -o test/$(OS)/httpstatetest httpstatetest.o httpstate.o plattime.o search.o fn.o utils.o os.o scopestdlib.o dbg.o test.o com.o cfg.o cfgutils.o mtc.o mtcformat.o strset.o ctl.o transport.o linklist.o log.o evtformat.o circbuf.o state.o metriccapture.o report.o httpagg.o $(TEST_AR) $(TEST_LD_FLAGS) -Wl,--wrap=cmdPostEvent -lrt $(CC) $(TEST_CFLAGS) -o test/$(OS)/httpheadertest httpheadertest.o report.o httpagg.o state.o com.o httpstate.o metriccapture.o plattime.o fn.o utils.o os.o ctl.o log.o transport.o scopestdlib.o dbg.o cfgutils.o cfg.o mtc.o evtformat.o mtcformat.o strset.o circbuf.o linklist.o search.o test.o $(TEST_AR) $(TEST_LD_FLAGS) -Wl,--wrap=cmdSendHttp -Wl,--wrap=cmdPostEvent $(CC) $(TEST_CFLAGS) -o test/$(OS)/httpaggtest httpaggtest.o httpagg.o fn.o utils.o scopestdlib.o dbg.o plattime.o os.o test.o $(TEST_AR) $(TEST_LD_FLAGS) + $(CC) $(TEST_CFLAGS) -o test/$(OS)/libstatetest libstatetest.o libstate.o scopestdlib.o dbg.o test.o $(TEST_AR) $(TEST_LD_FLAGS) $(CC) $(TEST_CFLAGS) -o test/$(OS)/reporttest reporttest.o report.o httpagg.o state.o httpstate.o metriccapture.o com.o plattime.o fn.o utils.o os.o ctl.o log.o transport.o scopestdlib.o dbg.o cfgutils.o cfg.o mtc.o evtformat.o mtcformat.o strset.o circbuf.o linklist.o search.o test.o $(TEST_AR) $(TEST_LD_FLAGS) -Wl,--wrap=cmdSendEvent -Wl,--wrap=cmdSendMetric $(CC) $(TEST_CFLAGS) -o test/$(OS)/mtcformattest mtcformattest.o mtcformat.o strset.o scopestdlib.o dbg.o log.o transport.o com.o ctl.o mtc.o evtformat.o cfg.o cfgutils.o linklist.o fn.o utils.o circbuf.o os.o test.o report.o search.o httpagg.o state.o httpstate.o metriccapture.o plattime.o $(TEST_AR) $(TEST_LD_FLAGS) $(CC) $(TEST_CFLAGS) -o test/$(OS)/circbuftest circbuftest.o circbuf.o scopestdlib.o dbg.o test.o $(TEST_AR) $(TEST_LD_FLAGS) diff --git a/os/linux/aarch64.mk b/os/linux/aarch64.mk index 7cc4d0a13..835ccfc94 100644 --- a/os/linux/aarch64.mk +++ b/os/linux/aarch64.mk @@ -5,7 +5,7 @@ ARCH_OBJ=$(ARCH) LD_FLAGS=$(MUSL_AR) $(UNWIND_AR) $(PCRE2_AR) $(LS_HPACK_AR) $(YAML_AR) $(JSON_AR) -ldl -lpthread -lrt -lresolv -Lcontrib/build/funchook -lfunchook -Lcontrib/build/funchook/capstone_src-prefix/src/capstone_src-build -lcapstone INCLUDES=-I./contrib/libyaml/include -I./contrib/cJSON -I./os/$(OS) -I./contrib/pcre2/src -I./contrib/build/pcre2 -I./contrib/funchook/capstone_src/include/ -I./contrib/jni -I./contrib/jni/linux/ -I./contrib/openssl/include -I./contrib/build/openssl/include -I./contrib/build/libunwind/include -I./contrib/libunwind/include/ -$(LIBSCOPE): src/wrap.c src/state.c src/httpstate.c src/metriccapture.c src/report.c src/httpagg.c src/plattime.c src/fn.c os/$(OS)/os.c src/cfgutils.c src/cfg.c src/transport.c src/log.c src/mtc.c src/circbuf.c src/linklist.c src/evtformat.c src/ctl.c src/mtcformat.c src/com.c src/scopestdlib.c src/dbg.c src/search.c src/scopeelf.c src/utils.c src/strset.c src/javabci.c src/javaagent.c +$(LIBSCOPE): src/wrap.c src/state.c src/httpstate.c src/metriccapture.c src/report.c src/httpagg.c src/plattime.c src/fn.c os/$(OS)/os.c src/cfgutils.c src/libstate.c src/cfg.c src/transport.c src/log.c src/mtc.c src/circbuf.c src/linklist.c src/evtformat.c src/ctl.c src/mtcformat.c src/com.c src/scopestdlib.c src/dbg.c src/search.c src/scopeelf.c src/utils.c src/strset.c src/javabci.c src/javaagent.c @$(MAKE) -C contrib funchook pcre2 openssl ls-hpack musl libyaml libunwind cJSON @echo "$${CI:+::group::}Building $@" $(CC) $(CFLAGS) \ diff --git a/os/linux/x86_64.mk b/os/linux/x86_64.mk index cb24576cf..60e2e86d0 100644 --- a/os/linux/x86_64.mk +++ b/os/linux/x86_64.mk @@ -11,7 +11,7 @@ INCLUDES=-I./contrib/libyaml/include -I./contrib/cJSON -I./os/$(OS) -I./contrib/ # objcopy -I binary -O elf64-x86-64 -B i386 ./lib/$(OS)/libscope.so ./lib/$(OS)/libscope.o && \ # rm -f ./lib/$(OS)/libscope.so -$(LIBSCOPE): src/wrap.c src/state.c src/httpstate.c src/metriccapture.c src/report.c src/httpagg.c src/plattime.c src/fn.c os/$(OS)/os.c src/cfgutils.c src/cfg.c src/transport.c src/log.c src/mtc.c src/circbuf.c src/linklist.c src/evtformat.c src/ctl.c src/mtcformat.c src/com.c src/scopestdlib.c src/dbg.c src/search.c src/sysexec.c src/gocontext.S src/scopeelf.c src/wrap_go.c src/utils.c src/strset.c src/javabci.c src/javaagent.c +$(LIBSCOPE): src/wrap.c src/state.c src/httpstate.c src/metriccapture.c src/report.c src/httpagg.c src/plattime.c src/fn.c os/$(OS)/os.c src/cfgutils.c src/libstate.c src/cfg.c src/transport.c src/log.c src/mtc.c src/circbuf.c src/linklist.c src/evtformat.c src/ctl.c src/mtcformat.c src/com.c src/scopestdlib.c src/dbg.c src/search.c src/sysexec.c src/gocontext.S src/scopeelf.c src/wrap_go.c src/utils.c src/strset.c src/javabci.c src/javaagent.c @$(MAKE) -C contrib funchook pcre2 openssl ls-hpack musl libyaml cJSON libunwind @echo "$${CI:+::group::}Building $@" $(CC) $(CFLAGS) $(ARCH_CFLAGS) \ diff --git a/src/libstate.c b/src/libstate.c new file mode 100644 index 000000000..383f20aa9 --- /dev/null +++ b/src/libstate.c @@ -0,0 +1,82 @@ +#include "libstate.h" +#include +#include "scopestdlib.h" + +static void *loadedStrMap = NULL; +#define LOADED_MAP_SIZE (4096) + +/* + * AppScope state describes the process state in context of the AppScope library. + * We recognize two states: + * - Scoped - when all the functions are funchooked + * - AppScope library is loaded - when execve family functions are funchooked + * + * The distinguish between the AppScope states is based on presence of the "loaded mapping". + * + * Example loaded mapping view in /proc//maps: + * 7fa2b4734000-7fa2b4735000 rw-s 00000000 103:07 23856559 /tmp/scope_loaded.2142471 (deleted) + */ + +/* + * libstateLoaded sets the loaded state for the current process by: + * - creating a temporary file `/tmp/scope_loaded.`. + * - the file is mapped into the process memory as "loaded mapping" + * - the file is removed (unlinked) + */ +bool +libstateLoaded(pid_t pid) { + char path[PATH_MAX] = {0}; + bool res = FALSE; + /* + * Switching to "loaded" AppScope state: + * We are done if mapping is present. + */ + if (loadedStrMap) { + return TRUE; + } + + if (scope_snprintf(path, sizeof(path), "/tmp/scope_loaded.%d", pid) < 0) { + return res; + } + + int outFd = scope_open(path, O_RDWR | O_CREAT, 0664); + if (outFd == -1) { + return res; + } + + if (scope_ftruncate(outFd, LOADED_MAP_SIZE) != 0) { + goto close_file; + } + + void* dest = scope_mmap(NULL, LOADED_MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, outFd, 0); + if (dest == MAP_FAILED) { + goto close_file; + } + + loadedStrMap = dest; + + res = TRUE; + +close_file: + scope_close(outFd); + if (scope_unlink(path) != 0 ) { + return FALSE; + } + return res; +} + +/* + * libstateScoped sets the scoped state for the current process by unmap the "loaded mapping" + */ +bool +libstateScoped(void) { + /* + * Switching to "scoped" AppScope state: + * We remove "loaded mapping" if present. + */ + if (loadedStrMap != NULL ) { + scope_munmap(loadedStrMap, LOADED_MAP_SIZE); + loadedStrMap = NULL; + } + return TRUE; +} diff --git a/src/libstate.h b/src/libstate.h new file mode 100644 index 000000000..204e1c3cb --- /dev/null +++ b/src/libstate.h @@ -0,0 +1,10 @@ + +#ifndef __LIBSTATE_H__ +#define __LIBSTATE_H__ + +#include "scopetypes.h" + +bool libstateLoaded(pid_t); +bool libstateScoped(void); + +#endif // __LIBSTATE_H__ diff --git a/src/runtimecfg.h b/src/runtimecfg.h index 0e6718ade..fcbf1f659 100644 --- a/src/runtimecfg.h +++ b/src/runtimecfg.h @@ -4,7 +4,7 @@ #include "cfg.h" typedef struct rtconfig_t { - bool funcs_attached; // TRUE when functions are interposed, FALSE otherwise + bool funcs_scoped; // TRUE when all the functions are interposed, FALSE if only exec* are int blockconn; config_t *staticfg; } rtconfig; diff --git a/src/wrap.c b/src/wrap.c index 997a55fad..82f74ae0d 100644 --- a/src/wrap.c +++ b/src/wrap.c @@ -27,6 +27,7 @@ #include "dns.h" #include "fn.h" #include "httpagg.h" +#include "libstate.h" #include "os.h" #include "plattime.h" #include "report.h" @@ -380,18 +381,22 @@ unHookAll(struct dl_phdr_info *info, size_t size, void *data) bool cmdDetach(void) { - if (!g_cfg.funcs_attached) return TRUE; + if (!g_cfg.funcs_scoped) return TRUE; + + libstateLoaded(g_proc.pid); scopeLog(CFG_LOG_DEBUG, "%s:%d", __FUNCTION__, __LINE__); dl_iterate_phdr(unHookAll, NULL); - g_cfg.funcs_attached = FALSE; + g_cfg.funcs_scoped = FALSE; return TRUE; } bool cmdAttach(void) { - if (g_cfg.funcs_attached) return TRUE; + if (g_cfg.funcs_scoped) return TRUE; + + libstateScoped(); bool filter = TRUE; scopeLog(CFG_LOG_DEBUG, "%s:%d", __FUNCTION__, __LINE__); @@ -399,7 +404,7 @@ cmdAttach(void) dl_iterate_phdr(hookAll, &filter); hookMain(filter); - g_cfg.funcs_attached = TRUE; + g_cfg.funcs_scoped = TRUE; return TRUE; } @@ -1076,7 +1081,7 @@ ssl_read_hook(SSL *ssl, void *buf, int num) int rc; WRAP_CHECK(SSL_read, -1); - if (g_cfg.funcs_attached == FALSE) return g_fn.SSL_read(ssl, buf, num); + if (g_cfg.funcs_scoped == FALSE) return g_fn.SSL_read(ssl, buf, num); scopeLog(CFG_LOG_TRACE, "ssl_read_hook"); rc = g_fn.SSL_read(ssl, buf, num); @@ -1096,7 +1101,7 @@ ssl_write_hook(SSL *ssl, void *buf, int num) int rc; WRAP_CHECK(SSL_write, -1); - if (g_cfg.funcs_attached == FALSE) return g_fn.SSL_write(ssl, buf, num); + if (g_cfg.funcs_scoped == FALSE) return g_fn.SSL_write(ssl, buf, num); scopeLog(CFG_LOG_TRACE, "ssl_write_hook"); rc = g_fn.SSL_write(ssl, buf, num); @@ -1341,6 +1346,13 @@ initHook(int attachedFlag) hookMain(filter); } + // Set information about library state + if (filter) { + libstateScoped(); + } else { + libstateLoaded(g_proc.pid); + } + // libmusl // Note that both stdout & stderr objects point to the same write function. // They are init'd with a static object. After the first write the @@ -1648,7 +1660,7 @@ init(void) if (!g_dbg) dbgInit(); g_getdelim = 0; - g_cfg.funcs_attached = TRUE; + g_cfg.funcs_scoped = TRUE; g_cfg.staticfg = g_staticfg; g_cfg.blockconn = DEFAULT_PORTBLOCK; @@ -1674,7 +1686,6 @@ init(void) } osInitJavaAgent(); - } EXPORTOFF int @@ -2768,7 +2779,7 @@ static ssize_t __write_libc(int fd, const void *buf, size_t size) { WRAP_CHECK(__write_libc, -1); - if ((g_ismusl == FALSE) && (g_cfg.funcs_attached == FALSE)) return g_fn.__write_libc(fd, buf, size); + if ((g_ismusl == FALSE) && (g_cfg.funcs_scoped == FALSE)) return g_fn.__write_libc(fd, buf, size); uint64_t initialTime = getTime(); @@ -2783,7 +2794,7 @@ static ssize_t __write_pthread(int fd, const void *buf, size_t size) { WRAP_CHECK(__write_pthread, -1); - if ((g_ismusl == FALSE) && (g_cfg.funcs_attached == FALSE)) return g_fn.__write_pthread(fd, buf, size); + if ((g_ismusl == FALSE) && (g_cfg.funcs_scoped == FALSE)) return g_fn.__write_pthread(fd, buf, size); uint64_t initialTime = getTime(); @@ -2824,7 +2835,7 @@ wrap_scope_syscall(long number, ...) WRAP_CHECK(syscall, -1); LOAD_FUNC_ARGS_VALIST(fArgs, number); - if (g_cfg.funcs_attached == FALSE) { + if (g_cfg.funcs_scoped == FALSE) { return g_fn.syscall(number, fArgs.arg[0], fArgs.arg[1], fArgs.arg[2], fArgs.arg[3], fArgs.arg[4], fArgs.arg[5]); } @@ -4666,7 +4677,7 @@ internal_sendto(int sockfd, const void *buf, size_t len, int flags, ssize_t rc; WRAP_CHECK(sendto, -1); rc = g_fn.sendto(sockfd, buf, len, flags, dest_addr, addrlen); - if ((g_ismusl == TRUE) && (g_cfg.funcs_attached == FALSE)) return rc; + if ((g_ismusl == TRUE) && (g_cfg.funcs_scoped == FALSE)) return rc; if (rc != -1) { scopeLog(CFG_LOG_TRACE, "fd:%d sendto", sockfd); @@ -4751,7 +4762,7 @@ internal_sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int fla WRAP_CHECK(sendmmsg, -1); rc = g_fn.sendmmsg(sockfd, msgvec, vlen, flags); - if ((g_ismusl == FALSE) && (g_cfg.funcs_attached == FALSE)) return rc; + if ((g_ismusl == FALSE) && (g_cfg.funcs_scoped == FALSE)) return rc; if (rc != -1) { scopeLog(CFG_LOG_TRACE, "fd:%d sendmmsg", sockfd); @@ -4850,7 +4861,7 @@ internal_recvfrom(int sockfd, void *buf, size_t len, int flags, WRAP_CHECK(recvfrom, -1); rc = g_fn.recvfrom(sockfd, buf, len, flags, src_addr, addrlen); - if ((g_ismusl == TRUE) && (g_cfg.funcs_attached == FALSE)) return rc; + if ((g_ismusl == TRUE) && (g_cfg.funcs_scoped == FALSE)) return rc; // If called with the MSG_PEEK flag set, don't do any scope processing // as it could result in processing of duplicate bytes later @@ -5295,7 +5306,7 @@ __fdelt_chk(long int fdelt) static void uv__read_hook(void *stream) { - if (g_cfg.funcs_attached == FALSE) return g_fn.uv__read(stream); + if (g_cfg.funcs_scoped == FALSE) return g_fn.uv__read(stream); if (SYMBOL_LOADED(uv_fileno)) g_fn.uv_fileno(stream, &g_ssl_fd); //scopeLog(CFG_LOG_TRACE, "%s: fd %d", __FUNCTION__, g_ssl_fd); diff --git a/test/execute.sh b/test/execute.sh index 100754309..1ca55b5e6 100755 --- a/test/execute.sh +++ b/test/execute.sh @@ -79,6 +79,7 @@ run_test test/${OS}/comtest run_test test/${OS}/dbgtest run_test test/${OS}/searchtest run_test test/${OS}/httpstatetest +run_test test/${OS}/libstatetest if [ "${OS}" = "linux" ]; then run_test test/${OS}/glibcvertest run_test test/${OS}/reporttest diff --git a/test/libstatetest.c b/test/libstatetest.c new file mode 100644 index 000000000..3c04b96e8 --- /dev/null +++ b/test/libstatetest.c @@ -0,0 +1,120 @@ +#define _GNU_SOURCE +#include "stdlib.h" +#include "libstate.h" +#include "dbg.h" +#include "scopestdlib.h" +#include "test.h" + + +static bool +isLoadedMappingPresent(pid_t pid) { + FILE *fstream; + char buffer[4096] = {0}; + char pidBuf[4096] = {0}; + bool status = FALSE; + + if (scope_snprintf(pidBuf, sizeof(pidBuf),"/tmp/scope_loaded.%d", pid) < 0) { + scope_perror("failed to create mapping string failed"); + exit(EXIT_FAILURE); + } + + if ((fstream = scope_fopen("/proc/self/maps", "r")) == NULL) { + scope_perror("fopen /proc/self/maps failed"); + exit(EXIT_FAILURE); + } + + while (scope_fgets(buffer, sizeof(buffer), fstream)) { + if (scope_strstr(buffer, pidBuf)) { + status = TRUE; + break; + } + } + + scope_fclose(fstream); + return status; +} + + +static void +libstateOnOff(void **state) { + bool opRes; + bool mapRes; + pid_t pid = scope_getpid(); + + opRes = libstateScoped(); + assert_true(opRes); + mapRes = isLoadedMappingPresent(pid); + assert_false(mapRes); + + opRes = libstateLoaded(pid); + assert_true(opRes); + mapRes = isLoadedMappingPresent(pid); + assert_true(mapRes); +} + +static void +libstateOffOn(void **state) { + bool opRes; + bool mapRes; + pid_t pid = scope_getpid(); + + opRes = libstateLoaded(pid); + assert_true(opRes); + mapRes = isLoadedMappingPresent(pid); + assert_true(mapRes); + + opRes = libstateScoped(); + assert_true(opRes); + mapRes = isLoadedMappingPresent(pid); + assert_false(mapRes); +} + + +static void +libstateOffOff(void **state) { + bool opRes; + bool mapRes; + pid_t pid = scope_getpid(); + + opRes = libstateLoaded(pid); + assert_true(opRes); + mapRes = isLoadedMappingPresent(pid); + assert_true(mapRes); + + opRes = libstateLoaded(pid); + assert_true(opRes); + mapRes = isLoadedMappingPresent(pid); + assert_true(mapRes); +} + +static void +libstateOnOn(void **state) { + bool opRes; + bool mapRes; + pid_t pid = scope_getpid(); + + opRes = libstateScoped(); + assert_true(opRes); + mapRes = isLoadedMappingPresent(pid); + assert_false(mapRes); + + opRes = libstateScoped(); + assert_true(opRes); + mapRes = isLoadedMappingPresent(pid); + assert_false(mapRes); +} + +int +main(int argc, char* argv[]) +{ + printf("running %s\n", argv[0]); + + const struct CMUnitTest tests[] = { + cmocka_unit_test(libstateOnOff), + cmocka_unit_test(libstateOffOn), + cmocka_unit_test(libstateOffOff), + cmocka_unit_test(libstateOnOn), + cmocka_unit_test(dbgHasNoUnexpectedFailures), + }; + return cmocka_run_group_tests(tests, groupSetup, groupTeardown); +}