gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/xattr.cc (about)

     1  // Copyright 2019 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #include <errno.h>
    16  #include <fcntl.h>
    17  #include <limits.h>
    18  #include <sys/types.h>
    19  #include <sys/xattr.h>
    20  #include <unistd.h>
    21  
    22  #include <string>
    23  #include <vector>
    24  
    25  #include "gmock/gmock.h"
    26  #include "gtest/gtest.h"
    27  #include "absl/container/flat_hash_set.h"
    28  #include "test/syscalls/linux/file_base.h"
    29  #include "test/util/capability_util.h"
    30  #include "test/util/file_descriptor.h"
    31  #include "test/util/fs_util.h"
    32  #include "test/util/posix_error.h"
    33  #include "test/util/temp_path.h"
    34  #include "test/util/test_util.h"
    35  
    36  namespace gvisor {
    37  namespace testing {
    38  
    39  namespace {
    40  
    41  using ::gvisor::testing::IsTmpfs;
    42  using ::testing::AnyOf;
    43  
    44  class XattrTest : public FileTest {};
    45  
    46  TEST_F(XattrTest, XattrNonexistentFile) {
    47    const char* path = "/does/not/exist";
    48    const char* name = "user.test";
    49    EXPECT_THAT(setxattr(path, name, nullptr, 0, /*flags=*/0),
    50                SyscallFailsWithErrno(ENOENT));
    51    EXPECT_THAT(getxattr(path, name, nullptr, 0), SyscallFailsWithErrno(ENOENT));
    52    EXPECT_THAT(listxattr(path, nullptr, 0), SyscallFailsWithErrno(ENOENT));
    53    EXPECT_THAT(removexattr(path, name), SyscallFailsWithErrno(ENOENT));
    54  }
    55  
    56  TEST_F(XattrTest, XattrNullName) {
    57    const char* path = test_file_name_.c_str();
    58  
    59    EXPECT_THAT(setxattr(path, nullptr, nullptr, 0, /*flags=*/0),
    60                SyscallFailsWithErrno(EFAULT));
    61    EXPECT_THAT(getxattr(path, nullptr, nullptr, 0),
    62                SyscallFailsWithErrno(EFAULT));
    63    EXPECT_THAT(removexattr(path, nullptr), SyscallFailsWithErrno(EFAULT));
    64  }
    65  
    66  TEST_F(XattrTest, XattrEmptyName) {
    67    const char* path = test_file_name_.c_str();
    68  
    69    EXPECT_THAT(setxattr(path, "", nullptr, 0, /*flags=*/0),
    70                SyscallFailsWithErrno(ERANGE));
    71    EXPECT_THAT(getxattr(path, "", nullptr, 0), SyscallFailsWithErrno(ERANGE));
    72    EXPECT_THAT(removexattr(path, ""), SyscallFailsWithErrno(ERANGE));
    73  }
    74  
    75  TEST_F(XattrTest, XattrLargeName) {
    76    const char* path = test_file_name_.c_str();
    77    std::string name = "user.";
    78    name += std::string(XATTR_NAME_MAX - name.length(), 'a');
    79  
    80    if (!IsRunningOnGvisor()) {
    81      // In gVisor, access to xattrs is controlled with an explicit list of
    82      // allowed names. This name isn't going to be configured to allow access, so
    83      // don't test it.
    84      EXPECT_THAT(setxattr(path, name.c_str(), nullptr, 0, /*flags=*/0),
    85                  SyscallSucceeds());
    86      EXPECT_THAT(getxattr(path, name.c_str(), nullptr, 0),
    87                  SyscallSucceedsWithValue(0));
    88    }
    89  
    90    name += "a";
    91    EXPECT_THAT(setxattr(path, name.c_str(), nullptr, 0, /*flags=*/0),
    92                SyscallFailsWithErrno(ERANGE));
    93    EXPECT_THAT(getxattr(path, name.c_str(), nullptr, 0),
    94                SyscallFailsWithErrno(ERANGE));
    95    EXPECT_THAT(removexattr(path, name.c_str()), SyscallFailsWithErrno(ERANGE));
    96  }
    97  
    98  TEST_F(XattrTest, XattrInvalidPrefix) {
    99    const char* path = test_file_name_.c_str();
   100    std::string name(XATTR_NAME_MAX, 'a');
   101    EXPECT_THAT(setxattr(path, name.c_str(), nullptr, 0, /*flags=*/0),
   102                SyscallFailsWithErrno(EOPNOTSUPP));
   103    EXPECT_THAT(getxattr(path, name.c_str(), nullptr, 0),
   104                SyscallFailsWithErrno(EOPNOTSUPP));
   105    EXPECT_THAT(removexattr(path, name.c_str()),
   106                SyscallFailsWithErrno(EOPNOTSUPP));
   107  }
   108  
   109  TEST_F(XattrTest, SecurityCapacityXattr) {
   110    SKIP_IF(!IsRunningOnGvisor());
   111    const char* path = test_file_name_.c_str();
   112    const char name[] = "security.capacity";
   113    const std::string val = "";
   114    EXPECT_THAT(lsetxattr(path, name, &val, val.size(), 0),
   115                SyscallFailsWithErrno(EOPNOTSUPP));
   116    int buf = 0;
   117    EXPECT_THAT(lgetxattr(path, name, &buf, /*size=*/128),
   118                SyscallFailsWithErrno(AnyOf(ENODATA, EOPNOTSUPP)));
   119    EXPECT_THAT(lremovexattr(path, name), SyscallFailsWithErrno(EOPNOTSUPP));
   120  }
   121  
   122  // Do not allow save/restore cycles after making the test file read-only, as
   123  // the restore will fail to open it with r/w permissions.
   124  TEST_F(XattrTest, XattrReadOnly) {
   125    // Drop capabilities that allow us to override file and directory permissions.
   126    AutoCapability cap1(CAP_DAC_OVERRIDE, false);
   127    AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
   128  
   129    const char* path = test_file_name_.c_str();
   130    const char name[] = "user.test";
   131    char val = 'a';
   132    size_t size = sizeof(val);
   133  
   134    EXPECT_THAT(setxattr(path, name, &val, size, /*flags=*/0), SyscallSucceeds());
   135  
   136    DisableSave ds;
   137    ASSERT_NO_ERRNO(testing::Chmod(test_file_name_, S_IRUSR));
   138  
   139    EXPECT_THAT(setxattr(path, name, &val, size, /*flags=*/0),
   140                SyscallFailsWithErrno(EACCES));
   141    EXPECT_THAT(removexattr(path, name), SyscallFailsWithErrno(EACCES));
   142  
   143    char buf = '-';
   144    EXPECT_THAT(getxattr(path, name, &buf, size), SyscallSucceedsWithValue(size));
   145    EXPECT_EQ(buf, val);
   146  
   147    char list[sizeof(name)];
   148    EXPECT_THAT(listxattr(path, list, sizeof(list)),
   149                SyscallSucceedsWithValue(sizeof(name)));
   150    EXPECT_STREQ(list, name);
   151  }
   152  
   153  // Do not allow save/restore cycles after making the test file write-only, as
   154  // the restore will fail to open it with r/w permissions.
   155  TEST_F(XattrTest, XattrWriteOnly) {
   156    // Drop capabilities that allow us to override file and directory permissions.
   157    AutoCapability cap1(CAP_DAC_OVERRIDE, false);
   158    AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
   159  
   160    DisableSave ds;
   161    ASSERT_NO_ERRNO(testing::Chmod(test_file_name_, S_IWUSR));
   162  
   163    const char* path = test_file_name_.c_str();
   164    const char name[] = "user.test";
   165    char val = 'a';
   166    size_t size = sizeof(val);
   167  
   168    EXPECT_THAT(setxattr(path, name, &val, size, /*flags=*/0), SyscallSucceeds());
   169  
   170    EXPECT_THAT(getxattr(path, name, nullptr, 0), SyscallFailsWithErrno(EACCES));
   171  
   172    // listxattr will succeed even without read permissions.
   173    char list[sizeof(name)];
   174    EXPECT_THAT(listxattr(path, list, sizeof(list)),
   175                SyscallSucceedsWithValue(sizeof(name)));
   176    EXPECT_STREQ(list, name);
   177  
   178    EXPECT_THAT(removexattr(path, name), SyscallSucceeds());
   179  }
   180  
   181  TEST_F(XattrTest, XattrTrustedWithNonadmin) {
   182    // TODO(b/148380782): Support setxattr and getxattr with "trusted" prefix.
   183    SKIP_IF(IsRunningOnGvisor());
   184    SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
   185  
   186    const char* path = test_file_name_.c_str();
   187    const char name[] = "trusted.abc";
   188    EXPECT_THAT(setxattr(path, name, nullptr, 0, /*flags=*/0),
   189                SyscallFailsWithErrno(EPERM));
   190    EXPECT_THAT(removexattr(path, name), SyscallFailsWithErrno(EPERM));
   191    EXPECT_THAT(getxattr(path, name, nullptr, 0), SyscallFailsWithErrno(ENODATA));
   192  }
   193  
   194  TEST_F(XattrTest, XattrOnDirectory) {
   195    TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   196    const char name[] = "user.test";
   197    EXPECT_THAT(setxattr(dir.path().c_str(), name, nullptr, 0, /*flags=*/0),
   198                SyscallSucceeds());
   199    EXPECT_THAT(getxattr(dir.path().c_str(), name, nullptr, 0),
   200                SyscallSucceedsWithValue(0));
   201  
   202    // Overlay may have private attributes. Even though it is not returned to
   203    // userspace, it is counted against the `size` argument in listxattr(2).
   204    // See fs/overlayfs/inode.c:ovl_listxattr(). Notice that `size` is not
   205    // extended to accommodate for private attributes that are filtered later.
   206    // So use a large enough buffer for xattr list.
   207    char list[64];
   208    EXPECT_THAT(listxattr(dir.path().c_str(), list, sizeof(list)),
   209                SyscallSucceedsWithValue(sizeof(name)));
   210    EXPECT_STREQ(list, name);
   211  
   212    EXPECT_THAT(removexattr(dir.path().c_str(), name), SyscallSucceeds());
   213  }
   214  
   215  TEST_F(XattrTest, XattrOnSymlink) {
   216    TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   217    TempPath link = ASSERT_NO_ERRNO_AND_VALUE(
   218        TempPath::CreateSymlinkTo(dir.path(), test_file_name_));
   219    const char name[] = "user.test";
   220    EXPECT_THAT(setxattr(link.path().c_str(), name, nullptr, 0, /*flags=*/0),
   221                SyscallSucceeds());
   222    EXPECT_THAT(getxattr(link.path().c_str(), name, nullptr, 0),
   223                SyscallSucceedsWithValue(0));
   224  
   225    char list[sizeof(name)];
   226    EXPECT_THAT(listxattr(link.path().c_str(), list, sizeof(list)),
   227                SyscallSucceedsWithValue(sizeof(name)));
   228    EXPECT_STREQ(list, name);
   229  
   230    EXPECT_THAT(removexattr(link.path().c_str(), name), SyscallSucceeds());
   231  }
   232  
   233  TEST_F(XattrTest, XattrOnInvalidFileTypes) {
   234    const char name[] = "user.test";
   235  
   236    char char_device[] = "/dev/zero";
   237    EXPECT_THAT(setxattr(char_device, name, nullptr, 0, /*flags=*/0),
   238                SyscallFailsWithErrno(EPERM));
   239    EXPECT_THAT(getxattr(char_device, name, nullptr, 0),
   240                SyscallFailsWithErrno(ENODATA));
   241    EXPECT_THAT(listxattr(char_device, nullptr, 0), SyscallSucceedsWithValue(0));
   242  
   243    // Use tmpfs, where creation of named pipes is supported.
   244    const std::string fifo = NewTempAbsPathInDir("/dev/shm");
   245    const char* path = fifo.c_str();
   246    EXPECT_THAT(mknod(path, S_IFIFO | S_IRUSR | S_IWUSR, 0), SyscallSucceeds());
   247    EXPECT_THAT(setxattr(path, name, nullptr, 0, /*flags=*/0),
   248                SyscallFailsWithErrno(EPERM));
   249    EXPECT_THAT(getxattr(path, name, nullptr, 0), SyscallFailsWithErrno(ENODATA));
   250    EXPECT_THAT(listxattr(path, nullptr, 0), SyscallSucceedsWithValue(0));
   251    EXPECT_THAT(removexattr(path, name), SyscallFailsWithErrno(EPERM));
   252  }
   253  
   254  TEST_F(XattrTest, SetXattrSizeSmallerThanValue) {
   255    const char* path = test_file_name_.c_str();
   256    const char name[] = "user.test";
   257    std::vector<char> val = {'a', 'a'};
   258    size_t size = 1;
   259    EXPECT_THAT(setxattr(path, name, val.data(), size, /*flags=*/0),
   260                SyscallSucceeds());
   261  
   262    std::vector<char> buf = {'-', '-'};
   263    std::vector<char> expected_buf = {'a', '-'};
   264    EXPECT_THAT(getxattr(path, name, buf.data(), buf.size()),
   265                SyscallSucceedsWithValue(size));
   266    EXPECT_EQ(buf, expected_buf);
   267  }
   268  
   269  TEST_F(XattrTest, SetXattrZeroSize) {
   270    const char* path = test_file_name_.c_str();
   271    const char name[] = "user.test";
   272    char val = 'a';
   273    EXPECT_THAT(setxattr(path, name, &val, 0, /*flags=*/0), SyscallSucceeds());
   274  
   275    char buf = '-';
   276    EXPECT_THAT(getxattr(path, name, &buf, 1), SyscallSucceedsWithValue(0));
   277    EXPECT_EQ(buf, '-');
   278  }
   279  
   280  TEST_F(XattrTest, SetXattrSizeTooLarge) {
   281    const char* path = test_file_name_.c_str();
   282    const char name[] = "user.test";
   283  
   284    // Note that each particular fs implementation may stipulate a lower size
   285    // limit, in which case we actually may fail (e.g. error with ENOSPC) for
   286    // some sizes under XATTR_SIZE_MAX.
   287    size_t size = XATTR_SIZE_MAX + 1;
   288    std::vector<char> val(size);
   289    EXPECT_THAT(setxattr(path, name, val.data(), size, /*flags=*/0),
   290                SyscallFailsWithErrno(E2BIG));
   291  
   292    EXPECT_THAT(getxattr(path, name, nullptr, 0), SyscallFailsWithErrno(ENODATA));
   293  }
   294  
   295  TEST_F(XattrTest, SetXattrNullValueAndNonzeroSize) {
   296    const char* path = test_file_name_.c_str();
   297    const char name[] = "user.test";
   298  #pragma GCC diagnostic push
   299  #pragma GCC diagnostic ignored "-Wnonnull"
   300    EXPECT_THAT(setxattr(path, name, nullptr, 1, /*flags=*/0),
   301                SyscallFailsWithErrno(EFAULT));
   302  #pragma GCC diagnostic pop
   303  
   304    EXPECT_THAT(getxattr(path, name, nullptr, 0), SyscallFailsWithErrno(ENODATA));
   305  }
   306  
   307  TEST_F(XattrTest, SetXattrNullValueAndZeroSize) {
   308    const char* path = test_file_name_.c_str();
   309    const char name[] = "user.test";
   310    EXPECT_THAT(setxattr(path, name, nullptr, 0, /*flags=*/0), SyscallSucceeds());
   311  
   312    EXPECT_THAT(getxattr(path, name, nullptr, 0), SyscallSucceedsWithValue(0));
   313  }
   314  
   315  TEST_F(XattrTest, SetXattrValueTooLargeButOKSize) {
   316    const char* path = test_file_name_.c_str();
   317    const char name[] = "user.test";
   318    std::vector<char> val(XATTR_SIZE_MAX + 1);
   319    std::fill(val.begin(), val.end(), 'a');
   320    size_t size = 1;
   321    EXPECT_THAT(setxattr(path, name, val.data(), size, /*flags=*/0),
   322                SyscallSucceeds());
   323  
   324    std::vector<char> buf = {'-', '-'};
   325    std::vector<char> expected_buf = {'a', '-'};
   326    EXPECT_THAT(getxattr(path, name, buf.data(), size),
   327                SyscallSucceedsWithValue(size));
   328    EXPECT_EQ(buf, expected_buf);
   329  }
   330  
   331  TEST_F(XattrTest, SetXattrReplaceWithSmaller) {
   332    const char* path = test_file_name_.c_str();
   333    const char name[] = "user.test";
   334    std::vector<char> val = {'a', 'a'};
   335    EXPECT_THAT(setxattr(path, name, val.data(), 2, /*flags=*/0),
   336                SyscallSucceeds());
   337    EXPECT_THAT(setxattr(path, name, val.data(), 1, /*flags=*/0),
   338                SyscallSucceeds());
   339  
   340    std::vector<char> buf = {'-', '-'};
   341    std::vector<char> expected_buf = {'a', '-'};
   342    EXPECT_THAT(getxattr(path, name, buf.data(), 2), SyscallSucceedsWithValue(1));
   343    EXPECT_EQ(buf, expected_buf);
   344  }
   345  
   346  TEST_F(XattrTest, SetXattrReplaceWithLarger) {
   347    const char* path = test_file_name_.c_str();
   348    const char name[] = "user.test";
   349    std::vector<char> val = {'a', 'a'};
   350    EXPECT_THAT(setxattr(path, name, val.data(), 1, /*flags=*/0),
   351                SyscallSucceeds());
   352    EXPECT_THAT(setxattr(path, name, val.data(), 2, /*flags=*/0),
   353                SyscallSucceeds());
   354  
   355    std::vector<char> buf = {'-', '-'};
   356    EXPECT_THAT(getxattr(path, name, buf.data(), 2), SyscallSucceedsWithValue(2));
   357    EXPECT_EQ(buf, val);
   358  }
   359  
   360  TEST_F(XattrTest, SetXattrCreateFlag) {
   361    const char* path = test_file_name_.c_str();
   362    const char name[] = "user.test";
   363    EXPECT_THAT(setxattr(path, name, nullptr, 0, XATTR_CREATE),
   364                SyscallSucceeds());
   365    EXPECT_THAT(setxattr(path, name, nullptr, 0, XATTR_CREATE),
   366                SyscallFailsWithErrno(EEXIST));
   367  
   368    EXPECT_THAT(getxattr(path, name, nullptr, 0), SyscallSucceedsWithValue(0));
   369  }
   370  
   371  TEST_F(XattrTest, SetXattrReplaceFlag) {
   372    const char* path = test_file_name_.c_str();
   373    const char name[] = "user.test";
   374    EXPECT_THAT(setxattr(path, name, nullptr, 0, XATTR_REPLACE),
   375                SyscallFailsWithErrno(ENODATA));
   376    EXPECT_THAT(setxattr(path, name, nullptr, 0, /*flags=*/0), SyscallSucceeds());
   377    EXPECT_THAT(setxattr(path, name, nullptr, 0, XATTR_REPLACE),
   378                SyscallSucceeds());
   379  
   380    EXPECT_THAT(getxattr(path, name, nullptr, 0), SyscallSucceedsWithValue(0));
   381  }
   382  
   383  TEST_F(XattrTest, SetXattrInvalidFlags) {
   384    const char* path = test_file_name_.c_str();
   385    int invalid_flags = 0xff;
   386    EXPECT_THAT(setxattr(path, nullptr, nullptr, 0, invalid_flags),
   387                SyscallFailsWithErrno(EINVAL));
   388  }
   389  
   390  TEST_F(XattrTest, GetXattr) {
   391    const char* path = test_file_name_.c_str();
   392    const char name[] = "user.test";
   393    int val = 1234;
   394    size_t size = sizeof(val);
   395    EXPECT_THAT(setxattr(path, name, &val, size, /*flags=*/0), SyscallSucceeds());
   396  
   397    int buf = 0;
   398    EXPECT_THAT(getxattr(path, name, &buf, size), SyscallSucceedsWithValue(size));
   399    EXPECT_EQ(buf, val);
   400  }
   401  
   402  TEST_F(XattrTest, GetXattrSizeSmallerThanValue) {
   403    const char* path = test_file_name_.c_str();
   404    const char name[] = "user.test";
   405    std::vector<char> val = {'a', 'a'};
   406    size_t size = val.size();
   407    EXPECT_THAT(setxattr(path, name, &val, size, /*flags=*/0), SyscallSucceeds());
   408  
   409    char buf = '-';
   410    EXPECT_THAT(getxattr(path, name, &buf, 1), SyscallFailsWithErrno(ERANGE));
   411    EXPECT_EQ(buf, '-');
   412  }
   413  
   414  TEST_F(XattrTest, GetXattrSizeLargerThanValue) {
   415    const char* path = test_file_name_.c_str();
   416    const char name[] = "user.test";
   417    char val = 'a';
   418    EXPECT_THAT(setxattr(path, name, &val, 1, /*flags=*/0), SyscallSucceeds());
   419  
   420    std::vector<char> buf(XATTR_SIZE_MAX);
   421    std::fill(buf.begin(), buf.end(), '-');
   422    std::vector<char> expected_buf = buf;
   423    expected_buf[0] = 'a';
   424    EXPECT_THAT(getxattr(path, name, buf.data(), buf.size()),
   425                SyscallSucceedsWithValue(1));
   426    EXPECT_EQ(buf, expected_buf);
   427  }
   428  
   429  TEST_F(XattrTest, GetXattrZeroSize) {
   430    const char* path = test_file_name_.c_str();
   431    const char name[] = "user.test";
   432    char val = 'a';
   433    EXPECT_THAT(setxattr(path, name, &val, sizeof(val), /*flags=*/0),
   434                SyscallSucceeds());
   435  
   436    char buf = '-';
   437    EXPECT_THAT(getxattr(path, name, &buf, 0),
   438                SyscallSucceedsWithValue(sizeof(val)));
   439    EXPECT_EQ(buf, '-');
   440  }
   441  
   442  TEST_F(XattrTest, GetXattrSizeTooLarge) {
   443    const char* path = test_file_name_.c_str();
   444    const char name[] = "user.test";
   445    char val = 'a';
   446    EXPECT_THAT(setxattr(path, name, &val, sizeof(val), /*flags=*/0),
   447                SyscallSucceeds());
   448  
   449    std::vector<char> buf(XATTR_SIZE_MAX + 1);
   450    std::fill(buf.begin(), buf.end(), '-');
   451    std::vector<char> expected_buf = buf;
   452    expected_buf[0] = 'a';
   453    EXPECT_THAT(getxattr(path, name, buf.data(), buf.size()),
   454                SyscallSucceedsWithValue(sizeof(val)));
   455    EXPECT_EQ(buf, expected_buf);
   456  }
   457  
   458  TEST_F(XattrTest, GetXattrNullValue) {
   459    const char* path = test_file_name_.c_str();
   460    const char name[] = "user.test";
   461    char val = 'a';
   462    size_t size = sizeof(val);
   463    EXPECT_THAT(setxattr(path, name, &val, size, /*flags=*/0), SyscallSucceeds());
   464  
   465  #pragma GCC diagnostic push
   466  #pragma GCC diagnostic ignored "-Wnonnull"
   467    EXPECT_THAT(getxattr(path, name, nullptr, size),
   468                SyscallFailsWithErrno(EFAULT));
   469  #pragma GCC diagnostic pop
   470  }
   471  
   472  TEST_F(XattrTest, GetXattrNullValueAndZeroSize) {
   473    const char* path = test_file_name_.c_str();
   474    const char name[] = "user.test";
   475    char val = 'a';
   476    size_t size = sizeof(val);
   477    // Set value with zero size.
   478    EXPECT_THAT(setxattr(path, name, &val, 0, /*flags=*/0), SyscallSucceeds());
   479    // Get value with nonzero size.
   480  #pragma GCC diagnostic push
   481  #pragma GCC diagnostic ignored "-Wnonnull"
   482    EXPECT_THAT(getxattr(path, name, nullptr, size), SyscallSucceedsWithValue(0));
   483  #pragma GCC diagnostic pop
   484  
   485    // Set value with nonzero size.
   486    EXPECT_THAT(setxattr(path, name, &val, size, /*flags=*/0), SyscallSucceeds());
   487    // Get value with zero size.
   488    EXPECT_THAT(getxattr(path, name, nullptr, 0), SyscallSucceedsWithValue(size));
   489  }
   490  
   491  TEST_F(XattrTest, GetXattrNonexistentName) {
   492    const char* path = test_file_name_.c_str();
   493    const char name[] = "user.test";
   494    EXPECT_THAT(getxattr(path, name, nullptr, 0), SyscallFailsWithErrno(ENODATA));
   495  }
   496  
   497  TEST_F(XattrTest, ListXattr) {
   498    const char* path = test_file_name_.c_str();
   499    const std::string name = "user.test";
   500    const std::string name2 = "user.test2";
   501    const std::string name3 = "user.test3";
   502    EXPECT_THAT(setxattr(path, name.c_str(), nullptr, 0, /*flags=*/0),
   503                SyscallSucceeds());
   504    EXPECT_THAT(setxattr(path, name2.c_str(), nullptr, 0, /*flags=*/0),
   505                SyscallSucceeds());
   506    EXPECT_THAT(setxattr(path, name3.c_str(), nullptr, 0, /*flags=*/0),
   507                SyscallSucceeds());
   508  
   509    std::vector<char> list(name.size() + 1 + name2.size() + 1 + name3.size() + 1);
   510    char* buf = list.data();
   511    EXPECT_THAT(listxattr(path, buf, XATTR_SIZE_MAX),
   512                SyscallSucceedsWithValue(list.size()));
   513  
   514    absl::flat_hash_set<std::string> got = {};
   515    for (char* p = buf; p < buf + list.size(); p += strlen(p) + 1) {
   516      got.insert(std::string{p});
   517    }
   518  
   519    absl::flat_hash_set<std::string> expected = {name, name2, name3};
   520    EXPECT_EQ(got, expected);
   521  }
   522  
   523  TEST_F(XattrTest, ListXattrNoXattrs) {
   524    const char* path = test_file_name_.c_str();
   525  
   526    std::vector<char> list, expected;
   527    EXPECT_THAT(listxattr(path, list.data(), sizeof(list)),
   528                SyscallSucceedsWithValue(0));
   529    EXPECT_EQ(list, expected);
   530  
   531    // ListXattr should succeed if there are no attributes, even if the buffer
   532    // passed in is a nullptr.
   533  #pragma GCC diagnostic push
   534  #pragma GCC diagnostic ignored "-Wnonnull"
   535    EXPECT_THAT(listxattr(path, nullptr, sizeof(list)),
   536                SyscallSucceedsWithValue(0));
   537  #pragma GCC diagnostic pop
   538  }
   539  
   540  TEST_F(XattrTest, ListXattrNullBuffer) {
   541    const char* path = test_file_name_.c_str();
   542    const char name[] = "user.test";
   543    EXPECT_THAT(setxattr(path, name, nullptr, 0, /*flags=*/0), SyscallSucceeds());
   544  
   545  #pragma GCC diagnostic push
   546  #pragma GCC diagnostic ignored "-Wnonnull"
   547    EXPECT_THAT(listxattr(path, nullptr, sizeof(name)),
   548                SyscallFailsWithErrno(EFAULT));
   549  #pragma GCC diagnostic pop
   550  }
   551  
   552  TEST_F(XattrTest, ListXattrSizeTooSmall) {
   553    const char* path = test_file_name_.c_str();
   554    const char name[] = "user.test";
   555    EXPECT_THAT(setxattr(path, name, nullptr, 0, /*flags=*/0), SyscallSucceeds());
   556  
   557    char list[sizeof(name) - 1];
   558    EXPECT_THAT(listxattr(path, list, sizeof(list)),
   559                SyscallFailsWithErrno(ERANGE));
   560  }
   561  
   562  TEST_F(XattrTest, ListXattrZeroSize) {
   563    const char* path = test_file_name_.c_str();
   564    const char name[] = "user.test";
   565    EXPECT_THAT(setxattr(path, name, nullptr, 0, /*flags=*/0), SyscallSucceeds());
   566    EXPECT_THAT(listxattr(path, nullptr, 0),
   567                SyscallSucceedsWithValue(sizeof(name)));
   568  }
   569  
   570  TEST_F(XattrTest, RemoveXattr) {
   571    const char* path = test_file_name_.c_str();
   572    const char name[] = "user.test";
   573    EXPECT_THAT(setxattr(path, name, nullptr, 0, /*flags=*/0), SyscallSucceeds());
   574    EXPECT_THAT(removexattr(path, name), SyscallSucceeds());
   575    EXPECT_THAT(getxattr(path, name, nullptr, 0), SyscallFailsWithErrno(ENODATA));
   576  }
   577  
   578  TEST_F(XattrTest, RemoveXattrNonexistentName) {
   579    const char* path = test_file_name_.c_str();
   580    const char name[] = "user.test";
   581    EXPECT_THAT(removexattr(path, name), SyscallFailsWithErrno(ENODATA));
   582  }
   583  
   584  TEST_F(XattrTest, LXattrOnSymlink) {
   585    const char name[] = "user.test";
   586    TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   587    TempPath link = ASSERT_NO_ERRNO_AND_VALUE(
   588        TempPath::CreateSymlinkTo(dir.path(), test_file_name_));
   589  
   590    EXPECT_THAT(lsetxattr(link.path().c_str(), name, nullptr, 0, 0),
   591                SyscallFailsWithErrno(EPERM));
   592    EXPECT_THAT(lgetxattr(link.path().c_str(), name, nullptr, 0),
   593                SyscallFailsWithErrno(ENODATA));
   594    EXPECT_THAT(llistxattr(link.path().c_str(), nullptr, 0),
   595                SyscallSucceedsWithValue(0));
   596    EXPECT_THAT(lremovexattr(link.path().c_str(), name),
   597                SyscallFailsWithErrno(EPERM));
   598  }
   599  
   600  TEST_F(XattrTest, LXattrOnNonsymlink) {
   601    const char* path = test_file_name_.c_str();
   602    const char name[] = "user.test";
   603    int val = 1234;
   604    size_t size = sizeof(val);
   605    EXPECT_THAT(lsetxattr(path, name, &val, size, /*flags=*/0),
   606                SyscallSucceeds());
   607  
   608    int buf = 0;
   609    EXPECT_THAT(lgetxattr(path, name, &buf, size),
   610                SyscallSucceedsWithValue(size));
   611    EXPECT_EQ(buf, val);
   612  
   613    char list[sizeof(name)];
   614    EXPECT_THAT(llistxattr(path, list, sizeof(list)),
   615                SyscallSucceedsWithValue(sizeof(name)));
   616    EXPECT_STREQ(list, name);
   617  
   618    EXPECT_THAT(lremovexattr(path, name), SyscallSucceeds());
   619  }
   620  
   621  TEST_F(XattrTest, XattrWithFD) {
   622    const FileDescriptor fd =
   623        ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_.c_str(), 0));
   624    const char name[] = "user.test";
   625    int val = 1234;
   626    size_t size = sizeof(val);
   627    EXPECT_THAT(fsetxattr(fd.get(), name, &val, size, /*flags=*/0),
   628                SyscallSucceeds());
   629  
   630    int buf = 0;
   631    EXPECT_THAT(fgetxattr(fd.get(), name, &buf, size),
   632                SyscallSucceedsWithValue(size));
   633    EXPECT_EQ(buf, val);
   634  
   635    char list[sizeof(name)];
   636    EXPECT_THAT(flistxattr(fd.get(), list, sizeof(list)),
   637                SyscallSucceedsWithValue(sizeof(name)));
   638    EXPECT_STREQ(list, name);
   639  
   640    EXPECT_THAT(fremovexattr(fd.get(), name), SyscallSucceeds());
   641  }
   642  
   643  TEST_F(XattrTest, XattrWithOPath) {
   644    const FileDescriptor fd =
   645        ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_.c_str(), O_PATH));
   646    const char name[] = "user.test";
   647    int val = 1234;
   648    size_t size = sizeof(val);
   649  
   650    // Bionic's implementations of f*xattr() use *xattr() when O_PATH is set
   651    // to circumvent the behavior this is testing for.
   652    // Use syscall() here to avoid running through Bionic on Android.
   653    EXPECT_THAT(syscall(SYS_fsetxattr, fd.get(), name, &val, size, /*flags=*/0),
   654                SyscallFailsWithErrno(EBADF));
   655  
   656    int buf;
   657    EXPECT_THAT(syscall(SYS_fgetxattr, fd.get(), name, &buf, size),
   658                SyscallFailsWithErrno(EBADF));
   659  
   660    char list[sizeof(name)];
   661    EXPECT_THAT(syscall(SYS_flistxattr, fd.get(), list, sizeof(list)),
   662                SyscallFailsWithErrno(EBADF));
   663  
   664    EXPECT_THAT(syscall(SYS_fremovexattr, fd.get(), name),
   665                SyscallFailsWithErrno(EBADF));
   666  }
   667  
   668  TEST_F(XattrTest, TrustedNamespaceWithCapSysAdmin) {
   669    // TODO(b/166162845): Only gVisor tmpfs currently supports trusted namespace.
   670    SKIP_IF(IsRunningOnGvisor() &&
   671            !ASSERT_NO_ERRNO_AND_VALUE(IsTmpfs(test_file_name_)));
   672  
   673    const char* path = test_file_name_.c_str();
   674    const char name[] = "trusted.test";
   675  
   676    // Writing to the trusted.* xattr namespace requires CAP_SYS_ADMIN in the root
   677    // user namespace. There's no easy way to check that, other than trying the
   678    // operation and seeing what happens. We'll call removexattr because it's
   679    // simplest.
   680    if (removexattr(path, name) < 0) {
   681      SKIP_IF(errno == EPERM);
   682      FAIL() << "unexpected errno from removexattr: " << errno;
   683    }
   684  
   685    // Set.
   686    char val = 'a';
   687    size_t size = sizeof(val);
   688    EXPECT_THAT(setxattr(path, name, &val, size, /*flags=*/0), SyscallSucceeds());
   689  
   690    // Get.
   691    char got = '\0';
   692    EXPECT_THAT(getxattr(path, name, &got, size), SyscallSucceedsWithValue(size));
   693    EXPECT_EQ(val, got);
   694  
   695    // List.
   696    char list[sizeof(name)];
   697    EXPECT_THAT(listxattr(path, list, sizeof(list)),
   698                SyscallSucceedsWithValue(sizeof(name)));
   699    EXPECT_STREQ(list, name);
   700  
   701    // Remove.
   702    EXPECT_THAT(removexattr(path, name), SyscallSucceeds());
   703  
   704    // Get should now return ENODATA.
   705    EXPECT_THAT(getxattr(path, name, &got, size), SyscallFailsWithErrno(ENODATA));
   706  }
   707  
   708  TEST_F(XattrTest, TrustedNamespaceWithoutCapSysAdmin) {
   709    // TODO(b/66162845): Only gVisor tmpfs currently supports trusted namespace.
   710    SKIP_IF(IsRunningOnGvisor() &&
   711            !ASSERT_NO_ERRNO_AND_VALUE(IsTmpfs(test_file_name_)));
   712  
   713    // Drop CAP_SYS_ADMIN if we have it.
   714    AutoCapability cap(CAP_SYS_ADMIN, false);
   715  
   716    const char* path = test_file_name_.c_str();
   717    const char name[] = "trusted.test";
   718  
   719    // Set fails.
   720    char val = 'a';
   721    size_t size = sizeof(val);
   722    EXPECT_THAT(setxattr(path, name, &val, size, /*flags=*/0),
   723                SyscallFailsWithErrno(EPERM));
   724  
   725    // Get fails.
   726    char got = '\0';
   727    EXPECT_THAT(getxattr(path, name, &got, size), SyscallFailsWithErrno(ENODATA));
   728  
   729    // List still works, but returns no items.
   730    char list[sizeof(name)];
   731    EXPECT_THAT(listxattr(path, list, sizeof(list)), SyscallSucceedsWithValue(0));
   732  
   733    // Remove fails.
   734    EXPECT_THAT(removexattr(path, name), SyscallFailsWithErrno(EPERM));
   735  }
   736  
   737  }  // namespace
   738  
   739  }  // namespace testing
   740  }  // namespace gvisor