1/*	$NetBSD: t_o_search.c,v 1.4 2013/03/17 04:46:06 jmmv 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.4 2013/03/17 04:46:06 jmmv Exp $");
33
34#include <atf-c.h>
35#include <errno.h>
36#include <fcntl.h>
37#include <limits.h>
38#include <paths.h>
39#include <stdio.h>
40#include <string.h>
41#include <unistd.h>
42#include <pwd.h>
43#include <sys/param.h>
44
45/*
46 * dholland 20130112: disable tests that require O_SEARCH semantics
47 * until a decision is reached about the semantics of O_SEARCH and a
48 * non-broken implementation is available.
49 */
50#if (O_MASK & O_SEARCH) != 0
51#define USE_O_SEARCH
52#endif
53
54#define DIR "dir"
55#define FILE "dir/o_search"
56#define BASEFILE "o_search"
57
58
59ATF_TC(o_search_perm1);
60ATF_TC_HEAD(o_search_perm1, tc)
61{
62	atf_tc_set_md_var(tc, "descr", "See that openat enforces search permission");
63	atf_tc_set_md_var(tc, "require.user", "unprivileged");
64}
65ATF_TC_BODY(o_search_perm1, tc)
66{
67	int dfd;
68	int fd;
69
70	ATF_REQUIRE(mkdir(DIR, 0755) == 0);
71	ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1);
72	ATF_REQUIRE(close(fd) == 0);
73
74	ATF_REQUIRE((dfd = open(DIR, O_RDONLY, 0)) != -1);
75
76	ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1);
77	ATF_REQUIRE(close(fd) == 0);
78
79	ATF_REQUIRE(fchmod(dfd, 644) == 0);
80
81	ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) == -1);
82	ATF_REQUIRE(errno == EACCES);
83
84	ATF_REQUIRE(close(dfd) == 0);
85}
86
87#ifdef USE_O_SEARCH
88
89ATF_TC(o_search_root_flag1);
90ATF_TC_HEAD(o_search_root_flag1, tc)
91{
92	atf_tc_set_md_var(tc, "descr", "See that root openat honours O_SEARCH");
93	atf_tc_set_md_var(tc, "require.user", "root");
94}
95ATF_TC_BODY(o_search_root_flag1, tc)
96{
97	int dfd;
98	int fd;
99
100	ATF_REQUIRE(mkdir(DIR, 0755) == 0);
101	ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1);
102	ATF_REQUIRE(close(fd) == 0);
103
104	ATF_REQUIRE((dfd = open(DIR, O_RDONLY|O_SEARCH, 0)) != -1);
105
106	ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1);
107	ATF_REQUIRE(close(fd) == 0);
108
109	ATF_REQUIRE(fchmod(dfd, 644) == 0);
110
111	ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1);
112	ATF_REQUIRE(close(fd) == 0);
113
114	ATF_REQUIRE(fchmod(dfd, 444) == 0);
115
116	ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1);
117
118	ATF_REQUIRE(close(dfd) == 0);
119}
120
121ATF_TC(o_search_unpriv_flag1);
122ATF_TC_HEAD(o_search_unpriv_flag1, tc)
123{
124	atf_tc_set_md_var(tc, "descr", "See that openat honours O_SEARCH");
125	atf_tc_set_md_var(tc, "require.user", "unprivileged");
126}
127ATF_TC_BODY(o_search_unpriv_flag1, tc)
128{
129	int dfd;
130	int fd;
131
132	ATF_REQUIRE(mkdir(DIR, 0755) == 0);
133	ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1);
134	ATF_REQUIRE(close(fd) == 0);
135
136	ATF_REQUIRE((dfd = open(DIR, O_RDONLY|O_SEARCH, 0)) != -1);
137
138	ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1);
139	ATF_REQUIRE(close(fd) == 0);
140
141	ATF_REQUIRE(fchmod(dfd, 644) == 0);
142
143	ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1);
144	ATF_REQUIRE(close(fd) == 0);
145
146	ATF_REQUIRE(fchmod(dfd, 444) == 0);
147
148	ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) != -1);
149
150	ATF_REQUIRE(close(dfd) == 0);
151}
152
153#endif /* USE_O_SEARCH */
154
155ATF_TC(o_search_perm2);
156ATF_TC_HEAD(o_search_perm2, tc)
157{
158	atf_tc_set_md_var(tc, "descr", "See that faccessat enforces search permission");
159	atf_tc_set_md_var(tc, "require.user", "unprivileged");
160}
161ATF_TC_BODY(o_search_perm2, tc)
162{
163	int dfd;
164	int fd;
165	ATF_REQUIRE(mkdir(DIR, 0755) == 0);
166	ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1);
167	ATF_REQUIRE(close(fd) == 0);
168
169	ATF_REQUIRE((dfd = open(DIR, O_RDONLY, 0)) != -1);
170
171	ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0);
172
173	ATF_REQUIRE(fchmod(dfd, 644) == 0);
174
175	ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == -1);
176	ATF_REQUIRE(errno == EACCES);
177
178	ATF_REQUIRE(close(dfd) == 0);
179}
180
181#ifdef USE_O_SEARCH
182
183ATF_TC(o_search_root_flag2);
184ATF_TC_HEAD(o_search_root_flag2, tc)
185{
186	atf_tc_set_md_var(tc, "descr", "See that root fstatat honours O_SEARCH");
187	atf_tc_set_md_var(tc, "require.user", "root");
188}
189ATF_TC_BODY(o_search_root_flag2, tc)
190{
191	int dfd;
192	int fd;
193
194	ATF_REQUIRE(mkdir(DIR, 0755) == 0);
195	ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1);
196	ATF_REQUIRE(close(fd) == 0);
197
198	ATF_REQUIRE((dfd = open(DIR, O_RDONLY|O_SEARCH, 0)) != -1);
199
200	ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0);
201
202	ATF_REQUIRE(fchmod(dfd, 644) == 0);
203
204	ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0);
205
206	ATF_REQUIRE(fchmod(dfd, 444) == 0);
207
208	ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0);
209
210	ATF_REQUIRE(close(dfd) == 0);
211}
212
213ATF_TC(o_search_unpriv_flag2);
214ATF_TC_HEAD(o_search_unpriv_flag2, tc)
215{
216	atf_tc_set_md_var(tc, "descr", "See that fstatat honours O_SEARCH");
217	atf_tc_set_md_var(tc, "require.user", "unprivileged");
218}
219ATF_TC_BODY(o_search_unpriv_flag2, tc)
220{
221	int dfd;
222	int fd;
223
224	ATF_REQUIRE(mkdir(DIR, 0755) == 0);
225	ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1);
226	ATF_REQUIRE(close(fd) == 0);
227
228	ATF_REQUIRE((dfd = open(DIR, O_RDONLY|O_SEARCH, 0)) != -1);
229
230	ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0);
231
232	ATF_REQUIRE(fchmod(dfd, 644) == 0);
233
234	ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0);
235
236	ATF_REQUIRE(fchmod(dfd, 444) == 0);
237
238	ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) == 0);
239
240	ATF_REQUIRE(close(dfd) == 0);
241}
242
243#endif /* USE_O_SEARCH */
244
245
246ATF_TC(o_search_notdir);
247ATF_TC_HEAD(o_search_notdir, tc)
248{
249	atf_tc_set_md_var(tc, "descr", "See that openat fails with non dir fd");
250}
251ATF_TC_BODY(o_search_notdir, tc)
252{
253	int dfd;
254	int fd;
255
256	ATF_REQUIRE(mkdir(DIR, 0755) == 0);
257	ATF_REQUIRE((dfd = open(FILE, O_CREAT|O_RDWR|O_SEARCH, 0644)) != -1);
258	ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) == -1);
259	ATF_REQUIRE(errno == ENOTDIR);
260}
261
262ATF_TP_ADD_TCS(tp)
263{
264
265	ATF_TP_ADD_TC(tp, o_search_perm1);
266#ifdef USE_O_SEARCH
267	ATF_TP_ADD_TC(tp, o_search_root_flag1);
268	ATF_TP_ADD_TC(tp, o_search_unpriv_flag1);
269#endif
270	ATF_TP_ADD_TC(tp, o_search_perm2);
271#ifdef USE_O_SEARCH
272	ATF_TP_ADD_TC(tp, o_search_root_flag2);
273	ATF_TP_ADD_TC(tp, o_search_unpriv_flag2);
274#endif
275	ATF_TP_ADD_TC(tp, o_search_notdir);
276
277	return atf_no_error();
278}
279