Skip to content

Commit 2cbdff6

Browse files
committed
Use POSIX capabilities
Use POSIX capabilities to retain network capabilities and drop all other permissions. This allows IP_TRANSPARENT as an otherwise unprivileged user. Further work needed to align this with the binder module, since the capabilities module makes the binder module unnecessary.
1 parent 782140a commit 2cbdff6

File tree

3 files changed

+65
-1
lines changed

3 files changed

+65
-1
lines changed

configure.ac

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ PKG_CHECK_MODULES([LIBPCRE], [libpcre], HAVE_LIBPCRE=yes; AC_DEFINE(HAVE_LIBPCRE
3737
fi
3838
])
3939

40+
PKG_CHECK_MODULES([LIBCAP], [libcap], HAVE_LIBCAP=yes; AC_DEFINE(HAVE_LIBCAP, 1),
41+
[AC_LIB_HAVE_LINKFLAGS(pcre,, [#include <sys/capability.h>], [cap_get_proc();])
42+
if test x$ac_cv_libcap = xyes; then
43+
AC_SUBST([LIBCAP_LIBS], [$LIBCAP])
44+
fi
45+
])
46+
4047
AC_ARG_ENABLE([dns],
4148
[AS_HELP_STRING([--disable-dns], [Disable DNS resolution])],
4249
[dns="$withval"], [dns=yes])

src/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,4 @@ sniproxy_SOURCES = sniproxy.c \
3333
tls.c \
3434
tls.h
3535

36-
sniproxy_LDADD = $(LIBEV_LIBS) $(LIBPCRE_LIBS) $(LIBUDNS_LIBS)
36+
sniproxy_LDADD = $(LIBEV_LIBS) $(LIBPCRE_LIBS) $(LIBUDNS_LIBS) $(LIBCAP_LIBS)

src/sniproxy.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535
#include <sys/stat.h>
3636
#include <sys/time.h>
3737
#include <sys/resource.h>
38+
#ifdef HAVE_LIBCAP
39+
#include <sys/prctl.h>
40+
#include <sys/capability.h>
41+
#endif
3842
#include <signal.h>
3943
#include <errno.h>
4044
#include <ev.h>
@@ -222,6 +226,30 @@ drop_perms(const char *username) {
222226
else if (user == NULL)
223227
fatal("getpwnam(): user %s does not exist", username);
224228

229+
#ifdef HAVE_LIBCAP
230+
cap_t caps;
231+
cap_value_t cap_list[1];
232+
233+
/* add permitted flag to capability needed for IP_TRANSPARENT */
234+
if (CAP_IS_SUPPORTED(CAP_NET_RAW)) {
235+
caps = cap_get_proc();
236+
if (caps == NULL)
237+
fatal("cap_get_proc(): %s", strerror(errno));
238+
239+
cap_list[0] = CAP_NET_RAW;
240+
if (cap_set_flag(caps, CAP_PERMITTED, 1, cap_list, CAP_SET) == -1)
241+
fatal("cap_set_flags(): %s", strerror(errno));
242+
243+
if (cap_set_proc(caps) == -1)
244+
fatal("cap_set_proc(): %s", strerror(errno));
245+
246+
cap_free(caps);
247+
248+
/* keep capabilities after setuid */
249+
prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
250+
}
251+
#endif
252+
225253
/* drop any supplementary groups */
226254
if (setgroups(1, &user->pw_gid) < 0)
227255
fatal("setgroups(): %s", strerror(errno));
@@ -231,6 +259,35 @@ drop_perms(const char *username) {
231259

232260
if (setuid(user->pw_uid) < 0)
233261
fatal("setuid(): %s", strerror(errno));
262+
263+
#ifdef HAVE_LIBCAP
264+
/* enable capability needed for IP_TRANSPARENT */
265+
if (CAP_IS_SUPPORTED(CAP_NET_RAW)) {
266+
caps = cap_get_proc();
267+
if (caps == NULL)
268+
fatal("cap_get_proc(): %s", strerror(errno));
269+
270+
/* remove every capability from the list */
271+
cap_clear(caps);
272+
cap_list[0] = CAP_NET_RAW;
273+
/* take back capability */
274+
if (cap_set_flag(caps, CAP_PERMITTED, 1, cap_list, CAP_SET) == -1)
275+
fatal("cap_set_flags(): %s", strerror(errno));
276+
/* take back capability */
277+
if (cap_set_flag(caps, CAP_EFFECTIVE, 1, cap_list, CAP_SET) == -1)
278+
fatal("cap_set_flags(): %s", strerror(errno));
279+
280+
if (cap_set_proc(caps) == -1)
281+
fatal("back cap_set_proc(): %s", strerror(errno));
282+
/* from now on it the new capability list is active,
283+
* no other capabilities may be enabled */
284+
285+
cap_free(caps);
286+
287+
/* disable keeping capabilities across setuid */
288+
prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0);
289+
}
290+
#endif
234291
}
235292

236293
static void

0 commit comments

Comments
 (0)