diff options
-rw-r--r-- | src/capabilities.c | 66 | ||||
-rw-r--r-- | src/config.c | 20 | ||||
-rw-r--r-- | src/config.h | 1 | ||||
-rw-r--r-- | src/fastd.c | 4 | ||||
-rw-r--r-- | src/fastd.h | 8 |
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 */ |