1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <gtest/gtest.h> 18 19 #include <errno.h> 20 #include <fcntl.h> 21 #include <string.h> 22 #include <sys/utsname.h> 23 #include <sys/vfs.h> 24 25 #include "TemporaryFile.h" 26 27 #include <android-base/stringprintf.h> 28 29 // Glibc v2.19 doesn't include these in fcntl.h so host builds will fail without. 30 #if !defined(FALLOC_FL_PUNCH_HOLE) || !defined(FALLOC_FL_KEEP_SIZE) 31 #include <linux/falloc.h> 32 #include <linux/magic.h> 33 #endif 34 35 TEST(fcntl, fcntl_smoke) { 36 int fd = open("/proc/version", O_RDONLY); 37 ASSERT_TRUE(fd != -1); 38 39 int flags = fcntl(fd, F_GETFD); 40 ASSERT_TRUE(flags != -1); 41 ASSERT_EQ(0, flags & FD_CLOEXEC); 42 43 int rc = fcntl(fd, F_SETFD, FD_CLOEXEC); 44 ASSERT_EQ(0, rc); 45 46 flags = fcntl(fd, F_GETFD); 47 ASSERT_TRUE(flags != -1); 48 ASSERT_EQ(FD_CLOEXEC, flags & FD_CLOEXEC); 49 50 close(fd); 51 } 52 53 TEST(fcntl, open_open64) { 54 int fd; 55 56 fd = open("/proc/version", O_RDONLY); 57 ASSERT_TRUE(fd != -1); 58 close(fd); 59 60 fd = open64("/proc/version", O_RDONLY); 61 ASSERT_TRUE(fd != -1); 62 close(fd); 63 } 64 65 TEST(fcntl, openat_openat64) { 66 int fd; 67 68 fd = openat(AT_FDCWD, "/proc/version", O_RDONLY); 69 ASSERT_TRUE(fd != -1); 70 close(fd); 71 72 fd = openat64(AT_FDCWD, "/proc/version", O_RDONLY); 73 ASSERT_TRUE(fd != -1); 74 close(fd); 75 } 76 77 TEST(fcntl, creat_creat64) { 78 ASSERT_EQ(-1, creat("", 0666)); 79 ASSERT_EQ(ENOENT, errno); 80 ASSERT_EQ(-1, creat64("", 0666)); 81 ASSERT_EQ(ENOENT, errno); 82 } 83 84 TEST(fcntl, posix_fadvise) { 85 TemporaryFile tf; 86 errno = 0; 87 88 EXPECT_EQ(EBADF, posix_fadvise(-1, 0, 0, POSIX_FADV_NORMAL)); 89 EXPECT_EQ(0, errno); 90 91 EXPECT_EQ(EBADF, posix_fadvise64(-1, 0, 0, POSIX_FADV_NORMAL)); 92 EXPECT_EQ(0, errno); 93 94 EXPECT_EQ(EINVAL, posix_fadvise(tf.fd, 0, 0, -1)); 95 EXPECT_EQ(0, errno); 96 97 EXPECT_EQ(EINVAL, posix_fadvise64(tf.fd, 0, 0, -1)); 98 EXPECT_EQ(0, errno); 99 100 EXPECT_EQ(0, posix_fadvise(tf.fd, 0, 0, POSIX_FADV_NORMAL)); 101 EXPECT_EQ(0, posix_fadvise64(tf.fd, 0, 0, POSIX_FADV_NORMAL)); 102 } 103 104 TEST(fcntl, fallocate_EINVAL) { 105 TemporaryFile tf; 106 107 // fallocate/fallocate64 set errno. 108 // posix_fallocate/posix_fallocate64 return an errno value. 109 110 errno = 0; 111 ASSERT_EQ(-1, fallocate(tf.fd, 0, 0, -1)); 112 ASSERT_EQ(EINVAL, errno); 113 114 errno = 0; 115 ASSERT_EQ(-1, fallocate64(tf.fd, 0, 0, -1)); 116 ASSERT_EQ(EINVAL, errno); 117 118 errno = 0; 119 ASSERT_EQ(EINVAL, posix_fallocate(tf.fd, 0, -1)); 120 ASSERT_EQ(0, errno); 121 122 errno = 0; 123 ASSERT_EQ(EINVAL, posix_fallocate64(tf.fd, 0, -1)); 124 ASSERT_EQ(0, errno); 125 } 126 127 TEST(fcntl, fallocate) { 128 TemporaryFile tf; 129 struct stat sb; 130 ASSERT_EQ(0, fstat(tf.fd, &sb)); 131 ASSERT_EQ(0, sb.st_size); 132 133 #if defined(__BIONIC__) 134 ASSERT_EQ(0, fallocate(tf.fd, 0, 0, 1)); 135 ASSERT_EQ(0, fstat(tf.fd, &sb)); 136 ASSERT_EQ(1, sb.st_size); 137 138 ASSERT_EQ(0, fallocate64(tf.fd, 0, 0, 2)); 139 ASSERT_EQ(0, fstat(tf.fd, &sb)); 140 ASSERT_EQ(2, sb.st_size); 141 #endif 142 143 ASSERT_EQ(0, posix_fallocate(tf.fd, 0, 3)); 144 ASSERT_EQ(0, fstat(tf.fd, &sb)); 145 ASSERT_EQ(3, sb.st_size); 146 147 ASSERT_EQ(0, posix_fallocate64(tf.fd, 0, 4)); 148 ASSERT_EQ(0, fstat(tf.fd, &sb)); 149 ASSERT_EQ(4, sb.st_size); 150 } 151 152 TEST(fcntl, f_getlk64) { 153 int fd = open64("/proc/version", O_RDONLY); 154 ASSERT_TRUE(fd != -1); 155 156 struct flock64 check_lock; 157 check_lock.l_type = F_WRLCK; 158 check_lock.l_start = 0; 159 check_lock.l_whence = SEEK_SET; 160 check_lock.l_len = 0; 161 162 int rc = fcntl(fd, F_GETLK64, &check_lock); 163 ASSERT_EQ(0, rc); 164 165 close(fd); 166 } 167 168 TEST(fcntl, splice) { 169 int pipe_fds[2]; 170 ASSERT_EQ(0, pipe(pipe_fds)); 171 172 int in = open("/proc/cpuinfo", O_RDONLY); 173 ASSERT_NE(in, -1); 174 175 TemporaryFile tf; 176 177 ssize_t bytes_read = splice(in, 0, pipe_fds[1], NULL, 8*1024, SPLICE_F_MORE | SPLICE_F_MOVE); 178 ASSERT_NE(bytes_read, -1); 179 180 ssize_t bytes_written = splice(pipe_fds[0], NULL, tf.fd, 0, bytes_read, SPLICE_F_MORE | SPLICE_F_MOVE); 181 ASSERT_EQ(bytes_read, bytes_written); 182 183 close(pipe_fds[0]); 184 close(pipe_fds[1]); 185 close(in); 186 } 187 188 TEST(fcntl, vmsplice) { 189 int pipe_fds[2]; 190 ASSERT_EQ(0, pipe(pipe_fds)); 191 192 iovec v[2]; 193 v[0].iov_base = const_cast<char*>("hello "); 194 v[0].iov_len = 6; 195 v[1].iov_base = const_cast<char*>("world\n"); 196 v[1].iov_len = 6; 197 ssize_t bytes_written = vmsplice(pipe_fds[1], v, sizeof(v)/sizeof(iovec), 0); 198 ASSERT_EQ(v[0].iov_len + v[1].iov_len, static_cast<size_t>(bytes_written)); 199 close(pipe_fds[1]); 200 201 char buf[BUFSIZ]; 202 FILE* fp = fdopen(pipe_fds[0], "r"); 203 ASSERT_TRUE(fp != NULL); 204 ASSERT_TRUE(fgets(buf, sizeof(buf), fp) != NULL); 205 fclose(fp); 206 ASSERT_STREQ("hello world\n", buf); 207 } 208 209 TEST(fcntl, tee) { 210 char expected[BUFSIZ]; 211 FILE* expected_fp = fopen("/proc/version", "r"); 212 ASSERT_TRUE(expected_fp != NULL); 213 ASSERT_TRUE(fgets(expected, sizeof(expected), expected_fp) != NULL); 214 fclose(expected_fp); 215 216 int pipe1[2]; 217 ASSERT_EQ(0, pipe(pipe1)); 218 219 int pipe2[2]; 220 ASSERT_EQ(0, pipe(pipe2)); 221 222 int in = open("/proc/version", O_RDONLY); 223 ASSERT_NE(in, -1); 224 225 // Write /proc/version into pipe1. 226 ssize_t bytes_read = splice(in, 0, pipe1[1], NULL, 8*1024, SPLICE_F_MORE | SPLICE_F_MOVE); 227 ASSERT_NE(bytes_read, -1); 228 close(pipe1[1]); 229 230 // Tee /proc/version from pipe1 into pipe2. 231 ssize_t bytes_teed = tee(pipe1[0], pipe2[1], SIZE_MAX, 0); 232 ASSERT_EQ(bytes_read, bytes_teed); 233 close(pipe2[1]); 234 235 // The out fds of both pipe1 and pipe2 should now contain /proc/version. 236 char buf1[BUFSIZ]; 237 FILE* fp1 = fdopen(pipe1[0], "r"); 238 ASSERT_TRUE(fp1 != NULL); 239 ASSERT_TRUE(fgets(buf1, sizeof(buf1), fp1) != NULL); 240 fclose(fp1); 241 242 char buf2[BUFSIZ]; 243 FILE* fp2 = fdopen(pipe2[0], "r"); 244 ASSERT_TRUE(fp2 != NULL); 245 ASSERT_TRUE(fgets(buf2, sizeof(buf2), fp2) != NULL); 246 fclose(fp2); 247 248 ASSERT_STREQ(expected, buf1); 249 ASSERT_STREQ(expected, buf2); 250 } 251 252 TEST(fcntl, readahead) { 253 // Just check that the function is available. 254 errno = 0; 255 ASSERT_EQ(-1, readahead(-1, 0, 123)); 256 ASSERT_EQ(EBADF, errno); 257 } 258 259 TEST(fcntl, sync_file_range) { 260 // Just check that the function is available. 261 errno = 0; 262 ASSERT_EQ(-1, sync_file_range(-1, 0, 0, 0)); 263 ASSERT_EQ(EBADF, errno); 264 265 TemporaryFile tf; 266 ASSERT_EQ(0, sync_file_range(tf.fd, 0, 0, 0)); 267 268 // The arguments to the underlying system call are in a different order on 32-bit ARM. 269 // Check that the `flags` argument gets passed to the kernel correctly. 270 errno = 0; 271 ASSERT_EQ(-1, sync_file_range(tf.fd, 0, 0, ~0)); 272 ASSERT_EQ(EINVAL, errno); 273 } 274 275 static bool parse_kernel_release(long* const major, long* const minor) { 276 struct utsname buf; 277 if (uname(&buf) == -1) { 278 return false; 279 } 280 return sscanf(buf.release, "%ld.%ld", major, minor) == 2; 281 } 282 283 /* 284 * b/28760453: 285 * Kernels older than 4.1 should have ext4 FALLOC_FL_PUNCH_HOLE disabled due to CVE-2015-8839. 286 * Devices that fail this test should cherry-pick the following commit: 287 * https://android.googlesource.com/kernel/msm/+/bdba352e898cbf57c8620ad68c8abf749c784d1f 288 */ 289 TEST(fcntl, falloc_punch) { 290 long major = 0, minor = 0; 291 ASSERT_TRUE(parse_kernel_release(&major, &minor)); 292 293 if (major < 4 || (major == 4 && minor < 1)) { 294 TemporaryFile tf; 295 struct statfs sfs; 296 ASSERT_EQ(0, fstatfs(tf.fd, &sfs)); 297 if (sfs.f_type == EXT4_SUPER_MAGIC) { 298 ASSERT_EQ(-1, fallocate(tf.fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 1)); 299 ASSERT_EQ(errno, EOPNOTSUPP); 300 } 301 } 302 } 303 304 TEST(fcntl, open_O_TMPFILE_mode) { 305 #if __BIONIC__ // Our glibc is too old for O_TMPFILE. 306 TemporaryDir dir; 307 // Without O_EXCL, we're allowed to give this a name later. 308 // (This is unrelated to the O_CREAT interaction with O_EXCL.) 309 const mode_t perms = S_IRUSR | S_IWUSR; 310 int fd = open(dir.dirname, O_TMPFILE | O_RDWR, perms); 311 312 // Ignore kernels without O_TMPFILE support (< 3.11). 313 if (fd == -1 && (errno == EISDIR || errno == EINVAL || errno == EOPNOTSUPP)) return; 314 315 ASSERT_TRUE(fd != -1) << strerror(errno); 316 317 // Does the fd claim to have the mode we set? 318 struct stat sb = {}; 319 ASSERT_EQ(0, fstat(fd, &sb)); 320 ASSERT_EQ(perms, (sb.st_mode & ~S_IFMT)); 321 322 // On Android if we're not root, we won't be able to create links anyway... 323 if (getuid() != 0) return; 324 325 std::string final_path = android::base::StringPrintf("%s/named_now", dir.dirname); 326 ASSERT_EQ(0, linkat(AT_FDCWD, android::base::StringPrintf("/proc/self/fd/%d", fd).c_str(), 327 AT_FDCWD, final_path.c_str(), 328 AT_SYMLINK_FOLLOW)); 329 ASSERT_EQ(0, close(fd)); 330 331 // Does the resulting file claim to have the mode we set? 332 ASSERT_EQ(0, stat(final_path.c_str(), &sb)); 333 ASSERT_EQ(perms, (sb.st_mode & ~S_IFMT)); 334 335 // With O_EXCL, you're not allowed to add a name later. 336 fd = open(dir.dirname, O_TMPFILE | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR); 337 ASSERT_TRUE(fd != -1) << strerror(errno); 338 errno = 0; 339 ASSERT_EQ(-1, linkat(AT_FDCWD, android::base::StringPrintf("/proc/self/fd/%d", fd).c_str(), 340 AT_FDCWD, android::base::StringPrintf("%s/no_chance", dir.dirname).c_str(), 341 AT_SYMLINK_FOLLOW)); 342 ASSERT_EQ(ENOENT, errno); 343 ASSERT_EQ(0, close(fd)); 344 #endif 345 } 346