|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | +/* |
| 3 | + * Copyright (c) International Business Machines Corp., 2006 |
| 4 | + * Copyright (c) Linux Test Project, 2007-2024 |
| 5 | + */ |
| 6 | + |
| 7 | +/*\ |
| 8 | + * [Description] |
| 9 | + * |
| 10 | + * Verify that, |
| 11 | + * - fchownat() returns -1 and sets errno to EACCES if there is no permission |
| 12 | + to access to the file. |
| 13 | + * - fchownat() returns -1 and sets errno to EBADF if the file descriptor |
| 14 | + * of the specified file is not valid. |
| 15 | + * - fchownat() returns -1 and sets errno to EFAULT if the filename points |
| 16 | + outside of accessable address space. |
| 17 | + * - fchownat() returns -1 and sets errno to EINVAL if the flag is invalid. |
| 18 | + * - fchownat() returns -1 and sets errno to ELOOP if too many symbolic links |
| 19 | + * were encountered in resolving filename. |
| 20 | + * - fchownat() returns -1 and sets errno to ENAMETOOLONG if the filename is |
| 21 | + too long. |
| 22 | + * - fchownat() returns -1 and sets errno to ENOENT if the specified file does |
| 23 | + * not exist. |
| 24 | + * - fchownat() returns -1 and sets errno to ENOTDIR if the file descriptor is |
| 25 | + * a file. |
| 26 | + * - fchownat() returns -1 and sets errno to EPERM if the effective user id |
| 27 | + * of process does not match the owner of the file and the process is not |
| 28 | + * super user. |
| 29 | + * - fchownat() returns -1 and sets errno to EROFS if the file is readonly. |
| 30 | + */ |
| 31 | + |
| 32 | +#define _GNU_SOURCE |
| 33 | +#include <pwd.h> |
| 34 | +#include "tst_test.h" |
| 35 | + |
| 36 | +#define TESTFILE "testfile" |
| 37 | +#define TESTFILE_EACCESS_DIR "eaccess" |
| 38 | +#define TESTFILE_EACCESS TESTFILE_EACCESS_DIR"/eaccess" |
| 39 | +#define TESTFILE_ELOOP "testfile_eloop" |
| 40 | +#define TESTFILE_ENOENT "/tmp/does/not/exist" |
| 41 | +#define TESTFILE_EPERM "/dev/null" |
| 42 | +#define TESTFILE_EROFS_MNT "ro_mntpoint" |
| 43 | +#define TESTFILE_EROFS TESTFILE_EROFS_MNT"/file" |
| 44 | + |
| 45 | +static int file_fd = -1; |
| 46 | +static int no_fd = -1; |
| 47 | +static int dir_fd = -1; |
| 48 | + |
| 49 | +static char *file_eaccess; |
| 50 | +static char *file_ebadf; |
| 51 | +static char *file_efault; |
| 52 | +static char *file_einval; |
| 53 | +static char *file_eloop; |
| 54 | +static char *file_enametoolong; |
| 55 | +static char *file_enoent; |
| 56 | +static char *file_enotdir; |
| 57 | +static char *file_eperm; |
| 58 | +static char *file_erofs; |
| 59 | + |
| 60 | +static struct tcase { |
| 61 | + char **filename; |
| 62 | + char *desc; |
| 63 | + int *fd; |
| 64 | + int flag; |
| 65 | + int exp_errno; |
| 66 | +} tcases[] = { |
| 67 | + {&file_eaccess, TESTFILE_EACCESS, &dir_fd, 0, EACCES}, |
| 68 | + {&file_ebadf, TESTFILE, &no_fd, 0, EBADF}, |
| 69 | + {&file_efault, "Invalid address", &dir_fd, 0, EFAULT}, |
| 70 | + {&file_einval, TESTFILE, &dir_fd, 9999, EINVAL}, |
| 71 | + {&file_eloop, TESTFILE_ELOOP, &dir_fd, 0, ELOOP}, |
| 72 | + {&file_enametoolong, "aaaa...", &dir_fd, 0, ENAMETOOLONG}, |
| 73 | + {&file_enoent, TESTFILE_ENOENT, &dir_fd, 0, ENOENT}, |
| 74 | + {&file_enotdir, TESTFILE, &file_fd, 0, ENOTDIR}, |
| 75 | + {&file_eperm, TESTFILE_EPERM, &dir_fd, 0, EPERM}, |
| 76 | + {&file_erofs, TESTFILE_EROFS, &dir_fd, 0, EROFS}, |
| 77 | +}; |
| 78 | + |
| 79 | +static void fchownat_verify(unsigned int n) |
| 80 | +{ |
| 81 | + uid_t euid = geteuid(); |
| 82 | + gid_t egid = getegid(); |
| 83 | + |
| 84 | + TST_EXP_FAIL(fchownat(*tcases[n].fd, *tcases[n].filename, euid, egid, tcases[n].flag), |
| 85 | + tcases[n].exp_errno, |
| 86 | + "fchownat(%d, %s, %d, %d, %d)", |
| 87 | + *tcases[n].fd, tcases[n].desc, euid, egid, tcases[n].flag); |
| 88 | +} |
| 89 | + |
| 90 | +static void setup(void) |
| 91 | +{ |
| 92 | + struct passwd *ltpuser; |
| 93 | + |
| 94 | + SAFE_TOUCH(TESTFILE, 0600, NULL); |
| 95 | + dir_fd = SAFE_OPEN("./", O_DIRECTORY); |
| 96 | + |
| 97 | + /* EACCES setting */ |
| 98 | + SAFE_SETEUID(0); |
| 99 | + SAFE_MKDIR(TESTFILE_EACCESS_DIR, S_IRWXU); |
| 100 | + SAFE_TOUCH(TESTFILE_EACCESS, 0666, NULL); |
| 101 | + ltpuser = SAFE_GETPWNAM("nobody"); |
| 102 | + SAFE_SETEUID(ltpuser->pw_uid); |
| 103 | + |
| 104 | + /* EFAULT setting */ |
| 105 | + file_efault = tst_get_bad_addr(NULL); |
| 106 | + |
| 107 | + /* ENOTDIR setting */ |
| 108 | + file_fd = SAFE_OPEN("file_fd", O_CREAT | O_RDWR, 0600); |
| 109 | + |
| 110 | + /* ELOOP setting */ |
| 111 | + SAFE_SYMLINK(TESTFILE_ELOOP, "test_file_eloop2"); |
| 112 | + SAFE_SYMLINK("test_file_eloop2", TESTFILE_ELOOP); |
| 113 | + |
| 114 | + /* ENAMETOOLONG setting */ |
| 115 | + memset(file_enametoolong, 'a', PATH_MAX+1); |
| 116 | + file_enametoolong[PATH_MAX+1] = 0; |
| 117 | +} |
| 118 | + |
| 119 | +static void cleanup(void) |
| 120 | +{ |
| 121 | + if (dir_fd != -1) |
| 122 | + SAFE_CLOSE(dir_fd); |
| 123 | + if (file_fd != -1) |
| 124 | + SAFE_CLOSE(file_fd); |
| 125 | +} |
| 126 | + |
| 127 | +static struct tst_test test = { |
| 128 | + .needs_tmpdir = 1, |
| 129 | + .needs_root = 1, |
| 130 | + .needs_rofs = 1, |
| 131 | + .mntpoint = TESTFILE_EROFS_MNT, |
| 132 | + .test = fchownat_verify, |
| 133 | + .tcnt = ARRAY_SIZE(tcases), |
| 134 | + .setup = setup, |
| 135 | + .cleanup = cleanup, |
| 136 | + .bufs = (struct tst_buffers []) { |
| 137 | + {&file_eaccess, .str = TESTFILE_EACCESS}, |
| 138 | + {&file_ebadf, .str = TESTFILE}, |
| 139 | + {&file_einval, .str = TESTFILE}, |
| 140 | + {&file_eloop, .str = TESTFILE_ELOOP}, |
| 141 | + {&file_enametoolong, .size = PATH_MAX+2}, |
| 142 | + {&file_enoent, .str = TESTFILE_ENOENT}, |
| 143 | + {&file_enotdir, .str = TESTFILE}, |
| 144 | + {&file_eperm, .str = TESTFILE_EPERM}, |
| 145 | + {&file_erofs, .str = TESTFILE_EROFS}, |
| 146 | + {} |
| 147 | + }, |
| 148 | +}; |
0 commit comments