summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Habets <thomas@habets.se>2021-12-09 18:35:34 +0000
committerThomas Habets <thomas@habets.se>2021-12-09 18:35:34 +0000
commitd847c55389c2de764d002770d3d87e6120000a8c (patch)
treea233600ae5841aabe069455552caedb5ff7e11fe
parentfe93525db89db289178f2dbbfad92d7a88c8226a (diff)
downloadarping-d847c55389c2de764d002770d3d87e6120000a8c.tar.gz
Add seccomp to drop syscall access before receiving any packets
seccomp is not as good as pledge(), in that different systems, and even different versions of any of the transitively dependent libraries, will need different syscalls. This feature is therefore off by default, and should be considered experimental. Maybe the right long term solution is to blacklist, not whitelist. Which is also not great, as new syscalls get created.
-rw-r--r--configure.ac9
-rw-r--r--doc/arping.811
-rw-r--r--doc/arping.yodl4
-rw-r--r--src/arping.c98
4 files changed, 108 insertions, 14 deletions
diff --git a/configure.ac b/configure.ac
index 6e808c3..5fd8ff6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -26,6 +26,7 @@ AC_CHECK_LIB([m], [sqrt])
AC_CHECK_LIB([socket], [socket])
AC_CHECK_LIB([nsl], [gethostbyname])
AC_CHECK_LIB([cap], [cap_init])
+AC_CHECK_LIB([seccomp], [seccomp_init])
AC_CHECK_LIB([rt], [clock_gettime])
AC_CHECK_LIB([net], [libnet_name_resolve],
[AC_MSG_ERROR([libnet 1.0.x found. Arping 2.x requires libnet 1.1 or newer])])
@@ -33,14 +34,20 @@ AC_CHECK_LIB([net], [libnet_init], ,[AC_MSG_ERROR([libnet 1.1.x not found])])
AC_CHECK_LIB([pcap], [pcap_open_live], ,[AC_MSG_ERROR([libpcap not found])])
AC_SEARCH_LIBS([clock_gettime], [rt])
+AC_ARG_ENABLE([seccomp], [Enable seccomp priv drops by default (-z to turn on, -Z for off)], [
+ AC_DEFINE([DEFAULT_SECCOMP], [1], [Enable seccomp by default])
+], [
+ AC_DEFINE([DEFAULT_SECCOMP], [0], [Disable seccomp by default])
+])
# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([\
arpa/inet.h \
+getopt.h \
netinet/in.h \
+seccomp.h \
stdlib.h \
sys/socket.h \
-getopt.h \
time.h \
grp.h \
sys/time.h \
diff --git a/doc/arping.8 b/doc/arping.8
index 074c067..1650f4a 100644
--- a/doc/arping.8
+++ b/doc/arping.8
@@ -109,12 +109,12 @@ Set target MAC address to use when pinging IP address\&.
.IP "\-T \fIIP\fP"
Use \-T as target address when pinging MACs that won\(cq\&t
respond to a broadcast ping but perhaps to a directed broadcast\&.
-.IP
+.PP
\fIExample\fP:
.nf
.sp
To check the address of MAC\-A, use knowledge of MAC\-B and IP\-B\&.
-.IP
+.PP
$ arping \-S <IP\-B> \-s <MAC\-B> \-p <MAC\-A>
.IP "\-u"
Show index=received/sent instead of just index=received when
@@ -123,7 +123,7 @@ pinging MACs\&.
Send unsolicited ARP\&. This sets the destination MAC address in
the ARP frame to the broadcast address\&. Unsolicited ARP is used
to update the neighbours\(cq\& ARP caches\&.
-.IP
+.PP
\fIExample\fP:
.nf
.sp
@@ -136,7 +136,10 @@ VLAN tag to set\&. Defaults to no VLAN tag\&.
Specify a timeout before ping exits regardless of how many packets have been sent or received\&.
.IP "\-W \fIsec\fP"
Time to wait between pings\&.
-
+.IP "\-z"
+Enable seccomp (default seccomp state depends on compile options)
+.IP "\-Z"
+Disable seccomp (default seccomp state depends on compile options)
.PP
.SH "EXAMPLES"
.nf
diff --git a/doc/arping.yodl b/doc/arping.yodl
index c907fdb..2bc3256 100644
--- a/doc/arping.yodl
+++ b/doc/arping.yodl
@@ -36,7 +36,6 @@ manpagedescription()
manpageoptions()
-startdit()
dit(--help) Show extended help. Not quite as extensive as this manpage,
but more than -h.
dit(-0) Use this option to ping with source IP address 0.0.0.0. Use this
@@ -104,7 +103,8 @@ mancommand(.sp)
dit(-V em(vlan)) VLAN tag to set. Defaults to no VLAN tag.
dit(-w em(sec)) Specify a timeout before ping exits regardless of how many packets have been sent or received.
dit(-W em(sec)) Time to wait between pings.
-enddit()
+ dit(-z) Enable seccomp (default seccomp state depends on compile options)
+ dit(-Z) Disable seccomp (default seccomp state depends on compile options)
manpagesection(EXAMPLES)
diff --git a/src/arping.c b/src/arping.c
index ab928aa..1844c67 100644
--- a/src/arping.c
+++ b/src/arping.c
@@ -123,6 +123,11 @@
#endif
#include <pcap.h>
+#if defined(HAVE_SECCOMP_H) && defined(HAVE_LIBSECCOMP)
+#define USE_SECCOMP 1
+#include <seccomp.h>
+#endif
+
#include "arping.h"
#ifndef ETH_ALEN
@@ -199,6 +204,9 @@ static int finddup = 0; /* finddup mode. -d */
static int dupfound = 0; /* set to 1 if dup found */
static char lastreplymac[ETH_ALEN]; /* if last different from this then dup */
+/* -z to turn on, -Z to turn off. Default is compile time option */
+static int use_seccomp = DEFAULT_SECCOMP;
+
unsigned int numsent = 0; /* packets sent */
unsigned int numrecvd = 0; /* packets received */
static unsigned int max_replies = UINT_MAX; /* exit after -C replies */
@@ -465,13 +473,73 @@ drop_privileges(const char* drop_group)
#endif
}
+#ifdef USE_SECCOMP
+static void seccomp_allow(scmp_filter_ctx ctx, const char* name)
+{
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, seccomp_syscall_resolve_name(name), 0)) {
+ perror("seccomp_rule_add_exact()");
+ exit(1);
+ }
+}
+
+static void drop_seccomp(int libnet_fd)
+{
+ //scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ERRNO(13));
+ scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL);
+ if (!ctx) {
+ perror("seccomp_init()");
+ exit(1);
+ }
+
+ //
+ // Whitelist.
+ //
+
+ // Write to stdout and stderr.
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 1, SCMP_A0(SCMP_CMP_EQ, STDOUT_FILENO))) {
+ perror("seccomp_rule_add(fstat stdout)");
+ exit(1);
+ }
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, SCMP_A0(SCMP_CMP_EQ, STDOUT_FILENO))) {
+ perror("seccomp_rule_add(write stdout)");
+ exit(1);
+ }
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, SCMP_A0(SCMP_CMP_EQ, STDERR_FILENO))) {
+ perror("seccomp_rule_add(write stderr)");
+ exit(1);
+ }
+
+ // Libnet.
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1, SCMP_A0(SCMP_CMP_EQ, libnet_fd))) {
+ perror("seccomp_rule_add(ioctl libnet)");
+ exit(1);
+ }
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sendto), 1, SCMP_A0(SCMP_CMP_EQ, libnet_fd))) {
+ perror("seccomp_rule_add(sendto libnet)");
+ exit(1);
+ }
+
+ // Other.
+ seccomp_allow(ctx, "select");
+ seccomp_allow(ctx, "exit_group");
+ seccomp_allow(ctx, "rt_sigreturn");
+
+ // Load.
+ if (seccomp_load(ctx)) {
+ perror("seccomp_load()");
+ exit(1);
+ }
+ seccomp_release(ctx);
+}
+#endif
+
/**
* drop even more privileges, where possible.
*
* After all setup is done and main loop is about to start.
*/
static void
-drop_more_privileges()
+drop_more_privileges(int libnet_fd)
{
#ifdef HAVE_PLEDGE
if (pledge("stdio tty", "")) {
@@ -482,9 +550,13 @@ drop_more_privileges()
printf("arping: Successfully pledged\n");
}
#endif
+#ifdef USE_SECCOMP
+ if (use_seccomp) {
+ drop_seccomp(libnet_fd);
+ }
+#endif
}
-
/**
* Do pcap_open_live(), except by using the pcap_create() interface
* introduced in 2008 (libpcap 0.4) where available.
@@ -833,7 +905,11 @@ extended_usage()
" -V num 802.1Q tag to add. Defaults to no VLAN tag.\n"
" -w sec Specify a timeout before ping exits regardless of how"
" many\npackets have been sent or received.\n"
- " -W sec Time to wait between pings.\n");
+ " -W sec Time to wait between pings.\n"
+ " -z Enable seccomp%s\n"
+ " -Z Disable seccomp%s\n",
+ DEFAULT_SECCOMP ? " (default)" : "",
+ DEFAULT_SECCOMP ? "" : " (default)");
printf("Report bugs to: thomas@habets.se\n"
"Arping home page: <http://www.habets.pp.se/synscan/>\n"
"Development repo: http://github.com/ThomasHabets/arping\n");
@@ -847,7 +923,7 @@ standard_usage()
{
printf("ARPing %s, by Thomas Habets <thomas@habets.se>\n",
version);
- printf("usage: arping [ -0aAbdDeFpPqrRuUv ] [ -w <sec> ] "
+ printf("usage: arping [ -0aAbdDeFpPqrRuUvzZ ] [ -w <sec> ] "
"[ -W <sec> ] "
"[ -S <host/ip> ]\n"
" "
@@ -1682,7 +1758,6 @@ ping_recv(pcap_t *pcap, uint32_t packetwait, pcap_handler func)
break;
}
}
-
if (trydispatch) {
int ret;
if (0 > (ret = pcap_dispatch(pcap, -1,
@@ -1763,7 +1838,7 @@ arping_main(int argc, char **argv)
memcpy(dstmac, ethxmas, ETH_ALEN);
while (EOF != (c = getopt(argc, argv,
- "0aAbBC:c:dDeFg:hi:I:m:pPqQ:rRs:S:t:T:uUvV:w:W:"))) {
+ "0aAbBC:c:dDeFg:hi:I:m:pPqQ:rRs:S:t:T:uUvV:w:W:zZ"))) {
switch(c) {
case '0':
srcip_opt = "0.0.0.0";
@@ -1891,6 +1966,12 @@ arping_main(int argc, char **argv)
case 'W':
packetwait = (unsigned)(1000000.0 * atof(optarg));
break;
+ case 'z':
+ use_seccomp = 1;
+ break;
+ case 'Z':
+ use_seccomp = 0;
+ break;
default:
usage(1);
}
@@ -2063,6 +2144,9 @@ arping_main(int argc, char **argv)
* libnet init (may be done already for resolving)
*/
do_libnet_init(ifname, 0);
+ if (verbose > 1) {
+ printf("arping: libnet_getfd(): %d\n", libnet_getfd(libnet));
+ }
/*
* Make sure dstip and parm like eachother
@@ -2249,7 +2333,7 @@ arping_main(int argc, char **argv)
format_mac(srcmac, buf, sizeof(buf)));
}
- drop_more_privileges();
+ drop_more_privileges(libnet_getfd(libnet));
if (display == NORMAL) {
printf("ARPING %s\n", parm);