Skip to content

Commit 5fa8554

Browse files
Privacy Sandbox Teamcopybara-github
Privacy Sandbox Team
authored andcommitted
feat: Add tests to check no edit is permitted
Bug: b/387989444 Change-Id: Ie1b778fcf46bfda336c2470235eca7ba4a66cdb5 GitOrigin-RevId: b09d80f30d29c1d4a20eb431b146730f2ab03ee1
1 parent bce0edb commit 5fa8554

File tree

5 files changed

+244
-13
lines changed

5 files changed

+244
-13
lines changed

src/roma/byob/sample_udf/BUILD.bazel

+27-5
Original file line numberDiff line numberDiff line change
@@ -190,13 +190,33 @@ cc_binary(
190190
)
191191

192192
cc_binary(
193-
name = "filesystem_udf",
194-
srcs = ["filesystem_udf.cc"],
193+
name = "filesystem_add_udf",
194+
srcs = ["filesystem_add_udf.cc"],
195+
visibility = ["//visibility:public"],
196+
deps = [
197+
":sample_byob_sdk_cc_proto",
198+
"@com_google_absl//absl/status",
199+
"@com_google_protobuf//:protobuf",
200+
],
201+
)
202+
203+
cc_binary(
204+
name = "filesystem_edit_udf",
205+
srcs = ["filesystem_edit_udf.cc"],
206+
visibility = ["//visibility:public"],
207+
deps = [
208+
":sample_byob_sdk_cc_proto",
209+
"@com_google_absl//absl/status",
210+
"@com_google_protobuf//:protobuf",
211+
],
212+
)
213+
214+
cc_binary(
215+
name = "filesystem_delete_udf",
216+
srcs = ["filesystem_delete_udf.cc"],
195217
visibility = ["//visibility:public"],
196218
deps = [
197219
":sample_byob_sdk_cc_proto",
198-
"//src/roma/byob/dispatcher:interface",
199-
"//src/roma/byob/utility:utils",
200220
"@com_google_absl//absl/status",
201221
"@com_google_protobuf//:protobuf",
202222
],
@@ -364,7 +384,9 @@ filegroup(
364384
":abort_early_udf",
365385
":abort_late_udf",
366386
":cap_udf",
367-
":filesystem_udf",
387+
":filesystem_add_udf",
388+
":filesystem_delete_udf",
389+
":filesystem_edit_udf",
368390
":log_benchmark_udf",
369391
":log_udf",
370392
":new_udf",

src/roma/byob/sample_udf/filesystem_udf.cc src/roma/byob/sample_udf/filesystem_add_udf.cc

-2
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@
2020

2121
#include "absl/status/status.h"
2222
#include "google/protobuf/util/delimited_message_util.h"
23-
#include "src/roma/byob/dispatcher/interface.h"
2423
#include "src/roma/byob/sample_udf/sample_udf_interface.pb.h"
25-
#include "src/roma/byob/utility/utils.h"
2624

2725
using google::protobuf::io::FileInputStream;
2826
using google::protobuf::util::ParseDelimitedFromZeroCopyStream;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright 2024 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 <fcntl.h>
16+
17+
#include <cstdlib>
18+
#include <filesystem>
19+
#include <fstream>
20+
#include <iostream>
21+
#include <system_error>
22+
23+
#include "absl/status/status.h"
24+
#include "google/protobuf/util/delimited_message_util.h"
25+
#include "src/roma/byob/sample_udf/sample_udf_interface.pb.h"
26+
27+
using google::protobuf::io::FileInputStream;
28+
using google::protobuf::util::ParseDelimitedFromZeroCopyStream;
29+
using google::protobuf::util::SerializeDelimitedToFileDescriptor;
30+
using privacy_sandbox::roma_byob::example::SampleRequest;
31+
using privacy_sandbox::roma_byob::example::SampleResponse;
32+
33+
SampleRequest ReadRequestFromFd(int fd) {
34+
SampleRequest req;
35+
FileInputStream stream(fd);
36+
google::protobuf::util::ParseDelimitedFromZeroCopyStream(&req, &stream,
37+
nullptr);
38+
return req;
39+
}
40+
41+
void WriteResponseToFd(int fd, std::string_view greeting) {
42+
SampleResponse response;
43+
response.set_greeting(greeting);
44+
google::protobuf::util::SerializeDelimitedToFileDescriptor(response, fd);
45+
}
46+
47+
// Parses the file system directory structure and tries to delete an existing
48+
// file/directory. If a file/directory can be deleted to, it sends a fail
49+
// message. Else, it succeeds.
50+
absl::Status ParseFileSystemAndVerifyNoDelete(std::filesystem::path path) {
51+
auto verify_no_delete = [](const std::filesystem::path& path) {
52+
if (std::error_code ec; std::filesystem::remove_all(path, ec) !=
53+
static_cast<std::uintmax_t>(-1)) {
54+
return absl::InternalError(
55+
absl::StrCat("Failure. Able to delete ", path.c_str(),
56+
". Expected read-only filesystem."));
57+
}
58+
return absl::OkStatus();
59+
};
60+
if (auto status = verify_no_delete(path); !status.ok()) {
61+
return status;
62+
}
63+
for (const auto& entry :
64+
std::filesystem::recursive_directory_iterator(path)) {
65+
// Recursively traverse subdirectories
66+
if (auto status = verify_no_delete(entry.path()); !status.ok()) {
67+
return status;
68+
}
69+
}
70+
return absl::OkStatus();
71+
}
72+
73+
int main(int argc, char* argv[]) {
74+
if (argc < 2) {
75+
std::cerr << "Not enough arguments!";
76+
return -1;
77+
}
78+
int fd = std::stoi(argv[1]);
79+
SampleRequest sample_request = ReadRequestFromFd(fd);
80+
auto status = ParseFileSystemAndVerifyNoDelete("/");
81+
if (status.ok()) {
82+
WriteResponseToFd(fd, "Success.");
83+
} else {
84+
WriteResponseToFd(fd, std::move(status).message());
85+
}
86+
return 0;
87+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Copyright 2024 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 <fcntl.h>
16+
17+
#include <cstdlib>
18+
#include <filesystem>
19+
#include <fstream>
20+
#include <iostream>
21+
22+
#include "absl/status/status.h"
23+
#include "google/protobuf/util/delimited_message_util.h"
24+
#include "src/roma/byob/sample_udf/sample_udf_interface.pb.h"
25+
26+
using google::protobuf::io::FileInputStream;
27+
using google::protobuf::util::ParseDelimitedFromZeroCopyStream;
28+
using google::protobuf::util::SerializeDelimitedToFileDescriptor;
29+
using privacy_sandbox::roma_byob::example::SampleRequest;
30+
using privacy_sandbox::roma_byob::example::SampleResponse;
31+
32+
SampleRequest ReadRequestFromFd(int fd) {
33+
SampleRequest req;
34+
FileInputStream stream(fd);
35+
google::protobuf::util::ParseDelimitedFromZeroCopyStream(&req, &stream,
36+
nullptr);
37+
return req;
38+
}
39+
40+
void WriteResponseToFd(int fd, std::string_view greeting) {
41+
SampleResponse response;
42+
response.set_greeting(greeting);
43+
google::protobuf::util::SerializeDelimitedToFileDescriptor(response, fd);
44+
}
45+
46+
// Parses the file system directory structure and tries to edit an existing
47+
// file. If a file can be written to, it sends a fail message. Else, it
48+
// succeeds.
49+
absl::Status ParseFileSystemAndVerifyNoEdit(std::filesystem::path dir) {
50+
auto verify_no_edit = [](const std::filesystem::path& path) {
51+
if (!std::filesystem::is_regular_file(path)) {
52+
return absl::OkStatus();
53+
}
54+
std::ofstream out_file(path.c_str());
55+
if (out_file.fail()) {
56+
return absl::OkStatus();
57+
}
58+
out_file << "Able to edit";
59+
out_file.close();
60+
return absl::InternalError(
61+
absl::StrCat("Failure. Able to edit ", path.c_str(),
62+
". Expected read-only filesystem."));
63+
};
64+
if (auto status = verify_no_edit(dir); !status.ok()) {
65+
return status;
66+
}
67+
for (const auto& entry : std::filesystem::recursive_directory_iterator(dir)) {
68+
// Recursively traverse subdirectories
69+
if (auto status = verify_no_edit(entry.path()); !status.ok()) {
70+
return status;
71+
}
72+
}
73+
return absl::OkStatus();
74+
}
75+
76+
int main(int argc, char* argv[]) {
77+
if (argc < 2) {
78+
std::cerr << "Not enough arguments!";
79+
return -1;
80+
}
81+
int fd = std::stoi(argv[1]);
82+
SampleRequest sample_request = ReadRequestFromFd(fd);
83+
auto status = ParseFileSystemAndVerifyNoEdit("/");
84+
if (status.ok()) {
85+
WriteResponseToFd(fd, "Success.");
86+
} else {
87+
WriteResponseToFd(fd, std::move(status).message());
88+
}
89+
return 0;
90+
}

src/roma/byob/test/roma_byob_test.cc

+40-6
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,12 @@ const std::filesystem::path kCPlusPlusBinaryFilename = "sample_udf";
5353
const std::filesystem::path kCPlusPlusCapBinaryFilename = "cap_udf";
5454
const std::filesystem::path kCPlusPlusSocketFinderBinaryFilename =
5555
"socket_finder_udf";
56-
const std::filesystem::path kCPlusPlusFileSystemModificationFilename =
57-
"filesystem_udf";
56+
const std::filesystem::path kCPlusPlusFileSystemAddFilename =
57+
"filesystem_add_udf";
58+
const std::filesystem::path kCPlusPlusFileSystemDeleteFilename =
59+
"filesystem_delete_udf";
60+
const std::filesystem::path kCPlusPlusFileSystemEditFilename =
61+
"filesystem_edit_udf";
5862
const std::filesystem::path kCPlusPlusNewBinaryFilename = "new_udf";
5963
const std::filesystem::path kCPlusPlusLogBinaryFilename = "log_udf";
6064
const std::filesystem::path kCPlusPlusPauseBinaryFilename = "pause_udf";
@@ -207,16 +211,46 @@ TEST(RomaByobTest, NoSocketFileInSandboxMode) {
207211
::testing::StrEq("Success."));
208212
}
209213

210-
TEST(RomaByobTest, NoFileSystemChangeEgressionInNonSandboxMode) {
214+
TEST(RomaByobTest, NoFileSystemCreateEgressionInNonSandboxMode) {
211215
Mode mode = Mode::kModeNoSandbox;
212216
if (!HasClonePermissionsByobWorker(mode)) {
213217
GTEST_SKIP() << "HasClonePermissionsByobWorker check returned false";
214218
}
215219
ByobSampleService<> roma_service = GetRomaService(mode);
216220

217-
std::string code_token = LoadCode(
218-
roma_service, kUdfPath / kCPlusPlusFileSystemModificationFilename,
219-
/*enable_log_egress=*/true, /*num_workers=*/1);
221+
std::string code_token =
222+
LoadCode(roma_service, kUdfPath / kCPlusPlusFileSystemAddFilename,
223+
/*enable_log_egress=*/true, /*num_workers=*/1);
224+
225+
EXPECT_THAT(SendRequestAndGetResponse(roma_service, code_token).greeting(),
226+
::testing::StrEq("Success."));
227+
}
228+
229+
TEST(RomaByobTest, NoFileSystemDeleteEgressionInNonSandboxMode) {
230+
Mode mode = Mode::kModeNoSandbox;
231+
if (!HasClonePermissionsByobWorker(mode)) {
232+
GTEST_SKIP() << "HasClonePermissionsByobWorker check returned false";
233+
}
234+
ByobSampleService<> roma_service = GetRomaService(mode);
235+
236+
std::string code_token =
237+
LoadCode(roma_service, kUdfPath / kCPlusPlusFileSystemDeleteFilename,
238+
/*enable_log_egress=*/true, /*num_workers=*/1);
239+
240+
EXPECT_THAT(SendRequestAndGetResponse(roma_service, code_token).greeting(),
241+
::testing::StrEq("Success."));
242+
}
243+
244+
TEST(RomaByobTest, NoFileSystemEditEgressionInNonSandboxMode) {
245+
Mode mode = Mode::kModeNoSandbox;
246+
if (!HasClonePermissionsByobWorker(mode)) {
247+
GTEST_SKIP() << "HasClonePermissionsByobWorker check returned false";
248+
}
249+
ByobSampleService<> roma_service = GetRomaService(mode);
250+
251+
std::string code_token =
252+
LoadCode(roma_service, kUdfPath / kCPlusPlusFileSystemEditFilename,
253+
/*enable_log_egress=*/true, /*num_workers=*/1);
220254

221255
EXPECT_THAT(SendRequestAndGetResponse(roma_service, code_token).greeting(),
222256
::testing::StrEq("Success."));

0 commit comments

Comments
 (0)