diff options
author | netblue30 <netblue30@yahoo.com> | 2017-11-18 08:39:02 -0500 |
---|---|---|
committer | netblue30 <netblue30@yahoo.com> | 2017-11-18 08:39:02 -0500 |
commit | ead4ec3089b97eda1b438da248caf76f169345ad (patch) | |
tree | 31bc22bcba4e6530b5f0daba3f332702efa7a4b9 /src | |
parent | Consistent home directory nomenclature (diff) | |
download | firejail-ead4ec3089b97eda1b438da248caf76f169345ad.tar.gz firejail-ead4ec3089b97eda1b438da248caf76f169345ad.tar.zst firejail-ead4ec3089b97eda1b438da248caf76f169345ad.zip |
netfilter template support
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/netfilter.c | 13 | ||||
-rw-r--r-- | src/firejail/usage.c | 2 | ||||
-rw-r--r-- | src/fnetfilter/main.c | 144 | ||||
-rw-r--r-- | src/man/firejail.txt | 23 |
4 files changed, 153 insertions, 29 deletions
diff --git a/src/firejail/netfilter.c b/src/firejail/netfilter.c index e1d0edd01..dd4009a2e 100644 --- a/src/firejail/netfilter.c +++ b/src/firejail/netfilter.c | |||
@@ -24,7 +24,6 @@ | |||
24 | #include <sys/wait.h> | 24 | #include <sys/wait.h> |
25 | #include <fcntl.h> | 25 | #include <fcntl.h> |
26 | 26 | ||
27 | |||
28 | void check_netfilter_file(const char *fname) { | 27 | void check_netfilter_file(const char *fname) { |
29 | EUID_ASSERT(); | 28 | EUID_ASSERT(); |
30 | 29 | ||
@@ -44,7 +43,6 @@ void check_netfilter_file(const char *fname) { | |||
44 | free(tmp); | 43 | free(tmp); |
45 | } | 44 | } |
46 | 45 | ||
47 | |||
48 | void netfilter(const char *fname) { | 46 | void netfilter(const char *fname) { |
49 | // find iptables command | 47 | // find iptables command |
50 | struct stat s; | 48 | struct stat s; |
@@ -150,6 +148,16 @@ void netfilter_print(pid_t pid, int ipv6) { | |||
150 | } | 148 | } |
151 | free(comm); | 149 | free(comm); |
152 | 150 | ||
151 | // check privileges for non-root users | ||
152 | uid_t uid = getuid(); | ||
153 | if (uid != 0) { | ||
154 | uid_t sandbox_uid = pid_get_uid(pid); | ||
155 | if (uid != sandbox_uid) { | ||
156 | fprintf(stderr, "Error: permission is denied to join a sandbox created by a different user.\n"); | ||
157 | exit(1); | ||
158 | } | ||
159 | } | ||
160 | |||
153 | // check network namespace | 161 | // check network namespace |
154 | char *name; | 162 | char *name; |
155 | if (asprintf(&name, "/run/firejail/network/%d-netmap", pid) == -1) | 163 | if (asprintf(&name, "/run/firejail/network/%d-netmap", pid) == -1) |
@@ -196,4 +204,3 @@ void netfilter_print(pid_t pid, int ipv6) { | |||
196 | 204 | ||
197 | sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 2, iptables, "-vL"); | 205 | sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 2, iptables, "-vL"); |
198 | } | 206 | } |
199 | |||
diff --git a/src/firejail/usage.c b/src/firejail/usage.c index f1581e847..89ea4ccca 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c | |||
@@ -122,7 +122,7 @@ void usage(void) { | |||
122 | printf(" --net=ethernet_interface - enable network namespaces and connect to this\n"); | 122 | printf(" --net=ethernet_interface - enable network namespaces and connect to this\n"); |
123 | printf("\tEthernet interface.\n"); | 123 | printf("\tEthernet interface.\n"); |
124 | printf(" --net=none - enable a new, unconnected network namespace.\n"); | 124 | printf(" --net=none - enable a new, unconnected network namespace.\n"); |
125 | printf(" --netfilter[=filename] - enable firewall.\n"); | 125 | printf(" --netfilter[=filename,arg1,arg2,arg3 ...] - enable firewall.\n"); |
126 | printf(" --netfilter.print=name|pid - print the firewall.\n"); | 126 | printf(" --netfilter.print=name|pid - print the firewall.\n"); |
127 | printf(" --netfilter6=filename - enable IPv6 firewall.\n"); | 127 | printf(" --netfilter6=filename - enable IPv6 firewall.\n"); |
128 | printf(" --netfilter6.print=name|pid - print the IPv6 firewall.\n"); | 128 | printf(" --netfilter6.print=name|pid - print the IPv6 firewall.\n"); |
diff --git a/src/fnetfilter/main.c b/src/fnetfilter/main.c index 67ab31832..723c1ac32 100644 --- a/src/fnetfilter/main.c +++ b/src/fnetfilter/main.c | |||
@@ -20,8 +20,12 @@ | |||
20 | #include "../include/common.h" | 20 | #include "../include/common.h" |
21 | 21 | ||
22 | #define MAXBUF 4098 | 22 | #define MAXBUF 4098 |
23 | #define MAXARGS 16 | ||
24 | static char *args[MAXARGS] = {0}; | ||
25 | static int argcnt = 0; | ||
23 | int arg_quiet = 0; | 26 | int arg_quiet = 0; |
24 | 27 | ||
28 | |||
25 | static char *default_filter = | 29 | static char *default_filter = |
26 | "*filter\n" | 30 | "*filter\n" |
27 | ":INPUT DROP [0:0]\n" | 31 | ":INPUT DROP [0:0]\n" |
@@ -29,7 +33,7 @@ static char *default_filter = | |||
29 | ":OUTPUT ACCEPT [0:0]\n" | 33 | ":OUTPUT ACCEPT [0:0]\n" |
30 | "-A INPUT -i lo -j ACCEPT\n" | 34 | "-A INPUT -i lo -j ACCEPT\n" |
31 | "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n" | 35 | "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n" |
32 | "# echo replay is handled by -m state RELATED/ESTABLISHED below\n" | 36 | "# echo replay is handled by -m state RELATED/ESTABLISHED above\n" |
33 | "#-A INPUT -p icmp --icmp-type echo-reply -j ACCEPT\n" | 37 | "#-A INPUT -p icmp --icmp-type echo-reply -j ACCEPT\n" |
34 | "-A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT\n" | 38 | "-A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT\n" |
35 | "-A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT\n" | 39 | "-A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT\n" |
@@ -46,6 +50,111 @@ static void usage(void) { | |||
46 | printf("\tfnetfilter netfilter-command destination-file\n"); | 50 | printf("\tfnetfilter netfilter-command destination-file\n"); |
47 | } | 51 | } |
48 | 52 | ||
53 | |||
54 | static void copy(const char *src, const char *dest) { | ||
55 | FILE *fp1 = fopen(src, "r"); | ||
56 | if (!fp1) { | ||
57 | fprintf(stderr, "Error fnetfilter: cannot open %s\n", src); | ||
58 | exit(1); | ||
59 | } | ||
60 | |||
61 | FILE *fp2 = fopen(dest, "w"); | ||
62 | if (!fp2) { | ||
63 | fprintf(stderr, "Error fnetfilter: cannot open %s\n", dest); | ||
64 | exit(1); | ||
65 | } | ||
66 | |||
67 | char buf[MAXBUF]; | ||
68 | while (fgets(buf, MAXBUF, fp1)) | ||
69 | fprintf(fp2, "%s", buf); | ||
70 | |||
71 | fclose(fp1); | ||
72 | fclose(fp2); | ||
73 | } | ||
74 | |||
75 | static void process_template(char *src, const char *dest) { | ||
76 | char *arg_start = strchr(src, ','); | ||
77 | assert(arg_start); | ||
78 | *arg_start = '\0'; | ||
79 | arg_start++; | ||
80 | if (*arg_start == '\0') { | ||
81 | fprintf(stderr, "Error fnetfilter: you need to provide at least on argument\n"); | ||
82 | exit(1); | ||
83 | } | ||
84 | |||
85 | // extract the arguments from command line | ||
86 | char *token = strtok(arg_start, ","); | ||
87 | while (token) { | ||
88 | // look for abnormal things | ||
89 | int len = strlen(token); | ||
90 | if (strcspn(token, "\\&!?\"'<>%^(){};,*[]") != (size_t)len) { | ||
91 | fprintf(stderr, "Error fnetfilter: invalid argument in netfilter command\n"); | ||
92 | exit(1); | ||
93 | } | ||
94 | args[argcnt] = token; | ||
95 | argcnt++; | ||
96 | token = strtok(NULL, ","); | ||
97 | } | ||
98 | #if 0 | ||
99 | { | ||
100 | printf("argcnt %d\n", argcnt); | ||
101 | int i; | ||
102 | for (i = 0; i < argcnt; i++) | ||
103 | printf("%s\n", args[i]); | ||
104 | } | ||
105 | #endif | ||
106 | |||
107 | // open the files | ||
108 | FILE *fp1 = fopen(src, "r"); | ||
109 | if (!fp1) { | ||
110 | fprintf(stderr, "Error fnetfilter: cannot open %s\n", src); | ||
111 | exit(1); | ||
112 | } | ||
113 | |||
114 | FILE *fp2 = fopen(dest, "w"); | ||
115 | if (!fp2) { | ||
116 | fprintf(stderr, "Error fnetfilter: cannot open %s\n", dest); | ||
117 | exit(1); | ||
118 | } | ||
119 | |||
120 | int line = 0; | ||
121 | char buf[MAXBUF]; | ||
122 | while (fgets(buf, MAXBUF, fp1)) { | ||
123 | line++; | ||
124 | char *ptr = buf; | ||
125 | while (*ptr != '\0') { | ||
126 | if (*ptr != '$') | ||
127 | fputc(*ptr, fp2); | ||
128 | else { | ||
129 | // parsing | ||
130 | int index = 0; | ||
131 | int rv = sscanf(ptr, "$ARG%u", &index) ; | ||
132 | if (rv != 1) { | ||
133 | fprintf(stderr, "Error fnetfilter: invalid template argument on line %d\n", line); | ||
134 | exit(1); | ||
135 | } | ||
136 | |||
137 | // print argument | ||
138 | if (index < 1 || index > argcnt) { | ||
139 | fprintf(stderr, "Error fnetfilter: $ARG%d on line %d was not defined\n", index, line); | ||
140 | exit(1); | ||
141 | } | ||
142 | fprintf(fp2, "%s", args[index - 1]); | ||
143 | |||
144 | // march to the end of argument | ||
145 | ptr += 4; | ||
146 | while (isdigit(*ptr)) | ||
147 | ptr++; | ||
148 | ptr--; | ||
149 | } | ||
150 | ptr++; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | fclose(fp1); | ||
155 | fclose(fp2); | ||
156 | } | ||
157 | |||
49 | int main(int argc, char **argv) { | 158 | int main(int argc, char **argv) { |
50 | #if 0 | 159 | #if 0 |
51 | { | 160 | { |
@@ -61,7 +170,7 @@ printf("\n"); | |||
61 | if (quiet && strcmp(quiet, "yes") == 0) | 170 | if (quiet && strcmp(quiet, "yes") == 0) |
62 | arg_quiet = 1; | 171 | arg_quiet = 1; |
63 | 172 | ||
64 | if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { | 173 | if (argc > 1 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0)) { |
65 | usage(); | 174 | usage(); |
66 | return 0; | 175 | return 0; |
67 | } | 176 | } |
@@ -75,6 +184,12 @@ printf("\n"); | |||
75 | char *command = (argc == 3)? argv[1]: NULL; | 184 | char *command = (argc == 3)? argv[1]: NULL; |
76 | //printf("command %s\n", command); | 185 | //printf("command %s\n", command); |
77 | //printf("destfile %s\n", destfile); | 186 | //printf("destfile %s\n", destfile); |
187 | // destfile is a real filename | ||
188 | int len = strlen(destfile); | ||
189 | if (strcspn(destfile, "\\&!?\"'<>%^(){};,*[]") != (size_t)len) { | ||
190 | fprintf(stderr, "Error fnetfilter: invalid destination file in netfilter command\n"); | ||
191 | exit(1); | ||
192 | } | ||
78 | 193 | ||
79 | // handle default config (command = NULL, destfile) | 194 | // handle default config (command = NULL, destfile) |
80 | if (command == NULL) { | 195 | if (command == NULL) { |
@@ -88,28 +203,11 @@ printf("\n"); | |||
88 | fclose(fp); | 203 | fclose(fp); |
89 | } | 204 | } |
90 | else { | 205 | else { |
91 | // copy the file | 206 | if (strrchr(command, ',')) |
92 | FILE *fp1 = fopen(command, "r"); | 207 | process_template(command, destfile); |
93 | if (!fp1) { | 208 | else |
94 | fprintf(stderr, "Error fnetfilter: cannot open %s\n", command); | 209 | copy(command, destfile); |
95 | exit(1); | ||
96 | } | ||
97 | |||
98 | FILE *fp2 = fopen(destfile, "w"); | ||
99 | if (!fp2) { | ||
100 | fprintf(stderr, "Error fnetfilter: cannot open %s\n", destfile); | ||
101 | exit(1); | ||
102 | } | ||
103 | |||
104 | char buf[MAXBUF]; | ||
105 | while (fgets(buf, MAXBUF, fp1)) | ||
106 | fprintf(fp2, "%s", buf); | ||
107 | |||
108 | fclose(fp1); | ||
109 | fclose(fp2); | ||
110 | } | 210 | } |
111 | 211 | ||
112 | |||
113 | printf("fnetfilter running\n"); | ||
114 | return 0; | 212 | return 0; |
115 | } | 213 | } |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index bf27c07ad..d9000fd5e 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -937,13 +937,32 @@ is a desktop client firewall that disable access to local network. Example: | |||
937 | $ firejail --netfilter=/etc/firejail/nolocal.net \\ | 937 | $ firejail --netfilter=/etc/firejail/nolocal.net \\ |
938 | .br | 938 | .br |
939 | --net=eth0 firefox | 939 | --net=eth0 firefox |
940 | |||
941 | |||
942 | |||
943 | |||
944 | .TP | ||
945 | \fB\-\-netfilter=filename,arg1,arg2,arg3 ... | ||
946 | This is the template version of the previous command. $ARG1, $ARG2, $ARG3 ... in the firewall script | ||
947 | are replaced with arg1, arg2, arg3 ... passed on the command line. Up to 16 arguments are supported. | ||
948 | Example: | ||
949 | .br | ||
950 | |||
951 | .br | ||
952 | $ firejail --net=eth0 --ip=192.168.1.105 \\ | ||
953 | .br | ||
954 | --netfilter=/etc/firejail/tcpserver.net,5001 server-program | ||
955 | .br | ||
956 | |||
957 | |||
958 | |||
940 | .TP | 959 | .TP |
941 | \fB\-\-netfilter.print=name|pid | 960 | \fB\-\-netfilter.print=name|pid |
942 | Print the firewall installed in the sandbox specified by name or PID. Example: | 961 | Print the firewall installed in the sandbox specified by name or PID. Example: |
943 | .br | 962 | .br |
944 | 963 | ||
945 | .br | 964 | .br |
946 | $ firejail --net=browser --net=eth0 --netfilter firefox & | 965 | $ firejail --name=browser --net=eth0 --netfilter firefox & |
947 | .br | 966 | .br |
948 | $ firejail --netfilter.print=browser | 967 | $ firejail --netfilter.print=browser |
949 | 968 | ||
@@ -959,7 +978,7 @@ Print the IPv6 firewall installed in the sandbox specified by name or PID. Examp | |||
959 | .br | 978 | .br |
960 | 979 | ||
961 | .br | 980 | .br |
962 | $ firejail --net=browser --net=eth0 --netfilter firefox & | 981 | $ firejail --name=browser --net=eth0 --netfilter firefox & |
963 | .br | 982 | .br |
964 | $ firejail --netfilter6.print=browser | 983 | $ firejail --netfilter6.print=browser |
965 | 984 | ||