xref: /freebsd/tests/sys/netpfil/pf/ioctl/validation.c (revision cc426dd31990b8b50b210efc450e404596548ca1)
1 /*-
2  * Copyright (c) 2018	Kristof Provost <kp@FreeBSD.org>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27 
28 #include <sys/param.h>
29 #include <sys/module.h>
30 #include <sys/types.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 
34 #include <net/if.h>
35 #include <net/pfvar.h>
36 
37 #include <fcntl.h>
38 #include <stdio.h>
39 
40 #include <atf-c.h>
41 
42 static int dev;
43 
44 #define COMMON_HEAD() \
45 	if (modfind("pf") == -1) \
46 		atf_tc_skip("pf not loaded"); \
47 	dev = open("/dev/pf", O_RDWR); \
48 	if (dev == -1) \
49 		atf_tc_skip("Failed to open /dev/pf");
50 
51 #define COMMON_CLEANUP() \
52 	close(dev);
53 
54 void
55 common_init_tbl(struct pfr_table *tbl)
56 {
57 	bzero(tbl, sizeof(struct pfr_table));
58 	strcpy(tbl->pfrt_anchor, "anchor");
59 	strcpy(tbl->pfrt_name, "name");
60 	tbl->pfrt_flags = 0;
61 	tbl->pfrt_fback = 0;
62 }
63 
64 ATF_TC_WITHOUT_HEAD(addtables);
65 ATF_TC_BODY(addtables, tc)
66 {
67 	struct pfioc_table io;
68 	struct pfr_table tbl;
69 	struct pfr_table tbls[4];
70 	int flags;
71 
72 	COMMON_HEAD();
73 
74 	flags = 0;
75 
76 	bzero(&io, sizeof(io));
77 	io.pfrio_flags = flags;
78 	io.pfrio_buffer = &tbl;
79 	io.pfrio_esize = sizeof(tbl);
80 
81 	/* Negative size */
82 	io.pfrio_size = -1;
83 	if (ioctl(dev, DIOCRADDTABLES, &io) == 0)
84 		atf_tc_fail("Request with size -1 succeeded");
85 
86 	/* Overly large size */
87 	io.pfrio_size = 1 << 24;
88 	if (ioctl(dev, DIOCRADDTABLES, &io) == 0)
89 		atf_tc_fail("Request with size 1 << 24 succeeded");
90 
91 	/* NULL buffer */
92 	io.pfrio_size = 1;
93 	io.pfrio_buffer = NULL;
94 	if (ioctl(dev, DIOCRADDTABLES, &io) == 0)
95 		atf_tc_fail("Request with NULL buffer succeeded");
96 
97 	/* This can provoke a memory leak, see r331225. */
98 	io.pfrio_size = 4;
99 	for (int i = 0; i < io.pfrio_size; i++)
100 		common_init_tbl(&tbls[i]);
101 
102 	io.pfrio_buffer = &tbls;
103 	ioctl(dev, DIOCRADDTABLES, &io);
104 
105 	COMMON_CLEANUP();
106 }
107 
108 ATF_TC_WITHOUT_HEAD(deltables);
109 ATF_TC_BODY(deltables, tc)
110 {
111 	struct pfioc_table io;
112 	struct pfr_table tbl;
113 	int flags;
114 
115 	COMMON_HEAD();
116 
117 	flags = 0;
118 
119 	bzero(&io, sizeof(io));
120 	io.pfrio_flags = flags;
121 	io.pfrio_buffer = &tbl;
122 	io.pfrio_esize = sizeof(tbl);
123 
124 	/* Negative size */
125 	io.pfrio_size = -1;
126 	if (ioctl(dev, DIOCRDELTABLES, &io) == 0)
127 		atf_tc_fail("Request with size -1 succeeded");
128 
129 	/* Overly large size */
130 	io.pfrio_size = 1 << 24;
131 	if (ioctl(dev, DIOCRDELTABLES, &io) == 0)
132 		atf_tc_fail("Request with size 1 << 24 succeeded");
133 
134 	/* NULL buffer */
135 	io.pfrio_size = 1;
136 	io.pfrio_buffer = NULL;
137 	if (ioctl(dev, DIOCRDELTABLES, &io) == 0)
138 		atf_tc_fail("Request with NULL buffer succeeded");
139 
140 	COMMON_CLEANUP();
141 }
142 
143 ATF_TC_WITHOUT_HEAD(gettables);
144 ATF_TC_BODY(gettables, tc)
145 {
146 	struct pfioc_table io;
147 	struct pfr_table tbl;
148 	int flags;
149 
150 	COMMON_HEAD();
151 
152 	flags = 0;
153 
154 	bzero(&io, sizeof(io));
155 	io.pfrio_flags = flags;
156 	io.pfrio_buffer = &tbl;
157 	io.pfrio_esize = sizeof(tbl);
158 
159 	/* Negative size. This will succeed, because the kernel will not copy
160 	 * tables than it has. */
161 	io.pfrio_size = -1;
162 	if (ioctl(dev, DIOCRGETTABLES, &io) != 0)
163 		atf_tc_fail("Request with size -1 failed");
164 
165 	/* Overly large size. See above. */
166 	io.pfrio_size = 1 << 24;
167 	if (ioctl(dev, DIOCRGETTABLES, &io) != 0)
168 		atf_tc_fail("Request with size 1 << 24 failed");
169 
170 	COMMON_CLEANUP();
171 }
172 
173 ATF_TC_WITHOUT_HEAD(gettstats);
174 ATF_TC_BODY(gettstats, tc)
175 {
176 	struct pfioc_table io;
177 	struct pfr_tstats stats;
178 	int flags;
179 
180 	COMMON_HEAD();
181 
182 	flags = 0;
183 
184 	bzero(&io, sizeof(io));
185 	io.pfrio_flags = flags;
186 	io.pfrio_buffer = &stats;
187 	io.pfrio_esize = sizeof(stats);
188 
189 	/* Negative size. This will succeed, because the kernel will not copy
190 	 * tables than it has. */
191 	io.pfrio_size = -1;
192 	if (ioctl(dev, DIOCRGETTSTATS, &io) != 0)
193 		atf_tc_fail("Request with size -1 failed");
194 
195 	/* Overly large size. See above. */
196 	io.pfrio_size = 1 << 24;
197 	if (ioctl(dev, DIOCRGETTSTATS, &io) != 0)
198 		atf_tc_fail("Request with size 1 << 24 failed");
199 
200 	COMMON_CLEANUP();
201 }
202 
203 ATF_TC_WITHOUT_HEAD(clrtstats);
204 ATF_TC_BODY(clrtstats, tc)
205 {
206 	struct pfioc_table io;
207 	struct pfr_table tbl;
208 	int flags;
209 
210 	COMMON_HEAD();
211 
212 	flags = 0;
213 
214 	common_init_tbl(&tbl);
215 
216 	bzero(&io, sizeof(io));
217 	io.pfrio_flags = flags;
218 	io.pfrio_buffer = &tbl;
219 	io.pfrio_esize = sizeof(tbl);
220 
221 	/* Negative size. This will succeed, because the kernel will not copy
222 	 * tables than it has. */
223 	io.pfrio_size = -1;
224 	if (ioctl(dev, DIOCRCLRTSTATS, &io) != 0)
225 		atf_tc_fail("Request with size -1 failed ");
226 
227 	/* Overly large size. See above. */
228 	io.pfrio_size = 1 << 24;
229 	if (ioctl(dev, DIOCRCLRTSTATS, &io) != 0)
230 		atf_tc_fail("Request with size 1 << 24 failed");
231 
232 	COMMON_CLEANUP();
233 }
234 
235 ATF_TC_WITHOUT_HEAD(settflags);
236 ATF_TC_BODY(settflags, tc)
237 {
238 	struct pfioc_table io;
239 	struct pfr_table tbl;
240 	int flags;
241 
242 	COMMON_HEAD();
243 
244 	flags = 0;
245 
246 	common_init_tbl(&tbl);
247 
248 	bzero(&io, sizeof(io));
249 	io.pfrio_flags = flags;
250 	io.pfrio_buffer = &tbl;
251 	io.pfrio_esize = sizeof(tbl);
252 
253 	/* Negative size. This will succeed, because the kernel will not copy
254 	 * tables than it has. */
255 	io.pfrio_size = -1;
256 	if (ioctl(dev, DIOCRSETTFLAGS, &io) != 0)
257 		atf_tc_fail("Request with size -1 failed");
258 
259 	/* Overly large size. See above. */
260 	io.pfrio_size = 1 << 28;
261 	if (ioctl(dev, DIOCRSETTFLAGS, &io) != 0)
262 		atf_tc_fail("Request with size 1 << 24 failed");
263 
264 	COMMON_CLEANUP();
265 }
266 
267 ATF_TC_WITHOUT_HEAD(addaddrs);
268 ATF_TC_BODY(addaddrs, tc)
269 {
270 	struct pfioc_table io;
271 	struct pfr_addr addr;
272 
273 	COMMON_HEAD();
274 
275 	bzero(&addr, sizeof(addr));
276 	bzero(&io, sizeof(io));
277 	io.pfrio_flags = 0;
278 	io.pfrio_buffer = &addr;
279 	io.pfrio_esize = sizeof(addr);
280 
281 	/* Negative size. */
282 	io.pfrio_size = -1;
283 	if (ioctl(dev, DIOCRADDADDRS, &io) == 0)
284 		atf_tc_fail("Request with size -1 succeeded");
285 
286 	/* Overly large size. */
287 	io.pfrio_size = 1 << 28;
288 	if (ioctl(dev, DIOCRADDADDRS, &io) == 0)
289 		atf_tc_fail("Reuqest with size 1 << 28 failed");
290 
291 	COMMON_CLEANUP();
292 }
293 
294 ATF_TC_WITHOUT_HEAD(deladdrs);
295 ATF_TC_BODY(deladdrs, tc)
296 {
297 	struct pfioc_table io;
298 	struct pfr_addr addr;
299 
300 	COMMON_HEAD();
301 
302 	bzero(&addr, sizeof(addr));
303 	bzero(&io, sizeof(io));
304 	io.pfrio_flags = 0;
305 	io.pfrio_buffer = &addr;
306 	io.pfrio_esize = sizeof(addr);
307 
308 	/* Negative size. */
309 	io.pfrio_size = -1;
310 	if (ioctl(dev, DIOCRDELADDRS, &io) == 0)
311 		atf_tc_fail("Request with size -1 succeeded");
312 
313 	/* Overly large size. */
314 	io.pfrio_size = 1 << 28;
315 	if (ioctl(dev, DIOCRDELADDRS, &io) == 0)
316 		atf_tc_fail("Reuqest with size 1 << 28 failed");
317 
318 	COMMON_CLEANUP();
319 }
320 
321 ATF_TC_WITHOUT_HEAD(setaddrs);
322 ATF_TC_BODY(setaddrs, tc)
323 {
324 	struct pfioc_table io;
325 	struct pfr_addr addr;
326 
327 	COMMON_HEAD();
328 
329 	bzero(&addr, sizeof(addr));
330 	bzero(&io, sizeof(io));
331 	io.pfrio_flags = 0;
332 	io.pfrio_buffer = &addr;
333 	io.pfrio_esize = sizeof(addr);
334 
335 	/* Negative size. */
336 	io.pfrio_size = -1;
337 	if (ioctl(dev, DIOCRSETADDRS, &io) == 0)
338 		atf_tc_fail("Request with size -1 succeeded");
339 
340 	/* Overly large size. */
341 	io.pfrio_size = 1 << 28;
342 	if (ioctl(dev, DIOCRSETADDRS, &io) == 0)
343 		atf_tc_fail("Reuqest with size 1 << 28 failed");
344 
345 	COMMON_CLEANUP();
346 }
347 
348 ATF_TC_WITHOUT_HEAD(getaddrs);
349 ATF_TC_BODY(getaddrs, tc)
350 {
351 	struct pfioc_table io;
352 	struct pfr_addr addr;
353 
354 	COMMON_HEAD();
355 
356 	bzero(&addr, sizeof(addr));
357 	bzero(&io, sizeof(io));
358 	io.pfrio_flags = 0;
359 	io.pfrio_buffer = &addr;
360 	io.pfrio_esize = sizeof(addr);
361 
362 	common_init_tbl(&io.pfrio_table);
363 
364 	/* Negative size. */
365 	io.pfrio_size = -1;
366 	if (ioctl(dev, DIOCRGETADDRS, &io) == 0)
367 		atf_tc_fail("Request with size -1 succeeded");
368 
369 	/* Overly large size. */
370 	io.pfrio_size = 1 << 24;
371 	if (ioctl(dev, DIOCRGETADDRS, &io) == 0)
372 		atf_tc_fail("Request with size 1 << 24 failed");
373 
374 	COMMON_CLEANUP();
375 }
376 
377 ATF_TC_WITHOUT_HEAD(getastats);
378 ATF_TC_BODY(getastats, tc)
379 {
380 	struct pfioc_table io;
381 	struct pfr_astats astats;
382 
383 	COMMON_HEAD();
384 
385 	bzero(&astats, sizeof(astats));
386 	bzero(&io, sizeof(io));
387 	io.pfrio_flags = 0;
388 	io.pfrio_buffer = &astats;
389 	io.pfrio_esize = sizeof(astats);
390 
391 	common_init_tbl(&io.pfrio_table);
392 
393 	/* Negative size. */
394 	io.pfrio_size = -1;
395 	if (ioctl(dev, DIOCRGETASTATS, &io) == 0)
396 		atf_tc_fail("Request with size -1 succeeded");
397 
398 	/* Overly large size. */
399 	io.pfrio_size = 1 << 24;
400 	if (ioctl(dev, DIOCRGETASTATS, &io) == 0)
401 		atf_tc_fail("Request with size 1 << 24 failed");
402 
403 	COMMON_CLEANUP();
404 }
405 
406 ATF_TC_WITHOUT_HEAD(clrastats);
407 ATF_TC_BODY(clrastats, tc)
408 {
409 	struct pfioc_table io;
410 	struct pfr_addr addr;
411 
412 	COMMON_HEAD();
413 
414 	bzero(&addr, sizeof(addr));
415 	bzero(&io, sizeof(io));
416 	io.pfrio_flags = 0;
417 	io.pfrio_buffer = &addr;
418 	io.pfrio_esize = sizeof(addr);
419 
420 	common_init_tbl(&io.pfrio_table);
421 
422 	/* Negative size. */
423 	io.pfrio_size = -1;
424 	if (ioctl(dev, DIOCRCLRASTATS, &io) == 0)
425 		atf_tc_fail("Request with size -1 succeeded");
426 
427 	/* Overly large size. */
428 	io.pfrio_size = 1 << 24;
429 	if (ioctl(dev, DIOCRCLRASTATS, &io) == 0)
430 		atf_tc_fail("Request with size 1 << 24 failed");
431 
432 	COMMON_CLEANUP();
433 }
434 
435 ATF_TC_WITHOUT_HEAD(tstaddrs);
436 ATF_TC_BODY(tstaddrs, tc)
437 {
438 	struct pfioc_table io;
439 	struct pfr_addr addr;
440 
441 	COMMON_HEAD();
442 
443 	bzero(&addr, sizeof(addr));
444 	bzero(&io, sizeof(io));
445 	io.pfrio_flags = 0;
446 	io.pfrio_buffer = &addr;
447 	io.pfrio_esize = sizeof(addr);
448 
449 	common_init_tbl(&io.pfrio_table);
450 
451 	/* Negative size. */
452 	io.pfrio_size = -1;
453 	if (ioctl(dev, DIOCRTSTADDRS, &io) == 0)
454 		atf_tc_fail("Request with size -1 succeeded");
455 
456 	/* Overly large size. */
457 	io.pfrio_size = 1 << 24;
458 	if (ioctl(dev, DIOCRTSTADDRS, &io) == 0)
459 		atf_tc_fail("Request with size 1 << 24 failed");
460 
461 	COMMON_CLEANUP();
462 }
463 
464 ATF_TC_WITHOUT_HEAD(inadefine);
465 ATF_TC_BODY(inadefine, tc)
466 {
467 	struct pfioc_table io;
468 	struct pfr_addr addr;
469 
470 	COMMON_HEAD();
471 
472 	bzero(&addr, sizeof(addr));
473 	bzero(&io, sizeof(io));
474 	io.pfrio_flags = 0;
475 	io.pfrio_buffer = &addr;
476 	io.pfrio_esize = sizeof(addr);
477 
478 	common_init_tbl(&io.pfrio_table);
479 
480 	/* Negative size. */
481 	io.pfrio_size = -1;
482 	if (ioctl(dev, DIOCRINADEFINE, &io) == 0)
483 		atf_tc_fail("Request with size -1 succeeded");
484 
485 	/* Overly large size. */
486 	io.pfrio_size = 1 << 24;
487 	if (ioctl(dev, DIOCRINADEFINE, &io) == 0)
488 		atf_tc_fail("Request with size 1 << 24 failed");
489 
490 	COMMON_CLEANUP();
491 }
492 
493 ATF_TC_WITHOUT_HEAD(igetifaces);
494 ATF_TC_BODY(igetifaces, tc)
495 {
496 	struct pfioc_iface io;
497 	struct pfi_kif kif;
498 
499 	COMMON_HEAD();
500 
501 	bzero(&io, sizeof(io));
502 	io.pfiio_flags = 0;
503 	io.pfiio_buffer = &kif;
504 	io.pfiio_esize = sizeof(kif);
505 
506 	/* Negative size */
507 	io.pfiio_size = -1;
508 	if (ioctl(dev, DIOCIGETIFACES, &io) == 0)
509 		atf_tc_fail("request with size -1 succeeded");
510 
511 	/* Overflow size */
512 	io.pfiio_size = 1 << 31;
513 	if (ioctl(dev, DIOCIGETIFACES, &io) == 0)
514 		atf_tc_fail("request with size 1 << 31 succeeded");
515 
516 	COMMON_CLEANUP();
517 }
518 
519 ATF_TC_WITHOUT_HEAD(cxbegin);
520 ATF_TC_BODY(cxbegin, tc)
521 {
522 	struct pfioc_trans io;
523 	struct pfioc_trans_e ioe;
524 
525 	COMMON_HEAD();
526 
527 	bzero(&io, sizeof(io));
528 	io.esize = sizeof(ioe);
529 	io.array = &ioe;
530 
531 	/* Negative size */
532 	io.size = -1;
533 	if (ioctl(dev, DIOCXBEGIN, &io) == 0)
534 		atf_tc_fail("request with size -1 succeeded");
535 
536 	/* Overflow size */
537 	io.size = 1 << 30;
538 	if (ioctl(dev, DIOCXBEGIN, &io) == 0)
539 		atf_tc_fail("request with size 1 << 30 succeeded");
540 
541 	/* NULL buffer */
542 	io.size = 1;
543 	io.array = NULL;
544 	if (ioctl(dev, DIOCXBEGIN, &io) == 0)
545 		atf_tc_fail("request with size -1 succeeded");
546 
547 	COMMON_CLEANUP();
548 }
549 
550 ATF_TC_WITHOUT_HEAD(cxrollback);
551 ATF_TC_BODY(cxrollback, tc)
552 {
553 	struct pfioc_trans io;
554 	struct pfioc_trans_e ioe;
555 
556 	COMMON_HEAD();
557 
558 	bzero(&io, sizeof(io));
559 	io.esize = sizeof(ioe);
560 	io.array = &ioe;
561 
562 	/* Negative size */
563 	io.size = -1;
564 	if (ioctl(dev, DIOCXROLLBACK, &io) == 0)
565 		atf_tc_fail("request with size -1 succeeded");
566 
567 	/* Overflow size */
568 	io.size = 1 << 30;
569 	if (ioctl(dev, DIOCXROLLBACK, &io) == 0)
570 		atf_tc_fail("request with size 1 << 30 succeeded");
571 
572 	/* NULL buffer */
573 	io.size = 1;
574 	io.array = NULL;
575 	if (ioctl(dev, DIOCXROLLBACK, &io) == 0)
576 		atf_tc_fail("request with size -1 succeeded");
577 
578 	COMMON_CLEANUP();
579 }
580 
581 ATF_TC_WITHOUT_HEAD(commit);
582 ATF_TC_BODY(commit, tc)
583 {
584 	struct pfioc_trans io;
585 	struct pfioc_trans_e ioe;
586 
587 	COMMON_HEAD();
588 
589 	bzero(&io, sizeof(io));
590 	io.esize = sizeof(ioe);
591 	io.array = &ioe;
592 
593 	/* Negative size */
594 	io.size = -1;
595 	if (ioctl(dev, DIOCXCOMMIT, &io) == 0)
596 		atf_tc_fail("request with size -1 succeeded");
597 
598 	/* Overflow size */
599 	io.size = 1 << 30;
600 	if (ioctl(dev, DIOCXCOMMIT, &io) == 0)
601 		atf_tc_fail("request with size 1 << 30 succeeded");
602 
603 	/* NULL buffer */
604 	io.size = 1;
605 	io.array = NULL;
606 	if (ioctl(dev, DIOCXCOMMIT, &io) == 0)
607 		atf_tc_fail("request with size -1 succeeded");
608 
609 	COMMON_CLEANUP();
610 }
611 
612 ATF_TP_ADD_TCS(tp)
613 {
614 	ATF_TP_ADD_TC(tp, addtables);
615 	ATF_TP_ADD_TC(tp, deltables);
616 	ATF_TP_ADD_TC(tp, gettables);
617 	ATF_TP_ADD_TC(tp, gettstats);
618 	ATF_TP_ADD_TC(tp, clrtstats);
619 	ATF_TP_ADD_TC(tp, settflags);
620 	ATF_TP_ADD_TC(tp, addaddrs);
621 	ATF_TP_ADD_TC(tp, deladdrs);
622 	ATF_TP_ADD_TC(tp, setaddrs);
623 	ATF_TP_ADD_TC(tp, getaddrs);
624 	ATF_TP_ADD_TC(tp, clrastats);
625 	ATF_TP_ADD_TC(tp, tstaddrs);
626 	ATF_TP_ADD_TC(tp, inadefine);
627 	ATF_TP_ADD_TC(tp, igetifaces);
628 	ATF_TP_ADD_TC(tp, cxbegin);
629 	ATF_TP_ADD_TC(tp, cxrollback);
630 	ATF_TP_ADD_TC(tp, commit);
631 
632 	return (atf_no_error());
633 }
634