Path: blob/main/tools/regression/security/open_to_operation/open_to_operation.c
48266 views
/*-1* Copyright (c) 2008 Robert N. M. Watson2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526/*-27* This regression test attempts to confirm that the flags used at open-time28* for a file descriptor properly limit system calls that should be affected29* by those flags. Currently:30*31* System call Policy Tested32* __acl_aclcheck_fd(2) any no33* __acl_delete_fd(2) any no34* __acl_get_fd(2) any no35* __acl_set_fd(2) any no36* aio_fsync(2) any no37* aio_read(2) O_RDONLY or O_RDWR yes38* aio_write(2) O_WRONLY or O_RDWR yes39* dup(2) any yes40* dup2(2) any yes41* extattr_delete_fd(2) O_WRONLY or O_RDWR no42* extattr_get_fd(2) O_RDONLY or O_RDWR no43* extattr_list_fd(2) O_RDONLY or O_RDWR no44* extattr_set_fd(2) O_WRONLY or O_RDWR no45* fchdir(2) any directory yes46* fchflags(2) any yes47* fchmod(2) any yes48* fchown(2) any yes49* flock(2) any yes50* fpathconf(2) any yes51* fstat(2) any yes52* fstatfs(2) any yes53* fsync(2) any yes54* ftruncate(2) O_WRONLY or O_RDWR yes55* futimes(2) any yes56* getdents(2) O_RDONLY directory yes57* lseek(2) any yes58* mmap(2) PROT_READ O_RDONLY or O_RDWR yes59* mmap(2) PROT_WRITE O_WRONLY or O_RDWR yes60* mmap(2) PROT_WRITE + MAP_PRIV O_RDONLY or O_RDWR yes61* mmap(2) PROT_EXEC O_RDONLY or O_RDWR yes62* pread(2) O_RDONLY or O_RDWR yes63* preadv(2) O_RDONLY or O_RDWR yes64* pwrite(2) O_WRONLY or O_RDWR yes65* pwritev(2) O_WRONLY or O_RDWR yes66* read(2) O_RDONLY or O_RDWR yes67* readv(2) O_RDONLY or O_RDWR yes68* sendfile(2) O_RDONLY or O_RDWR on file yes69* write(2) O_WRONLY or O_RDWR yes70* writev(2) O_WRONLY or O_RDWR yes71*72* These checks do not verify that original permissions would allow the73* operation or that open is properly impacted by permissions, just that once74* a file descriptor is held, open-time limitations are implemented.75*76* We do, however, test that directories cannot be opened as writable.77*78* XXXRW: Arguably we should also test combinations of bits to mmap(2).79*80* XXXRW: Should verify mprotect() remapping limits.81*82* XXXRW: kqueue(2)/kevent(2), poll(2), select(2)83*84* XXXRW: oaio_read(2), oaio_write(2), freebsd6_*(2).85*86* XXXRW: __mac*(2)87*88* XXXRW: message queue and shared memory fds?89*/9091#include <sys/param.h>92#include <sys/mman.h>93#include <sys/mount.h>94#include <sys/socket.h>95#include <sys/stat.h>96#include <sys/sysctl.h>97#include <sys/uio.h>9899#include <aio.h>100#include <dirent.h>101#include <err.h>102#include <errno.h>103#include <fcntl.h>104#include <limits.h>105#include <stdio.h>106#include <stdlib.h>107#include <string.h>108#include <unistd.h>109110#define PERM_FILE 0644 /* Allow read, write. Someday exec? */111#define PERM_DIR 0755 /* Allow read, write, exec. */112113/*114* Modes to try all tests with.115*/116static const int file_modes[] = { O_RDONLY, O_WRONLY, O_RDWR,117O_RDONLY | O_TRUNC, O_WRONLY | O_TRUNC, O_RDWR | O_TRUNC };118static const int file_modes_count = nitems(file_modes);119120static const int dir_modes[] = { O_RDONLY };121static const int dir_modes_count = nitems(dir_modes);122123static int testnum;124static int aio_present;125126static void127ok_mode(const char *testname, const char *comment, int mode)128{129130testnum++;131if (comment == NULL)132printf("ok %d - %s # mode 0x%x\n", testnum, testname, mode);133else134printf("ok %d - %s # mode 0x%x - %s\n", testnum, testname,135mode, comment);136}137138static void139notok_mode(const char *testname, const char *comment, int mode)140{141142testnum++;143if (comment == NULL)144printf("not ok %d - %s # mode 0x%x\n", testnum, testname,145mode);146else147printf("not ok %d - %s # mode 0x%x - %s\n", testnum, testname,148mode, comment);149}150151/*152* Before we get started, confirm that we can't open directories writable.153*/154static void155try_directory_open(const char *testname, const char *directory,156int mode, int expected_errno)157{158int dfd;159160dfd = open(directory, mode);161if (dfd >= 0) {162if (expected_errno)163notok_mode(testname, "opened", mode);164else165ok_mode(testname, NULL, mode);166close(dfd);167} else {168if (expected_errno && expected_errno == errno)169ok_mode(testname, NULL, mode);170else if (expected_errno != 0)171notok_mode(testname, "wrong errno", mode);172else173notok_mode(testname, "failed", mode);174}175}176177static void178check_directory_open_modes(const char *directory, const int *modes,179int modes_count)180{181int expected_errno, i, mode;182183/*184* Directories should only open with O_RDONLY. Notice that we use185* file_modes and not dirmodes.186*/187for (i = 0; i < modes_count; i++) {188mode = modes[i];189if (mode == O_RDONLY)190expected_errno = 0;191else192expected_errno = EISDIR;193try_directory_open(__func__, directory, mode,194expected_errno);195}196}197198static void199check_dup(const char *testname, const char *path, const int *modes,200int modes_count)201{202int dfd, fd, i, mode;203204/*205* dup() should work regardless of open mode.206*/207for (i = 0; i < modes_count; i++) {208mode = modes[i];209fd = open(path, mode);210if (fd < 0) {211notok_mode(testname, "open", mode);212continue;213}214dfd = dup(fd);215if (dfd >= 0) {216ok_mode(testname, NULL, mode);217close(dfd);218} else219notok_mode(testname, NULL, mode);220close(fd);221}222}223224static void225check_dup2(const char *testname, const char *path, const int *modes,226int modes_count)227{228int dfd, fd, i, mode;229230/*231* dup2() should work regardless of open mode.232*/233for (i = 0; i < modes_count; i++) {234mode = modes[i];235fd = open(path, mode);236if (fd < 0) {237notok_mode(testname, "open", mode);238continue;239}240dfd = dup2(fd, 500); /* Arbitrary but high number. */241if (dfd >= 0) {242ok_mode(testname, NULL, mode);243close(dfd);244} else245notok_mode(testname, NULL, mode);246close(fd);247}248}249250static void251check_fchdir(const char *testname, const char *path, const int *modes,252int modes_count)253{254int fd, i, mode;255256/*257* fchdir() should work regardless of open mode.258*/259for (i = 0; i < modes_count; i++) {260mode = modes[i];261fd = open(path, mode);262if (fd < 0) {263notok_mode(testname, "open", mode);264continue;265}266if (fchdir(fd) == 0)267ok_mode(testname, NULL, mode);268else269notok_mode(testname, "failed", mode);270close(fd);271}272}273274static void275check_fchflags(const char *testname, const char *path, const int *modes,276int modes_count)277{278int fd, i, mode;279280/*281* fchflags() should work regardless of open mode.282*/283for (i = 0; i < modes_count; i++) {284mode = modes[i];285fd = open(path, mode);286if (fd < 0) {287notok_mode(testname, "open", mode);288continue;289}290if (fchflags(fd, UF_NODUMP) == 0)291ok_mode(testname, NULL, mode);292else293notok_mode(testname, "failed", mode);294close(fd);295}296}297298static void299check_fchmod(const char *testname, const char *path, int setmode,300const int *modes, int modes_count)301{302int fd, i, mode;303304/*305* fchmod() should work regardless of open mode.306*/307for (i = 0; i < modes_count; i++) {308mode = modes[i];309fd = open(path, mode);310if (fd < 0) {311notok_mode(testname, "open", mode);312continue;313}314if (fchmod(fd, setmode) == 0)315ok_mode(testname, NULL, mode);316else317notok_mode(testname, "failed", mode);318close(fd);319}320}321322static void323check_fchown(const char *testname, const char *path, const int *modes,324int modes_count)325{326int fd, i, mode;327328/*329* fchown() should work regardless of open mode.330*/331for (i = 0; i < modes_count; i++) {332mode = modes[i];333fd = open(path, mode);334if (fd < 0) {335notok_mode(testname, "open", mode);336continue;337}338if (fchown(fd, -1, -1) == 0)339ok_mode(testname, NULL, mode);340else341notok_mode(testname, "failed", mode);342close(fd);343}344}345346static void347check_flock(const char *testname, const char *path, const int *modes,348int modes_count)349{350int fd, i, mode;351352/*353* flock() should work regardless of open mode.354*/355for (i = 0; i < modes_count; i++) {356mode = modes[i];357fd = open(path, mode);358if (fd < 0) {359notok_mode(testname, "open", mode);360continue;361}362if (flock(fd, LOCK_EX) == 0)363ok_mode(testname, NULL, mode);364else365notok_mode(testname, "failed", mode);366close(fd);367}368}369370static void371check_fpathconf(const char *testname, const char *path, const int *modes,372int modes_count)373{374int fd, i, mode;375long l;376377/*378* fpathconf() should work regardless of open mode.379*/380for (i = 0; i < modes_count; i++) {381mode = modes[i];382fd = open(path, mode);383if (fd < 0) {384notok_mode(testname, "open", mode);385continue;386}387l = fpathconf(fd, _PC_FILESIZEBITS);388if (l >= 0)389ok_mode(testname, NULL, mode);390else391notok_mode(testname, "failed", mode);392close(fd);393}394}395396static void397check_fstat(const char *testname, const char *path, const int *modes,398int modes_count)399{400struct stat sb;401int fd, i, mode;402403/*404* fstat() should work regardless of open mode.405*/406for (i = 0; i < modes_count; i++) {407mode = modes[i];408fd = open(path, mode);409if (fd < 0) {410notok_mode(testname, "open", mode);411continue;412}413if (fstat(fd, &sb) == 0)414ok_mode(testname, NULL, mode);415else416notok_mode(testname, "failed", mode);417close(fd);418}419}420421static void422check_fstatfs(const char *testname, const char *path, const int *modes,423int modes_count)424{425struct statfs statfs;426int fd, i, mode;427428/*429* fstatfs() should work regardless of open mode.430*/431for (i = 0; i < modes_count; i++) {432mode = modes[i];433fd = open(path, mode);434if (fd < 0) {435notok_mode(testname, "open", mode);436continue;437}438if (fstatfs(fd, &statfs) == 0)439ok_mode(testname, NULL, mode);440else441notok_mode(testname, "failed", mode);442close(fd);443}444}445446static void447check_fsync(const char *testname, const char *path, const int *modes,448int modes_count)449{450int fd, i, mode;451452/*453* fstatfs() should work regardless of open mode.454*/455for (i = 0; i < modes_count; i++) {456mode = modes[i];457fd = open(path, mode);458if (fd < 0) {459notok_mode(testname, "open", mode);460continue;461}462if (fsync(fd) == 0)463ok_mode(testname, NULL, mode);464else465notok_mode(testname, "failed", mode);466close(fd);467}468}469470static void471check_ftruncate(const char *testname, const char *path, const int *modes,472int modes_count)473{474struct stat sb;475int fd, i, mode;476477/*478* ftruncate() should work as long as long as (mode & O_ACCMODE) is479* O_RDWR or O_WRONLY.480*481* Directories should never be writable, so this test should always482* pass for directories...483*/484for (i = 0; i < modes_count; i++) {485mode = modes[i];486fd = open(path, mode);487if (fd < 0) {488notok_mode(testname, "open", mode);489notok_mode(testname, "truncate1 skipped", mode);490notok_mode(testname, "truncate2 skipped", mode);491notok_mode(testname, "truncate3 skipped", mode);492continue;493}494if (fstat(fd, &sb) < 0) {495notok_mode(testname, "fstat", mode);496notok_mode(testname, "truncate1 skipped", mode);497notok_mode(testname, "truncate2 skipped", mode);498notok_mode(testname, "truncate3 skipped", mode);499close(fd);500continue;501}502ok_mode(testname, "setup", mode);503504/* Truncate to grow file. */505if (ftruncate(fd, sb.st_size + 1) == 0) {506if (((mode & O_ACCMODE) == O_WRONLY) ||507((mode & O_ACCMODE) == O_RDWR))508ok_mode(testname, "truncate1 succeeded",509mode);510else {511notok_mode(testname, "truncate1 succeeded",512mode);513notok_mode(testname, "truncate2 skipped",514mode);515notok_mode(testname, "truncate3 skipped",516mode);517close(fd);518continue;519}520} else {521if (((mode & O_ACCMODE) == O_WRONLY) ||522((mode & O_ACCMODE) == O_RDWR)) {523notok_mode(testname, "truncate1 failed",524mode);525notok_mode(testname, "truncate2 skipped",526mode);527notok_mode(testname, "truncate3 skipped",528mode);529close(fd);530continue;531} else532ok_mode(testname, "truncate1 failed", mode);533}534535/* Truncate to same size. */536if (ftruncate(fd, sb.st_size + 1) == 0) {537if (((mode & O_ACCMODE) == O_WRONLY) ||538((mode & O_ACCMODE) == O_RDWR))539ok_mode(testname, "truncate2 succeeded",540mode);541else {542notok_mode(testname, "truncate2 succeeded",543mode);544notok_mode(testname, "truncate3 skipped",545mode);546close(fd);547continue;548}549} else {550if (((mode & O_ACCMODE) == O_WRONLY) ||551((mode & O_ACCMODE) == O_RDWR)) {552notok_mode(testname, "truncate2 failed",553mode);554notok_mode(testname, "truncate3 skipped",555mode);556close(fd);557continue;558} else559ok_mode(testname, "truncate2 failed", mode);560}561562/* Truncate to shrink. */563if (ftruncate(fd, sb.st_size) == 0) {564if (((mode & O_ACCMODE) == O_WRONLY) ||565((mode & O_ACCMODE) == O_RDWR))566ok_mode(testname, "truncate3 succeeded",567mode);568else569notok_mode(testname, "truncate3 succeeded",570mode);571} else {572if (((mode & O_ACCMODE) == O_WRONLY) ||573((mode & O_ACCMODE) == O_RDWR))574notok_mode(testname, "truncate3 failed",575mode);576else577ok_mode(testname, "truncate3 failed", mode);578}579close(fd);580}581}582583static void584check_futimes(const char *testname, const char *path, const int *modes,585int modes_count)586{587int fd, i, mode;588589/*590* futimes() should work regardless of open mode.591*/592for (i = 0; i < modes_count; i++) {593mode = modes[i];594fd = open(path, mode);595if (fd < 0) {596notok_mode(testname, "open", mode);597continue;598}599if (futimes(fd, NULL) == 0)600ok_mode(testname, NULL, mode);601else602notok_mode(testname, "failed", mode);603close(fd);604}605}606607static void608check_lseek(const char *testname, const char *path, const int *modes,609int modes_count)610{611int fd, i, mode;612613/*614* lseek() should work regardless of open mode.615*/616for (i = 0; i < modes_count; i++) {617mode = modes[i];618fd = open(path, mode);619if (fd < 0) {620notok_mode(testname, "open", mode);621continue;622}623if (lseek(fd, 100, SEEK_SET) == 100)624ok_mode(testname, NULL, mode);625else626notok_mode(testname, "failed", mode);627close(fd);628}629}630631static void632check_getdents(const char *testname, const char *path, int isdir,633const int *modes, int modes_count)634{635int fd, i, mode;636char buf[8192];637638/*639* getdents() should always work on directories and never on files,640* assuming directories are always opened for read (which they are).641*/642for (i = 0; i < modes_count; i++) {643mode = modes[i];644fd = open(path, mode);645if (fd < 0) {646notok_mode(testname, "open", mode);647continue;648}649if (getdents(fd, buf, sizeof(buf)) >= 0) {650if (isdir && ((mode & O_ACCMODE) == O_RDONLY))651ok_mode(testname, "directory succeeded",652mode);653else if (isdir)654notok_mode(testname, "directory succeeded",655mode);656else657notok_mode(testname, "file succeeded", mode);658} else {659if (isdir && ((mode & O_ACCMODE) == O_RDONLY))660notok_mode(testname, "directory failed",661mode);662else if (isdir)663ok_mode(testname, "directory failed", mode);664else665ok_mode(testname, "file failed", mode);666}667close(fd);668}669}670671static void672check_sendfile(const char *testname, const char *path, int isdir,673const int *modes, int modes_count)674{675int fd, i, mode, sv[2];676off_t sent;677678/*679* sendfile() should work only on files, and only when the access mode680* is O_RDONLY or O_RDWR.681*/682for (i = 0; i < modes_count; i++) {683mode = modes[i];684fd = open(path, mode);685if (fd < 0) {686notok_mode(testname, "open", mode);687continue;688}689if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sv) < 0) {690notok_mode(testname, "socketpair", mode);691continue;692}693if (sendfile(fd, sv[0], 0, 1, NULL, &sent, 0) == 0) {694if (isdir)695notok_mode(testname, "directory succeeded",696mode);697else if (((mode & O_ACCMODE) == O_RDONLY) ||698((mode & O_ACCMODE) == O_RDWR))699ok_mode(testname, "succeeded", mode);700else701notok_mode(testname, "succeeded", mode);702} else {703if (isdir)704ok_mode(testname, "directory failed", mode);705else if (((mode & O_ACCMODE) == O_RDONLY) ||706((mode & O_ACCMODE) == O_RDWR))707notok_mode(testname, "failed", mode);708else709ok_mode(testname, "failed", mode);710}711close(sv[0]);712close(sv[1]);713close(fd);714}715}716717/*718* Various functions write, so just make write-like wrappers for them.719*/720typedef ssize_t (*write_fn)(int d, const void *buf, size_t nbytes);721722static ssize_t723writev_wrapper(int d, const void *buf, size_t nbytes)724{725struct iovec iov;726727iov.iov_base = (void *)buf;728iov.iov_len = nbytes;729return (writev(d, &iov, 1));730}731732static ssize_t733pwrite_wrapper(int d, const void *buf, size_t nbytes)734{735736return (pwrite(d, buf, nbytes, 0));737}738739static ssize_t740pwritev_wrapper(int d, const void *buf, size_t nbytes)741{742struct iovec iov;743744iov.iov_base = (void *)buf;745iov.iov_len = nbytes;746return (pwritev(d, &iov, 1, 0));747}748749static ssize_t750aio_write_wrapper(int d, const void *buf, size_t nbytes)751{752struct aiocb aiocb;753struct aiocb const *aiocb_array[] = { &aiocb };754755bzero(&aiocb, sizeof(aiocb));756aiocb.aio_fildes = d;757aiocb.aio_buf = (void *)buf;758aiocb.aio_nbytes = nbytes;759if (aio_write(&aiocb) < 0)760return (-1);761aiocb_array[0] = &aiocb;762if (aio_suspend(aiocb_array, 1, NULL) < 0)763return (-1);764return (aio_return(&aiocb));765}766767static void768check_write(const char *testname, write_fn fn, const char *path,769const int *modes, int modes_count)770{771int fd, i, mode;772char ch;773774/*775* write() should never succeed for directories, but especially776* because they can only be opened read-only. write() on files777* should succeed for O_WRONLY and O_RDWR descriptors.778*/779780for (i = 0; i < modes_count; i++) {781mode = modes[i];782fd = open(path, mode);783if (fd < 0) {784notok_mode(testname, "open", mode);785continue;786}787if (fn(fd, &ch, sizeof(ch)) < 0) {788if ((mode & O_ACCMODE) == O_WRONLY ||789(mode & O_ACCMODE) == O_RDWR)790notok_mode(testname, "write failed", mode);791else792ok_mode(testname, "write failed", mode);793} else {794if (!((mode & O_ACCMODE) == O_WRONLY ||795(mode & O_ACCMODE) == O_RDWR))796notok_mode(testname, "write succeeded", mode);797else798ok_mode(testname, "write succeeded", mode);799}800close(fd);801}802}803804/*805* Various functions read, so just make read-like wrappers for them.806*/807typedef ssize_t (*read_fn)(int d, void *buf, size_t nbytes);808809static ssize_t810readv_wrapper(int d, void *buf, size_t nbytes)811{812struct iovec iov;813814iov.iov_base = buf;815iov.iov_len = nbytes;816return (readv(d, &iov, 1));817}818819static ssize_t820pread_wrapper(int d, void *buf, size_t nbytes)821{822823return (pread(d, buf, nbytes, 0));824}825826static ssize_t827preadv_wrapper(int d, void *buf, size_t nbytes)828{829struct iovec iov;830831iov.iov_base = buf;832iov.iov_len = nbytes;833return (preadv(d, &iov, 1, 0));834}835836static ssize_t837aio_read_wrapper(int d, void *buf, size_t nbytes)838{839struct aiocb aiocb;840struct aiocb const *aiocb_array[] = { &aiocb };841842bzero(&aiocb, sizeof(aiocb));843aiocb.aio_fildes = d;844aiocb.aio_buf = buf;845aiocb.aio_nbytes = nbytes;846if (aio_read(&aiocb) < 0)847return (-1);848if (aio_suspend(aiocb_array, 1, NULL) < 0)849return (-1);850return (aio_return(&aiocb));851}852853static void854check_read(const char *testname, read_fn fn, const char *path,855const int *modes, int modes_count)856{857int fd, i, mode;858char ch;859860/*861* read() should (generally) succeeded on directories. read() on862* files should succeed for O_RDONLY and O_RDWR descriptors.863*/864for (i = 0; i < modes_count; i++) {865mode = modes[i];866fd = open(path, mode);867if (fd < 0) {868notok_mode(testname, "open", mode);869continue;870}871if (fn(fd, &ch, sizeof(ch)) < 0) {872if ((mode & O_ACCMODE) == O_RDONLY ||873(mode & O_ACCMODE) == O_RDWR)874notok_mode(testname, "read failed", mode);875else876ok_mode(testname, "read failed", mode);877} else {878if (!((mode & O_ACCMODE) == O_RDONLY ||879(mode & O_ACCMODE) == O_RDWR))880notok_mode(testname, "read succeeded", mode);881else882ok_mode(testname, "read succeeded", mode);883}884close(fd);885}886}887888static void889check_mmap_read(const char *testname, const char *path, int isdir,890const int *modes, int modes_count)891{892int fd, i, mode;893char *addr;894895/*896* mmap() read should fail for directories (ideally?) but succeed for897* O_RDONLY and O_RDWR file descriptors.898*/899for (i = 0; i < modes_count; i++) {900mode = modes[i];901fd = open(path, mode);902if (fd < 0) {903notok_mode(testname, "open", mode);904continue;905}906addr = mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, fd,9070);908if (addr == MAP_FAILED) {909if (isdir)910ok_mode(testname, "mmap dir failed", mode);911else if ((mode & O_ACCMODE) == O_RDONLY ||912(mode & O_ACCMODE) == O_RDWR)913notok_mode(testname, "mmap file failed",914mode);915else916ok_mode(testname, "mmap file failed", mode);917} else {918if (isdir)919notok_mode(testname, "mmap dir succeeded",920mode);921else if ((mode & O_ACCMODE) == O_RDONLY ||922(mode & O_ACCMODE) == O_RDWR)923ok_mode(testname, "mmap file succeeded",924mode);925else926notok_mode(testname, "mmap file succeeded",927mode);928(void)munmap(addr, getpagesize());929}930close(fd);931}932}933934static void935check_mmap_write(const char *testname, const char *path, const int *modes,936int modes_count)937{938int fd, i, mode;939char *addr;940941/*942* mmap() will always fail for directories (ideally) as they are943* always open O_RDONLY. Check for O_WRONLY or O_RDWR to permit a944* write mapping. This variant does a MAP_SHARED mapping, but we945* are also interested in MAP_PRIVATE.946*/947for (i = 0; i < modes_count; i++) {948mode = modes[i];949fd = open(path, mode);950if (fd < 0) {951notok_mode(testname, "open", mode);952continue;953}954addr = mmap(NULL, getpagesize(), PROT_WRITE, MAP_SHARED, fd,9550);956if (addr == MAP_FAILED) {957if ((mode & O_ACCMODE) == O_WRONLY ||958(mode & O_ACCMODE) == O_RDWR)959notok_mode(testname, "mmap failed",960mode);961else962ok_mode(testname, "mmap failed", mode);963} else {964if ((mode & O_ACCMODE) == O_WRONLY ||965(mode & O_ACCMODE) == O_RDWR)966ok_mode(testname, "mmap succeeded",967mode);968else969notok_mode(testname, "mmap succeeded", mode);970(void)munmap(addr, getpagesize());971}972close(fd);973}974}975976static void977check_mmap_exec(const char *testname, const char *path, int isdir,978const int *modes, int modes_count)979{980int fd, i, mode;981char *addr;982983/*984* mmap() exec should fail for directories (ideally?) but succeed for985* O_RDONLY and O_RDWR file descriptors.986*/987for (i = 0; i < modes_count; i++) {988mode = modes[i];989fd = open(path, mode);990if (fd < 0) {991notok_mode(testname, "open", mode);992continue;993}994addr = mmap(NULL, getpagesize(), PROT_EXEC, MAP_SHARED, fd,9950);996if (addr == MAP_FAILED) {997if (isdir)998ok_mode(testname, "mmap dir failed", mode);999else if ((mode & O_ACCMODE) == O_RDONLY ||1000(mode & O_ACCMODE) == O_RDWR)1001notok_mode(testname, "mmap file failed",1002mode);1003else1004ok_mode(testname, "mmap file failed", mode);1005} else {1006if (isdir)1007notok_mode(testname, "mmap dir succeeded",1008mode);1009else1010ok_mode(testname, "mmap file succeeded",1011mode);1012(void)munmap(addr, getpagesize());1013}1014close(fd);1015}1016}10171018static void1019check_mmap_write_private(const char *testname, const char *path, int isdir,1020const int *modes, int modes_count)1021{1022int fd, i, mode;1023char *addr;10241025/*1026* mmap() write private should succeed for readable descriptors1027* except for directories.1028*/1029for (i = 0; i < modes_count; i++) {1030mode = modes[i];1031fd = open(path, mode);1032if (fd < 0) {1033notok_mode(testname, "open", mode);1034continue;1035}1036addr = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE,1037MAP_PRIVATE, fd, 0);1038if (addr == MAP_FAILED) {1039if (isdir)1040ok_mode(testname, "mmap dir failed", mode);1041else if ((mode & O_ACCMODE) == O_RDONLY ||1042(mode & O_ACCMODE) == O_RDWR)1043notok_mode(testname, "mmap file failed",1044mode);1045else1046ok_mode(testname, "mmap file failed", mode);1047} else {1048if (isdir)1049notok_mode(testname, "mmap dir succeeded",1050mode);1051else if ((mode & O_ACCMODE) == O_RDONLY ||1052(mode & O_ACCMODE) == O_RDWR)1053ok_mode(testname, "mmap file succeeded",1054mode);1055else1056notok_mode(testname, "mmap file succeeded",1057mode);1058(void)munmap(addr, getpagesize());1059}1060close(fd);1061}1062}10631064int1065main(void)1066{1067char dir_path[PATH_MAX], file_path[PATH_MAX];1068int dummy, fd;1069size_t size;10701071aio_present = 0;1072size = sizeof(dummy);1073if (sysctlbyname("vfs.aio", &dummy, &size, NULL, 0) < 0) {1074if (errno == EISDIR)1075aio_present = 1;1076}10771078strlcpy(dir_path, "/tmp/open-dir.XXXXXXXXXXX", sizeof(dir_path));1079if (mkdtemp(dir_path) == NULL)1080err(1, "mkdtemp");1081if (chmod(dir_path, PERM_DIR) < 0) {1082warn("chmod %s", dir_path);1083(void)rmdir(dir_path);1084exit(1);1085}1086strlcpy(file_path, "/tmp/open-file.XXXXXXXXXXX", sizeof(file_path));1087fd = mkstemp(file_path);1088if (fd < 0) {1089warn("mkstemp");1090(void)rmdir(dir_path);1091exit(1);1092}1093close(fd);1094if (chmod(file_path, PERM_FILE) < 0) {1095warn("chmod %s", file_path);1096(void)unlink(file_path);1097(void)rmdir(dir_path);1098exit(1);1099}1100check_directory_open_modes(dir_path, file_modes, file_modes_count);11011102check_dup("check_dup_dir", dir_path, dir_modes, dir_modes_count);1103check_dup("check_dup_file", file_path, file_modes, file_modes_count);11041105check_dup2("check_dup2_dir", dir_path, dir_modes, dir_modes_count);1106check_dup2("check_dup2_file", file_path, file_modes,1107file_modes_count);11081109check_fchdir("check_fchdir", dir_path, dir_modes, dir_modes_count);11101111check_fchflags("check_fchflags_dir", dir_path, dir_modes,1112dir_modes_count);1113check_fchflags("check_fchflags_file", file_path, file_modes,1114file_modes_count);11151116check_fchmod("check_fchmod_dir", dir_path, PERM_DIR, dir_modes,1117dir_modes_count);1118check_fchmod("check_fchmod_file", file_path, PERM_FILE, file_modes,1119file_modes_count);11201121check_fchown("check_fchown_dir", dir_path, dir_modes,1122dir_modes_count);1123check_fchown("check_fchown_file", file_path, file_modes,1124file_modes_count);11251126check_flock("check_flock_dir", dir_path, dir_modes, dir_modes_count);1127check_flock("check_flock_file", file_path, file_modes,1128file_modes_count);11291130check_fpathconf("check_fpathconf_dir", dir_path, dir_modes,1131dir_modes_count);1132check_fpathconf("check_fpathconf_file", file_path, file_modes,1133file_modes_count);11341135check_fstat("check_fstat_dir", dir_path, dir_modes, dir_modes_count);1136check_fstat("check_fstat_file", file_path, file_modes,1137file_modes_count);11381139check_fstatfs("check_fstatfs_dir", dir_path, dir_modes,1140dir_modes_count);1141check_fstatfs("check_fstatfs_file", file_path, file_modes,1142file_modes_count);11431144check_fsync("check_fsync_dir", dir_path, dir_modes, dir_modes_count);1145check_fsync("check_fsync_file", file_path, file_modes,1146file_modes_count);11471148check_ftruncate("check_ftruncate_dir", dir_path, dir_modes,1149dir_modes_count);1150check_ftruncate("check_ftruncate_file", file_path, file_modes,1151file_modes_count);11521153check_futimes("check_futimes_dir", dir_path, dir_modes,1154dir_modes_count);1155check_futimes("check_futimes_file", file_path, file_modes,1156file_modes_count);11571158check_lseek("check_lseek_dir", dir_path, dir_modes, dir_modes_count);1159check_lseek("check_lseek_file", file_path, file_modes,1160file_modes_count);11611162check_getdents("check_getdents_dir", dir_path, 1, dir_modes,1163dir_modes_count);1164check_getdents("check_getdents_file", file_path, 0, file_modes,1165file_modes_count);11661167check_sendfile("check_sendfile_dir", dir_path, 1, dir_modes,1168dir_modes_count);1169check_sendfile("check_sendfile_file", file_path, 0, file_modes,1170file_modes_count);11711172check_write("check_write_dir", write, dir_path, dir_modes,1173dir_modes_count);1174check_write("check_write_file", write, file_path, file_modes,1175file_modes_count);11761177check_write("check_writev_dir", writev_wrapper, dir_path, dir_modes,1178dir_modes_count);1179check_write("check_writev_file", writev_wrapper, file_path,1180file_modes, file_modes_count);11811182check_write("check_pwrite_dir", pwrite_wrapper, dir_path, dir_modes,1183dir_modes_count);1184check_write("check_pwrite_file", pwrite_wrapper, file_path,1185file_modes, file_modes_count);11861187check_write("check_pwritev_dir", pwritev_wrapper, dir_path,1188dir_modes, dir_modes_count);1189check_write("check_pwritev_file", pwritev_wrapper, file_path,1190file_modes, file_modes_count);11911192if (aio_present) {1193check_write("check_aio_write_dir", aio_write_wrapper,1194dir_path, dir_modes, dir_modes_count);1195check_write("check_aio_write_file", aio_write_wrapper,1196file_path, file_modes, file_modes_count);1197}11981199check_read("check_read_dir", read, dir_path, dir_modes,1200dir_modes_count);1201check_read("check_read_file", read, file_path, file_modes,1202file_modes_count);12031204check_read("check_readv_dir", readv_wrapper, dir_path, dir_modes,1205dir_modes_count);1206check_read("check_readv_file", readv_wrapper, file_path,1207file_modes, file_modes_count);12081209check_read("check_pread_dir", pread_wrapper, dir_path, dir_modes,1210dir_modes_count);1211check_read("check_pread_file", pread_wrapper, file_path,1212file_modes, file_modes_count);12131214check_read("check_preadv_dir", preadv_wrapper, dir_path,1215dir_modes, dir_modes_count);1216check_read("check_preadv_file", preadv_wrapper, file_path,1217file_modes, file_modes_count);12181219if (aio_present) {1220check_read("check_aio_read_dir", aio_read_wrapper, dir_path,1221dir_modes, dir_modes_count);1222check_read("check_aio_read_file", aio_read_wrapper,1223file_path, file_modes, file_modes_count);1224}12251226check_mmap_read("check_mmap_read_dir", dir_path, 1, dir_modes,1227dir_modes_count);1228check_mmap_read("check_mmap_read_file", file_path, 0, file_modes,1229file_modes_count);12301231check_mmap_write("check_mmap_write_dir", dir_path, dir_modes,1232dir_modes_count);1233check_mmap_write("check_mmap_write_file", file_path, file_modes,1234file_modes_count);12351236check_mmap_exec("check_mmap_exec_dir", dir_path, 1, dir_modes,1237dir_modes_count);1238check_mmap_exec("check_mmap_exec_file", file_path, 0, file_modes,1239file_modes_count);12401241check_mmap_write_private("check_mmap_write_private_dir", dir_path, 1,1242dir_modes, dir_modes_count);1243check_mmap_write_private("check_mmap_write_private_file", file_path,12440, file_modes, file_modes_count);12451246(void)unlink(file_path);1247(void)rmdir(dir_path);1248exit(0);1249}125012511252