xref: /freebsd/tests/sys/netpfil/pf/ioctl/validation.c (revision 1bb72c29435659dc4b24b2e0663cca1f53eb11df)
198c5f988SKristof Provost /*-
298c5f988SKristof Provost  * Copyright (c) 2018	Kristof Provost <kp@FreeBSD.org>
398c5f988SKristof Provost  *
498c5f988SKristof Provost  * Redistribution and use in source and binary forms, with or without
598c5f988SKristof Provost  * modification, are permitted provided that the following conditions
698c5f988SKristof Provost  * are met:
798c5f988SKristof Provost  * 1. Redistributions of source code must retain the above copyright
898c5f988SKristof Provost  *    notice, this list of conditions and the following disclaimer.
998c5f988SKristof Provost  * 2. Redistributions in binary form must reproduce the above copyright
1098c5f988SKristof Provost  *    notice, this list of conditions and the following disclaimer in the
1198c5f988SKristof Provost  *    documentation and/or other materials provided with the distribution.
1298c5f988SKristof Provost  *
1398c5f988SKristof Provost  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1498c5f988SKristof Provost  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1598c5f988SKristof Provost  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1698c5f988SKristof Provost  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1798c5f988SKristof Provost  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1898c5f988SKristof Provost  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1998c5f988SKristof Provost  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2098c5f988SKristof Provost  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2198c5f988SKristof Provost  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2298c5f988SKristof Provost  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2398c5f988SKristof Provost  * SUCH DAMAGE.
2498c5f988SKristof Provost  *
2598c5f988SKristof Provost  * $FreeBSD$
2698c5f988SKristof Provost  */
2798c5f988SKristof Provost 
2898c5f988SKristof Provost #include <sys/param.h>
2998c5f988SKristof Provost #include <sys/module.h>
3098c5f988SKristof Provost #include <sys/types.h>
3198c5f988SKristof Provost #include <sys/ioctl.h>
3298c5f988SKristof Provost #include <sys/socket.h>
3398c5f988SKristof Provost 
3498c5f988SKristof Provost #include <net/if.h>
3598c5f988SKristof Provost #include <net/pfvar.h>
3698c5f988SKristof Provost 
3798c5f988SKristof Provost #include <fcntl.h>
3898c5f988SKristof Provost #include <stdio.h>
3998c5f988SKristof Provost 
4098c5f988SKristof Provost #include <atf-c.h>
4198c5f988SKristof Provost 
4298c5f988SKristof Provost static int dev;
4398c5f988SKristof Provost 
4498c5f988SKristof Provost #define COMMON_HEAD() \
4598c5f988SKristof Provost 	if (modfind("pf") == -1) \
4698c5f988SKristof Provost 		atf_tc_skip("pf not loaded"); \
4798c5f988SKristof Provost 	dev = open("/dev/pf", O_RDWR); \
4898c5f988SKristof Provost 	if (dev == -1) \
4998c5f988SKristof Provost 		atf_tc_skip("Failed to open /dev/pf");
5098c5f988SKristof Provost 
5198c5f988SKristof Provost #define COMMON_CLEANUP() \
5298c5f988SKristof Provost 	close(dev);
5398c5f988SKristof Provost 
541ff545d6SKristof Provost void
551ff545d6SKristof Provost common_init_tbl(struct pfr_table *tbl)
561ff545d6SKristof Provost {
571ff545d6SKristof Provost 	bzero(tbl, sizeof(struct pfr_table));
581ff545d6SKristof Provost 	strcpy(tbl->pfrt_anchor, "anchor");
591ff545d6SKristof Provost 	strcpy(tbl->pfrt_name, "name");
601ff545d6SKristof Provost 	tbl->pfrt_flags = 0;
611ff545d6SKristof Provost 	tbl->pfrt_fback = 0;
621ff545d6SKristof Provost }
631ff545d6SKristof Provost 
6498c5f988SKristof Provost ATF_TC_WITHOUT_HEAD(addtables);
6598c5f988SKristof Provost ATF_TC_BODY(addtables, tc)
6698c5f988SKristof Provost {
6798c5f988SKristof Provost 	struct pfioc_table io;
6898c5f988SKristof Provost 	struct pfr_table tbl;
69*1bb72c29SKristof Provost 	struct pfr_table tbls[4];
7098c5f988SKristof Provost 	int flags;
7198c5f988SKristof Provost 
7298c5f988SKristof Provost 	COMMON_HEAD();
7398c5f988SKristof Provost 
7498c5f988SKristof Provost 	flags = 0;
7598c5f988SKristof Provost 
7698c5f988SKristof Provost 	bzero(&io, sizeof(io));
7798c5f988SKristof Provost 	io.pfrio_flags = flags;
7898c5f988SKristof Provost 	io.pfrio_buffer = &tbl;
7998c5f988SKristof Provost 	io.pfrio_esize = sizeof(tbl);
8098c5f988SKristof Provost 
8198c5f988SKristof Provost 	/* Negative size */
8298c5f988SKristof Provost 	io.pfrio_size = -1;
8398c5f988SKristof Provost 	if (ioctl(dev, DIOCRADDTABLES, &io) == 0)
8498c5f988SKristof Provost 		atf_tc_fail("Request with size -1 succeeded");
8598c5f988SKristof Provost 
8698c5f988SKristof Provost 	/* Overly large size */
8798c5f988SKristof Provost 	io.pfrio_size = 1 << 24;
8898c5f988SKristof Provost 	if (ioctl(dev, DIOCRADDTABLES, &io) == 0)
8998c5f988SKristof Provost 		atf_tc_fail("Request with size 1 << 24 succeeded");
9098c5f988SKristof Provost 
9198c5f988SKristof Provost 	/* NULL buffer */
9298c5f988SKristof Provost 	io.pfrio_size = 1;
9398c5f988SKristof Provost 	io.pfrio_buffer = NULL;
9498c5f988SKristof Provost 	if (ioctl(dev, DIOCRADDTABLES, &io) == 0)
9598c5f988SKristof Provost 		atf_tc_fail("Request with NULL buffer succeeded");
9698c5f988SKristof Provost 
97*1bb72c29SKristof Provost 	/* This can provoke a memory leak, see r331225. */
98*1bb72c29SKristof Provost 	io.pfrio_size = 4;
99*1bb72c29SKristof Provost 	for (int i = 0; i < io.pfrio_size; i++)
100*1bb72c29SKristof Provost 		common_init_tbl(&tbls[i]);
101*1bb72c29SKristof Provost 
102*1bb72c29SKristof Provost 	io.pfrio_buffer = &tbls;
103*1bb72c29SKristof Provost 	ioctl(dev, DIOCRADDTABLES, &io);
104*1bb72c29SKristof Provost 
10598c5f988SKristof Provost 	COMMON_CLEANUP();
10698c5f988SKristof Provost }
10798c5f988SKristof Provost 
10898c5f988SKristof Provost ATF_TC_WITHOUT_HEAD(deltables);
10998c5f988SKristof Provost ATF_TC_BODY(deltables, tc)
11098c5f988SKristof Provost {
11198c5f988SKristof Provost 	struct pfioc_table io;
11298c5f988SKristof Provost 	struct pfr_table tbl;
11398c5f988SKristof Provost 	int flags;
11498c5f988SKristof Provost 
11598c5f988SKristof Provost 	COMMON_HEAD();
11698c5f988SKristof Provost 
11798c5f988SKristof Provost 	flags = 0;
11898c5f988SKristof Provost 
11998c5f988SKristof Provost 	bzero(&io, sizeof(io));
12098c5f988SKristof Provost 	io.pfrio_flags = flags;
12198c5f988SKristof Provost 	io.pfrio_buffer = &tbl;
12298c5f988SKristof Provost 	io.pfrio_esize = sizeof(tbl);
12398c5f988SKristof Provost 
12498c5f988SKristof Provost 	/* Negative size */
12598c5f988SKristof Provost 	io.pfrio_size = -1;
12698c5f988SKristof Provost 	if (ioctl(dev, DIOCRDELTABLES, &io) == 0)
12798c5f988SKristof Provost 		atf_tc_fail("Request with size -1 succeeded");
12898c5f988SKristof Provost 
12998c5f988SKristof Provost 	/* Overly large size */
13098c5f988SKristof Provost 	io.pfrio_size = 1 << 24;
13198c5f988SKristof Provost 	if (ioctl(dev, DIOCRDELTABLES, &io) == 0)
13298c5f988SKristof Provost 		atf_tc_fail("Request with size 1 << 24 succeeded");
13398c5f988SKristof Provost 
13498c5f988SKristof Provost 	/* NULL buffer */
13598c5f988SKristof Provost 	io.pfrio_size = 1;
13698c5f988SKristof Provost 	io.pfrio_buffer = NULL;
13798c5f988SKristof Provost 	if (ioctl(dev, DIOCRDELTABLES, &io) == 0)
13898c5f988SKristof Provost 		atf_tc_fail("Request with NULL buffer succeeded");
13998c5f988SKristof Provost 
14098c5f988SKristof Provost 	COMMON_CLEANUP();
14198c5f988SKristof Provost }
14298c5f988SKristof Provost 
1431ff545d6SKristof Provost ATF_TC_WITHOUT_HEAD(gettables);
1441ff545d6SKristof Provost ATF_TC_BODY(gettables, tc)
1451ff545d6SKristof Provost {
1461ff545d6SKristof Provost 	struct pfioc_table io;
1471ff545d6SKristof Provost 	struct pfr_table tbl;
1481ff545d6SKristof Provost 	int flags;
1491ff545d6SKristof Provost 
1501ff545d6SKristof Provost 	COMMON_HEAD();
1511ff545d6SKristof Provost 
1521ff545d6SKristof Provost 	flags = 0;
1531ff545d6SKristof Provost 
1541ff545d6SKristof Provost 	bzero(&io, sizeof(io));
1551ff545d6SKristof Provost 	io.pfrio_flags = flags;
1561ff545d6SKristof Provost 	io.pfrio_buffer = &tbl;
1571ff545d6SKristof Provost 	io.pfrio_esize = sizeof(tbl);
1581ff545d6SKristof Provost 
1591ff545d6SKristof Provost 	/* Negative size. This will succeed, because the kernel will not copy
1601ff545d6SKristof Provost 	 * tables than it has. */
1611ff545d6SKristof Provost 	io.pfrio_size = -1;
1621ff545d6SKristof Provost 	if (ioctl(dev, DIOCRGETTABLES, &io) != 0)
1631ff545d6SKristof Provost 		atf_tc_fail("Request with size -1 failed");
1641ff545d6SKristof Provost 
1651ff545d6SKristof Provost 	/* Overly large size. See above. */
1661ff545d6SKristof Provost 	io.pfrio_size = 1 << 24;
1671ff545d6SKristof Provost 	if (ioctl(dev, DIOCRGETTABLES, &io) != 0)
1681ff545d6SKristof Provost 		atf_tc_fail("Request with size 1 << 24 failed");
1691ff545d6SKristof Provost 
1701ff545d6SKristof Provost 	COMMON_CLEANUP();
1711ff545d6SKristof Provost }
1721ff545d6SKristof Provost 
1731ff545d6SKristof Provost ATF_TC_WITHOUT_HEAD(gettstats);
1741ff545d6SKristof Provost ATF_TC_BODY(gettstats, tc)
1751ff545d6SKristof Provost {
1761ff545d6SKristof Provost 	struct pfioc_table io;
1771ff545d6SKristof Provost 	struct pfr_tstats stats;
1781ff545d6SKristof Provost 	int flags;
1791ff545d6SKristof Provost 
1801ff545d6SKristof Provost 	COMMON_HEAD();
1811ff545d6SKristof Provost 
1821ff545d6SKristof Provost 	flags = 0;
1831ff545d6SKristof Provost 
1841ff545d6SKristof Provost 	bzero(&io, sizeof(io));
1851ff545d6SKristof Provost 	io.pfrio_flags = flags;
1861ff545d6SKristof Provost 	io.pfrio_buffer = &stats;
1871ff545d6SKristof Provost 	io.pfrio_esize = sizeof(stats);
1881ff545d6SKristof Provost 
1891ff545d6SKristof Provost 	/* Negative size. This will succeed, because the kernel will not copy
1901ff545d6SKristof Provost 	 * tables than it has. */
1911ff545d6SKristof Provost 	io.pfrio_size = -1;
1921ff545d6SKristof Provost 	if (ioctl(dev, DIOCRGETTSTATS, &io) != 0)
1931ff545d6SKristof Provost 		atf_tc_fail("Request with size -1 failed");
1941ff545d6SKristof Provost 
1951ff545d6SKristof Provost 	/* Overly large size. See above. */
1961ff545d6SKristof Provost 	io.pfrio_size = 1 << 24;
1971ff545d6SKristof Provost 	if (ioctl(dev, DIOCRGETTSTATS, &io) != 0)
1981ff545d6SKristof Provost 		atf_tc_fail("Request with size 1 << 24 failed");
1991ff545d6SKristof Provost 
2001ff545d6SKristof Provost 	COMMON_CLEANUP();
2011ff545d6SKristof Provost }
2021ff545d6SKristof Provost 
2031ff545d6SKristof Provost ATF_TC_WITHOUT_HEAD(clrtstats);
2041ff545d6SKristof Provost ATF_TC_BODY(clrtstats, tc)
2051ff545d6SKristof Provost {
2061ff545d6SKristof Provost 	struct pfioc_table io;
2071ff545d6SKristof Provost 	struct pfr_table tbl;
2081ff545d6SKristof Provost 	int flags;
2091ff545d6SKristof Provost 
2101ff545d6SKristof Provost 	COMMON_HEAD();
2111ff545d6SKristof Provost 
2121ff545d6SKristof Provost 	flags = 0;
2131ff545d6SKristof Provost 
2141ff545d6SKristof Provost 	common_init_tbl(&tbl);
2151ff545d6SKristof Provost 
2161ff545d6SKristof Provost 	bzero(&io, sizeof(io));
2171ff545d6SKristof Provost 	io.pfrio_flags = flags;
2181ff545d6SKristof Provost 	io.pfrio_buffer = &tbl;
2191ff545d6SKristof Provost 	io.pfrio_esize = sizeof(tbl);
2201ff545d6SKristof Provost 
2211ff545d6SKristof Provost 	/* Negative size. This will succeed, because the kernel will not copy
2221ff545d6SKristof Provost 	 * tables than it has. */
2231ff545d6SKristof Provost 	io.pfrio_size = -1;
2241ff545d6SKristof Provost 	if (ioctl(dev, DIOCRCLRTSTATS, &io) != 0)
2251ff545d6SKristof Provost 		atf_tc_fail("Request with size -1 failed ");
2261ff545d6SKristof Provost 
2271ff545d6SKristof Provost 	/* Overly large size. See above. */
2281ff545d6SKristof Provost 	io.pfrio_size = 1 << 24;
2291ff545d6SKristof Provost 	if (ioctl(dev, DIOCRCLRTSTATS, &io) != 0)
2301ff545d6SKristof Provost 		atf_tc_fail("Request with size 1 << 24 failed");
2311ff545d6SKristof Provost 
2321ff545d6SKristof Provost 	COMMON_CLEANUP();
2331ff545d6SKristof Provost }
2341ff545d6SKristof Provost 
2351ff545d6SKristof Provost ATF_TC_WITHOUT_HEAD(settflags);
2361ff545d6SKristof Provost ATF_TC_BODY(settflags, tc)
2371ff545d6SKristof Provost {
2381ff545d6SKristof Provost 	struct pfioc_table io;
2391ff545d6SKristof Provost 	struct pfr_table tbl;
2401ff545d6SKristof Provost 	int flags;
2411ff545d6SKristof Provost 
2421ff545d6SKristof Provost 	COMMON_HEAD();
2431ff545d6SKristof Provost 
2441ff545d6SKristof Provost 	flags = 0;
2451ff545d6SKristof Provost 
2461ff545d6SKristof Provost 	common_init_tbl(&tbl);
2471ff545d6SKristof Provost 
2481ff545d6SKristof Provost 	bzero(&io, sizeof(io));
2491ff545d6SKristof Provost 	io.pfrio_flags = flags;
2501ff545d6SKristof Provost 	io.pfrio_buffer = &tbl;
2511ff545d6SKristof Provost 	io.pfrio_esize = sizeof(tbl);
2521ff545d6SKristof Provost 
2531ff545d6SKristof Provost 	/* Negative size. This will succeed, because the kernel will not copy
2541ff545d6SKristof Provost 	 * tables than it has. */
2551ff545d6SKristof Provost 	io.pfrio_size = -1;
2561ff545d6SKristof Provost 	if (ioctl(dev, DIOCRSETTFLAGS, &io) != 0)
2571ff545d6SKristof Provost 		atf_tc_fail("Request with size -1 failed");
2581ff545d6SKristof Provost 
2591ff545d6SKristof Provost 	/* Overly large size. See above. */
2601ff545d6SKristof Provost 	io.pfrio_size = 1 << 28;
2611ff545d6SKristof Provost 	if (ioctl(dev, DIOCRSETTFLAGS, &io) != 0)
2621ff545d6SKristof Provost 		atf_tc_fail("Request with size 1 << 24 failed");
2631ff545d6SKristof Provost 
2641ff545d6SKristof Provost 	COMMON_CLEANUP();
2651ff545d6SKristof Provost }
2661ff545d6SKristof Provost 
2678e748b94SKristof Provost ATF_TC_WITHOUT_HEAD(igetifaces);
2688e748b94SKristof Provost ATF_TC_BODY(igetifaces, tc)
2698e748b94SKristof Provost {
2708e748b94SKristof Provost 	struct pfioc_iface io;
2718e748b94SKristof Provost 	struct pfi_kif kif;
2728e748b94SKristof Provost 
2738e748b94SKristof Provost 	COMMON_HEAD();
2748e748b94SKristof Provost 
2758e748b94SKristof Provost 	bzero(&io, sizeof(io));
2768e748b94SKristof Provost 	io.pfiio_flags = 0;
2778e748b94SKristof Provost 	io.pfiio_buffer = &kif;
2788e748b94SKristof Provost 	io.pfiio_esize = sizeof(kif);
2798e748b94SKristof Provost 
2808e748b94SKristof Provost 	/* Negative size */
2818e748b94SKristof Provost 	io.pfiio_size = -1;
2828e748b94SKristof Provost 	if (ioctl(dev, DIOCIGETIFACES, &io) == 0)
2838e748b94SKristof Provost 		atf_tc_fail("request with size -1 succeeded");
2848e748b94SKristof Provost 
2858e748b94SKristof Provost 	/* Overflow size */
2868e748b94SKristof Provost 	io.pfiio_size = 1 << 31;
2878e748b94SKristof Provost 	if (ioctl(dev, DIOCIGETIFACES, &io) == 0)
2888e748b94SKristof Provost 		atf_tc_fail("request with size 1 << 31 succeeded");
2898e748b94SKristof Provost 
2908e748b94SKristof Provost 	COMMON_CLEANUP();
2918e748b94SKristof Provost }
2928e748b94SKristof Provost 
2938e748b94SKristof Provost ATF_TC_WITHOUT_HEAD(commit);
2948e748b94SKristof Provost ATF_TC_BODY(commit, tc)
2958e748b94SKristof Provost {
2968e748b94SKristof Provost 	struct pfioc_trans io;
2978e748b94SKristof Provost 	struct pfioc_trans_e ioe;
2988e748b94SKristof Provost 
2998e748b94SKristof Provost 	COMMON_HEAD();
3008e748b94SKristof Provost 
3018e748b94SKristof Provost 	bzero(&io, sizeof(io));
3028e748b94SKristof Provost 	io.esize = sizeof(ioe);
3038e748b94SKristof Provost 	io.array = &ioe;
3048e748b94SKristof Provost 
3058e748b94SKristof Provost 	/* Negative size */
3068e748b94SKristof Provost 	io.size = -1;
3078e748b94SKristof Provost 	if (ioctl(dev, DIOCXCOMMIT, &io) == 0)
3088e748b94SKristof Provost 		atf_tc_fail("request with size -1 succeeded");
3098e748b94SKristof Provost 
3108e748b94SKristof Provost 	/* Overflow size */
3118e748b94SKristof Provost 	io.size = 1 << 30;
3128e748b94SKristof Provost 	if (ioctl(dev, DIOCXCOMMIT, &io) == 0)
3138e748b94SKristof Provost 		atf_tc_fail("request with size 1 << 30 succeeded");
3148e748b94SKristof Provost 
3158e748b94SKristof Provost 	/* NULL buffer */
3168e748b94SKristof Provost 	io.size = 1;
3178e748b94SKristof Provost 	io.array = NULL;
3188e748b94SKristof Provost 	if (ioctl(dev, DIOCXCOMMIT, &io) == 0)
3198e748b94SKristof Provost 		atf_tc_fail("request with size -1 succeeded");
3208e748b94SKristof Provost 
3218e748b94SKristof Provost 	COMMON_CLEANUP();
3228e748b94SKristof Provost }
3238e748b94SKristof Provost 
32498c5f988SKristof Provost ATF_TP_ADD_TCS(tp)
32598c5f988SKristof Provost {
32698c5f988SKristof Provost 	ATF_TP_ADD_TC(tp, addtables);
32798c5f988SKristof Provost 	ATF_TP_ADD_TC(tp, deltables);
3281ff545d6SKristof Provost 	ATF_TP_ADD_TC(tp, gettables);
3291ff545d6SKristof Provost 	ATF_TP_ADD_TC(tp, gettstats);
3301ff545d6SKristof Provost 	ATF_TP_ADD_TC(tp, clrtstats);
3311ff545d6SKristof Provost 	ATF_TP_ADD_TC(tp, settflags);
3328e748b94SKristof Provost 	ATF_TP_ADD_TC(tp, igetifaces);
3338e748b94SKristof Provost 	ATF_TP_ADD_TC(tp, commit);
33498c5f988SKristof Provost 
33598c5f988SKristof Provost 	return (atf_no_error());
33698c5f988SKristof Provost }
337