Skip to content

Commit

Permalink
(#1108) IPC mechanism server side
Browse files Browse the repository at this point in the history
    - handle IPC mechanism communication between scoped application and
      CLI

    TODO:
    - cli
    - unit test
    - integration test
    - IPC namespace switch

Closes: #1108
  • Loading branch information
michalbiesek committed Nov 23, 2022
1 parent 68a7e7a commit 1ba6384
Show file tree
Hide file tree
Showing 10 changed files with 290 additions and 4 deletions.
22 changes: 22 additions & 0 deletions cli/cmd/inspect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package cmd

import (
"github.com/criblio/scope/inspect"
"github.com/spf13/cobra"
)

// inspectCmd represents the inspect command
var inspectCmd = &cobra.Command{
Use: "inspect [flags]",
Short: "Display scope inspect",
Long: `Outputs inspect info.`,
Example: `scope inspect`,
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
inspect.Inspect()
},
}

func init() {
RootCmd.AddCommand(inspectCmd)
}
9 changes: 9 additions & 0 deletions cli/inspect/inspect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package inspect

import "fmt"

// startConfig represents a processed configuration
func Inspect() error {
fmt.Println("inspect Test")
return nil
}
8 changes: 8 additions & 0 deletions docs/IPC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# IPC Notes

- For IPC communication we are using pair of message queue:

- `scope` is responsible to create and read on `ScopeCLI`
- Scoped application is responsible to create and read `ScopeIPC.<PID>`

TODO: Picture
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 -z noexecstack
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/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 src/ipc.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/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 src/ipc.c
@$(MAKE) -C contrib funchook pcre2 openssl ls-hpack musl libyaml cJSON libunwind
@echo "$${CI:+::group::}Building $@"
$(CC) $(CFLAGS) $(ARCH_CFLAGS) \
Expand Down
2 changes: 1 addition & 1 deletion os/macOS/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ $(PCRE2_AR):
cd contrib/pcre2/build && cmake ..
cd contrib/pcre2/build && make

libscope.so: src/wrap.c src/state.c src/httpstate.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/utils.c $(YAML_SRC) contrib/cJSON/cJSON.c
libscope.so: src/wrap.c src/state.c src/httpstate.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/utils.c $(YAML_SRC) contrib/cJSON/cJSON.c src/ipc.c
@echo "Building libscope.so ..."
make $(PCRE2_AR)
$(CC) $(CFLAGS) -shared -fvisibility=hidden -DSCOPE_VER=\"$(SCOPE_VER)\" $(YAML_DEFINES) -o ./lib/$(OS)/$@ $(INCLUDES) $^ -e,prog_version $(LD_FLAGS)
Expand Down
78 changes: 78 additions & 0 deletions src/ipc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#define _GNU_SOURCE

#include "ipc.h"

/* Message-queue
*
* Message-queue system limits which are related to `ipcOpenConnection`
* are defined in following files:
*
* "/proc/sys/fs/mqueue/msg_max"
* - describes maximum number of messsages in a queue (QUEUE_MSG_MAX)
*
* "/proc/sys/fs/mqueue/msgsize_max"
* - describes maximum message size in a queue (QUEUE_MSG_SIZE)
*
* "/proc/sys/fs/mqueue/queues_max"
* - describes system-wide limit on the number of message queues that can be created
*
* See details in: https://man7.org/linux/man-pages/man7/mq_overview.7.html
*/

#define QUEUE_MSG_MAX 10
#define QUEUE_MSG_SIZE 8192

int
ipcSend(mqd_t mqdes, const char *data, size_t len) {
return scope_mq_send(mqdes, data, len, 0);
}

int
ipcSendWithTimeout(mqd_t mqdes, const char *data, size_t len, const struct timespec *req) {
return scope_mq_timedsend(mqdes, data, len, 0, req);
}

ssize_t
ipcRecv(mqd_t mqdes, char *buf, size_t len) {
return scope_mq_receive(mqdes, buf, len, 0);
}

ssize_t
ipcRecvWithTimeout(mqd_t mqdes, char *buf, size_t len, const struct timespec *req) {
return scope_mq_timedreceive(mqdes, buf, len, 0, req);
}

mqd_t
ipcCreateNonBlockReadConnection(const char *name) {
struct mq_attr attr = {.mq_flags = 0,
.mq_maxmsg = QUEUE_MSG_MAX,
.mq_msgsize = QUEUE_MSG_SIZE,
.mq_curmsgs = 0};
return scope_mq_open(name, O_RDONLY | O_CREAT | O_CLOEXEC | O_NONBLOCK, 0666, &attr);
}

mqd_t
ipcOpenWriteConnection(const char *name) {
return scope_mq_open(name, O_WRONLY | O_NONBLOCK);
}

int
ipcCloseConnection(mqd_t mqdes) {
return scope_mq_close(mqdes);
}

int
ipcDestroyConnection(const char *name) {
return scope_mq_unlink(name);
}

int
ipcGetInfo(mqd_t mqdes, long *mqFlags, long *mqMaxMsg, long *mqMsgSize, long *mqCurMsgs) {
struct mq_attr attr;
int res = scope_mq_getattr(mqdes, &attr);
*mqFlags = attr.mq_flags;
*mqMaxMsg = attr.mq_maxmsg;
*mqMsgSize = attr.mq_msgsize;
*mqCurMsgs = attr.mq_curmsgs;
return res;
}
22 changes: 22 additions & 0 deletions src/ipc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#ifndef __IPC_H__
#define __IPC_H__

#include "scopestdlib.h"

// Send message from Inter-process communication
int ipcSend(mqd_t, const char *, size_t);
int ipcSendWithTimeout(mqd_t, const char *, size_t, const struct timespec *);

// Receive message from Inter-process communication
ssize_t ipcRecv(mqd_t, char *, size_t);
ssize_t ipcRecvWithTimeout(mqd_t, char *, size_t, const struct timespec *);

// Manage Inter-process communication
mqd_t ipcCreateNonBlockReadConnection(const char *);
mqd_t ipcOpenWriteConnection(const char *);
int ipcCloseConnection(mqd_t);
int ipcDestroyConnection(const char *);
int ipcGetInfo(mqd_t, long *, long *, long *, long *);


#endif // __IPC_H__
53 changes: 52 additions & 1 deletion src/wrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "runtimecfg.h"
#include "javaagent.h"
#include "inject.h"
#include "ipc.h"
#include "scopestdlib.h"
#include "../contrib/libmusl/musl.h"

Expand All @@ -55,6 +56,7 @@ static const char *g_cmddir;
static list_t *g_nsslist;
static uint64_t reentrancy_guard = 0ULL;
static rlim_t g_max_fds = 0;
static mqd_t g_receiver_msg_q = (mqd_t) -1;

typedef int (*ssl_rdfunc_t)(SSL *, void *, int);
typedef int (*ssl_wrfunc_t)(SSL *, const void *, int);
Expand Down Expand Up @@ -423,8 +425,41 @@ cmdAttach(void)
return TRUE;
}



static void
remoteConfig()
mqConfig(void) {
// If the receiver msg_q does not exists
if (g_receiver_msg_q == (mqd_t)-1) {
return;
}

// Handle request
// TODO: allocate buffer dynamically ??
char readBuffer[8192] = {0};
char writeBuffer[8192] = {0};
struct timespec ts = {.tv_sec = 1, .tv_nsec = 0}; // 1 s
ssize_t recvRes = ipcRecvWithTimeout(g_receiver_msg_q, readBuffer, sizeof(readBuffer), &ts);
if (recvRes == -1) {
return;
}

// Handle response
mqd_t climqdes = ipcOpenWriteConnection("/ScopeCLI");
if (climqdes == (mqd_t)-1) {
scopeLogError("Error during open /ScopeCLI message queue %d.", scope_errno);
return;
}

int sendRes = ipcSend(climqdes, writeBuffer, sizeof(writeBuffer));
if (sendRes == -1) {
scopeLogError("Error: %d during sending message to /ScopeCLI.", scope_errno);
}
ipcCloseConnection(climqdes);
}

static void
remoteConfig(void)
{
int timeout;
struct pollfd fds;
Expand Down Expand Up @@ -1002,6 +1037,11 @@ handleExit(void)
ctlDisconnect(g_ctl, CFG_CTL);
logFlush(g_log);
logDisconnect(g_log);
ipcCloseConnection(g_receiver_msg_q);
g_receiver_msg_q = (mqd_t) -1;
char name[256];
scope_snprintf(name, sizeof(name), "/ScopeIPC.%d", g_proc.pid);
ipcDestroyConnection(name);
}

static void *
Expand Down Expand Up @@ -1081,6 +1121,7 @@ periodic(void *arg)
}
}
remoteConfig();
mqConfig();
}

return NULL;
Expand Down Expand Up @@ -1636,6 +1677,11 @@ init(void)
setMachineID(g_proc.machine_id);
setUUID(g_proc.uuid);

// Create IPC connection message queue
char name[256];
scope_snprintf(name, sizeof(name), "/ScopeIPC.%d", g_proc.pid);
g_receiver_msg_q = ipcCreateNonBlockReadConnection(name);

// initEnv() will set this TRUE if it detects `scope_attach_PID.env` in
// `/dev/shm` with our PID indicating we were injected into a running
// process.
Expand Down Expand Up @@ -1764,6 +1810,11 @@ init(void)
osCreateSM(&g_proc, (unsigned long)cmdAttach);
}

// TODO: remove this
if (g_receiver_msg_q == (mqd_t)-1) {
scopeLogError("Error during creation of %s", name);
}

osInitJavaAgent();

}
Expand Down
96 changes: 96 additions & 0 deletions test/manual/ipcclient.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* ipcclient - IPC client
*
* A simple program to test communication between scoped process using
* gcc -g test/manual/ipcclient.c -lrt -o ipcclient
* ./ipcclient <scoped_PID>
*/

#include <stdio.h>
#include <stdlib.h>
#include <mqueue.h>
#include <string.h>
#include <sys/stat.h>

#define MAX_MESSAGES 10
#define MSG_BUFFER_SIZE 8192

static mqd_t readMqDesc;
#define READ_MQ_NAME "/ScopeCLI"

void cleanupReadDesc(void) {
mq_close(readMqDesc);
mq_unlink(READ_MQ_NAME);
}

int main(int argc, char **argv) {
struct mq_attr attr = {.mq_flags = 0,
.mq_maxmsg = MAX_MESSAGES,
.mq_msgsize = MSG_BUFFER_SIZE,
.mq_curmsgs = 0};

int res = EXIT_FAILURE;
char WriteMqName[4096] = {0};
if (argc != 2) {
printf("Usage: %s <pid_scope_process>\n", argv[0]);
return res;
}

snprintf(WriteMqName, sizeof(WriteMqName), "/ScopeIPC.%s", argv[1]);

mqd_t writeMqDesc;

// Ugly hack disable umask to handle run as a root
mode_t oldMask = umask(0);
readMqDesc = mq_open(READ_MQ_NAME, O_RDONLY | O_CREAT, 0666, &attr);
if (readMqDesc == (mqd_t)-1) {
perror("!mq_open readMqDesc failed");
return res;
}
umask(oldMask);

atexit(cleanupReadDesc);

writeMqDesc = mq_open(WriteMqName, O_WRONLY);
if (writeMqDesc == (mqd_t)-1) {
perror("!mq_open writeMqDesc failed");
return res;
}

char Txbuf[MSG_BUFFER_SIZE] = {0};
char RxBuf[MSG_BUFFER_SIZE] = {0};

printf("\nPass example message to stdin [type 'quit' to stop]\n");
while (fgets(Txbuf, MSG_BUFFER_SIZE, stdin) != NULL) {
struct mq_attr readAttr = {0};
if(strcmp("quit\n", Txbuf) == 0) {
break;
}

// Send message to scoped process
if (mq_send(writeMqDesc, Txbuf, strlen(Txbuf) + 1, 0) == -1) {
perror("!mq_send writeMqDesc failed");
goto end_iteration;
}


// Read response
if (mq_receive(readMqDesc, RxBuf, MSG_BUFFER_SIZE, NULL) == -1) {
perror("!mq_receive readMqDesc failed");
goto end_iteration;
}

printf("Response from pid process %s : %s", argv[1], RxBuf);

end_iteration:
printf("\nPass example message to stdin [type 'quit' to stop]\n");
memset(Txbuf, 0, MSG_BUFFER_SIZE);
memset(RxBuf, 0, MSG_BUFFER_SIZE);
}

if (mq_close(writeMqDesc) == -1) {
perror ("!mq_close writeMqDesc failed");
}

return EXIT_SUCCESS;
}

0 comments on commit 1ba6384

Please sign in to comment.