Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tools/regression/security/open_to_operation/open_to_operation.c
48266 views
1
/*-
2
* Copyright (c) 2008 Robert N. M. Watson
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
* SUCH DAMAGE.
25
*/
26
27
/*-
28
* This regression test attempts to confirm that the flags used at open-time
29
* for a file descriptor properly limit system calls that should be affected
30
* by those flags. Currently:
31
*
32
* System call Policy Tested
33
* __acl_aclcheck_fd(2) any no
34
* __acl_delete_fd(2) any no
35
* __acl_get_fd(2) any no
36
* __acl_set_fd(2) any no
37
* aio_fsync(2) any no
38
* aio_read(2) O_RDONLY or O_RDWR yes
39
* aio_write(2) O_WRONLY or O_RDWR yes
40
* dup(2) any yes
41
* dup2(2) any yes
42
* extattr_delete_fd(2) O_WRONLY or O_RDWR no
43
* extattr_get_fd(2) O_RDONLY or O_RDWR no
44
* extattr_list_fd(2) O_RDONLY or O_RDWR no
45
* extattr_set_fd(2) O_WRONLY or O_RDWR no
46
* fchdir(2) any directory yes
47
* fchflags(2) any yes
48
* fchmod(2) any yes
49
* fchown(2) any yes
50
* flock(2) any yes
51
* fpathconf(2) any yes
52
* fstat(2) any yes
53
* fstatfs(2) any yes
54
* fsync(2) any yes
55
* ftruncate(2) O_WRONLY or O_RDWR yes
56
* futimes(2) any yes
57
* getdents(2) O_RDONLY directory yes
58
* lseek(2) any yes
59
* mmap(2) PROT_READ O_RDONLY or O_RDWR yes
60
* mmap(2) PROT_WRITE O_WRONLY or O_RDWR yes
61
* mmap(2) PROT_WRITE + MAP_PRIV O_RDONLY or O_RDWR yes
62
* mmap(2) PROT_EXEC O_RDONLY or O_RDWR yes
63
* pread(2) O_RDONLY or O_RDWR yes
64
* preadv(2) O_RDONLY or O_RDWR yes
65
* pwrite(2) O_WRONLY or O_RDWR yes
66
* pwritev(2) O_WRONLY or O_RDWR yes
67
* read(2) O_RDONLY or O_RDWR yes
68
* readv(2) O_RDONLY or O_RDWR yes
69
* sendfile(2) O_RDONLY or O_RDWR on file yes
70
* write(2) O_WRONLY or O_RDWR yes
71
* writev(2) O_WRONLY or O_RDWR yes
72
*
73
* These checks do not verify that original permissions would allow the
74
* operation or that open is properly impacted by permissions, just that once
75
* a file descriptor is held, open-time limitations are implemented.
76
*
77
* We do, however, test that directories cannot be opened as writable.
78
*
79
* XXXRW: Arguably we should also test combinations of bits to mmap(2).
80
*
81
* XXXRW: Should verify mprotect() remapping limits.
82
*
83
* XXXRW: kqueue(2)/kevent(2), poll(2), select(2)
84
*
85
* XXXRW: oaio_read(2), oaio_write(2), freebsd6_*(2).
86
*
87
* XXXRW: __mac*(2)
88
*
89
* XXXRW: message queue and shared memory fds?
90
*/
91
92
#include <sys/param.h>
93
#include <sys/mman.h>
94
#include <sys/mount.h>
95
#include <sys/socket.h>
96
#include <sys/stat.h>
97
#include <sys/sysctl.h>
98
#include <sys/uio.h>
99
100
#include <aio.h>
101
#include <dirent.h>
102
#include <err.h>
103
#include <errno.h>
104
#include <fcntl.h>
105
#include <limits.h>
106
#include <stdio.h>
107
#include <stdlib.h>
108
#include <string.h>
109
#include <unistd.h>
110
111
#define PERM_FILE 0644 /* Allow read, write. Someday exec? */
112
#define PERM_DIR 0755 /* Allow read, write, exec. */
113
114
/*
115
* Modes to try all tests with.
116
*/
117
static const int file_modes[] = { O_RDONLY, O_WRONLY, O_RDWR,
118
O_RDONLY | O_TRUNC, O_WRONLY | O_TRUNC, O_RDWR | O_TRUNC };
119
static const int file_modes_count = nitems(file_modes);
120
121
static const int dir_modes[] = { O_RDONLY };
122
static const int dir_modes_count = nitems(dir_modes);
123
124
static int testnum;
125
static int aio_present;
126
127
static void
128
ok_mode(const char *testname, const char *comment, int mode)
129
{
130
131
testnum++;
132
if (comment == NULL)
133
printf("ok %d - %s # mode 0x%x\n", testnum, testname, mode);
134
else
135
printf("ok %d - %s # mode 0x%x - %s\n", testnum, testname,
136
mode, comment);
137
}
138
139
static void
140
notok_mode(const char *testname, const char *comment, int mode)
141
{
142
143
testnum++;
144
if (comment == NULL)
145
printf("not ok %d - %s # mode 0x%x\n", testnum, testname,
146
mode);
147
else
148
printf("not ok %d - %s # mode 0x%x - %s\n", testnum, testname,
149
mode, comment);
150
}
151
152
/*
153
* Before we get started, confirm that we can't open directories writable.
154
*/
155
static void
156
try_directory_open(const char *testname, const char *directory,
157
int mode, int expected_errno)
158
{
159
int dfd;
160
161
dfd = open(directory, mode);
162
if (dfd >= 0) {
163
if (expected_errno)
164
notok_mode(testname, "opened", mode);
165
else
166
ok_mode(testname, NULL, mode);
167
close(dfd);
168
} else {
169
if (expected_errno && expected_errno == errno)
170
ok_mode(testname, NULL, mode);
171
else if (expected_errno != 0)
172
notok_mode(testname, "wrong errno", mode);
173
else
174
notok_mode(testname, "failed", mode);
175
}
176
}
177
178
static void
179
check_directory_open_modes(const char *directory, const int *modes,
180
int modes_count)
181
{
182
int expected_errno, i, mode;
183
184
/*
185
* Directories should only open with O_RDONLY. Notice that we use
186
* file_modes and not dirmodes.
187
*/
188
for (i = 0; i < modes_count; i++) {
189
mode = modes[i];
190
if (mode == O_RDONLY)
191
expected_errno = 0;
192
else
193
expected_errno = EISDIR;
194
try_directory_open(__func__, directory, mode,
195
expected_errno);
196
}
197
}
198
199
static void
200
check_dup(const char *testname, const char *path, const int *modes,
201
int modes_count)
202
{
203
int dfd, fd, i, mode;
204
205
/*
206
* dup() should work regardless of open mode.
207
*/
208
for (i = 0; i < modes_count; i++) {
209
mode = modes[i];
210
fd = open(path, mode);
211
if (fd < 0) {
212
notok_mode(testname, "open", mode);
213
continue;
214
}
215
dfd = dup(fd);
216
if (dfd >= 0) {
217
ok_mode(testname, NULL, mode);
218
close(dfd);
219
} else
220
notok_mode(testname, NULL, mode);
221
close(fd);
222
}
223
}
224
225
static void
226
check_dup2(const char *testname, const char *path, const int *modes,
227
int modes_count)
228
{
229
int dfd, fd, i, mode;
230
231
/*
232
* dup2() should work regardless of open mode.
233
*/
234
for (i = 0; i < modes_count; i++) {
235
mode = modes[i];
236
fd = open(path, mode);
237
if (fd < 0) {
238
notok_mode(testname, "open", mode);
239
continue;
240
}
241
dfd = dup2(fd, 500); /* Arbitrary but high number. */
242
if (dfd >= 0) {
243
ok_mode(testname, NULL, mode);
244
close(dfd);
245
} else
246
notok_mode(testname, NULL, mode);
247
close(fd);
248
}
249
}
250
251
static void
252
check_fchdir(const char *testname, const char *path, const int *modes,
253
int modes_count)
254
{
255
int fd, i, mode;
256
257
/*
258
* fchdir() should work regardless of open mode.
259
*/
260
for (i = 0; i < modes_count; i++) {
261
mode = modes[i];
262
fd = open(path, mode);
263
if (fd < 0) {
264
notok_mode(testname, "open", mode);
265
continue;
266
}
267
if (fchdir(fd) == 0)
268
ok_mode(testname, NULL, mode);
269
else
270
notok_mode(testname, "failed", mode);
271
close(fd);
272
}
273
}
274
275
static void
276
check_fchflags(const char *testname, const char *path, const int *modes,
277
int modes_count)
278
{
279
int fd, i, mode;
280
281
/*
282
* fchflags() should work regardless of open mode.
283
*/
284
for (i = 0; i < modes_count; i++) {
285
mode = modes[i];
286
fd = open(path, mode);
287
if (fd < 0) {
288
notok_mode(testname, "open", mode);
289
continue;
290
}
291
if (fchflags(fd, UF_NODUMP) == 0)
292
ok_mode(testname, NULL, mode);
293
else
294
notok_mode(testname, "failed", mode);
295
close(fd);
296
}
297
}
298
299
static void
300
check_fchmod(const char *testname, const char *path, int setmode,
301
const int *modes, int modes_count)
302
{
303
int fd, i, mode;
304
305
/*
306
* fchmod() should work regardless of open mode.
307
*/
308
for (i = 0; i < modes_count; i++) {
309
mode = modes[i];
310
fd = open(path, mode);
311
if (fd < 0) {
312
notok_mode(testname, "open", mode);
313
continue;
314
}
315
if (fchmod(fd, setmode) == 0)
316
ok_mode(testname, NULL, mode);
317
else
318
notok_mode(testname, "failed", mode);
319
close(fd);
320
}
321
}
322
323
static void
324
check_fchown(const char *testname, const char *path, const int *modes,
325
int modes_count)
326
{
327
int fd, i, mode;
328
329
/*
330
* fchown() should work regardless of open mode.
331
*/
332
for (i = 0; i < modes_count; i++) {
333
mode = modes[i];
334
fd = open(path, mode);
335
if (fd < 0) {
336
notok_mode(testname, "open", mode);
337
continue;
338
}
339
if (fchown(fd, -1, -1) == 0)
340
ok_mode(testname, NULL, mode);
341
else
342
notok_mode(testname, "failed", mode);
343
close(fd);
344
}
345
}
346
347
static void
348
check_flock(const char *testname, const char *path, const int *modes,
349
int modes_count)
350
{
351
int fd, i, mode;
352
353
/*
354
* flock() should work regardless of open mode.
355
*/
356
for (i = 0; i < modes_count; i++) {
357
mode = modes[i];
358
fd = open(path, mode);
359
if (fd < 0) {
360
notok_mode(testname, "open", mode);
361
continue;
362
}
363
if (flock(fd, LOCK_EX) == 0)
364
ok_mode(testname, NULL, mode);
365
else
366
notok_mode(testname, "failed", mode);
367
close(fd);
368
}
369
}
370
371
static void
372
check_fpathconf(const char *testname, const char *path, const int *modes,
373
int modes_count)
374
{
375
int fd, i, mode;
376
long l;
377
378
/*
379
* fpathconf() should work regardless of open mode.
380
*/
381
for (i = 0; i < modes_count; i++) {
382
mode = modes[i];
383
fd = open(path, mode);
384
if (fd < 0) {
385
notok_mode(testname, "open", mode);
386
continue;
387
}
388
l = fpathconf(fd, _PC_FILESIZEBITS);
389
if (l >= 0)
390
ok_mode(testname, NULL, mode);
391
else
392
notok_mode(testname, "failed", mode);
393
close(fd);
394
}
395
}
396
397
static void
398
check_fstat(const char *testname, const char *path, const int *modes,
399
int modes_count)
400
{
401
struct stat sb;
402
int fd, i, mode;
403
404
/*
405
* fstat() should work regardless of open mode.
406
*/
407
for (i = 0; i < modes_count; i++) {
408
mode = modes[i];
409
fd = open(path, mode);
410
if (fd < 0) {
411
notok_mode(testname, "open", mode);
412
continue;
413
}
414
if (fstat(fd, &sb) == 0)
415
ok_mode(testname, NULL, mode);
416
else
417
notok_mode(testname, "failed", mode);
418
close(fd);
419
}
420
}
421
422
static void
423
check_fstatfs(const char *testname, const char *path, const int *modes,
424
int modes_count)
425
{
426
struct statfs statfs;
427
int fd, i, mode;
428
429
/*
430
* fstatfs() should work regardless of open mode.
431
*/
432
for (i = 0; i < modes_count; i++) {
433
mode = modes[i];
434
fd = open(path, mode);
435
if (fd < 0) {
436
notok_mode(testname, "open", mode);
437
continue;
438
}
439
if (fstatfs(fd, &statfs) == 0)
440
ok_mode(testname, NULL, mode);
441
else
442
notok_mode(testname, "failed", mode);
443
close(fd);
444
}
445
}
446
447
static void
448
check_fsync(const char *testname, const char *path, const int *modes,
449
int modes_count)
450
{
451
int fd, i, mode;
452
453
/*
454
* fstatfs() should work regardless of open mode.
455
*/
456
for (i = 0; i < modes_count; i++) {
457
mode = modes[i];
458
fd = open(path, mode);
459
if (fd < 0) {
460
notok_mode(testname, "open", mode);
461
continue;
462
}
463
if (fsync(fd) == 0)
464
ok_mode(testname, NULL, mode);
465
else
466
notok_mode(testname, "failed", mode);
467
close(fd);
468
}
469
}
470
471
static void
472
check_ftruncate(const char *testname, const char *path, const int *modes,
473
int modes_count)
474
{
475
struct stat sb;
476
int fd, i, mode;
477
478
/*
479
* ftruncate() should work as long as long as (mode & O_ACCMODE) is
480
* O_RDWR or O_WRONLY.
481
*
482
* Directories should never be writable, so this test should always
483
* pass for directories...
484
*/
485
for (i = 0; i < modes_count; i++) {
486
mode = modes[i];
487
fd = open(path, mode);
488
if (fd < 0) {
489
notok_mode(testname, "open", mode);
490
notok_mode(testname, "truncate1 skipped", mode);
491
notok_mode(testname, "truncate2 skipped", mode);
492
notok_mode(testname, "truncate3 skipped", mode);
493
continue;
494
}
495
if (fstat(fd, &sb) < 0) {
496
notok_mode(testname, "fstat", mode);
497
notok_mode(testname, "truncate1 skipped", mode);
498
notok_mode(testname, "truncate2 skipped", mode);
499
notok_mode(testname, "truncate3 skipped", mode);
500
close(fd);
501
continue;
502
}
503
ok_mode(testname, "setup", mode);
504
505
/* Truncate to grow file. */
506
if (ftruncate(fd, sb.st_size + 1) == 0) {
507
if (((mode & O_ACCMODE) == O_WRONLY) ||
508
((mode & O_ACCMODE) == O_RDWR))
509
ok_mode(testname, "truncate1 succeeded",
510
mode);
511
else {
512
notok_mode(testname, "truncate1 succeeded",
513
mode);
514
notok_mode(testname, "truncate2 skipped",
515
mode);
516
notok_mode(testname, "truncate3 skipped",
517
mode);
518
close(fd);
519
continue;
520
}
521
} else {
522
if (((mode & O_ACCMODE) == O_WRONLY) ||
523
((mode & O_ACCMODE) == O_RDWR)) {
524
notok_mode(testname, "truncate1 failed",
525
mode);
526
notok_mode(testname, "truncate2 skipped",
527
mode);
528
notok_mode(testname, "truncate3 skipped",
529
mode);
530
close(fd);
531
continue;
532
} else
533
ok_mode(testname, "truncate1 failed", mode);
534
}
535
536
/* Truncate to same size. */
537
if (ftruncate(fd, sb.st_size + 1) == 0) {
538
if (((mode & O_ACCMODE) == O_WRONLY) ||
539
((mode & O_ACCMODE) == O_RDWR))
540
ok_mode(testname, "truncate2 succeeded",
541
mode);
542
else {
543
notok_mode(testname, "truncate2 succeeded",
544
mode);
545
notok_mode(testname, "truncate3 skipped",
546
mode);
547
close(fd);
548
continue;
549
}
550
} else {
551
if (((mode & O_ACCMODE) == O_WRONLY) ||
552
((mode & O_ACCMODE) == O_RDWR)) {
553
notok_mode(testname, "truncate2 failed",
554
mode);
555
notok_mode(testname, "truncate3 skipped",
556
mode);
557
close(fd);
558
continue;
559
} else
560
ok_mode(testname, "truncate2 failed", mode);
561
}
562
563
/* Truncate to shrink. */
564
if (ftruncate(fd, sb.st_size) == 0) {
565
if (((mode & O_ACCMODE) == O_WRONLY) ||
566
((mode & O_ACCMODE) == O_RDWR))
567
ok_mode(testname, "truncate3 succeeded",
568
mode);
569
else
570
notok_mode(testname, "truncate3 succeeded",
571
mode);
572
} else {
573
if (((mode & O_ACCMODE) == O_WRONLY) ||
574
((mode & O_ACCMODE) == O_RDWR))
575
notok_mode(testname, "truncate3 failed",
576
mode);
577
else
578
ok_mode(testname, "truncate3 failed", mode);
579
}
580
close(fd);
581
}
582
}
583
584
static void
585
check_futimes(const char *testname, const char *path, const int *modes,
586
int modes_count)
587
{
588
int fd, i, mode;
589
590
/*
591
* futimes() should work regardless of open mode.
592
*/
593
for (i = 0; i < modes_count; i++) {
594
mode = modes[i];
595
fd = open(path, mode);
596
if (fd < 0) {
597
notok_mode(testname, "open", mode);
598
continue;
599
}
600
if (futimes(fd, NULL) == 0)
601
ok_mode(testname, NULL, mode);
602
else
603
notok_mode(testname, "failed", mode);
604
close(fd);
605
}
606
}
607
608
static void
609
check_lseek(const char *testname, const char *path, const int *modes,
610
int modes_count)
611
{
612
int fd, i, mode;
613
614
/*
615
* lseek() should work regardless of open mode.
616
*/
617
for (i = 0; i < modes_count; i++) {
618
mode = modes[i];
619
fd = open(path, mode);
620
if (fd < 0) {
621
notok_mode(testname, "open", mode);
622
continue;
623
}
624
if (lseek(fd, 100, SEEK_SET) == 100)
625
ok_mode(testname, NULL, mode);
626
else
627
notok_mode(testname, "failed", mode);
628
close(fd);
629
}
630
}
631
632
static void
633
check_getdents(const char *testname, const char *path, int isdir,
634
const int *modes, int modes_count)
635
{
636
int fd, i, mode;
637
char buf[8192];
638
639
/*
640
* getdents() should always work on directories and never on files,
641
* assuming directories are always opened for read (which they are).
642
*/
643
for (i = 0; i < modes_count; i++) {
644
mode = modes[i];
645
fd = open(path, mode);
646
if (fd < 0) {
647
notok_mode(testname, "open", mode);
648
continue;
649
}
650
if (getdents(fd, buf, sizeof(buf)) >= 0) {
651
if (isdir && ((mode & O_ACCMODE) == O_RDONLY))
652
ok_mode(testname, "directory succeeded",
653
mode);
654
else if (isdir)
655
notok_mode(testname, "directory succeeded",
656
mode);
657
else
658
notok_mode(testname, "file succeeded", mode);
659
} else {
660
if (isdir && ((mode & O_ACCMODE) == O_RDONLY))
661
notok_mode(testname, "directory failed",
662
mode);
663
else if (isdir)
664
ok_mode(testname, "directory failed", mode);
665
else
666
ok_mode(testname, "file failed", mode);
667
}
668
close(fd);
669
}
670
}
671
672
static void
673
check_sendfile(const char *testname, const char *path, int isdir,
674
const int *modes, int modes_count)
675
{
676
int fd, i, mode, sv[2];
677
off_t sent;
678
679
/*
680
* sendfile() should work only on files, and only when the access mode
681
* is O_RDONLY or O_RDWR.
682
*/
683
for (i = 0; i < modes_count; i++) {
684
mode = modes[i];
685
fd = open(path, mode);
686
if (fd < 0) {
687
notok_mode(testname, "open", mode);
688
continue;
689
}
690
if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sv) < 0) {
691
notok_mode(testname, "socketpair", mode);
692
continue;
693
}
694
if (sendfile(fd, sv[0], 0, 1, NULL, &sent, 0) == 0) {
695
if (isdir)
696
notok_mode(testname, "directory succeeded",
697
mode);
698
else if (((mode & O_ACCMODE) == O_RDONLY) ||
699
((mode & O_ACCMODE) == O_RDWR))
700
ok_mode(testname, "succeeded", mode);
701
else
702
notok_mode(testname, "succeeded", mode);
703
} else {
704
if (isdir)
705
ok_mode(testname, "directory failed", mode);
706
else if (((mode & O_ACCMODE) == O_RDONLY) ||
707
((mode & O_ACCMODE) == O_RDWR))
708
notok_mode(testname, "failed", mode);
709
else
710
ok_mode(testname, "failed", mode);
711
}
712
close(sv[0]);
713
close(sv[1]);
714
close(fd);
715
}
716
}
717
718
/*
719
* Various functions write, so just make write-like wrappers for them.
720
*/
721
typedef ssize_t (*write_fn)(int d, const void *buf, size_t nbytes);
722
723
static ssize_t
724
writev_wrapper(int d, const void *buf, size_t nbytes)
725
{
726
struct iovec iov;
727
728
iov.iov_base = (void *)buf;
729
iov.iov_len = nbytes;
730
return (writev(d, &iov, 1));
731
}
732
733
static ssize_t
734
pwrite_wrapper(int d, const void *buf, size_t nbytes)
735
{
736
737
return (pwrite(d, buf, nbytes, 0));
738
}
739
740
static ssize_t
741
pwritev_wrapper(int d, const void *buf, size_t nbytes)
742
{
743
struct iovec iov;
744
745
iov.iov_base = (void *)buf;
746
iov.iov_len = nbytes;
747
return (pwritev(d, &iov, 1, 0));
748
}
749
750
static ssize_t
751
aio_write_wrapper(int d, const void *buf, size_t nbytes)
752
{
753
struct aiocb aiocb;
754
struct aiocb const *aiocb_array[] = { &aiocb };
755
756
bzero(&aiocb, sizeof(aiocb));
757
aiocb.aio_fildes = d;
758
aiocb.aio_buf = (void *)buf;
759
aiocb.aio_nbytes = nbytes;
760
if (aio_write(&aiocb) < 0)
761
return (-1);
762
aiocb_array[0] = &aiocb;
763
if (aio_suspend(aiocb_array, 1, NULL) < 0)
764
return (-1);
765
return (aio_return(&aiocb));
766
}
767
768
static void
769
check_write(const char *testname, write_fn fn, const char *path,
770
const int *modes, int modes_count)
771
{
772
int fd, i, mode;
773
char ch;
774
775
/*
776
* write() should never succeed for directories, but especially
777
* because they can only be opened read-only. write() on files
778
* should succeed for O_WRONLY and O_RDWR descriptors.
779
*/
780
781
for (i = 0; i < modes_count; i++) {
782
mode = modes[i];
783
fd = open(path, mode);
784
if (fd < 0) {
785
notok_mode(testname, "open", mode);
786
continue;
787
}
788
if (fn(fd, &ch, sizeof(ch)) < 0) {
789
if ((mode & O_ACCMODE) == O_WRONLY ||
790
(mode & O_ACCMODE) == O_RDWR)
791
notok_mode(testname, "write failed", mode);
792
else
793
ok_mode(testname, "write failed", mode);
794
} else {
795
if (!((mode & O_ACCMODE) == O_WRONLY ||
796
(mode & O_ACCMODE) == O_RDWR))
797
notok_mode(testname, "write succeeded", mode);
798
else
799
ok_mode(testname, "write succeeded", mode);
800
}
801
close(fd);
802
}
803
}
804
805
/*
806
* Various functions read, so just make read-like wrappers for them.
807
*/
808
typedef ssize_t (*read_fn)(int d, void *buf, size_t nbytes);
809
810
static ssize_t
811
readv_wrapper(int d, void *buf, size_t nbytes)
812
{
813
struct iovec iov;
814
815
iov.iov_base = buf;
816
iov.iov_len = nbytes;
817
return (readv(d, &iov, 1));
818
}
819
820
static ssize_t
821
pread_wrapper(int d, void *buf, size_t nbytes)
822
{
823
824
return (pread(d, buf, nbytes, 0));
825
}
826
827
static ssize_t
828
preadv_wrapper(int d, void *buf, size_t nbytes)
829
{
830
struct iovec iov;
831
832
iov.iov_base = buf;
833
iov.iov_len = nbytes;
834
return (preadv(d, &iov, 1, 0));
835
}
836
837
static ssize_t
838
aio_read_wrapper(int d, void *buf, size_t nbytes)
839
{
840
struct aiocb aiocb;
841
struct aiocb const *aiocb_array[] = { &aiocb };
842
843
bzero(&aiocb, sizeof(aiocb));
844
aiocb.aio_fildes = d;
845
aiocb.aio_buf = buf;
846
aiocb.aio_nbytes = nbytes;
847
if (aio_read(&aiocb) < 0)
848
return (-1);
849
if (aio_suspend(aiocb_array, 1, NULL) < 0)
850
return (-1);
851
return (aio_return(&aiocb));
852
}
853
854
static void
855
check_read(const char *testname, read_fn fn, const char *path,
856
const int *modes, int modes_count)
857
{
858
int fd, i, mode;
859
char ch;
860
861
/*
862
* read() should (generally) succeeded on directories. read() on
863
* files should succeed for O_RDONLY and O_RDWR descriptors.
864
*/
865
for (i = 0; i < modes_count; i++) {
866
mode = modes[i];
867
fd = open(path, mode);
868
if (fd < 0) {
869
notok_mode(testname, "open", mode);
870
continue;
871
}
872
if (fn(fd, &ch, sizeof(ch)) < 0) {
873
if ((mode & O_ACCMODE) == O_RDONLY ||
874
(mode & O_ACCMODE) == O_RDWR)
875
notok_mode(testname, "read failed", mode);
876
else
877
ok_mode(testname, "read failed", mode);
878
} else {
879
if (!((mode & O_ACCMODE) == O_RDONLY ||
880
(mode & O_ACCMODE) == O_RDWR))
881
notok_mode(testname, "read succeeded", mode);
882
else
883
ok_mode(testname, "read succeeded", mode);
884
}
885
close(fd);
886
}
887
}
888
889
static void
890
check_mmap_read(const char *testname, const char *path, int isdir,
891
const int *modes, int modes_count)
892
{
893
int fd, i, mode;
894
char *addr;
895
896
/*
897
* mmap() read should fail for directories (ideally?) but succeed for
898
* O_RDONLY and O_RDWR file descriptors.
899
*/
900
for (i = 0; i < modes_count; i++) {
901
mode = modes[i];
902
fd = open(path, mode);
903
if (fd < 0) {
904
notok_mode(testname, "open", mode);
905
continue;
906
}
907
addr = mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, fd,
908
0);
909
if (addr == MAP_FAILED) {
910
if (isdir)
911
ok_mode(testname, "mmap dir failed", mode);
912
else if ((mode & O_ACCMODE) == O_RDONLY ||
913
(mode & O_ACCMODE) == O_RDWR)
914
notok_mode(testname, "mmap file failed",
915
mode);
916
else
917
ok_mode(testname, "mmap file failed", mode);
918
} else {
919
if (isdir)
920
notok_mode(testname, "mmap dir succeeded",
921
mode);
922
else if ((mode & O_ACCMODE) == O_RDONLY ||
923
(mode & O_ACCMODE) == O_RDWR)
924
ok_mode(testname, "mmap file succeeded",
925
mode);
926
else
927
notok_mode(testname, "mmap file succeeded",
928
mode);
929
(void)munmap(addr, getpagesize());
930
}
931
close(fd);
932
}
933
}
934
935
static void
936
check_mmap_write(const char *testname, const char *path, const int *modes,
937
int modes_count)
938
{
939
int fd, i, mode;
940
char *addr;
941
942
/*
943
* mmap() will always fail for directories (ideally) as they are
944
* always open O_RDONLY. Check for O_WRONLY or O_RDWR to permit a
945
* write mapping. This variant does a MAP_SHARED mapping, but we
946
* are also interested in MAP_PRIVATE.
947
*/
948
for (i = 0; i < modes_count; i++) {
949
mode = modes[i];
950
fd = open(path, mode);
951
if (fd < 0) {
952
notok_mode(testname, "open", mode);
953
continue;
954
}
955
addr = mmap(NULL, getpagesize(), PROT_WRITE, MAP_SHARED, fd,
956
0);
957
if (addr == MAP_FAILED) {
958
if ((mode & O_ACCMODE) == O_WRONLY ||
959
(mode & O_ACCMODE) == O_RDWR)
960
notok_mode(testname, "mmap failed",
961
mode);
962
else
963
ok_mode(testname, "mmap failed", mode);
964
} else {
965
if ((mode & O_ACCMODE) == O_WRONLY ||
966
(mode & O_ACCMODE) == O_RDWR)
967
ok_mode(testname, "mmap succeeded",
968
mode);
969
else
970
notok_mode(testname, "mmap succeeded", mode);
971
(void)munmap(addr, getpagesize());
972
}
973
close(fd);
974
}
975
}
976
977
static void
978
check_mmap_exec(const char *testname, const char *path, int isdir,
979
const int *modes, int modes_count)
980
{
981
int fd, i, mode;
982
char *addr;
983
984
/*
985
* mmap() exec should fail for directories (ideally?) but succeed for
986
* O_RDONLY and O_RDWR file descriptors.
987
*/
988
for (i = 0; i < modes_count; i++) {
989
mode = modes[i];
990
fd = open(path, mode);
991
if (fd < 0) {
992
notok_mode(testname, "open", mode);
993
continue;
994
}
995
addr = mmap(NULL, getpagesize(), PROT_EXEC, MAP_SHARED, fd,
996
0);
997
if (addr == MAP_FAILED) {
998
if (isdir)
999
ok_mode(testname, "mmap dir failed", mode);
1000
else if ((mode & O_ACCMODE) == O_RDONLY ||
1001
(mode & O_ACCMODE) == O_RDWR)
1002
notok_mode(testname, "mmap file failed",
1003
mode);
1004
else
1005
ok_mode(testname, "mmap file failed", mode);
1006
} else {
1007
if (isdir)
1008
notok_mode(testname, "mmap dir succeeded",
1009
mode);
1010
else
1011
ok_mode(testname, "mmap file succeeded",
1012
mode);
1013
(void)munmap(addr, getpagesize());
1014
}
1015
close(fd);
1016
}
1017
}
1018
1019
static void
1020
check_mmap_write_private(const char *testname, const char *path, int isdir,
1021
const int *modes, int modes_count)
1022
{
1023
int fd, i, mode;
1024
char *addr;
1025
1026
/*
1027
* mmap() write private should succeed for readable descriptors
1028
* except for directories.
1029
*/
1030
for (i = 0; i < modes_count; i++) {
1031
mode = modes[i];
1032
fd = open(path, mode);
1033
if (fd < 0) {
1034
notok_mode(testname, "open", mode);
1035
continue;
1036
}
1037
addr = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE,
1038
MAP_PRIVATE, fd, 0);
1039
if (addr == MAP_FAILED) {
1040
if (isdir)
1041
ok_mode(testname, "mmap dir failed", mode);
1042
else if ((mode & O_ACCMODE) == O_RDONLY ||
1043
(mode & O_ACCMODE) == O_RDWR)
1044
notok_mode(testname, "mmap file failed",
1045
mode);
1046
else
1047
ok_mode(testname, "mmap file failed", mode);
1048
} else {
1049
if (isdir)
1050
notok_mode(testname, "mmap dir succeeded",
1051
mode);
1052
else if ((mode & O_ACCMODE) == O_RDONLY ||
1053
(mode & O_ACCMODE) == O_RDWR)
1054
ok_mode(testname, "mmap file succeeded",
1055
mode);
1056
else
1057
notok_mode(testname, "mmap file succeeded",
1058
mode);
1059
(void)munmap(addr, getpagesize());
1060
}
1061
close(fd);
1062
}
1063
}
1064
1065
int
1066
main(void)
1067
{
1068
char dir_path[PATH_MAX], file_path[PATH_MAX];
1069
int dummy, fd;
1070
size_t size;
1071
1072
aio_present = 0;
1073
size = sizeof(dummy);
1074
if (sysctlbyname("vfs.aio", &dummy, &size, NULL, 0) < 0) {
1075
if (errno == EISDIR)
1076
aio_present = 1;
1077
}
1078
1079
strlcpy(dir_path, "/tmp/open-dir.XXXXXXXXXXX", sizeof(dir_path));
1080
if (mkdtemp(dir_path) == NULL)
1081
err(1, "mkdtemp");
1082
if (chmod(dir_path, PERM_DIR) < 0) {
1083
warn("chmod %s", dir_path);
1084
(void)rmdir(dir_path);
1085
exit(1);
1086
}
1087
strlcpy(file_path, "/tmp/open-file.XXXXXXXXXXX", sizeof(file_path));
1088
fd = mkstemp(file_path);
1089
if (fd < 0) {
1090
warn("mkstemp");
1091
(void)rmdir(dir_path);
1092
exit(1);
1093
}
1094
close(fd);
1095
if (chmod(file_path, PERM_FILE) < 0) {
1096
warn("chmod %s", file_path);
1097
(void)unlink(file_path);
1098
(void)rmdir(dir_path);
1099
exit(1);
1100
}
1101
check_directory_open_modes(dir_path, file_modes, file_modes_count);
1102
1103
check_dup("check_dup_dir", dir_path, dir_modes, dir_modes_count);
1104
check_dup("check_dup_file", file_path, file_modes, file_modes_count);
1105
1106
check_dup2("check_dup2_dir", dir_path, dir_modes, dir_modes_count);
1107
check_dup2("check_dup2_file", file_path, file_modes,
1108
file_modes_count);
1109
1110
check_fchdir("check_fchdir", dir_path, dir_modes, dir_modes_count);
1111
1112
check_fchflags("check_fchflags_dir", dir_path, dir_modes,
1113
dir_modes_count);
1114
check_fchflags("check_fchflags_file", file_path, file_modes,
1115
file_modes_count);
1116
1117
check_fchmod("check_fchmod_dir", dir_path, PERM_DIR, dir_modes,
1118
dir_modes_count);
1119
check_fchmod("check_fchmod_file", file_path, PERM_FILE, file_modes,
1120
file_modes_count);
1121
1122
check_fchown("check_fchown_dir", dir_path, dir_modes,
1123
dir_modes_count);
1124
check_fchown("check_fchown_file", file_path, file_modes,
1125
file_modes_count);
1126
1127
check_flock("check_flock_dir", dir_path, dir_modes, dir_modes_count);
1128
check_flock("check_flock_file", file_path, file_modes,
1129
file_modes_count);
1130
1131
check_fpathconf("check_fpathconf_dir", dir_path, dir_modes,
1132
dir_modes_count);
1133
check_fpathconf("check_fpathconf_file", file_path, file_modes,
1134
file_modes_count);
1135
1136
check_fstat("check_fstat_dir", dir_path, dir_modes, dir_modes_count);
1137
check_fstat("check_fstat_file", file_path, file_modes,
1138
file_modes_count);
1139
1140
check_fstatfs("check_fstatfs_dir", dir_path, dir_modes,
1141
dir_modes_count);
1142
check_fstatfs("check_fstatfs_file", file_path, file_modes,
1143
file_modes_count);
1144
1145
check_fsync("check_fsync_dir", dir_path, dir_modes, dir_modes_count);
1146
check_fsync("check_fsync_file", file_path, file_modes,
1147
file_modes_count);
1148
1149
check_ftruncate("check_ftruncate_dir", dir_path, dir_modes,
1150
dir_modes_count);
1151
check_ftruncate("check_ftruncate_file", file_path, file_modes,
1152
file_modes_count);
1153
1154
check_futimes("check_futimes_dir", dir_path, dir_modes,
1155
dir_modes_count);
1156
check_futimes("check_futimes_file", file_path, file_modes,
1157
file_modes_count);
1158
1159
check_lseek("check_lseek_dir", dir_path, dir_modes, dir_modes_count);
1160
check_lseek("check_lseek_file", file_path, file_modes,
1161
file_modes_count);
1162
1163
check_getdents("check_getdents_dir", dir_path, 1, dir_modes,
1164
dir_modes_count);
1165
check_getdents("check_getdents_file", file_path, 0, file_modes,
1166
file_modes_count);
1167
1168
check_sendfile("check_sendfile_dir", dir_path, 1, dir_modes,
1169
dir_modes_count);
1170
check_sendfile("check_sendfile_file", file_path, 0, file_modes,
1171
file_modes_count);
1172
1173
check_write("check_write_dir", write, dir_path, dir_modes,
1174
dir_modes_count);
1175
check_write("check_write_file", write, file_path, file_modes,
1176
file_modes_count);
1177
1178
check_write("check_writev_dir", writev_wrapper, dir_path, dir_modes,
1179
dir_modes_count);
1180
check_write("check_writev_file", writev_wrapper, file_path,
1181
file_modes, file_modes_count);
1182
1183
check_write("check_pwrite_dir", pwrite_wrapper, dir_path, dir_modes,
1184
dir_modes_count);
1185
check_write("check_pwrite_file", pwrite_wrapper, file_path,
1186
file_modes, file_modes_count);
1187
1188
check_write("check_pwritev_dir", pwritev_wrapper, dir_path,
1189
dir_modes, dir_modes_count);
1190
check_write("check_pwritev_file", pwritev_wrapper, file_path,
1191
file_modes, file_modes_count);
1192
1193
if (aio_present) {
1194
check_write("check_aio_write_dir", aio_write_wrapper,
1195
dir_path, dir_modes, dir_modes_count);
1196
check_write("check_aio_write_file", aio_write_wrapper,
1197
file_path, file_modes, file_modes_count);
1198
}
1199
1200
check_read("check_read_dir", read, dir_path, dir_modes,
1201
dir_modes_count);
1202
check_read("check_read_file", read, file_path, file_modes,
1203
file_modes_count);
1204
1205
check_read("check_readv_dir", readv_wrapper, dir_path, dir_modes,
1206
dir_modes_count);
1207
check_read("check_readv_file", readv_wrapper, file_path,
1208
file_modes, file_modes_count);
1209
1210
check_read("check_pread_dir", pread_wrapper, dir_path, dir_modes,
1211
dir_modes_count);
1212
check_read("check_pread_file", pread_wrapper, file_path,
1213
file_modes, file_modes_count);
1214
1215
check_read("check_preadv_dir", preadv_wrapper, dir_path,
1216
dir_modes, dir_modes_count);
1217
check_read("check_preadv_file", preadv_wrapper, file_path,
1218
file_modes, file_modes_count);
1219
1220
if (aio_present) {
1221
check_read("check_aio_read_dir", aio_read_wrapper, dir_path,
1222
dir_modes, dir_modes_count);
1223
check_read("check_aio_read_file", aio_read_wrapper,
1224
file_path, file_modes, file_modes_count);
1225
}
1226
1227
check_mmap_read("check_mmap_read_dir", dir_path, 1, dir_modes,
1228
dir_modes_count);
1229
check_mmap_read("check_mmap_read_file", file_path, 0, file_modes,
1230
file_modes_count);
1231
1232
check_mmap_write("check_mmap_write_dir", dir_path, dir_modes,
1233
dir_modes_count);
1234
check_mmap_write("check_mmap_write_file", file_path, file_modes,
1235
file_modes_count);
1236
1237
check_mmap_exec("check_mmap_exec_dir", dir_path, 1, dir_modes,
1238
dir_modes_count);
1239
check_mmap_exec("check_mmap_exec_file", file_path, 0, file_modes,
1240
file_modes_count);
1241
1242
check_mmap_write_private("check_mmap_write_private_dir", dir_path, 1,
1243
dir_modes, dir_modes_count);
1244
check_mmap_write_private("check_mmap_write_private_file", file_path,
1245
0, file_modes, file_modes_count);
1246
1247
(void)unlink(file_path);
1248
(void)rmdir(dir_path);
1249
exit(0);
1250
}
1251
1252