t_bpf.c revision 314817
1/*	$NetBSD: t_bpf.c,v 1.7 2017/02/01 08:04:49 ozaki-r Exp $	*/
2
3/*-
4 * Copyright (c) 2010 Antti Kantee.  All Rights Reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27#include <sys/cdefs.h>
28__RCSID("$NetBSD: t_bpf.c,v 1.7 2017/02/01 08:04:49 ozaki-r Exp $");
29
30#include <sys/param.h>
31#include <sys/ioctl.h>
32#include <sys/socket.h>
33#include <sys/mbuf.h>
34#include <sys/sysctl.h>
35#include <sys/mman.h>
36#include <unistd.h>
37
38#include <net/if.h>
39#include <net/bpf.h>
40
41#include <fcntl.h>
42#include <stdio.h>
43#include <string.h>
44
45#include <rump/rump.h>
46#include <rump/rump_syscalls.h>
47
48/* XXX: atf-c.h has collisions with mbuf */
49#undef m_type
50#undef m_data
51#include <atf-c.h>
52
53#include "h_macros.h"
54#include "../config/netconfig.c"
55
56ATF_TC(bpfwriteleak);
57ATF_TC_HEAD(bpfwriteleak, tc)
58{
59
60	atf_tc_set_md_var(tc, "descr", "Checks that writing to /dev/bpf "
61	    "does not leak mbufs");
62}
63
64static int
65getmtdata(void)
66{
67	struct mbstat mbstat;
68	size_t mbstatlen = sizeof(mbstat);
69	const int mbstat_mib[] = { CTL_KERN, KERN_MBUF, MBUF_STATS };
70
71	RL(rump_sys___sysctl(mbstat_mib, __arraycount(mbstat_mib),
72	    &mbstat, &mbstatlen, NULL, 0));
73	return mbstat.m_mtypes[MT_DATA];
74}
75
76ATF_TC_BODY(bpfwriteleak, tc)
77{
78	char buf[28]; /* sizeof(garbage) > etherhdrlen */
79	struct ifreq ifr;
80	int ifnum, bpfd;
81
82	RZ(rump_init());
83	RZ(rump_pub_shmif_create(NULL, &ifnum));
84	sprintf(ifr.ifr_name, "shmif%d", ifnum);
85
86	RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
87	RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
88	RL(rump_sys_ioctl(bpfd, BIOCSFEEDBACK, &ifr));
89
90	if (getmtdata() != 0)
91		atf_tc_fail("test precondition failed: MT_DATA mbufs != 0");
92
93	ATF_REQUIRE_ERRNO(ENETDOWN, rump_sys_write(bpfd, buf, sizeof(buf))==-1);
94
95	ATF_REQUIRE_EQ(getmtdata(), 0);
96}
97
98#if (SIZE_MAX > UINT_MAX)
99ATF_TC(bpfwritetrunc);
100ATF_TC_HEAD(bpfwritetrunc, tc)
101{
102	atf_tc_set_md_var(tc, "descr", "Checks that write to /dev/bpf "
103	    "does not truncate size_t to int");
104}
105
106ATF_TC_BODY(bpfwritetrunc, tc)
107{
108	int bpfd;
109	struct ifreq ifr;
110	struct iovec *iov;
111	size_t iovlen, sz;
112	const size_t extra_bytes = 28;
113	const size_t total = extra_bytes + UINT_MAX + 1;
114	long iov_max, vm_page_size; /* round_page wants vm_page_size variable */
115
116	memset(&ifr, 0, sizeof(ifr));
117
118	iov_max      = sysconf(_SC_IOV_MAX);
119	vm_page_size = sysconf(_SC_PAGE_SIZE);
120	ATF_REQUIRE(iov_max > 1 && vm_page_size > 1);
121
122	/*
123	 * Minimize memory consumption by using many iovecs
124	 * all pointing to one memory region.
125	 */
126	iov = calloc(iov_max, sizeof(struct iovec));
127	ATF_REQUIRE(iov != NULL);
128
129	sz = round_page((total + (iov_max - 1)) / iov_max);
130
131	iov[0].iov_len = sz;
132	iov[0].iov_base = mmap(NULL, sz, PROT_READ, MAP_ANON, -1, 0);
133	ATF_REQUIRE(iov[0].iov_base != MAP_FAILED);
134
135	iovlen = 1;
136	while (sz + iov[0].iov_len <= total)
137	{
138		iov[iovlen].iov_len  = iov[0].iov_len;
139		iov[iovlen].iov_base = iov[0].iov_base;
140		sz += iov[0].iov_len;
141		iovlen++;
142	}
143
144	if (sz < total)
145	{
146		iov[iovlen].iov_len = total - sz;
147		iov[iovlen].iov_base = iov[0].iov_base;
148		iovlen++;
149	}
150
151	/* Sanity checks */
152	ATF_REQUIRE(iovlen >= 1 && iovlen <= (size_t)iov_max);
153	ATF_REQUIRE_EQ(iov[iovlen-1].iov_len, total % iov[0].iov_len);
154
155	RZ(rump_init());
156	netcfg_rump_makeshmif("bpfwritetrunc", ifr.ifr_name);
157	netcfg_rump_if(ifr.ifr_name, "10.1.1.1", "255.0.0.0");
158
159	RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
160	RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
161
162	ATF_CHECK_ERRNO(EMSGSIZE, rump_sys_writev(bpfd, iov, iovlen) == -1);
163
164	munmap(iov[0].iov_base, iov[0].iov_len);
165	free(iov);
166}
167#endif /* #if (SIZE_MAX > UINT_MAX) */
168
169ATF_TC(bpf_ioctl_BLEN);
170ATF_TC_HEAD(bpf_ioctl_BLEN, tc)
171{
172
173	atf_tc_set_md_var(tc, "descr", "Checks behaviors of BIOCGBLEN and "
174	    "BIOCSBLEN");
175}
176
177ATF_TC_BODY(bpf_ioctl_BLEN, tc)
178{
179	struct ifreq ifr;
180	int ifnum, bpfd;
181	u_int blen = 0;
182
183	RZ(rump_init());
184	RZ(rump_pub_shmif_create(NULL, &ifnum));
185	sprintf(ifr.ifr_name, "shmif%d", ifnum);
186
187	RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
188
189	RL(rump_sys_ioctl(bpfd, BIOCGBLEN, &blen));
190	ATF_REQUIRE(blen != 0);
191	blen = 100;
192	RL(rump_sys_ioctl(bpfd, BIOCSBLEN, &blen));
193	RL(rump_sys_ioctl(bpfd, BIOCGBLEN, &blen));
194	ATF_REQUIRE_EQ(blen, 100);
195
196	RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
197
198	ATF_REQUIRE_EQ_MSG(rump_sys_ioctl(bpfd, BIOCSBLEN, &blen), -1,
199	    "Don't allow to change buflen after binding bpf to an interface");
200}
201
202ATF_TP_ADD_TCS(tp)
203{
204
205	ATF_TP_ADD_TC(tp, bpfwriteleak);
206#if (SIZE_MAX > UINT_MAX)
207	ATF_TP_ADD_TC(tp, bpfwritetrunc);
208#endif
209	ATF_TP_ADD_TC(tp, bpf_ioctl_BLEN);
210	return atf_no_error();
211}
212