Home | History | Annotate | Download | only in tests
      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