diff options
author | Rahat Mahmood <rahat@google.com> | 2021-05-14 11:06:07 -0700 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-05-14 11:07:57 -0700 |
commit | 78ae3db1a39c0cd925c6b75807fa1dc76ba99986 (patch) | |
tree | f4efaef41e425289ed253596c8e632431e21fdc2 /test/syscalls | |
parent | 2b457d9ee9ba50da4a9208d957053fac2c77932d (diff) |
Fix cgroup hierarchy registration.
Previously, registration was racy because we were publishing
hierarchies in the registry without fully initializing the underlying
filesystem. This led to concurrent mount(2)s discovering the partially
intialized filesystems and dropping the final refs on them which cause
them to be freed prematurely.
Reported-by: syzbot+13f54e77bdf59f0171f0@syzkaller.appspotmail.com
Reported-by: syzbot+2c7f0a9127ac6a84f17e@syzkaller.appspotmail.com
PiperOrigin-RevId: 373824552
Diffstat (limited to 'test/syscalls')
-rw-r--r-- | test/syscalls/linux/BUILD | 2 | ||||
-rw-r--r-- | test/syscalls/linux/cgroup.cc | 52 |
2 files changed, 54 insertions, 0 deletions
diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD index 94a582256..efed4aeb0 100644 --- a/test/syscalls/linux/BUILD +++ b/test/syscalls/linux/BUILD @@ -4247,10 +4247,12 @@ cc_binary( "//test/util:mount_util", "@com_google_absl//absl/strings", gtest, + "//test/util:cleanup", "//test/util:posix_error", "//test/util:temp_path", "//test/util:test_main", "//test/util:test_util", + "//test/util:thread_util", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/container:flat_hash_set", ], diff --git a/test/syscalls/linux/cgroup.cc b/test/syscalls/linux/cgroup.cc index 70ad5868f..a009ade7e 100644 --- a/test/syscalls/linux/cgroup.cc +++ b/test/syscalls/linux/cgroup.cc @@ -25,9 +25,11 @@ #include "absl/strings/str_split.h" #include "test/util/capability_util.h" #include "test/util/cgroup_util.h" +#include "test/util/cleanup.h" #include "test/util/mount_util.h" #include "test/util/temp_path.h" #include "test/util/test_util.h" +#include "test/util/thread_util.h" namespace gvisor { namespace testing { @@ -192,6 +194,56 @@ TEST(Cgroup, MoptAllMustBeExclusive) { SyscallFailsWithErrno(EINVAL)); } +TEST(Cgroup, MountRace) { + SKIP_IF(!CgroupsAvailable()); + + TempPath mountpoint = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); + + const DisableSave ds; // Too many syscalls. + + auto mount_thread = [&mountpoint]() { + for (int i = 0; i < 100; ++i) { + mount("none", mountpoint.path().c_str(), "cgroup", 0, 0); + } + }; + std::list<ScopedThread> threads; + for (int i = 0; i < 10; ++i) { + threads.emplace_back(mount_thread); + } + for (auto& t : threads) { + t.Join(); + } + + auto cleanup = Cleanup([&mountpoint] { + // We need 1 umount call per successful mount. If some of the mount calls + // were unsuccessful, their corresponding umount will silently fail. + for (int i = 0; i < (10 * 100) + 1; ++i) { + umount(mountpoint.path().c_str()); + } + }); + + Cgroup c = Cgroup(mountpoint.path()); + // c should be a valid cgroup. + EXPECT_NO_ERRNO(c.ContainsCallingProcess()); +} + +TEST(Cgroup, UnmountRepeated) { + SKIP_IF(!CgroupsAvailable()); + + const DisableSave ds; // Too many syscalls. + + Mounter m(ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir())); + Cgroup c = ASSERT_NO_ERRNO_AND_VALUE(m.MountCgroupfs("")); + + // First unmount should succeed. + EXPECT_THAT(umount(c.Path().c_str()), SyscallSucceeds()); + + // We just manually unmounted, so release managed resources. + m.release(c); + + EXPECT_THAT(umount(c.Path().c_str()), SyscallFailsWithErrno(EINVAL)); +} + TEST(MemoryCgroup, MemoryUsageInBytes) { SKIP_IF(!CgroupsAvailable()); |