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

new(gvisor): get socket from configuration file, fix tests #429

Merged
merged 4 commits into from
Jun 24, 2022
Merged
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
4 changes: 2 additions & 2 deletions userspace/libscap/engine/gvisor/gvisor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ static SCAP_HANDLE_T *gvisor_alloc_handle(scap_t* main_handle, char *lasterr_ptr
static int32_t gvisor_init(scap_t* main_handle, scap_open_args* open_args)
{
scap_gvisor::engine *gv = main_handle->m_engine.m_handle;
return gv->init(open_args->gvisor_socket, open_args->gvisor_root_path, open_args->gvisor_trace_session_path);
return gv->init(open_args->gvisor_config_path, open_args->gvisor_root_path);
}

static void gvisor_free_handle(struct scap_engine_handle engine)
Expand Down Expand Up @@ -78,7 +78,7 @@ static int32_t gvisor_next(struct scap_engine_handle engine, scap_evt **pevent,

static bool gvisor_match(scap_open_args* open_args)
{
return open_args->gvisor_socket != NULL;
return open_args->gvisor_config_path != NULL;
}

static int32_t gvisor_configure(struct scap_engine_handle engine, enum scap_setting setting, unsigned long arg1, unsigned long arg2)
Expand Down
13 changes: 12 additions & 1 deletion userspace/libscap/engine/gvisor/gvisor.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ struct procfs_result {
scap_threadinfo tinfo;
};

struct config_result {
// the scap status of the operation
uint32_t status;
// description of the error in case of failure
std::string error;
// the socket path
std::string socket_path;
};

/*!
\brief Translate a gVisor seccheck protobuf into one, or more, scap events
\param gvisor_buf the source buffer that contains the raw event coming from gVisor
Expand All @@ -82,6 +91,8 @@ procfs_result parse_procfs_json(const std::string &input, const std::string &san

uint64_t get_vxid(uint64_t vxid);

config_result parse_config(std::string config);

} // namespace parsers

namespace runsc
Expand Down Expand Up @@ -115,7 +126,7 @@ class engine {
public:
engine(char *lasterr);
~engine();
int32_t init(std::string socket_path, std::string root_path, std::string trace_session_path);
int32_t init(std::string config_path, std::string root_path);
int32_t close();

int32_t start_capture();
Expand Down
64 changes: 62 additions & 2 deletions userspace/libscap/engine/gvisor/parsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,7 @@ procfs_result parse_procfs_json(const std::string &input, const std::string &san
return res;
}
std::string args;
for(Json::Value::ArrayIndex i = 0; i != root.size(); i++)
for(Json::Value::ArrayIndex i = 0; i < root["args"].size(); i++)
{
args += root["args"][i].asString();
args.push_back('\0');
Expand All @@ -824,7 +824,7 @@ procfs_result parse_procfs_json(const std::string &input, const std::string &san
return res;
}
std::string env;
for(Json::Value::ArrayIndex i = 0; i != root.size(); i++)
for(Json::Value::ArrayIndex i = 0; i < root["env"].size(); i++)
{
env += root["env"][i].asString();
env.push_back('\0');
Expand Down Expand Up @@ -882,5 +882,65 @@ procfs_result parse_procfs_json(const std::string &input, const std::string &san
return res;
}

config_result parse_config(std::string config)
{
config_result res;
res.socket_path = "";
res.error = "";
res.status = SCAP_FAILURE;

std::string err;
Json::Value root;
Json::CharReaderBuilder builder;
const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());

bool json_parse = reader->parse(config.c_str(), config.c_str() + config.size() - 1, &root, &err);
if(!json_parse)
{
res.error = "Could not parse configuration file contents.";
return res;
}

if(!root.isMember("trace_session"))
{
res.error = "Could not find trace_session entry in configuration";
return res;
}
Json::Value &trace_session = root["trace_session"];

if(!trace_session.isMember("sinks") || !trace_session["sinks"].isArray())
{
res.error = "Could not find trace_session -> sinks array in configuration";
return res;
}

if(trace_session["sinks"].size() == 0)
{
res.error = "trace_session -> sinks array is empty";
return res;
}

// We don't know how to distinguish between sinks in case there is more than one
// we're taking the first for now but this can be tweaked if necessary.
Json::Value &sink = trace_session["sinks"][0];

if(!sink.isMember("config"))
{
res.error = "Could not find config in sink item";
return res;
}
Json::Value &sink_config = sink["config"];

if(!sink_config.isMember("endpoint") || !sink_config["endpoint"].isString())
{
res.error = "Could not find endpoint in sink configuration";
return res;
}

res.socket_path = sink_config["endpoint"].asString();
res.status = SCAP_SUCCESS;
return res;
}

} // namespace parsers
} // namespace scap_gvisor
25 changes: 22 additions & 3 deletions userspace/libscap/engine/gvisor/scap_gvisor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ limitations under the License.
#include <sys/stat.h>

#include <vector>
#include <fstream>
#include <sstream>

#include "gvisor.h"
#include "pkg/sentry/seccheck/points/common.pb.h"
Expand Down Expand Up @@ -86,13 +88,30 @@ engine::~engine()

}

int32_t engine::init(std::string socket_path, std::string root_path, std::string trace_session_path)
int32_t engine::init(std::string config_path, std::string root_path)
{
m_root_path = root_path;
m_trace_session_path = trace_session_path;
m_trace_session_path = config_path;

std::ifstream config_file(config_path);
if (config_file.fail())
{
snprintf(m_lasterr, SCAP_LASTERR_SIZE, "Could not open gVisor configuration file %s", config_path.c_str());
return SCAP_FAILURE;
}
std::stringstream config_buf;
config_buf << config_file.rdbuf();

parsers::config_result config_result = parsers::parse_config(config_buf.str());
if(config_result.status != SCAP_SUCCESS)
{
snprintf(m_lasterr, SCAP_LASTERR_SIZE, "Could not parse gVisor configuration file %s : %s",
config_path.c_str(), config_result.error.c_str());
return config_result.status;
}

// Initialize the listen fd
m_socket_path = socket_path;
m_socket_path = config_result.socket_path;
if (m_socket_path.empty())
{
strlcpy(m_lasterr, "Empty gVisor socket path", SCAP_LASTERR_SIZE);
Expand Down
2 changes: 1 addition & 1 deletion userspace/libscap/scap.c
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,7 @@ scap_t* scap_open(scap_open_args args, char *error, int32_t *rc)
args.import_users,
args.suppressed_comms);
}
else if (args.gvisor_socket != NULL)
else if (args.gvisor)
{
return scap_open_gvisor_int(error, rc, &args);
}
Expand Down
3 changes: 1 addition & 2 deletions userspace/libscap/scap_open.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,8 @@ typedef struct scap_open_args
// values via scap_suppress_events_comm().
bool udig; ///< If true, UDIG will be used for event capture.
bool gvisor; //< If true, gVisor will be used for event capture
const char *gvisor_socket; ///< When using gVisor, this contains the gvisor socket
const char *gvisor_root_path; ///< When using gvisor, the root path used by runsc commands
const char *gvisor_trace_session_path; ///< When using gvisor, the trace session config file
const char *gvisor_config_path; ///< When using gvisor, the path to the configuration file

interesting_ppm_sc_set ppm_sc_of_interest;

Expand Down
166 changes: 116 additions & 50 deletions userspace/libscap/test/scap_gvisor_parsers.ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,55 +192,57 @@ TEST(gvisor_parsers, procfs_entry)
EXPECT_EQ(res.status, SCAP_FAILURE);
EXPECT_STREQ(res.error.c_str(), "Malformed json string: cannot parse procfs entry");

std::string json =
"{"
" \"args\" : [ \"bash\" ],"
" \"clone_ts\" : 1655473752715788585,"
" \"cwd\" : \"/\","
" \"env\" : ["
" \"HOSTNAME=91e91fdd849d\","
" \"TERM=xterm\","
" \"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\","
" \"HOME=/root\""
" ],"
" \"exe\" : \"/usr/bin/bash\","
" \"fdlist\" : ["
" {"
" \"path\" : \"host:[1]\""
" },"
" {"
" \"number\" : 1,"
" \"path\" : \"host:[1]\""
" },"
" {"
" \"number\" : 2,"
" \"path\" : \"host:[1]\""
" },"
" {"
" \"number\" : 255,"
" \"path\" : \"host:[1]\""
" }"
" ],"
" \"limits\" : {"
" \"RLIMIT_NOFILE\" : {"
" \"cur\" : 1048576,"
" \"max\" : 1048576"
" }"
" },"
" \"root\" : \"/\","
" \"stat\" : {"
" \"pgid\" : 1,"
" \"sid\" : 1"
" },"
" \"status\" : {"
" \"comm\" : \"bash\","
" \"gid\" : {},"
" \"pid\" : 1,"
" \"uid\" : {},"
" \"vm_rss\" : 4664,"
" \"vm_size\" : 12164"
" }"
"}\n";
std::string json = R"(
{
"args": [ "bash" ],
"clone_ts": 1655473752715788585,
"cwd": "/",
"env": [
"HOSTNAME=91e91fdd849d",
"TERM=xterm",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"HOME=/root"
],
"exe": "/usr/bin/bash",
"fdlist": [
{
"path": "host:[1]"
},
{
"number": 1,
"path": "host:[1]"
},
{
"number": 2,
"path": "host:[1]"
},
{
"number": 255,
"path": "host:[1]"
}
],
"limits": {
"RLIMIT_NOFILE": {
"cur": 1048576,
"max": 1048576
}
},
"root": "/",
"stat": {
"pgid": 1,
"sid": 1
},
"status": {
"comm": "bash",
"gid": {"effective": 0, "real": 0, "saved": 0},
"pid": 1,
"uid": {"effective": 0, "real": 0, "saved": 0},
"vm_rss": 4664,
"vm_size": 12164
}
}
)";

res = scap_gvisor::parsers::parse_procfs_json(json, sandbox_id);
EXPECT_EQ(res.status, SCAP_SUCCESS);
EXPECT_EQ(res.tinfo.vtid, 1);
Expand All @@ -267,4 +269,68 @@ TEST(gvisor_parsers, procfs_entry)
EXPECT_EQ(res.status, SCAP_FAILURE);
EXPECT_STREQ(res.error.c_str(), "Missing json field or wrong type: cannot parse procfs entry");

}
}

TEST(gvisor_parsers, config_socket)
{
std::string config = R"(
{
"trace_session": {
"name": "Default",
"points": [
{
"name": "container/start",
"context_fields": [
"cwd",
"time"
]
},
{
"name": "syscall/openat/enter",
"context_fields": [
"credentials",
"container_id",
"thread_id",
"task_start_time",
"time"
]
},
{
"name": "syscall/openat/exit",
"context_fields": [
"credentials",
"container_id",
"thread_id",
"task_start_time",
"time"
]
},
{
"name": "sentry/task_exit",
"context_fields": [
"credentials",
"container_id",
"thread_id",
"task_start_time",
"time"
]
}
],
"sinks": [
{
"name": "remote",
"config": {
"endpoint": "/tmp/gvisor.sock"
}
}
]
}
}
)";

scap_gvisor::parsers::config_result res;

res = scap_gvisor::parsers::parse_config(config);
EXPECT_EQ(res.status, SCAP_SUCCESS);
EXPECT_STREQ(res.socket_path.c_str(), "/tmp/gvisor.sock");
}
Loading