Skip to content

Commit 3799d1f

Browse files
Privacy Sandbox Teamcopybara-github
Privacy Sandbox Team
authored andcommitted
fix: Mount lib_mounts to root in sandbox
Bug: N/A Change-Id: Icc210b91acd807ce27c819b856faec253e82ff90 GitOrigin-RevId: a89678ad03480c5aa0c5a179b01df78f4f4bb640
1 parent 50f9ea8 commit 3799d1f

File tree

7 files changed

+159
-51
lines changed

7 files changed

+159
-51
lines changed

src/roma/byob/config/config.h

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ struct Config {
7777
std::uint64_t memory_limit_soft = 0;
7878
std::uint64_t memory_limit_hard = 0;
7979
std::string roma_container_name;
80+
// Mounts /x -> /x and /y/z -> /z.
8081
std::string lib_mounts = LIB_MOUNTS;
8182
};
8283
} // namespace privacy_sandbox::server_common::byob

src/roma/byob/container/run_workers.cc

+28-16
Original file line numberDiff line numberDiff line change
@@ -226,14 +226,16 @@ struct ReloaderImplArg {
226226
};
227227

228228
std::vector<std::pair<std::filesystem::path, std::filesystem::path>>
229-
GetSourcesAndTargets(const std::filesystem::path& pivot_root_dir,
230-
absl::Span<const std::string> mounts) {
229+
GetSourcesAndTargets(absl::Span<const std::string> mounts) {
231230
std::vector<std::pair<std::filesystem::path, std::filesystem::path>>
232231
sources_and_targets;
233232
sources_and_targets.reserve(mounts.size());
234233
for (const std::filesystem::path mount : mounts) {
234+
// Mount /x -> /x and /y/z -> /z.
235235
sources_and_targets.push_back(
236-
{mount, pivot_root_dir / mount.relative_path()});
236+
{mount,
237+
"/" /
238+
(mount.has_filename() ? mount : mount.parent_path()).filename()});
237239
}
238240
return sources_and_targets;
239241
}
@@ -248,21 +250,32 @@ int ReloaderImpl(void* arg) {
248250
const absl::StatusOr<std::filesystem::path> pivot_root_dir =
249251
CreatePivotRootDir();
250252
CHECK_OK(pivot_root_dir);
251-
const std::vector<std::pair<std::filesystem::path, std::filesystem::path>>
252-
sources_and_targets_read_only =
253-
GetSourcesAndTargets(*pivot_root_dir, reloader_impl_arg.mounts);
254253
{
255254
const std::filesystem::path socket_dir =
256255
std::filesystem::path(reloader_impl_arg.socket_name).parent_path();
257256
std::vector<std::pair<std::filesystem::path, std::filesystem::path>>
258-
socket_dir_read_and_write = {
259-
{socket_dir, *pivot_root_dir / socket_dir.relative_path()}};
257+
sources_and_targets_read_only =
258+
GetSourcesAndTargets(reloader_impl_arg.mounts);
259+
sources_and_targets_read_only.push_back({socket_dir, socket_dir});
260+
260261
// SetupPivotRoot reduces the base filesystem image size. This pivot root
261262
// includes the socket_dir, which must not be shared with the pivot_root
262263
// created by the worker.
263264
CHECK_OK(::privacy_sandbox::server_common::byob::SetupPivotRoot(
264-
*pivot_root_dir, socket_dir_read_and_write,
265-
/*cleanup_pivot_root_dir=*/true, sources_and_targets_read_only));
265+
*pivot_root_dir, sources_and_targets_read_only,
266+
/*cleanup_pivot_root_dir=*/true,
267+
/*sources_and_targets_read_and_write=*/
268+
{{reloader_impl_arg.log_dir_name, reloader_impl_arg.log_dir_name}}));
269+
}
270+
271+
// Reloader mounts /x -> /x and /y/z -> /z.
272+
// Workers mounts /a -> /a.
273+
std::vector<std::pair<std::filesystem::path, std::filesystem::path>>
274+
sources_and_targets_read_only;
275+
sources_and_targets_read_only.reserve(reloader_impl_arg.mounts.size());
276+
for (const auto& [_, target] :
277+
GetSourcesAndTargets(reloader_impl_arg.mounts)) {
278+
sources_and_targets_read_only.push_back({target, target});
266279
}
267280
while (true) {
268281
// Start a new worker.
@@ -488,7 +501,7 @@ class WorkerRunner final : public WorkerRunnerService::Service {
488501
return absl::OkStatus();
489502
}
490503

491-
absl::Status CreateWorkerPool(std::filesystem::path binary_path,
504+
absl::Status CreateWorkerPool(const std::filesystem::path binary_path,
492505
std::string_view code_token,
493506
const int num_workers,
494507
const bool enable_log_egress)
@@ -498,15 +511,14 @@ class WorkerRunner final : public WorkerRunnerService::Service {
498511
code_token_to_reloader_pids_[code_token].reserve(num_workers);
499512
}
500513
std::vector<std::string> mounts = mounts_;
501-
mounts.push_back(binary_path.parent_path());
502-
if (enable_log_egress) {
503-
mounts.push_back(log_dir_name_);
504-
}
514+
const std::filesystem::path binary_dir = binary_path.parent_path();
515+
mounts.push_back(binary_dir);
505516
ReloaderImplArg reloader_impl_arg{
506517
.mounts = std::move(mounts),
507518
.socket_name = socket_name_,
508519
.code_token = std::string(code_token),
509-
.binary_path = std::move(binary_path),
520+
// Within the pivot root, binary_dir is a child of root, not progdir.
521+
.binary_path = binary_dir.filename() / binary_path.filename(),
510522
.dev_null_fd = dev_null_fd_,
511523
.enable_log_egress = enable_log_egress,
512524
.log_dir_name = log_dir_name_,

src/roma/byob/interface/roma_service.cc

+12-20
Original file line numberDiff line numberDiff line change
@@ -48,29 +48,21 @@ LocalHandle::LocalHandle(int pid, std::string_view mounts,
4848
std::filesystem::path(CONTAINER_PATH) / CONTAINER_ROOT_RELPATH;
4949
std::vector<std::pair<std::filesystem::path, std::filesystem::path>>
5050
sources_and_targets = {
51-
{log_dir,
52-
root_dir / std::filesystem::path(log_dir).relative_path()},
53-
{socket_dir,
54-
root_dir / std::filesystem::path(socket_dir).relative_path()},
51+
{log_dir, "/log_dir"},
52+
{socket_dir, "/socket_dir"},
5553
// Needs to be mounted for Cancel to work (kill by cmdline)
56-
{"/proc",
57-
root_dir / std::filesystem::path("/proc").relative_path()},
58-
{"/dev", root_dir / std::filesystem::path("/dev").relative_path()}};
54+
{"/proc", "/proc"},
55+
{"/dev", "/dev"}};
5956
CHECK_OK(::privacy_sandbox::server_common::byob::SetupPivotRoot(
6057
root_dir, /*sources_and_targets_read_only=*/{},
6158
/*cleanup_pivot_root_dir=*/false, sources_and_targets));
6259
const std::string mounts_flag = absl::StrCat("--mounts=", mounts);
63-
const std::string control_socket_name_flag =
64-
absl::StrCat("--control_socket_name=", control_socket_path);
65-
const std::string udf_socket_name_flag =
66-
absl::StrCat("--udf_socket_name=", udf_socket_path);
67-
const std::string log_dir_flag = absl::StrCat("--log_dir=", log_dir);
6860
const char* argv[] = {
6961
"/server/bin/run_workers",
7062
mounts_flag.c_str(),
71-
control_socket_name_flag.c_str(),
72-
udf_socket_name_flag.c_str(),
73-
log_dir_flag.c_str(),
63+
"--control_socket_name=/socket_dir/control.sock",
64+
"--udf_socket_name=/socket_dir/byob_rpc.sock",
65+
"--log_dir=/log_dir",
7466
nullptr,
7567
};
7668
const char* envp[] = {
@@ -123,9 +115,9 @@ ByobHandle::ByobHandle(int pid, std::string_view mounts,
123115
config["process"]["args"] = {
124116
"/server/bin/run_workers",
125117
absl::StrCat("--mounts=", mounts),
126-
absl::StrCat("--control_socket_name=", control_socket_path),
127-
absl::StrCat("--udf_socket_name=", udf_socket_path),
128-
absl::StrCat("--log_dir=", log_dir),
118+
"--control_socket_name=/socket_dir/control.sock",
119+
"--udf_socket_name=/socket_dir/byob_rpc.sock",
120+
"--log_dir=/log_dir",
129121
};
130122
config["process"]["rlimits"] = {};
131123
// If a memory limit has been configured, apply it.
@@ -146,13 +138,13 @@ ByobHandle::ByobHandle(int pid, std::string_view mounts,
146138
config["mounts"] = {
147139
{
148140
{"source", socket_dir},
149-
{"destination", socket_dir},
141+
{"destination", "/socket_dir"},
150142
{"type", "bind"},
151143
{"options", {"rbind", "rprivate"}},
152144
},
153145
{
154146
{"source", log_dir},
155-
{"destination", log_dir},
147+
{"destination", "/log_dir"},
156148
{"type", "bind"},
157149
{"options", {"rbind", "rprivate"}},
158150
},

src/roma/byob/sample_udf/BUILD.bazel

+11
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,16 @@ cc_binary(
169169
],
170170
)
171171

172+
cc_binary(
173+
name = "socket_finder_udf",
174+
srcs = ["socket_finder_udf.cc"],
175+
visibility = ["//visibility:public"],
176+
deps = [
177+
":sample_byob_sdk_cc_proto",
178+
"@com_google_protobuf//:protobuf",
179+
],
180+
)
181+
172182
cc_binary(
173183
name = "pause_udf",
174184
srcs = ["pause_udf.cc"],
@@ -365,6 +375,7 @@ filegroup(
365375
":sample_go_udf",
366376
":sample_java_native_udf",
367377
":sample_udf",
378+
":socket_finder_udf",
368379
":sort_list_100k_udf",
369380
":sort_list_10k_udf",
370381
":sort_list_1m_udf",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright 2025 Google LLC
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 <fstream>
16+
#include <iostream>
17+
18+
#include "google/protobuf/util/delimited_message_util.h"
19+
#include "src/roma/byob/sample_udf/sample_udf_interface.pb.h"
20+
21+
using ::google::protobuf::io::FileInputStream;
22+
using ::google::protobuf::util::ParseDelimitedFromZeroCopyStream;
23+
using ::google::protobuf::util::SerializeDelimitedToFileDescriptor;
24+
using ::privacy_sandbox::roma_byob::example::SampleRequest;
25+
using ::privacy_sandbox::roma_byob::example::SampleResponse;
26+
27+
void ReadRequestFromFd(int fd) {
28+
SampleRequest bin_request;
29+
FileInputStream input(fd);
30+
ParseDelimitedFromZeroCopyStream(&bin_request, &input, nullptr);
31+
}
32+
33+
void WriteResponseToFd(int fd, SampleResponse resp) {
34+
google::protobuf::util::SerializeDelimitedToFileDescriptor(resp, fd);
35+
}
36+
37+
bool CanFindSocketInFileSystem() {
38+
for (const auto& entry : std::filesystem::recursive_directory_iterator("/")) {
39+
if (std::filesystem::is_socket(entry.path())) {
40+
return true;
41+
}
42+
}
43+
return false;
44+
}
45+
46+
int main(int argc, char* argv[]) {
47+
if (argc < 2) {
48+
std::cerr << "Not enough arguments!" << std::endl;
49+
return -1;
50+
}
51+
int fd = std::stoi(argv[1]);
52+
ReadRequestFromFd(fd);
53+
SampleResponse bin_response;
54+
if (CanFindSocketInFileSystem()) {
55+
bin_response.set_greeting("Failure. Able to find a socket file.");
56+
} else {
57+
bin_response.set_greeting("Success.");
58+
}
59+
WriteResponseToFd(fd, std::move(bin_response));
60+
return 0;
61+
}

src/roma/byob/test/roma_byob_test.cc

+32-6
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ const std::filesystem::path kUdfPath = "/udf";
5151
const std::filesystem::path kGoLangBinaryFilename = "sample_go_udf";
5252
const std::filesystem::path kCPlusPlusBinaryFilename = "sample_udf";
5353
const std::filesystem::path kCPlusPlusCapBinaryFilename = "cap_udf";
54+
const std::filesystem::path kCPlusPlusSocketFinderBinaryFilename =
55+
"socket_finder_udf";
5456
const std::filesystem::path kCPlusPlusFileSystemModificationFilename =
5557
"filesystem_udf";
5658
const std::filesystem::path kCPlusPlusNewBinaryFilename = "new_udf";
@@ -179,8 +181,33 @@ std::pair<SampleResponse, absl::Status> GetResponseAndLogStatus(
179181
return {*bin_response, log_status};
180182
}
181183

182-
// TODO: b/387989444 - Enable once the filesystem egression issue is fixed.
183-
TEST(RomaByobTest, DISABLED_NoFileSystemChangeEgressionInNonSandboxMode) {
184+
TEST(RomaByobTest, NoSocketFileInNonSandboxMode) {
185+
Mode mode = Mode::kModeNoSandbox;
186+
if (!HasClonePermissionsByobWorker(mode)) {
187+
GTEST_SKIP() << "HasClonePermissionsByobWorker check returned false";
188+
}
189+
ByobSampleService<> roma_service = GetRomaService(mode);
190+
191+
std::string code_token =
192+
LoadCode(roma_service, kUdfPath / kCPlusPlusSocketFinderBinaryFilename,
193+
/*enable_log_egress=*/true, /*num_workers=*/1);
194+
195+
EXPECT_THAT(SendRequestAndGetResponse(roma_service, code_token).greeting(),
196+
::testing::StrEq("Success."));
197+
}
198+
199+
TEST(RomaByobTest, NoSocketFileInSandboxMode) {
200+
ByobSampleService<> roma_service = GetRomaService(Mode::kModeSandbox);
201+
202+
std::string code_token =
203+
LoadCode(roma_service, kUdfPath / kCPlusPlusSocketFinderBinaryFilename,
204+
/*enable_log_egress=*/true, /*num_workers=*/1);
205+
206+
EXPECT_THAT(SendRequestAndGetResponse(roma_service, code_token).greeting(),
207+
::testing::StrEq("Success."));
208+
}
209+
210+
TEST(RomaByobTest, NoFileSystemChangeEgressionInNonSandboxMode) {
184211
Mode mode = Mode::kModeNoSandbox;
185212
if (!HasClonePermissionsByobWorker(mode)) {
186213
GTEST_SKIP() << "HasClonePermissionsByobWorker check returned false";
@@ -189,11 +216,10 @@ TEST(RomaByobTest, DISABLED_NoFileSystemChangeEgressionInNonSandboxMode) {
189216

190217
std::string code_token = LoadCode(
191218
roma_service, kUdfPath / kCPlusPlusFileSystemModificationFilename,
192-
/*enable_log_egress=*/false, /*num_workers=*/1);
219+
/*enable_log_egress=*/true, /*num_workers=*/1);
193220

194-
EXPECT_THAT(
195-
SendRequestAndGetResponse(roma_service, code_token).greeting(),
196-
::testing::StrEq("Success. Could not write file in any directory."));
221+
EXPECT_THAT(SendRequestAndGetResponse(roma_service, code_token).greeting(),
222+
::testing::StrEq("Success."));
197223
}
198224

199225
TEST(RomaByobTest, LoadBinaryInSandboxMode) {

src/roma/byob/utility/utils.cc

+14-9
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,18 @@ absl::Status SetupPivotRoot(
9797
// https://man7.org/linux/man-pages/man2/pivot_root.2.html.
9898
PS_RETURN_IF_ERROR(Mount(nullptr, "/", nullptr, MS_REC | MS_PRIVATE));
9999
for (const auto& [source, target] : sources_and_targets_read_only) {
100-
PS_RETURN_IF_ERROR(CreateDirectories(target));
101-
PS_RETURN_IF_ERROR(
102-
Mount(source.c_str(), target.c_str(), nullptr, MS_BIND | MS_RDONLY));
100+
const std::filesystem::path mount_target =
101+
pivot_root_dir / target.relative_path();
102+
PS_RETURN_IF_ERROR(CreateDirectories(mount_target));
103+
PS_RETURN_IF_ERROR(Mount(source.c_str(), mount_target.c_str(), nullptr,
104+
MS_BIND | MS_RDONLY));
103105
}
104106
for (const auto& [source, target] : sources_and_targets_read_and_write) {
105-
PS_RETURN_IF_ERROR(CreateDirectories(target));
106-
PS_RETURN_IF_ERROR(Mount(source.c_str(), target.c_str(), nullptr, MS_BIND));
107+
const std::filesystem::path mount_target =
108+
pivot_root_dir / target.relative_path();
109+
PS_RETURN_IF_ERROR(CreateDirectories(mount_target));
110+
PS_RETURN_IF_ERROR(
111+
Mount(source.c_str(), mount_target.c_str(), nullptr, MS_BIND));
107112
}
108113

109114
// MS_REC needed here to get other mounts (/lib, /lib64 etc)
@@ -129,13 +134,13 @@ absl::Status SetupPivotRoot(
129134
if (::rmdir("/pivot") == -1) {
130135
return absl::ErrnoToStatus(errno, "rmdir('/pivot')");
131136
}
132-
for (const auto& [source, _] : sources_and_targets_read_only) {
133-
PS_RETURN_IF_ERROR(Mount(source.c_str(), source.c_str(), nullptr,
137+
for (const auto& [_, target] : sources_and_targets_read_only) {
138+
PS_RETURN_IF_ERROR(Mount(target.c_str(), target.c_str(), nullptr,
134139
MS_REMOUNT | MS_BIND | MS_RDONLY));
135140
}
136-
for (const auto& [source, _] : sources_and_targets_read_and_write) {
141+
for (const auto& [_, target] : sources_and_targets_read_and_write) {
137142
PS_RETURN_IF_ERROR(
138-
Mount(source.c_str(), source.c_str(), nullptr, MS_REMOUNT | MS_BIND));
143+
Mount(target.c_str(), target.c_str(), nullptr, MS_REMOUNT | MS_BIND));
139144
}
140145
return absl::OkStatus();
141146
}

0 commit comments

Comments
 (0)