--- iputils-s20101006/ping.c 2012-06-25 09:53:03.779506643 +0200 +++ iputils-s20101006-patch/ping.c 2012-06-25 10:40:17.610143823 +0200 @@ -66,10 +66,6 @@ char copyright[] = #include #include -#ifdef HAVE_CAPABILITIES -#include -#endif - #ifndef ICMP_FILTER #define ICMP_FILTER 1 struct icmp_filter { @@ -119,7 +115,6 @@ struct sockaddr_in source; char *device; int pmtudisc = -1; - int main(int argc, char **argv) { @@ -130,7 +125,8 @@ main(int argc, char **argv) char *target, hnamebuf[MAX_HOSTNAMELEN]; char rspace[3 + 4 * NROUTES + 1]; /* record route space */ #ifdef HAVE_CAPABILITIES - cap_t caps; + cap_t cap; + cap_flag_value_t net_admin_set = CAP_CLEAR; #endif char *idn; @@ -147,13 +143,21 @@ main(int argc, char **argv) } #ifdef HAVE_CAPABILITIES - /* drop all capabilities unconditionally so even root isn't special anymore */ - caps = cap_init(); - if (cap_set_proc(caps) < 0) { - perror("ping: cap_set_proc"); + /* check for cap_net_admin because it may be needed to set packet marks */ + if ((cap = cap_get_proc()) == NULL) { + perror("ping: cap_get_proc"); exit(-1); } - cap_free(caps); + if (cap_get_flag(cap, CAP_NET_ADMIN, CAP_EFFECTIVE, &net_admin_set) != 0) { + perror("ping: cap_get_flag"); + exit(-1); + } + cap_free(cap); + + /* if CAP_NET_ADMIN is not set, drop all capabilities now, otherwise defer + * dropping after the SO_MARK sock opt is set */ + if (net_admin_set == CAP_CLEAR) + drop_capabilities(); #endif source.sin_family = AF_INET; --- iputils-s20101006/ping6.c 2012-06-26 08:55:58.751744660 +0200 +++ iputils-s20101006-patch/ping6.c 2012-06-26 08:57:38.276803832 +0200 @@ -73,10 +73,6 @@ char copyright[] = #include #include -#ifdef HAVE_CAPABILITIES -#include -#endif - #include "ping6_niquery.h" #include "in6_flowlabel.h" @@ -538,7 +534,8 @@ int main(int argc, char *argv[]) #endif static uint32_t scope_id = 0; #ifdef HAVE_CAPABILITIES - cap_t caps; + cap_t cap; + cap_flag_value_t net_admin_set = CAP_CLEAR; #endif icmp_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); @@ -551,13 +548,21 @@ int main(int argc, char *argv[]) } #ifdef HAVE_CAPABILITIES - /* drop all capabilities unconditionally so even root isn't special anymore */ - caps = cap_init(); - if (cap_set_proc(caps) < 0) { - perror("ping: cap_set_proc"); + /* check for cap_net_admin because it may be needed to set packet marks */ + if ((cap = cap_get_proc()) == NULL) { + perror("ping: cap_get_proc"); exit(-1); } - cap_free(caps); + if (cap_get_flag(cap, CAP_NET_ADMIN, CAP_EFFECTIVE, &net_admin_set) != 0) { + perror("ping: cap_get_flag"); + exit(-1); + } + cap_free(cap); + + /* if CAP_NET_ADMIN is not set, drop all capabilities now, otherwise defer + * dropping after the SO_MARK sock opt is set */ + if (net_admin_set == CAP_CLEAR) + drop_capabilities(); #endif source.sin6_family = AF_INET6; --- iputils-s20101006/ping_common.h 2010-10-06 13:59:20.000000000 +0200 +++ iputils-s20101006-patch/ping_common.h 2012-06-25 10:43:21.676189489 +0200 @@ -17,6 +17,10 @@ #include #include +#ifdef HAVE_CAPABILITIES +#include +#endif + #include #include #include @@ -188,6 +192,15 @@ static inline void advance_ntransmitted( acked = (__u16)ntransmitted + 1; } +static inline void drop_capabilities(void) +{ + cap_t cap = cap_init(); + if (cap_set_proc(cap) < 0) { + perror("ping: cap_set_proc"); + exit(-1); + } + cap_free(cap); +} extern int send_probe(void); extern int receive_error_msg(void); --- iputils-s20101006/ping_common.c 2012-06-25 09:53:03.705506619 +0200 +++ iputils-s20101006-patch/ping_common.c 2012-06-25 10:40:40.220150202 +0200 @@ -486,6 +486,10 @@ void setup(int icmp_sock) * dont support mark .. */ fprintf(stderr, "Warning: Failed to set mark %d\n", mark); +#ifdef HAVE_CAPABILITIES + /* in case we deferred dropping capabilities because of SO_MARK */ + drop_capabilities(); +#endif } }