[PATCH 3/4] params: Add parsing of -f|--fds option

Cyrill Gorcunov <[email protected]>
Newsgroups org.kernel.vger.trinity
Message-ID <[email protected]>
Here we introduce a trivial tokenizer to control socket
domains assignment. It might be needed to disabled some
sockets (or even all of them, if you're not interested
in testing sockets). For this sake -f|--fds option introduced.

The option takes argument in form of

	--fds sockets:[(all,)|(none,)|(PF_X,^PF_X)]

where PF_X is appropriate domain like PF_INET and such.
The prefix ^ before name means to exclude some particular
family from being tested.

Also note that all|none do overwrite previous option, this
is done in a sake of code simplicity. IOW, if

	--fds sockets:^PF_INET,all

is passed, in result all socket families are allowed.

Signed-off-by: Cyrill Gorcunov <[email protected]>
---
 include/net.h   |  6 +++-
 net/protocols.c | 11 +++++++
 params.c        | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 107 insertions(+), 2 deletions(-)

diff --git a/include/net.h b/include/net.h
index 4e43546..c5baaf4 100644
--- a/include/net.h
+++ b/include/net.h
@@ -1,9 +1,12 @@
 #ifndef _NET_H
 #define _NET_H 1
 
+#include <sys/types.h>
+#include <sys/socket.h>
 #include <netinet/in.h>
 
 extern unsigned int nr_sockets;
+extern char disabled_protos[PF_MAX];
 void open_sockets(void);
 void generate_sockaddr(unsigned long *addr, unsigned long *addrlen, int pf);
 
@@ -11,7 +14,8 @@ void generate_sockaddr(unsigned long *addr, unsigned long *addrlen, int pf);
 extern unsigned int specific_proto;
 const char * get_proto_name(unsigned int proto);
 void find_specific_proto(const char *protoarg);
-
+unsigned int find_proto_by_name(const char *name);
+int disable_socket(const char *domain);
 
 /* glibc headers might be older than the kernel, so chances are we know
  * about more protocols than glibc does. So we define our own PF_MAX */
diff --git a/net/protocols.c b/net/protocols.c
index 891acfe..6aedd29 100644
--- a/net/protocols.c
+++ b/net/protocols.c
@@ -58,6 +58,17 @@ static const struct protocol protocols[] = {
 	{ "PF_VSOCK",        40 },
 };
 
+unsigned int find_proto_by_name(const char *name)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(protocols); i++) {
+		if (!strcmp(protocols[i].name, name))
+			return protocols[i].proto;
+	}
+	return -1u;
+}
+
 const char * get_proto_name(unsigned int proto)
 {
 	unsigned int i;
diff --git a/params.c b/params.c
index 77dc7e4..f2b31a3 100644
--- a/params.c
+++ b/params.c
@@ -5,6 +5,7 @@
 #include <getopt.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/socket.h>
 
 #include "trinity.h"	// progname
 #include "random.h"
@@ -12,6 +13,7 @@
 #include "log.h"
 #include "params.h"
 #include "tables.h"
+#include "net.h"
 
 #define TAINT_NAME_LEN 32
 
@@ -53,6 +55,13 @@ int kernel_taint_initial = 0;
 int kernel_taint_mask = 0xFFFFFFFF;
 bool kernel_taint_param_occured = FALSE;
 
+/*
+ * Some socket domains might be disabled in command line,
+ * track the option here, probably worth to convert to
+ * bitmap.
+ */
+char disabled_protos[PF_MAX];
+
 static void usage(void)
 {
 	outputerr("%s\n", progname);
@@ -64,6 +73,7 @@ static void usage(void)
 	outputerr(" --kernel_taint, -T: controls which kernel taint flags should be considered, for more details refer to README file. \n");
 	outputerr(" --list,-L: list all syscalls known on this architecture.\n");
 	outputerr(" --logging,-l: (off=disable logging).\n");
+	outputerr(" --fds,-f: controls which kind of sockets and files to use.\n");
 	outputerr(" --monochrome,-m: don't output ANSI codes\n");
 	outputerr(" --no_files,-n: Only pass sockets as fd's, not files\n");
 	outputerr(" --proto,-P: specify specific network protocol for sockets.\n");
@@ -91,6 +101,7 @@ static const struct option longopts[] = {
 	{ "list", no_argument, NULL, 'L' },
 	{ "ioctls", no_argument, NULL, 'I' },
 	{ "logging", required_argument, NULL, 'l' },
+	{ "fds", required_argument, NULL, 'f' },
 	{ "monochrome", no_argument, NULL, 'm' },
 	{ "no_files", no_argument, NULL, 'n' },
 	{ "proto", required_argument, NULL, 'P' },
@@ -172,11 +183,86 @@ static void process_taint_arg(char *taintarg) {
 	toggle_taint_flag_by_name(beg,end);
 }
 
+static void parse_fds(char *arg)
+{
+	enum {
+		FDS_NONE,
+		FDS_SOCKET,
+	} context = FDS_NONE;
+	char *p = strdup(arg);
+	char *tok;
+
+	if (!p) {
+		outputerr("No memory to parse %s\n", arg);
+		exit(EXIT_FAILURE);
+	}
+
+	/*
+	 * We're expecting here the following format,
+	 * but our parser is a way more greedy and simplier:
+	 * spaces, semicolons and commas are all separators.
+	 *
+	 * 	sockets:[(all,)|(none,)(PF_X,^PF_X)]
+	 *
+	 * note, we're context dependant -- by default all sockets
+	 * are enabled, if you need to disable a particular socket,
+	 * the "^PF_" prefix should be passed. But if you need only
+	 * a few sockets to be enabled then it must be "none,PF_X,PF_X".
+	 *
+	 * It might be not that convenient to type but easier to parse ;-)
+	 */
+	for (tok = strtok(p, " :,"); tok; tok = strtok(NULL, " :,")) {
+		if (strcmp(tok, "sockets") == 0) {
+			context = FDS_SOCKET;
+			continue;
+		}
+
+		switch (context) {
+		case FDS_SOCKET:
+			if (strcmp(tok, "all") == 0) {
+				memset(disabled_protos, 'n', sizeof(disabled_protos));
+			} else if (strcmp(tok, "none") == 0) {
+				memset(disabled_protos, 'y', sizeof(disabled_protos));
+			} else if (strncmp(tok, "PF_", 3) == 0 ||
+				   strncmp(tok, "^PF_", 4) == 0) {
+				int neg = tok[0] == '^';
+				unsigned int proto;
+
+
+				proto = find_proto_by_name(&tok[neg]);
+				if (proto == -1u)
+					goto err;
+				else if (proto > ARRAY_SIZE(disabled_protos))
+					BUG_ON(1);
+				else {
+					if (neg)
+						disabled_protos[proto] = 'y';
+					else
+						disabled_protos[proto] = 'n';
+				}
+			}
+			break;
+		case FDS_NONE:
+		default:
+			outputerr("Unknown context.\n");
+			goto err;
+		}
+	}
+
+	free(p);
+	return;
+
+err:
+	free(p);
+	outputerr("Unrecognizable option in \"%s\".\n", arg);
+	exit(EXIT_FAILURE);
+}
+
 void parse_args(int argc, char *argv[])
 {
 	int opt;
 
-	while ((opt = getopt_long(argc, argv, "a:c:C:dDg:hIl:LN:mnP:pqr:s:T:SV:vx:", longopts, NULL)) != -1) {
+	while ((opt = getopt_long(argc, argv, "a:c:C:dDg:hIlf:LN:mnP:pqr:s:T:SV:vx:", longopts, NULL)) != -1) {
 		switch (opt) {
 		default:
 			if (opt == '?')
@@ -240,6 +326,10 @@ void parse_args(int argc, char *argv[])
 				logging = 0;
 			break;
 
+		case 'f':
+			parse_fds(optarg);
+			break;
+
 		case 'L':
 			show_syscall_list = TRUE;
 			break;
-- 
1.8.3.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.