]> git.proxmox.com Git - mirror_iproute2.git/blob - misc/ssfilter.y
ss: fix NULL pointer access when parsing unix sockets with oldformat
[mirror_iproute2.git] / misc / ssfilter.y
1 %{
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <malloc.h>
6 #include <string.h>
7 #include "ssfilter.h"
8
9 typedef struct ssfilter * ssfilter_t;
10
11 #define YYSTYPE ssfilter_t
12
13 static struct ssfilter * alloc_node(int type, void *pred)
14 {
15 struct ssfilter *n = malloc(sizeof(*n));
16 if (n == NULL)
17 abort();
18 n->type = type;
19 n->pred = pred;
20 n->post = NULL;
21 return n;
22 }
23
24 static char **yy_argv;
25 static int yy_argc;
26 static FILE *yy_fp;
27 static ssfilter_t *yy_ret;
28 static int tok_type = -1;
29
30 static int yylex(void);
31
32 static void yyerror(char *s)
33 {
34 fprintf(stderr, "ss: bison bellows (while parsing filter): \"%s!\"", s);
35 }
36
37 %}
38
39 %token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND DEVCOND DEVNAME MARKMASK FWMARK
40 %left '|'
41 %left '&'
42 %nonassoc '!'
43
44 %%
45 applet: null expr
46 {
47 *yy_ret = $2;
48 $$ = $2;
49 }
50 | null
51 ;
52 null: /* NOTHING */ { $$ = NULL; }
53 ;
54 expr: DCOND HOSTCOND
55 {
56 $$ = alloc_node(SSF_DCOND, $2);
57 }
58 | SCOND HOSTCOND
59 {
60 $$ = alloc_node(SSF_SCOND, $2);
61 }
62 | DPORT GEQ HOSTCOND
63 {
64 $$ = alloc_node(SSF_D_GE, $3);
65 }
66 | DPORT LEQ HOSTCOND
67 {
68 $$ = alloc_node(SSF_D_LE, $3);
69 }
70 | DPORT '>' HOSTCOND
71 {
72 $$ = alloc_node(SSF_NOT, alloc_node(SSF_D_LE, $3));
73 }
74 | DPORT '<' HOSTCOND
75 {
76 $$ = alloc_node(SSF_NOT, alloc_node(SSF_D_GE, $3));
77 }
78 | DPORT '=' HOSTCOND
79 {
80 $$ = alloc_node(SSF_DCOND, $3);
81 }
82 | DPORT NEQ HOSTCOND
83 {
84 $$ = alloc_node(SSF_NOT, alloc_node(SSF_DCOND, $3));
85 }
86
87 | SPORT GEQ HOSTCOND
88 {
89 $$ = alloc_node(SSF_S_GE, $3);
90 }
91 | SPORT LEQ HOSTCOND
92 {
93 $$ = alloc_node(SSF_S_LE, $3);
94 }
95 | SPORT '>' HOSTCOND
96 {
97 $$ = alloc_node(SSF_NOT, alloc_node(SSF_S_LE, $3));
98 }
99 | SPORT '<' HOSTCOND
100 {
101 $$ = alloc_node(SSF_NOT, alloc_node(SSF_S_GE, $3));
102 }
103 | SPORT '=' HOSTCOND
104 {
105 $$ = alloc_node(SSF_SCOND, $3);
106 }
107 | SPORT NEQ HOSTCOND
108 {
109 $$ = alloc_node(SSF_NOT, alloc_node(SSF_SCOND, $3));
110 }
111 | DEVNAME '=' DEVCOND
112 {
113 $$ = alloc_node(SSF_DEVCOND, $3);
114 }
115 | DEVNAME NEQ DEVCOND
116 {
117 $$ = alloc_node(SSF_NOT, alloc_node(SSF_DEVCOND, $3));
118 }
119 | FWMARK '=' MARKMASK
120 {
121 $$ = alloc_node(SSF_MARKMASK, $3);
122 }
123 | FWMARK NEQ MARKMASK
124 {
125 $$ = alloc_node(SSF_NOT, alloc_node(SSF_MARKMASK, $3));
126 }
127 | AUTOBOUND
128 {
129 $$ = alloc_node(SSF_S_AUTO, NULL);
130 }
131 | expr '|' expr
132 {
133 $$ = alloc_node(SSF_OR, $1);
134 $$->post = $3;
135 }
136 | expr expr
137 {
138 $$ = alloc_node(SSF_AND, $1);
139 $$->post = $2;
140 }
141 | expr '&' expr
142
143 {
144 $$ = alloc_node(SSF_AND, $1);
145 $$->post = $3;
146 }
147 | '!' expr
148 {
149 $$ = alloc_node(SSF_NOT, $2);
150 }
151 | '(' expr ')'
152 {
153 $$ = $2;
154 }
155 ;
156 %%
157
158 static char *get_token_from_line(char **ptr)
159 {
160 char *tok, *cp = *ptr;
161
162 while (*cp == ' ' || *cp == '\t') cp++;
163
164 if (*cp == 0) {
165 *ptr = cp;
166 return NULL;
167 }
168
169 tok = cp;
170
171 while (*cp != 0 && *cp != ' ' && *cp != '\t') {
172 /* Backslash escapes everything. */
173 if (*cp == '\\') {
174 char *tp;
175 for (tp = cp; tp != tok; tp--)
176 *tp = *(tp-1);
177 cp++;
178 tok++;
179 if (*cp == 0)
180 break;
181 }
182 cp++;
183 }
184 if (*cp)
185 *cp++ = 0;
186 *ptr = cp;
187 return tok;
188 }
189
190 int yylex(void)
191 {
192 static char argbuf[1024];
193 static char *tokptr = argbuf;
194 static int argc;
195 char *curtok;
196
197 do {
198 while (*tokptr == 0) {
199 tokptr = NULL;
200 if (argc < yy_argc) {
201 tokptr = yy_argv[argc];
202 argc++;
203 } else if (yy_fp) {
204 while (tokptr == NULL) {
205 size_t len;
206
207 if (fgets(argbuf, sizeof(argbuf), yy_fp) == NULL)
208 return 0;
209
210 len = strnlen(argbuf, sizeof(argbuf));
211 if (len == 0) {
212 fprintf(stderr, "Invalid line\n");
213 exit(-1);
214 }
215
216 if (len >= sizeof(argbuf) - 1) {
217 fprintf(stderr, "Too long line in filter\n");
218 exit(-1);
219 }
220 if (argbuf[len - 1] == '\n')
221 argbuf[len-1] = 0;
222 if (argbuf[0] == '#' || argbuf[0] == '0')
223 continue;
224 tokptr = argbuf;
225 }
226 } else {
227 return 0;
228 }
229 }
230 } while ((curtok = get_token_from_line(&tokptr)) == NULL);
231
232 if (strcmp(curtok, "!") == 0 ||
233 strcmp(curtok, "not") == 0)
234 return '!';
235 if (strcmp(curtok, "&") == 0 ||
236 strcmp(curtok, "&&") == 0 ||
237 strcmp(curtok, "and") == 0)
238 return '&';
239 if (strcmp(curtok, "|") == 0 ||
240 strcmp(curtok, "||") == 0 ||
241 strcmp(curtok, "or") == 0)
242 return '|';
243 if (strcmp(curtok, "(") == 0)
244 return '(';
245 if (strcmp(curtok, ")") == 0)
246 return ')';
247 if (strcmp(curtok, "dst") == 0) {
248 tok_type = DCOND;
249 return DCOND;
250 }
251 if (strcmp(curtok, "src") == 0) {
252 tok_type = SCOND;
253 return SCOND;
254 }
255 if (strcmp(curtok, "dport") == 0) {
256 tok_type = DPORT;
257 return DPORT;
258 }
259 if (strcmp(curtok, "sport") == 0) {
260 tok_type = SPORT;
261 return SPORT;
262 }
263 if (strcmp(curtok, "dev") == 0) {
264 tok_type = DEVNAME;
265 return DEVNAME;
266 }
267 if (strcmp(curtok, "fwmark") == 0) {
268 tok_type = FWMARK;
269 return FWMARK;
270 }
271 if (strcmp(curtok, ">=") == 0 ||
272 strcmp(curtok, "ge") == 0 ||
273 strcmp(curtok, "geq") == 0)
274 return GEQ;
275 if (strcmp(curtok, "<=") == 0 ||
276 strcmp(curtok, "le") == 0 ||
277 strcmp(curtok, "leq") == 0)
278 return LEQ;
279 if (strcmp(curtok, "!=") == 0 ||
280 strcmp(curtok, "ne") == 0 ||
281 strcmp(curtok, "neq") == 0)
282 return NEQ;
283 if (strcmp(curtok, "=") == 0 ||
284 strcmp(curtok, "==") == 0 ||
285 strcmp(curtok, "eq") == 0)
286 return '=';
287 if (strcmp(curtok, ">") == 0 ||
288 strcmp(curtok, "gt") == 0)
289 return '>';
290 if (strcmp(curtok, "<") == 0 ||
291 strcmp(curtok, "lt") == 0)
292 return '<';
293 if (strcmp(curtok, "autobound") == 0) {
294 tok_type = AUTOBOUND;
295 return AUTOBOUND;
296 }
297 if (tok_type == DEVNAME) {
298 yylval = (void*)parse_devcond(curtok);
299 if (yylval == NULL) {
300 fprintf(stderr, "Cannot parse device.\n");
301 exit(1);
302 }
303 return DEVCOND;
304 }
305 if (tok_type == FWMARK) {
306 yylval = (void*)parse_markmask(curtok);
307 if (yylval == NULL) {
308 fprintf(stderr, "Cannot parse mark %s.\n", curtok);
309 exit(1);
310 }
311 return MARKMASK;
312 }
313 yylval = (void*)parse_hostcond(curtok, tok_type == SPORT || tok_type == DPORT);
314 if (yylval == NULL) {
315 fprintf(stderr, "Cannot parse dst/src address.\n");
316 exit(1);
317 }
318 return HOSTCOND;
319 }
320
321 int ssfilter_parse(struct ssfilter **f, int argc, char **argv, FILE *fp)
322 {
323 yy_argc = argc;
324 yy_argv = argv;
325 yy_fp = fp;
326 yy_ret = f;
327
328 if (yyparse()) {
329 fprintf(stderr, " Sorry.\n");
330 return -1;
331 }
332 return 0;
333 }