1*49a6e16fSderaadt /* $OpenBSD: t_mkfifo.c,v 1.2 2021/12/13 16:56:48 deraadt Exp $ */
2a545a52cSbluhm /* $NetBSD: t_mkfifo.c,v 1.3 2019/06/20 03:31:54 kamil Exp $ */
3a545a52cSbluhm
4a545a52cSbluhm /*-
5a545a52cSbluhm * Copyright (c) 2011 The NetBSD Foundation, Inc.
6a545a52cSbluhm * All rights reserved.
7a545a52cSbluhm *
8a545a52cSbluhm * This code is derived from software contributed to The NetBSD Foundation
9a545a52cSbluhm * by Jukka Ruohonen.
10a545a52cSbluhm *
11a545a52cSbluhm * Redistribution and use in source and binary forms, with or without
12a545a52cSbluhm * modification, are permitted provided that the following conditions
13a545a52cSbluhm * are met:
14a545a52cSbluhm * 1. Redistributions of source code must retain the above copyright
15a545a52cSbluhm * notice, this list of conditions and the following disclaimer.
16a545a52cSbluhm * 2. Redistributions in binary form must reproduce the above copyright
17a545a52cSbluhm * notice, this list of conditions and the following disclaimer in the
18a545a52cSbluhm * documentation and/or other materials provided with the distribution.
19a545a52cSbluhm *
20a545a52cSbluhm * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21a545a52cSbluhm * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22a545a52cSbluhm * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23a545a52cSbluhm * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24a545a52cSbluhm * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25a545a52cSbluhm * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26a545a52cSbluhm * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27a545a52cSbluhm * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28a545a52cSbluhm * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29a545a52cSbluhm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30a545a52cSbluhm * POSSIBILITY OF SUCH DAMAGE.
31a545a52cSbluhm */
32a545a52cSbluhm
33a545a52cSbluhm #include "macros.h"
34a545a52cSbluhm
35a545a52cSbluhm #include <sys/stat.h>
36a545a52cSbluhm #include <sys/wait.h>
37a545a52cSbluhm
38a545a52cSbluhm #include "atf-c.h"
39a545a52cSbluhm #include <errno.h>
40a545a52cSbluhm #include <fcntl.h>
41a545a52cSbluhm #include <limits.h>
42a545a52cSbluhm #include <stdlib.h>
43a545a52cSbluhm #include <signal.h>
44a545a52cSbluhm #include <string.h>
45a545a52cSbluhm #include <unistd.h>
46a545a52cSbluhm
47a545a52cSbluhm static const char path[] = "fifo";
48a545a52cSbluhm static void support(void);
49a545a52cSbluhm
50a545a52cSbluhm static void
support(void)51a545a52cSbluhm support(void)
52a545a52cSbluhm {
53a545a52cSbluhm
54a545a52cSbluhm errno = 0;
55a545a52cSbluhm
56a545a52cSbluhm if (mkfifo(path, 0600) == 0) {
57a545a52cSbluhm ATF_REQUIRE(unlink(path) == 0);
58a545a52cSbluhm return;
59a545a52cSbluhm }
60a545a52cSbluhm
61a545a52cSbluhm if (errno == EOPNOTSUPP)
62a545a52cSbluhm atf_tc_skip("the kernel does not support FIFOs");
63a545a52cSbluhm else {
64a545a52cSbluhm atf_tc_fail("mkfifo(2) failed");
65a545a52cSbluhm }
66a545a52cSbluhm }
67a545a52cSbluhm
68a545a52cSbluhm ATF_TC_WITH_CLEANUP(mkfifo_block);
ATF_TC_HEAD(mkfifo_block,tc)69a545a52cSbluhm ATF_TC_HEAD(mkfifo_block, tc)
70a545a52cSbluhm {
71a545a52cSbluhm atf_tc_set_md_var(tc, "descr", "Test that FIFOs block");
72a545a52cSbluhm }
73a545a52cSbluhm
ATF_TC_BODY(mkfifo_block,tc)74a545a52cSbluhm ATF_TC_BODY(mkfifo_block, tc)
75a545a52cSbluhm {
76a545a52cSbluhm int sta, fd = -1;
77a545a52cSbluhm pid_t pid;
78a545a52cSbluhm
79a545a52cSbluhm support();
80a545a52cSbluhm
81a545a52cSbluhm ATF_REQUIRE(mkfifo(path, 0600) == 0);
82a545a52cSbluhm
83a545a52cSbluhm pid = fork();
84a545a52cSbluhm ATF_REQUIRE(pid >= 0);
85a545a52cSbluhm
86a545a52cSbluhm if (pid == 0) {
87a545a52cSbluhm
88a545a52cSbluhm /*
89a545a52cSbluhm * If we open the FIFO as read-only (write-only),
90a545a52cSbluhm * the call should block until another process
91a545a52cSbluhm * opens the FIFO for writing (reading).
92a545a52cSbluhm */
93a545a52cSbluhm fd = open(path, O_RDONLY);
94a545a52cSbluhm
95a545a52cSbluhm _exit(EXIT_FAILURE); /* NOTREACHED */
96a545a52cSbluhm }
97a545a52cSbluhm
98a545a52cSbluhm (void)sleep(1);
99a545a52cSbluhm
100a545a52cSbluhm ATF_REQUIRE(kill(pid, SIGKILL) == 0);
101a545a52cSbluhm
102a545a52cSbluhm (void)wait(&sta);
103a545a52cSbluhm
104a545a52cSbluhm if (WIFSIGNALED(sta) == 0 || WTERMSIG(sta) != SIGKILL)
105a545a52cSbluhm atf_tc_fail("FIFO did not block");
106a545a52cSbluhm
107a545a52cSbluhm (void)close(fd);
108a545a52cSbluhm (void)unlink(path);
109a545a52cSbluhm }
110a545a52cSbluhm
ATF_TC_CLEANUP(mkfifo_block,tc)111a545a52cSbluhm ATF_TC_CLEANUP(mkfifo_block, tc)
112a545a52cSbluhm {
113a545a52cSbluhm (void)unlink(path);
114a545a52cSbluhm }
115a545a52cSbluhm
116a545a52cSbluhm ATF_TC_WITH_CLEANUP(mkfifo_err);
ATF_TC_HEAD(mkfifo_err,tc)117a545a52cSbluhm ATF_TC_HEAD(mkfifo_err, tc)
118a545a52cSbluhm {
119a545a52cSbluhm atf_tc_set_md_var(tc, "descr", "Test erros from mkfifo(2)");
120a545a52cSbluhm }
121a545a52cSbluhm
ATF_TC_BODY(mkfifo_err,tc)122a545a52cSbluhm ATF_TC_BODY(mkfifo_err, tc)
123a545a52cSbluhm {
124a545a52cSbluhm char buf[PATH_MAX + 1];
125a545a52cSbluhm
126a545a52cSbluhm support();
127a545a52cSbluhm
128a545a52cSbluhm (void)memset(buf, 'x', sizeof(buf));
129a545a52cSbluhm ATF_REQUIRE(mkfifo(path, 0600) == 0);
130a545a52cSbluhm
131a545a52cSbluhm errno = 0;
132a545a52cSbluhm ATF_REQUIRE_ERRNO(EFAULT, mkfifo((char *)-1, 0600) == -1);
133a545a52cSbluhm
134a545a52cSbluhm errno = 0;
135a545a52cSbluhm ATF_REQUIRE_ERRNO(EEXIST, mkfifo("/etc/passwd", 0600) == -1);
136a545a52cSbluhm
137a545a52cSbluhm errno = 0;
138a545a52cSbluhm ATF_REQUIRE_ERRNO(EEXIST, mkfifo(path, 0600) == -1);
139a545a52cSbluhm
140a545a52cSbluhm errno = 0;
141a545a52cSbluhm ATF_REQUIRE_ERRNO(ENAMETOOLONG, mkfifo(buf, 0600) == -1);
142a545a52cSbluhm
143a545a52cSbluhm errno = 0;
144a545a52cSbluhm ATF_REQUIRE_ERRNO(ENOENT, mkfifo("/a/b/c/d/e/f/g", 0600) == -1);
145a545a52cSbluhm
146a545a52cSbluhm ATF_REQUIRE(unlink(path) == 0);
147a545a52cSbluhm }
148a545a52cSbluhm
ATF_TC_CLEANUP(mkfifo_err,tc)149a545a52cSbluhm ATF_TC_CLEANUP(mkfifo_err, tc)
150a545a52cSbluhm {
151a545a52cSbluhm (void)unlink(path);
152a545a52cSbluhm }
153a545a52cSbluhm
154a545a52cSbluhm ATF_TC_WITH_CLEANUP(mkfifo_nonblock);
ATF_TC_HEAD(mkfifo_nonblock,tc)155a545a52cSbluhm ATF_TC_HEAD(mkfifo_nonblock, tc)
156a545a52cSbluhm {
157a545a52cSbluhm atf_tc_set_md_var(tc, "descr", "Test O_NONBLOCK with FIFOs");
158a545a52cSbluhm }
159a545a52cSbluhm
ATF_TC_BODY(mkfifo_nonblock,tc)160a545a52cSbluhm ATF_TC_BODY(mkfifo_nonblock, tc)
161a545a52cSbluhm {
162a545a52cSbluhm int fd, sta;
163a545a52cSbluhm pid_t pid;
164a545a52cSbluhm
165a545a52cSbluhm support();
166a545a52cSbluhm
167a545a52cSbluhm fd = -1;
168a545a52cSbluhm ATF_REQUIRE(mkfifo(path, 0600) == 0);
169a545a52cSbluhm
170a545a52cSbluhm pid = fork();
171a545a52cSbluhm ATF_REQUIRE(pid >= 0);
172a545a52cSbluhm
173a545a52cSbluhm if (pid == 0) {
174a545a52cSbluhm
175a545a52cSbluhm /*
176a545a52cSbluhm * If we open the FIFO as O_NONBLOCK, the O_RDONLY
177a545a52cSbluhm * call should return immediately, whereas the call
178a545a52cSbluhm * for write-only should fail with ENXIO.
179a545a52cSbluhm */
180a545a52cSbluhm fd = open(path, O_RDONLY | O_NONBLOCK);
181a545a52cSbluhm
182a545a52cSbluhm if (fd >= 0)
183a545a52cSbluhm _exit(EXIT_SUCCESS);
184a545a52cSbluhm
185a545a52cSbluhm (void)pause(); /* NOTREACHED */
186a545a52cSbluhm }
187a545a52cSbluhm
188a545a52cSbluhm (void)sleep(1);
189a545a52cSbluhm
190a545a52cSbluhm errno = 0;
191a545a52cSbluhm ATF_REQUIRE_ERRNO(ENXIO, open(path, O_WRONLY | O_NONBLOCK) == -1);
192a545a52cSbluhm
193a545a52cSbluhm (void)kill(pid, SIGKILL);
194a545a52cSbluhm (void)wait(&sta);
195a545a52cSbluhm
196a545a52cSbluhm if (WIFSIGNALED(sta) != 0 || WTERMSIG(sta) == SIGKILL)
197a545a52cSbluhm atf_tc_fail("FIFO blocked for O_NONBLOCK open(2)");
198a545a52cSbluhm
199a545a52cSbluhm (void)close(fd);
200a545a52cSbluhm (void)unlink(path);
201a545a52cSbluhm }
202a545a52cSbluhm
ATF_TC_CLEANUP(mkfifo_nonblock,tc)203a545a52cSbluhm ATF_TC_CLEANUP(mkfifo_nonblock, tc)
204a545a52cSbluhm {
205a545a52cSbluhm (void)unlink(path);
206a545a52cSbluhm }
207a545a52cSbluhm
208a545a52cSbluhm ATF_TC_WITH_CLEANUP(mkfifo_perm);
ATF_TC_HEAD(mkfifo_perm,tc)209a545a52cSbluhm ATF_TC_HEAD(mkfifo_perm, tc)
210a545a52cSbluhm {
211a545a52cSbluhm atf_tc_set_md_var(tc, "descr", "Test permissions with mkfifo(2)");
212a545a52cSbluhm atf_tc_set_md_var(tc, "require.user", "unprivileged");
213a545a52cSbluhm }
214a545a52cSbluhm
ATF_TC_BODY(mkfifo_perm,tc)215a545a52cSbluhm ATF_TC_BODY(mkfifo_perm, tc)
216a545a52cSbluhm {
217a545a52cSbluhm
218a545a52cSbluhm support();
219a545a52cSbluhm
220a545a52cSbluhm errno = 0;
221a545a52cSbluhm ATF_REQUIRE_ERRNO(EACCES, mkfifo("/root/fifo", 0600) == -1);
222a545a52cSbluhm
223a545a52cSbluhm ATF_REQUIRE(mkfifo(path, 0600) == 0);
224a545a52cSbluhm
225a545a52cSbluhm /*
226a545a52cSbluhm * For some reason this fails with EFTYPE...
227a545a52cSbluhm */
228a545a52cSbluhm errno = 0;
229a545a52cSbluhm ATF_REQUIRE_ERRNO(EFTYPE, chmod(path, 1777) == -1);
230a545a52cSbluhm
231a545a52cSbluhm ATF_REQUIRE(unlink(path) == 0);
232a545a52cSbluhm }
233a545a52cSbluhm
ATF_TC_CLEANUP(mkfifo_perm,tc)234a545a52cSbluhm ATF_TC_CLEANUP(mkfifo_perm, tc)
235a545a52cSbluhm {
236a545a52cSbluhm (void)unlink(path);
237a545a52cSbluhm }
238a545a52cSbluhm
239a545a52cSbluhm ATF_TC_WITH_CLEANUP(mkfifo_stat);
ATF_TC_HEAD(mkfifo_stat,tc)240a545a52cSbluhm ATF_TC_HEAD(mkfifo_stat, tc)
241a545a52cSbluhm {
242a545a52cSbluhm atf_tc_set_md_var(tc, "descr", "Test mkfifo(2) with stat");
243a545a52cSbluhm }
244a545a52cSbluhm
ATF_TC_BODY(mkfifo_stat,tc)245a545a52cSbluhm ATF_TC_BODY(mkfifo_stat, tc)
246a545a52cSbluhm {
247a545a52cSbluhm struct stat st;
248a545a52cSbluhm
249a545a52cSbluhm support();
250a545a52cSbluhm
251a545a52cSbluhm (void)memset(&st, 0, sizeof(struct stat));
252a545a52cSbluhm
253a545a52cSbluhm ATF_REQUIRE(mkfifo(path, 0600) == 0);
254a545a52cSbluhm ATF_REQUIRE(stat(path, &st) == 0);
255a545a52cSbluhm
256a545a52cSbluhm if (S_ISFIFO(st.st_mode) == 0)
257a545a52cSbluhm atf_tc_fail("invalid mode from mkfifo(2)");
258a545a52cSbluhm
259a545a52cSbluhm ATF_REQUIRE(unlink(path) == 0);
260a545a52cSbluhm }
261a545a52cSbluhm
ATF_TC_CLEANUP(mkfifo_stat,tc)262a545a52cSbluhm ATF_TC_CLEANUP(mkfifo_stat, tc)
263a545a52cSbluhm {
264a545a52cSbluhm (void)unlink(path);
265a545a52cSbluhm }
266a545a52cSbluhm
267a545a52cSbluhm ATF_TC_WITH_CLEANUP(mknod_s_ififo);
ATF_TC_HEAD(mknod_s_ififo,tc)268a545a52cSbluhm ATF_TC_HEAD(mknod_s_ififo, tc)
269a545a52cSbluhm {
270a545a52cSbluhm atf_tc_set_md_var(tc, "descr", "Test mknod(2) with S_IFIFO");
271a545a52cSbluhm }
272a545a52cSbluhm
ATF_TC_BODY(mknod_s_ififo,tc)273a545a52cSbluhm ATF_TC_BODY(mknod_s_ififo, tc)
274a545a52cSbluhm {
275a545a52cSbluhm struct stat st;
276a545a52cSbluhm
277a545a52cSbluhm support();
278a545a52cSbluhm
279a545a52cSbluhm (void)memset(&st, 0, sizeof(struct stat));
280a545a52cSbluhm
281a545a52cSbluhm ATF_REQUIRE(mknod(path, S_IFIFO | 0600, 0) == 0);
282a545a52cSbluhm ATF_REQUIRE(stat(path, &st) == 0);
283a545a52cSbluhm
284a545a52cSbluhm if (S_ISFIFO(st.st_mode) == 0)
285a545a52cSbluhm atf_tc_fail("invalid mode from mknod(2) with S_IFIFO");
286a545a52cSbluhm
287a545a52cSbluhm ATF_REQUIRE(unlink(path) == 0);
288a545a52cSbluhm }
289a545a52cSbluhm
ATF_TC_CLEANUP(mknod_s_ififo,tc)290a545a52cSbluhm ATF_TC_CLEANUP(mknod_s_ififo, tc)
291a545a52cSbluhm {
292a545a52cSbluhm (void)unlink(path);
293a545a52cSbluhm }
294a545a52cSbluhm
ATF_TP_ADD_TCS(tp)295a545a52cSbluhm ATF_TP_ADD_TCS(tp)
296a545a52cSbluhm {
297a545a52cSbluhm
298a545a52cSbluhm ATF_TP_ADD_TC(tp, mkfifo_block);
299a545a52cSbluhm ATF_TP_ADD_TC(tp, mkfifo_err);
300a545a52cSbluhm ATF_TP_ADD_TC(tp, mkfifo_nonblock);
301a545a52cSbluhm ATF_TP_ADD_TC(tp, mkfifo_perm);
302a545a52cSbluhm ATF_TP_ADD_TC(tp, mkfifo_stat);
303a545a52cSbluhm ATF_TP_ADD_TC(tp, mknod_s_ififo);
304a545a52cSbluhm
305a545a52cSbluhm return atf_no_error();
306a545a52cSbluhm }
307