Skip to content

Commit 7ccd76f

Browse files
happyCoder92copybara-github
authored andcommitted
Add ability to allow mount propagation for specific mounts
PiperOrigin-RevId: 781573464 Change-Id: I4fcd09e0f1063680fac8fd6f6801dfd898bbea6f
1 parent 2535eef commit 7ccd76f

6 files changed

Lines changed: 60 additions & 18 deletions

File tree

sandboxed_api/sandbox2/mount_tree.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ message MountTree {
3434
message DirNode {
3535
string outside = 2;
3636
bool writable = 3;
37+
bool allow_mount_propagation = 4;
3738
}
3839

3940
// TmpfsNode mounts a tmpfs with given options.

sandboxed_api/sandbox2/mounts.cc

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,21 @@ absl::Status Mounts::Remove(absl::string_view path) {
176176
return absl::OkStatus();
177177
}
178178

179+
absl::StatusOr<MountTree::Node> Mounts::GetNode(absl::string_view path) {
180+
std::vector<absl::string_view> parts =
181+
absl::StrSplit(absl::StripPrefix(path, "/"), '/');
182+
MountTree* curtree = &mount_tree_;
183+
for (absl::string_view part : parts) {
184+
auto it = curtree->mutable_entries()->find(std::string(part));
185+
if (it == curtree->mutable_entries()->end()) {
186+
return absl::NotFoundError(
187+
absl::StrCat("Path does not exist in mounts: ", path));
188+
}
189+
curtree = &it->second;
190+
}
191+
return curtree->node();
192+
}
193+
179194
absl::Status Mounts::Insert(absl::string_view path,
180195
const MountTree::Node& new_node) {
181196
// Some sandboxes allow the inside/outside paths to be partially
@@ -353,6 +368,16 @@ absl::Status Mounts::AddTmpfs(absl::string_view inside, size_t sz) {
353368
return Insert(inside, node);
354369
}
355370

371+
absl::Status Mounts::AllowMountPropagation(absl::string_view inside) {
372+
SAPI_ASSIGN_OR_RETURN(MountTree::Node node, GetNode(inside));
373+
if (!node.has_dir_node()) {
374+
return absl::InvalidArgumentError(
375+
absl::StrCat("Path is not a directory: ", inside));
376+
}
377+
node.mutable_dir_node()->set_allow_mount_propagation(true);
378+
return absl::OkStatus();
379+
}
380+
356381
namespace {
357382

358383
uint64_t GetMountFlagsFor(const std::string& path) {
@@ -508,7 +533,8 @@ bool IsSymlink(const std::string& path) {
508533

509534
// Traverses the MountTree to create all required files and perform the mounts.
510535
void CreateMounts(const MountTree& tree, const std::string& root_path,
511-
const std::string& path, bool create_backing_files) {
536+
const std::string& path, bool create_backing_files,
537+
bool allow_mount_propagation) {
512538
// First, create the backing files if needed.
513539
if (create_backing_files) {
514540
switch (tree.node().node_case()) {
@@ -549,8 +575,12 @@ void CreateMounts(const MountTree& tree, const std::string& root_path,
549575
create_backing_files = false;
550576

551577
auto node = tree.node().dir_node();
552-
MountWithDefaults(node.outside(), path, "", MS_BIND, nullptr,
553-
!node.writable());
578+
MountWithDefaults(
579+
node.outside(), path, "",
580+
MS_BIND | (node.allow_mount_propagation() || allow_mount_propagation
581+
? MS_SHARED
582+
: MS_PRIVATE),
583+
nullptr, !node.writable());
554584
break;
555585
}
556586
case MountTree::Node::kTmpfsNode: {
@@ -580,14 +610,17 @@ void CreateMounts(const MountTree& tree, const std::string& root_path,
580610
// Traverse the subtrees.
581611
for (const auto& [key, value] : GetSortedEntries(tree)) {
582612
std::string new_path = sapi::file::JoinPath(path, key);
583-
CreateMounts(*value, root_path, new_path, create_backing_files);
613+
CreateMounts(*value, root_path, new_path, create_backing_files,
614+
allow_mount_propagation);
584615
}
585616
}
586617

587618
} // namespace
588619

589-
void Mounts::CreateMounts(const std::string& root_path) const {
590-
sandbox2::CreateMounts(mount_tree_, root_path, root_path, true);
620+
void Mounts::CreateMounts(const std::string& root_path,
621+
bool allow_mount_propagation) const {
622+
sandbox2::CreateMounts(mount_tree_, root_path, root_path, true,
623+
allow_mount_propagation);
591624
}
592625

593626
namespace {

sandboxed_api/sandbox2/mounts.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,12 @@ class Mounts {
7171

7272
absl::Status AddTmpfs(absl::string_view inside, size_t sz);
7373

74+
absl::Status AllowMountPropagation(absl::string_view inside);
75+
7476
absl::Status Remove(absl::string_view path);
7577

76-
void CreateMounts(const std::string& root_path) const;
78+
void CreateMounts(const std::string& root_path,
79+
bool allow_mount_propagation) const;
7780

7881
MountTree GetMountTree() const { return mount_tree_; }
7982

@@ -101,6 +104,7 @@ class Mounts {
101104
private:
102105
friend class MountTreeTest;
103106

107+
absl::StatusOr<MountTree::Node> GetNode(absl::string_view path);
104108
absl::Status Insert(absl::string_view path, const MountTree::Node& node);
105109

106110
MountTree mount_tree_;

sandboxed_api/sandbox2/namespace.cc

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ int MountFallbackToReadOnly(const char* source, const char* target,
6464
return rv;
6565
}
6666

67-
void PrepareChroot(const Mounts& mounts) {
67+
void PrepareChroot(const Mounts& mounts, bool allow_mount_propagation) {
6868
// Create a tmpfs mount for the new rootfs.
6969
SAPI_RAW_CHECK(
7070
file_util::fileops::CreateDirectoryRecursively(kSandbox2ChrootPath, 0700),
@@ -73,7 +73,7 @@ void PrepareChroot(const Mounts& mounts) {
7373
"mounting rootfs failed");
7474

7575
// Walk the tree and perform all the mount operations.
76-
mounts.CreateMounts(kSandbox2ChrootPath);
76+
mounts.CreateMounts(kSandbox2ChrootPath, allow_mount_propagation);
7777

7878
if (mounts.IsRootReadOnly()) {
7979
// Remount the chroot read-only
@@ -258,7 +258,7 @@ void Namespace::InitializeNamespaces(uid_t uid, gid_t gid, int32_t clone_flags,
258258
ActivateLoopbackInterface();
259259
}
260260

261-
PrepareChroot(mounts);
261+
PrepareChroot(mounts, allow_mount_propagation);
262262

263263
if (avoid_pivot_root) {
264264
// Keep a reference to /proc/self as it might not be mounted later
@@ -325,14 +325,6 @@ void Namespace::InitializeNamespaces(uid_t uid, gid_t gid, int32_t clone_flags,
325325
SAPI_RAW_PCHECK(chdir("/") == 0,
326326
"changing cwd after mntns initialization failed");
327327

328-
if (allow_mount_propagation) {
329-
SAPI_RAW_PCHECK(mount("/", "/", "", MS_SLAVE | MS_REC, nullptr) == 0,
330-
"changing mount propagation to slave failed");
331-
} else {
332-
SAPI_RAW_PCHECK(mount("/", "/", "", MS_PRIVATE | MS_REC, nullptr) == 0,
333-
"changing mount propagation to private failed");
334-
}
335-
336328
if (SAPI_RAW_VLOG_IS_ON(2)) {
337329
SAPI_RAW_VLOG(2, "Dumping the sandboxee's filesystem:");
338330
LogFilesystem("/");

sandboxed_api/sandbox2/policybuilder.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1798,6 +1798,15 @@ PolicyBuilder& PolicyBuilder::Allow(MountPropagation) {
17981798
return *this;
17991799
}
18001800

1801+
PolicyBuilder& PolicyBuilder::Allow(MountPropagation,
1802+
absl::string_view inside) {
1803+
if (absl::Status status = mounts_.AllowMountPropagation(inside);
1804+
!status.ok()) {
1805+
SetError(status);
1806+
}
1807+
return *this;
1808+
}
1809+
18011810
PolicyBuilder& PolicyBuilder::DangerAllowMountPropagation() {
18021811
return Allow(MountPropagation());
18031812
}

sandboxed_api/sandbox2/policybuilder.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,9 @@ class PolicyBuilder final {
940940
ABSL_DEPRECATED("Use Allow(sandbox2::MapExec()) instead")
941941
PolicyBuilder& DangerAllowMountPropagation();
942942
PolicyBuilder& Allow(MountPropagation);
943+
// Changes mounts propagation from MS_PRIVATE to MS_SHARED for a specific
944+
// mount.
945+
PolicyBuilder& Allow(MountPropagation, absl::string_view inside);
943946

944947
// Allows connections to this IP.
945948
PolicyBuilder& AllowIPv4(const std::string& ip_and_mask, uint32_t port = 0);

0 commit comments

Comments
 (0)