t_o_search.c revision 313535
1/*	$NetBSD: t_o_search.c,v 1.5 2017/01/10 22:25:01 christos Exp $ */
2
3/*-
4 * Copyright (c) 2012 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Emmanuel Dreyfus.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31#include <sys/cdefs.h>
32__RCSID("$NetBSD: t_o_search.c,v 1.5 2017/01/10 22:25:01 christos Exp $");
33
34#include <atf-c.h>
35
36#include <sys/param.h>
37#include <sys/stat.h>
38
39#include <errno.h>
40#include <fcntl.h>
41#include <limits.h>
42#include <paths.h>
43#include <stdio.h>
44#include <string.h>
45#include <unistd.h>
46#include <pwd.h>
47
48/*
49 * dholland 20130112: disable tests that require O_SEARCH semantics
50 * until a decision is reached about the semantics of O_SEARCH and a
51 * non-broken implementation is available.
52 */
53#if (O_MASK & O_SEARCH) != 0
54#define USE_O_SEARCH
55#endif
56
57#define DIR "dir"
58#define FILE "dir/o_search"
59#define BASEFILE "o_search"
60
61
62ATF_TC(o_search_perm1);
63ATF_TC_HEAD(o_search_perm1, tc)
64{
65	atf_tc_set_md_var(tc, "descr", "See that openat enforces search permission");
66	atf_tc_set_md_var(tc, "require.user", "unprivileged");
67}
68ATF_TC_BODY(o_search_perm1, tc)
69{
70	int dfd;
71	int fd;
72
73	ATF_REQUIRE(mkdir(DIR, 0755) == 0);
74	ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1);
75	ATF_REQUIRE(close(fd) == 0);
76
77	ATF_REQUIRE((dfd = open(DIR, O_RDONLY, 0)) != -1);
78
79	ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1);
80	ATF_REQUIRE(close(fd) == 0);
81
82	ATF_REQUIRE(fchmod(dfd, 644) == 0);
83
84	ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) == -1);
85	ATF_REQUIRE(errno == EACCES);
86
87	ATF_REQUIRE(close(dfd) == 0);
88}
89
90#ifdef USE_O_SEARCH
91
92ATF_TC(o_search_root_flag1);
93ATF_TC_HEAD(o_search_root_flag1, tc)
94{
95	atf_tc_set_md_var(tc, "descr", "See that root openat honours O_SEARCH");
96	atf_tc_set_md_var(tc, "require.user", "root");
97}
98ATF_TC_BODY(o_search_root_flag1, tc)
99{
100	int dfd;
101	int fd;
102
103	ATF_REQUIRE(mkdir(DIR, 0755) == 0);
104	ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1);
105	ATF_REQUIRE(close(fd) == 0);
106
107	ATF_REQUIRE((dfd = open(DIR, O_RDONLY|O_SEARCH, 0)) != -1);
108
109	ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1);
110	ATF_REQUIRE(close(fd) == 0);
111
112	ATF_REQUIRE(fchmod(dfd, 644) == 0);
113
114	ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1);
115	ATF_REQUIRE(close(fd) == 0);
116
117	ATF_REQUIRE(fchmod(dfd, 444) == 0);
118
119	ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1);
120
121	ATF_REQUIRE(close(dfd) == 0);
122}
123
124ATF_TC(o_search_unpriv_flag1);
125ATF_TC_HEAD(o_search_unpriv_flag1, tc)
126{
127	atf_tc_set_md_var(tc, "descr", "See that openat honours O_SEARCH");
128	atf_tc_set_md_var(tc, "require.user", "unprivileged");
129}
130ATF_TC_BODY(o_search_unpriv_flag1, tc)
131{
132	int dfd;
133	int fd;
134
135	ATF_REQUIRE(mkdir(DIR, 0755) == 0);
136	ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1);
137	ATF_REQUIRE(close(fd) == 0);
138
139	ATF_REQUIRE((dfd = open(DIR, O_RDONLY|O_SEARCH, 0)) != -1);
140
141	ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1);
142	ATF_REQUIRE(close(fd) == 0);
143
144	ATF_REQUIRE(fchmod(dfd, 644) == 0);
145
146	ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1);
147	ATF_REQUIRE(close(fd) == 0);
148
149	ATF_REQUIRE(fchmod(dfd, 444) == 0);
150
151	ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1);
152
153	ATF_REQUIRE(close(dfd) == 0);
154}
155
156#endif /* USE_O_SEARCH */
157
158ATF_TC(o_search_perm2);
159ATF_TC_HEAD(o_search_perm2, tc)
160{
161	atf_tc_set_md_var(tc, "descr", "See that faccessat enforces search permission");
162	atf_tc_set_md_var(tc, "require.user", "unprivileged");
163}
164ATF_TC_BODY(o_search_perm2, tc)
165{
166	int dfd;
167	int fd;
168	ATF_REQUIRE(mkdir(DIR, 0755) == 0);
169	ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1);
170	ATF_REQUIRE(close(fd) == 0);
171
172	ATF_REQUIRE((dfd = open(DIR, O_RDONLY, 0)) != -1);
173
174	ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0);
175
176	ATF_REQUIRE(fchmod(dfd, 644) == 0);
177
178	ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == -1);
179	ATF_REQUIRE(errno == EACCES);
180
181	ATF_REQUIRE(close(dfd) == 0);
182}
183
184#ifdef USE_O_SEARCH
185
186ATF_TC(o_search_root_flag2);
187ATF_TC_HEAD(o_search_root_flag2, tc)
188{
189	atf_tc_set_md_var(tc, "descr", "See that root fstatat honours O_SEARCH");
190	atf_tc_set_md_var(tc, "require.user", "root");
191}
192ATF_TC_BODY(o_search_root_flag2, tc)
193{
194	int dfd;
195	int fd;
196
197	ATF_REQUIRE(mkdir(DIR, 0755) == 0);
198	ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1);
199	ATF_REQUIRE(close(fd) == 0);
200
201	ATF_REQUIRE((dfd = open(DIR, O_RDONLY|O_SEARCH, 0)) != -1);
202
203	ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0);
204
205	ATF_REQUIRE(fchmod(dfd, 644) == 0);
206
207	ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0);
208
209	ATF_REQUIRE(fchmod(dfd, 444) == 0);
210
211	ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0);
212
213	ATF_REQUIRE(close(dfd) == 0);
214}
215
216ATF_TC(o_search_unpriv_flag2);
217ATF_TC_HEAD(o_search_unpriv_flag2, tc)
218{
219	atf_tc_set_md_var(tc, "descr", "See that fstatat honours O_SEARCH");
220	atf_tc_set_md_var(tc, "require.user", "unprivileged");
221}
222ATF_TC_BODY(o_search_unpriv_flag2, tc)
223{
224	int dfd;
225	int fd;
226
227	ATF_REQUIRE(mkdir(DIR, 0755) == 0);
228	ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1);
229	ATF_REQUIRE(close(fd) == 0);
230
231	ATF_REQUIRE((dfd = open(DIR, O_RDONLY|O_SEARCH, 0)) != -1);
232
233	ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0);
234
235	ATF_REQUIRE(fchmod(dfd, 644) == 0);
236
237	ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0);
238
239	ATF_REQUIRE(fchmod(dfd, 444) == 0);
240
241	ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0);
242
243	ATF_REQUIRE(close(dfd) == 0);
244}
245
246#endif /* USE_O_SEARCH */
247
248
249ATF_TC(o_search_notdir);
250ATF_TC_HEAD(o_search_notdir, tc)
251{
252	atf_tc_set_md_var(tc, "descr", "See that openat fails with non dir fd");
253}
254ATF_TC_BODY(o_search_notdir, tc)
255{
256	int dfd;
257	int fd;
258
259	ATF_REQUIRE(mkdir(DIR, 0755) == 0);
260	ATF_REQUIRE((dfd = open(FILE, O_CREAT|O_RDWR|O_SEARCH, 0644)) != -1);
261	ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) == -1);
262	ATF_REQUIRE(errno == ENOTDIR);
263}
264
265ATF_TP_ADD_TCS(tp)
266{
267
268	ATF_TP_ADD_TC(tp, o_search_perm1);
269#ifdef USE_O_SEARCH
270	ATF_TP_ADD_TC(tp, o_search_root_flag1);
271	ATF_TP_ADD_TC(tp, o_search_unpriv_flag1);
272#endif
273	ATF_TP_ADD_TC(tp, o_search_perm2);
274#ifdef USE_O_SEARCH
275	ATF_TP_ADD_TC(tp, o_search_root_flag2);
276	ATF_TP_ADD_TC(tp, o_search_unpriv_flag2);
277#endif
278	ATF_TP_ADD_TC(tp, o_search_notdir);
279
280	return atf_no_error();
281}
282