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

starter: introduce possibility to keep capability NET_BIND_SERVICE #650

Merged
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
5 changes: 4 additions & 1 deletion cilium/privileged_service_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ namespace PrivilegedService {

ProtocolClient::ProtocolClient()
: Protocol(CILIUM_PRIVILEGED_SERVICE_FD), call_mutex_(PTHREAD_MUTEX_INITIALIZER), seq_(0) {
RELEASE_ASSERT(get_capabilities(CAP_EFFECTIVE) == 0 && get_capabilities(CAP_PERMITTED) == 0,
// Check that the Envoy process isn't running with privileges.
// The only exception is CAP_NET_BIND_SERVICE (if explicitly excluded from being dropped).
RELEASE_ASSERT((get_capabilities(CAP_EFFECTIVE) & ~(1UL << CAP_NET_BIND_SERVICE)) == 0 &&
(get_capabilities(CAP_PERMITTED) & ~(1UL << CAP_NET_BIND_SERVICE)) == 0,
"cilium-envoy running with privileges, exiting");

if (!check_privileged_service()) {
Expand Down
94 changes: 78 additions & 16 deletions starter/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
#error "Linux platform file is part of non-Linux build."
#endif

#include <cstring>
#include <errno.h>
#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <syscall.h>
#include <unistd.h>
#include <vector>

#include "starter/privileged_service_server.h"

Expand All @@ -16,16 +18,7 @@
#define STARTER_SUFFIX "-starter"
#define STARTER_SUFFIX_LEN (sizeof(STARTER_SUFFIX) - 1)

int main(int /* argc */, char** argv) {
// Check that we have the required capabilities
uint64_t caps = Envoy::Cilium::PrivilegedService::get_capabilities(CAP_EFFECTIVE);
if ((caps & (1UL << CAP_NET_ADMIN)) == 0 ||
(caps & (1UL << CAP_SYS_ADMIN | 1UL << CAP_BPF)) == 0) {
fprintf(stderr, "CAP_NET_ADMIN and either CAP_SYS_ADMIN or CAP_BPF capabilities are needed for "
"Cilium datapath integration.\n");
exit(1);
}

int main(int argc, char** argv) {
// Get the path we're running from
char* path = new char[PATH_MAX];
constexpr size_t path_size = PATH_MAX;
Expand All @@ -52,6 +45,62 @@ int main(int /* argc */, char** argv) {
exit(1);
}

// Check that we have the required capabilities
uint64_t caps = Envoy::Cilium::PrivilegedService::get_capabilities(CAP_EFFECTIVE);
if ((caps & (1UL << CAP_NET_ADMIN)) == 0 ||
(caps & (1UL << CAP_SYS_ADMIN | 1UL << CAP_BPF)) == 0) {
fprintf(stderr, "CAP_NET_ADMIN and either CAP_SYS_ADMIN or CAP_BPF capabilities are needed for "
"Cilium datapath integration.\n");
exit(1);
}

bool delimiter_present = false;
std::vector<char*> args;

// skip first arg (program name)
for (int i = 1; i < argc; ++i) {
if (std::strcmp(argv[i], "--") == 0) {
delimiter_present = true;
}

args.push_back(argv[i]);
}

bool keep_cap_netbindservice = false;
std::vector<char*> envoy_args;
envoy_args.push_back(path); // program

if (!delimiter_present) {
// backwards compabitility: handle all args as Envoys if delimiter isn't present
envoy_args.insert(envoy_args.begin(), args.begin(), args.end());
} else {
// parse arguments and split by delimiter "--"
// before: arguments for starter process
// after: pass to envoy process
bool delimiter_reached = false;
for (char* arg : args) {
if (delimiter_reached) {
// argument for Envoy
envoy_args.push_back(arg);
continue;
}

if (std::strcmp(arg, "--") == 0) {
delimiter_reached = true;
continue;
}

if (std::strcmp(arg, "--keep-cap-net-bind-service") == 0) {
// keep CAP_NET_BIND_SERVICE if it's present in the effective capabilities
keep_cap_netbindservice = (caps & (1UL << CAP_NET_BIND_SERVICE)) != 0;
continue;
}

fprintf(stderr, "Unknown starter argument '%s'.\n", arg);
exit(1);
}
}
jrajahalme marked this conversation as resolved.
Show resolved Hide resolved

int fds[2];
int rc = socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, fds);
RELEASE_ASSERT(rc == 0, "socketpair failed");
Expand All @@ -69,6 +118,12 @@ int main(int /* argc */, char** argv) {
};
struct __user_cap_data_struct data[2];
memset(&data, 0, sizeof(data));

if (keep_cap_netbindservice) {
data[0].permitted = (1UL << CAP_NET_BIND_SERVICE);
data[0].effective = data[0].permitted;
}

if (::syscall(SYS_capset, &hdr, &data, sizeof(data)) != 0) {
perror("capset");
exit(1);
Expand All @@ -80,10 +135,17 @@ int main(int /* argc */, char** argv) {
exit(1);
}

RELEASE_ASSERT(Envoy::Cilium::PrivilegedService::get_capabilities(CAP_EFFECTIVE) == 0 &&
Envoy::Cilium::PrivilegedService::get_capabilities(CAP_PERMITTED) == 0 &&
Envoy::Cilium::PrivilegedService::get_capabilities(CAP_INHERITABLE) == 0,
"Failed dropping privileges");
uint64_t exp_eff_cap = 0;
uint64_t exp_perm_cap = 0;
if (keep_cap_netbindservice) {
exp_eff_cap = (1UL << CAP_NET_BIND_SERVICE);
exp_perm_cap = (1UL << CAP_NET_BIND_SERVICE);
}
RELEASE_ASSERT(
Envoy::Cilium::PrivilegedService::get_capabilities(CAP_EFFECTIVE) == exp_eff_cap &&
Envoy::Cilium::PrivilegedService::get_capabilities(CAP_PERMITTED) == exp_perm_cap &&
Envoy::Cilium::PrivilegedService::get_capabilities(CAP_INHERITABLE) == 0,
"Failed dropping privileges");

// Dup the client end to CILIUM_PRIVILEGED_SERVICE_FD
if (fds[1] != CILIUM_PRIVILEGED_SERVICE_FD) {
Expand All @@ -94,8 +156,8 @@ int main(int /* argc */, char** argv) {
close(fds[1]);
}

// Exec cilium-envoy process
execv(path, argv);
envoy_args.push_back(nullptr);
execv(path, &envoy_args[0]);
jrajahalme marked this conversation as resolved.
Show resolved Hide resolved
perror("execv");
exit(1);
}
Expand Down
Loading