b.a.t.m.a.n.lists.open-mesh.org archive mirror
 help / color / mirror / Atom feed
* [B.A.T.M.A.N.] [PATCH] alfred: Drop capabilities when not needed
@ 2015-02-23 19:18 Sven Eckelmann
  2015-02-28 20:04 ` MK
  2015-03-11 12:07 ` Simon Wunderlich
  0 siblings, 2 replies; 5+ messages in thread
From: Sven Eckelmann @ 2015-02-23 19:18 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Sven Eckelmann

The alfred process only requires the capability to bind to a raw socket
(CAP_NET_RAW). It is enough to mark this capability as permitted on program
startup and mark it again as effective whenever a new netsock is initialized.
All other capabilities can be dropped completely.

Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
 Makefile  | 24 ++++++++++++++++++
 main.c    | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 netsock.c | 44 +++++++++++++++++++++++++++++++++
 3 files changed, 151 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 8e944c9..4e22d76 100644
--- a/Makefile
+++ b/Makefile
@@ -27,6 +27,9 @@ MANPAGE = man/alfred.8
 CFLAGS += -pedantic -Wall -W -std=gnu99 -fno-strict-aliasing -MD -MP
 LDLIBS += -lrt
 
+# B.A.T.M.A.N. debugging:
+export CONFIG_ALFRED_CAPABILITIES=y
+
 # disable verbose output
 ifneq ($(findstring $(MAKEFLAGS),s),s)
 ifndef V
@@ -70,6 +73,27 @@ ifneq ($(CONFIG_ALFRED_GPSD),n)
 	GPSD_INSTALL=gpsd-install
 endif
 
+ifneq ($(CONFIG_ALFRED_CAPABILITIES),n)
+  ifeq ($(origin PKG_CONFIG), undefined)
+    PKG_CONFIG = pkg-config
+    ifeq ($(shell which $(PKG_CONFIG) 2>/dev/null),)
+      $(error $(PKG_CONFIG) not found)
+    endif
+  endif
+
+  ifeq ($(origin LIBCAP_CFLAGS) $(origin LIBCAP_LDLIBS), undefined undefined)
+    LIBCAP_NAME ?= libcap
+    ifeq ($(shell $(PKG_CONFIG) --modversion $(LIBCAP_NAME) 2>/dev/null),)
+      $(error No $(LIBCAP_NAME) development libraries found!)
+    endif
+    LIBCAP_CFLAGS += $(shell $(PKG_CONFIG) --cflags $(LIBCAP_NAME))
+    LIBCAP_LDLIBS +=  $(shell $(PKG_CONFIG) --libs $(LIBCAP_NAME))
+  endif
+  CFLAGS += $(LIBCAP_CFLAGS)
+  CPPFLAGS += -DCONFIG_ALFRED_CAPABILITIES
+  LDLIBS += $(LIBCAP_LDLIBS)
+endif
+
 
 # default target
 all: $(BINARY_NAME) $(VIS_ALL) $(GPSD_ALL)
diff --git a/main.c b/main.c
index d298d65..982bd2a 100644
--- a/main.c
+++ b/main.c
@@ -24,6 +24,11 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#ifdef CONFIG_ALFRED_CAPABILITIES
+#include <sys/prctl.h>
+#include <sys/capability.h>
+#include <unistd.h>
+#endif
 #include "alfred.h"
 #include "packet.h"
 #include "list.h"
@@ -60,9 +65,82 @@ static void alfred_usage(void)
 	printf("\n");
 }
 
+static int reduce_capabilities(void)
+{
+	int ret = 0;
+
+#ifdef CONFIG_ALFRED_CAPABILITIES
+	cap_t cap_cur;
+	cap_t cap_new;
+	cap_flag_value_t cap_flag;
+	cap_value_t cap_net_raw = CAP_NET_RAW;
+
+	/* get current process capabilities */
+	cap_cur = cap_get_proc();
+	if (!cap_cur) {
+		perror("cap_get_proc");
+		return -1;
+	}
+
+	/* create new capabilities */
+	cap_new = cap_init();
+	if (!cap_new) {
+		perror("cap_init");
+		cap_free(cap_new);
+		return -1;
+	}
+
+	/* copy capability as non-effictive but permitted */
+	cap_flag = CAP_CLEAR;
+	cap_get_flag(cap_cur, CAP_NET_RAW, CAP_PERMITTED, &cap_flag);
+	if (cap_flag != CAP_CLEAR) {
+		ret = cap_set_flag(cap_new, CAP_PERMITTED, 1, &cap_net_raw,
+				   CAP_SET);
+		if (ret < 0) {
+			perror("cap_set_flag");
+			goto out;
+		}
+	}
+
+	/* set minimal capabilities field */
+	ret = cap_set_proc(cap_new);
+	if (ret < 0) {
+		perror("cap_set_proc");
+		goto out;
+	}
+
+	/* don't drop capabilities with setuid */
+	ret = prctl(PR_SET_KEEPCAPS, 1);
+	if (ret < 0) {
+		perror("prctl PR_SET_KEEPCAPS(1)");
+		goto out;
+	}
+
+	/* drop euid */
+	ret = setuid(getuid());
+	if (ret < 0) {
+		perror("setuid");
+		goto out;
+	}
+
+	/* drop capabilities with setuid */
+	ret = prctl(PR_SET_KEEPCAPS, 0);
+	if (ret < 0) {
+		perror("prctl PR_SET_KEEPCAPS(0)");
+		goto out;
+	}
+
+out:
+	cap_free(cap_new);
+	cap_free(cap_cur);
+#endif
+
+	return ret;
+}
+
 static struct globals *alfred_init(int argc, char *argv[])
 {
-	int opt, opt_ind, i;
+	int opt, opt_ind, i, ret;
 	struct globals *globals;
 	struct option long_options[] = {
 		{"set-data",		required_argument,	NULL,	's'},
@@ -78,6 +156,10 @@ static struct globals *alfred_init(int argc, char *argv[])
 		{NULL,			0,			NULL,	0},
 	};
 
+	ret = reduce_capabilities();
+	if (ret < 0)
+		return NULL;
+
 	globals = &alfred_globals;
 	memset(globals, 0, sizeof(*globals));
 
diff --git a/netsock.c b/netsock.c
index cc2e9a5..592f3e3 100644
--- a/netsock.c
+++ b/netsock.c
@@ -34,6 +34,9 @@
 #include <sys/types.h>
 #include <stdlib.h>
 #include <sys/select.h>
+#ifdef CONFIG_ALFRED_CAPABILITIES
+#include <sys/capability.h>
+#endif
 #include "alfred.h"
 #include "batadv_query.h"
 #include "packet.h"
@@ -165,6 +168,45 @@ int netsock_set_interfaces(struct globals *globals, char *interfaces)
 	return 0;
 }
 
+static int enable_raw_bind_capability(int enable)
+{
+	int ret = 0;
+
+#ifdef CONFIG_ALFRED_CAPABILITIES
+	cap_t cap_cur;
+	cap_flag_value_t cap_flag;
+	cap_value_t cap_net_raw = CAP_NET_RAW;
+
+	if (enable)
+		cap_flag = CAP_SET;
+	else
+		cap_flag = CAP_CLEAR;
+
+	cap_cur = cap_get_proc();
+	if (!cap_cur) {
+		perror("cap_get_proc");
+		return -1;
+	}
+
+	ret = cap_set_flag(cap_cur, CAP_EFFECTIVE, 1, &cap_net_raw, cap_flag);
+	if (ret < 0) {
+		perror("cap_set_flag");
+		goto out;
+	}
+
+	ret = cap_set_proc(cap_cur);
+	if (ret < 0) {
+		perror("cap_set_proc");
+		goto out;
+	}
+
+out:
+	cap_free(cap_cur);
+#endif
+
+	return ret;
+}
+
 static int netsock_open(struct interface *interface)
 {
 	int sock;
@@ -204,11 +246,13 @@ static int netsock_open(struct interface *interface)
 	memcpy(&interface->hwaddr, &ifr.ifr_hwaddr.sa_data, 6);
 	mac_to_ipv6(&interface->hwaddr, &interface->address);
 
+	enable_raw_bind_capability(1);
 	if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interface->interface,
 		       strlen(interface->interface) + 1)) {
 		perror("can't bind to device");
 		goto err;
 	}
+	enable_raw_bind_capability(0);
 
 	if (bind(sock, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) {
 		perror("can't bind");
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [B.A.T.M.A.N.] [PATCH] alfred: Drop capabilities when not needed
  2015-02-23 19:18 [B.A.T.M.A.N.] [PATCH] alfred: Drop capabilities when not needed Sven Eckelmann
@ 2015-02-28 20:04 ` MK
  2015-02-28 22:36   ` Simon Wunderlich
  2015-03-05  8:05   ` Sven Eckelmann
  2015-03-11 12:07 ` Simon Wunderlich
  1 sibling, 2 replies; 5+ messages in thread
From: MK @ 2015-02-28 20:04 UTC (permalink / raw)
  To: b.a.t.m.a.n

Hi!

Thanks for the patch. Setup seems to be still working. How can I verify that 
privileges really dropped?

There are further questions:

Is _read_ access for the alfred user (resp. group) sufficient in 
/sys/kernel/debug/batman_adv/* ?
Or is write access on the socket file in this directory mandatory for full 
functionality?

Thanks 
Martin




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [B.A.T.M.A.N.] [PATCH] alfred: Drop capabilities when not needed
  2015-02-28 20:04 ` MK
@ 2015-02-28 22:36   ` Simon Wunderlich
  2015-03-05  8:05   ` Sven Eckelmann
  1 sibling, 0 replies; 5+ messages in thread
From: Simon Wunderlich @ 2015-02-28 22:36 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: MK

[-- Attachment #1: Type: text/plain, Size: 529 bytes --]

On Saturday 28 February 2015 21:04:19 MK wrote:
> Hi!
> 
> Thanks for the patch. Setup seems to be still working. How can I verify that
> privileges really dropped?
> 
> There are further questions:
> 
> Is _read_ access for the alfred user (resp. group) sufficient in
> /sys/kernel/debug/batman_adv/* ?
> Or is write access on the socket file in this directory mandatory for full
> functionality?

Read functionality should be enough. We are only reading the originator table 
and (global) translation table.

Cheers,
    Simon

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [B.A.T.M.A.N.] [PATCH] alfred: Drop capabilities when not needed
  2015-02-28 20:04 ` MK
  2015-02-28 22:36   ` Simon Wunderlich
@ 2015-03-05  8:05   ` Sven Eckelmann
  1 sibling, 0 replies; 5+ messages in thread
From: Sven Eckelmann @ 2015-03-05  8:05 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: MK

Hi,

Please Cc me when you want an answer from me (I am not subscribed to this 
mailing list). I just found this mail by pure luck.

On Saturday 28 February 2015 21:04:19 MK wrote:
> Thanks for the patch. Setup seems to be still working. How can I verify that
> privileges really dropped?

The privileges of a process can be found in

$ cat /proc/`pidof alfred`/status

The active capabilities are CapEff. The capabilities the process can request 
can be found in CapPrm.

> There are further questions:
> 
> Is _read_ access for the alfred user (resp. group) sufficient in
> /sys/kernel/debug/batman_adv/* ?
> Or is write access on the socket file in this directory mandatory for full
> functionality?

The process needs to access the path and read the files. For example my system 
allows read of this files by default BUT disallows non-root access to 
/sys/kernel/debug

$ ls -ltrd /sys/kernel/debug
drwx------ 27 root root 0 Mar  2 18:58 /sys/kernel/debug

I would have to allow other users o+rx access to this path before being able 
to access the batman-adv files:

$ cat /sys/kernel/debug/batman_adv/bat0/originators
cat: /sys/kernel/debug/batman_adv/bat0/originators: Permission denied
$ sudo chmod o+rx /sys/kernel/debug
$ cat /sys/kernel/debug/batman_adv/bat0/originators
[B.A.T.M.A.N. adv 2014.3.0, MainIF/MAC: eth0/XX:XX:XX:XX:XX:XX (bat0 
BATMAN_IV)]
  Originator      last-seen (#/255)           Nexthop [outgoingIF]:   
Potential nexthops ...
No batman nodes in range ...


!!!! WARNING !!!!
I don't recommend to grant all users access to /sys/kernel/debug.

Kind regards,
	Sven

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [B.A.T.M.A.N.] [PATCH] alfred: Drop capabilities when not needed
  2015-02-23 19:18 [B.A.T.M.A.N.] [PATCH] alfred: Drop capabilities when not needed Sven Eckelmann
  2015-02-28 20:04 ` MK
@ 2015-03-11 12:07 ` Simon Wunderlich
  1 sibling, 0 replies; 5+ messages in thread
From: Simon Wunderlich @ 2015-03-11 12:07 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Sven Eckelmann

[-- Attachment #1: Type: text/plain, Size: 501 bytes --]

On Monday 23 February 2015 20:18:50 Sven Eckelmann wrote:
> The alfred process only requires the capability to bind to a raw socket
> (CAP_NET_RAW). It is enough to mark this capability as permitted on program
> startup and mark it again as effective whenever a new netsock is
> initialized. All other capabilities can be dropped completely.
> 
> Signed-off-by: Sven Eckelmann <sven@narfation.org>

Applied in revision b0877b3 (just replaced that "B.A.T.M.A.N. debugging 
comment).

Thanks!
     Simon

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2015-03-11 12:07 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-23 19:18 [B.A.T.M.A.N.] [PATCH] alfred: Drop capabilities when not needed Sven Eckelmann
2015-02-28 20:04 ` MK
2015-02-28 22:36   ` Simon Wunderlich
2015-03-05  8:05   ` Sven Eckelmann
2015-03-11 12:07 ` Simon Wunderlich

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).