Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Distinguish the process AppScope state (Unscoped/Attached/Detached) #1097

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cli/cmd/ps.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
},
}
Expand Down
6 changes: 3 additions & 3 deletions cli/run/attach.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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:")
Expand Down
2 changes: 1 addition & 1 deletion cli/run/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
72 changes: 46 additions & 26 deletions cli/util/proc.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -85,7 +98,7 @@ func pidScopeMapSearch(inputArg string, sF searchFun) (PidScopeMapState, error)
}

if sF(pid, inputArg) {
pidMap[pid] = PidScoped(pid)
pidMap[pid] = PidScopeState(pid)
}
}

Expand Down Expand Up @@ -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++
}
Expand Down Expand Up @@ -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++
}
Expand All @@ -234,24 +247,31 @@ 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
pidMap := string(pidMapFile)
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
Expand Down
16 changes: 8 additions & 8 deletions cli/util/proc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions os/linux/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion os/linux/aarch64.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
2 changes: 1 addition & 1 deletion os/linux/x86_64.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
82 changes: 82 additions & 0 deletions src/libstate.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#include "libstate.h"
#include <fcntl.h>
#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/<PID>/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.<pid>`.
* - 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;
}
10 changes: 10 additions & 0 deletions src/libstate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

#ifndef __LIBSTATE_H__
#define __LIBSTATE_H__

#include "scopetypes.h"

bool libstateLoaded(pid_t);
bool libstateScoped(void);

#endif // __LIBSTATE_H__
2 changes: 1 addition & 1 deletion src/runtimecfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading