summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2016-02-22 21:03:40 +0100
committerMatthias Schiffer <mschiffer@universe-factory.net>2016-02-22 21:03:40 +0100
commit69c830f36376058df238bda39d15d42a0507af53 (patch)
tree0ea9ae4a898c04d0ff5df5679981290faf9b0232
parent995380597a0df69504ffa2f1782290ffa2614d18 (diff)
downloadfastd-69c830f36376058df238bda39d15d42a0507af53.tar
fastd-69c830f36376058df238bda39d15d42a0507af53.zip
Improve capability handling, retain required capabilities
-rw-r--r--src/capabilities.c66
-rw-r--r--src/config.c20
-rw-r--r--src/config.h1
-rw-r--r--src/fastd.c4
-rw-r--r--src/fastd.h8
5 files changed, 74 insertions, 25 deletions
diff --git a/src/capabilities.c b/src/capabilities.c
index a4290a1..1feabba 100644
--- a/src/capabilities.c
+++ b/src/capabilities.c
@@ -34,7 +34,10 @@
#ifdef WITH_CAPABILITIES
+#include "config.h"
+
#include <sys/capability.h>
+#include <sys/prctl.h>
/** Tries to acquire a capability */
@@ -48,20 +51,16 @@ static void try_cap(cap_value_t cap) {
goto end_free;
cap_flag_value_t val;
- if (cap_get_flag(caps, cap, CAP_EFFECTIVE, &val) < 0) {
- pr_debug_errno("cap_get_flag");
- goto end_free;
- }
+ if (cap_get_flag(caps, cap, CAP_EFFECTIVE, &val) < 0)
+ exit_errno("cap_get_flag");
if (val == CAP_SET)
goto end_free;
- pr_verbose("Trying to acquire %s", name);
+ pr_verbose("trying to acquire %s", name);
- if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_SET) < 0) {
- pr_debug_errno("cap_set_flags");
- goto end_free;
- }
+ if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_SET) < 0)
+ exit_errno("cap_set_flags");
if (cap_set_proc(caps) < 0) {
pr_debug_errno("cap_set_proc");
@@ -75,31 +74,60 @@ static void try_cap(cap_value_t cap) {
cap_free(name);
}
+/** Returns true if CAP_NET_ADMIN should be retained */
+static bool need_cap_net_admin(void) {
+ return !fastd_config_persistent_ifaces();
+}
+
+/** Returns true if CAP_NET_RAW should be retained */
+static bool need_cap_net_raw(void) {
+ if (!ctx.sock_default_v4 && conf.bind_addr_default_v4 && conf.bind_addr_default_v4->bindtodev)
+ return true;
+
+ if (!ctx.sock_default_v6 && conf.bind_addr_default_v6 && conf.bind_addr_default_v6->bindtodev)
+ return true;
+
+ return false;
+}
+
+static void set_cap(cap_t caps, cap_value_t cap) {
+ if (cap_set_flag(caps, CAP_PERMITTED, 1, &cap, CAP_SET) < 0)
+ exit_errno("cap_set_flags");
+ if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_SET) < 0)
+ exit_errno("cap_set_flags");
+}
+
/** Tries to acquire the capabilities needed to perform initialization without root privileges */
-void fastd_cap_init(void) {
+void fastd_cap_acquire(void) {
/* interface creation */
try_cap(CAP_NET_ADMIN);
/* privileged binds */
try_cap(CAP_NET_BIND_SERVICE);
- /* for device binds */
+ /* device binds */
try_cap(CAP_NET_RAW);
+
+ if (prctl(PR_SET_KEEPCAPS, 1) < 0)
+ pr_warn_errno("prctl(PR_SET_KEEPCAPS)");
}
-/** Drops all capabilities */
-void fastd_cap_drop(void) {
+/** Reacquires required capabilities, drops the rest */
+void fastd_cap_reacquire_drop(void) {
cap_t caps = cap_init();
- if (cap_set_proc(caps) < 0) {
- pr_debug_errno("cap_set_proc");
- }
- else {
+ if (need_cap_net_admin())
+ set_cap(caps, CAP_NET_ADMIN);
+
+ if (need_cap_net_raw())
+ set_cap(caps, CAP_NET_RAW);
+
+ if (cap_set_proc(caps) < 0)
+ exit_errno("unable to retain required capabilities");
+ else
pr_verbose("dropped capabilities");
- }
cap_free(caps);
-
}
#endif
diff --git a/src/config.c b/src/config.c
index 805cb98..494ab1e 100644
--- a/src/config.c
+++ b/src/config.c
@@ -602,6 +602,26 @@ bool fastd_config_single_iface(void) {
return (VECTOR_LEN(ctx.peers) == 1);
}
+bool fastd_config_persistent_ifaces(void) {
+ if (fastd_use_android_integration())
+ return true;
+
+ if (conf.mode == MODE_TAP)
+ return true;
+
+ if (!conf.iface_persist)
+ return false;
+
+ if (has_peer_group_peer_dirs(conf.peer_group))
+ return false;
+
+ if (fastd_allow_verify())
+ return false;
+
+ return true;
+
+}
+
/** Performs the verify-config checks */
void fastd_config_verify(void) {
config_check_base();
diff --git a/src/config.h b/src/config.h
index b8a73c1..9b79014 100644
--- a/src/config.h
+++ b/src/config.h
@@ -65,3 +65,4 @@ void fastd_configure_peers(void);
void fastd_config_check(void);
void fastd_config_load_peer_dirs(bool dirs_only);
bool fastd_config_single_iface(void);
+bool fastd_config_persistent_ifaces(void);
diff --git a/src/fastd.c b/src/fastd.c
index 2a03858..37b00f9 100644
--- a/src/fastd.c
+++ b/src/fastd.c
@@ -355,7 +355,7 @@ static void set_groups(void) {
/** Switches the user and drops all capabilities */
static void drop_caps(void) {
set_user();
- fastd_cap_drop();
+ fastd_cap_reacquire_drop();
}
/** Will double fork and wait for a status notification from the child before exiting in the original parent */
@@ -536,7 +536,7 @@ static inline void init(int argc, char *argv[]) {
fastd_update_time();
ctx.started = ctx.now;
- fastd_cap_init();
+ fastd_cap_acquire();
fastd_poll_init();
diff --git a/src/fastd.h b/src/fastd.h
index 56d337f..08cfb5f 100644
--- a/src/fastd.h
+++ b/src/fastd.h
@@ -392,13 +392,13 @@ bool fastd_android_protect_socket(int fd);
#ifdef WITH_CAPABILITIES
-void fastd_cap_init(void);
-void fastd_cap_drop(void);
+void fastd_cap_acquire(void);
+void fastd_cap_reacquire_drop(void);
#else /* WITH_CAPABILITIES */
-static inline void fastd_cap_init(void) {}
-static inline void fastd_cap_drop(void) {}
+static inline void fastd_cap_acquire(void) {}
+static inline void fastd_cap_reacquire_drop(void) {}
#endif /* WITH_CAPABILITIES */