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