Skip to content

Commit a9d499d

Browse files
Sandboxed API Teamcopybara-github
authored andcommitted
Rollforward PassthroughBackend implementation with fixes
PiperOrigin-RevId: 897052219 Change-Id: Id798168d5564a559a1fc94a68a898ca6e3458566
1 parent 6ab0caa commit a9d499d

9 files changed

Lines changed: 452 additions & 44 deletions

File tree

sandboxed_api/BUILD

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,3 +412,28 @@ cc_library(
412412
],
413413
visibility = ["//visibility:public"],
414414
)
415+
416+
cc_library(
417+
name = "passthrough_backend",
418+
srcs = [
419+
"passthrough_rpcchannel.cc",
420+
"passthrough_rpcchannel.h",
421+
],
422+
hdrs = [
423+
"passthrough_backend.h",
424+
],
425+
deps = [
426+
":call",
427+
":rpcchannel",
428+
":sandbox_config",
429+
":var_type",
430+
"@abseil-cpp//absl/base:core_headers",
431+
"@abseil-cpp//absl/container:flat_hash_set",
432+
"@abseil-cpp//absl/functional:any_invocable",
433+
"@abseil-cpp//absl/status",
434+
"@abseil-cpp//absl/status:statusor",
435+
"@abseil-cpp//absl/synchronization",
436+
"@abseil-cpp//absl/time",
437+
"@abseil-cpp//absl/types:span",
438+
],
439+
)

sandboxed_api/CMakeLists.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,30 @@ target_link_libraries(sapi_shared_memory_rpcchannel
9494
sapi::status
9595
)
9696

97+
# sandboxed_api:passthrough_backend
98+
add_library(sapi_passthrough_backend ${SAPI_LIB_TYPE}
99+
passthrough_backend.h
100+
passthrough_rpcchannel.cc
101+
passthrough_rpcchannel.h
102+
)
103+
add_library(sapi::passthrough_backend ALIAS sapi_passthrough_backend)
104+
target_link_libraries(sapi_passthrough_backend
105+
PRIVATE absl::any_invocable
106+
absl::flat_hash_set
107+
absl::status
108+
absl::statusor
109+
absl::span
110+
absl::synchronization
111+
absl::time
112+
sapi::base
113+
sapi::call
114+
sapi::rpcchannel
115+
sapi::sandbox_config
116+
sapi::var_type
117+
${CMAKE_DL_LIBS}
118+
PUBLIC absl::check
119+
)
120+
97121
# sandboxed_api:sandbox2_backend
98122
add_library(sapi_sandbox2_backend ${SAPI_LIB_TYPE}
99123
sandbox2_backend.cc
@@ -172,6 +196,7 @@ target_link_libraries(sapi_sapi
172196
sandbox2::sandbox2
173197
sapi::base
174198
sapi::sandbox_config
199+
sapi::passthrough_backend
175200
sapi::sandbox2_backend
176201
sapi::status
177202
)

sandboxed_api/bazel/sapi.bzl

Lines changed: 55 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ def _sapi_interface_impl(ctx):
166166
append_arg(args, "--sapi_functions", ",".join(ctx.attr.functions))
167167
append_arg(args, "--sapi_ns", ctx.attr.namespace)
168168

169+
if use_clang_generator:
170+
append_arg(args, "--sapi_sandbox_mode", ctx.attr.sandbox_mode)
171+
169172
if use_clang_generator and ctx.outputs.sandboxee_src_out:
170173
append_arg(args, "--sapi_sandboxee_src_out", ctx.outputs.sandboxee_src_out.path)
171174
outs.append(ctx.outputs.sandboxee_src_out)
@@ -261,6 +264,7 @@ sapi_interface = rule(
261264
"_generator_v1": make_exec_label(
262265
"//sandboxed_api/tools/python_generator:sapi_generator",
263266
),
267+
"sandbox_mode": attr.string(default = "sandbox2"),
264268
"symbol_list_gen": attr.bool(default = False),
265269
"_generator_v2": make_exec_label(
266270
# TODO(cblichmann): Add prebuilt version of Clang based generator
@@ -331,7 +335,8 @@ def sapi_library(
331335
visibility = None,
332336
compatible_with = None,
333337
default_copts = [],
334-
exec_properties = {}):
338+
exec_properties = {},
339+
sandbox_mode = "sandbox2"):
335340
"""Provides the implementation of a Sandboxed API library.
336341
337342
Args:
@@ -371,13 +376,17 @@ def sapi_library(
371376
default_copts: List of package level default copts, an additional
372377
attribute since copts already has default value.
373378
exec_properties: Dict of executable properties to be passed to the generated binary targets.
379+
sandbox_mode: Sandbox mode to use for the generated library. Either "sandbox2" (default) or "passthrough".
374380
"""
375381

376382
common = _common_kwargs(tags, visibility, compatible_with)
377383
generated_file_prefix = name + ".sapi"
378384
generated_header = generated_file_prefix + ".h"
379385
generated_sandboxee_src = generated_file_prefix + ".sandboxee.cc"
380386
use_sandboxee_generation = generator_version == 3
387+
if sandbox_mode == "passthrough":
388+
embed = False
389+
in_process = sandbox_mode == "passthrough"
381390

382391
# Reference (pull into the archive) required functions only. If the functions'
383392
# array is empty, pull in the whole archive (may not compile with MSAN).
@@ -387,16 +396,48 @@ def sapi_library(
387396
"-Wl,--whole-archive",
388397
"-Wl,--allow-multiple-definition",
389398
]
399+
sandboxee_linkopts = [
400+
"-ldl", # For dlopen(), dlsym()
401+
# The sandboxing client must have access to all
402+
"-Wl,-E", # symbols used in the sandboxed library, so these
403+
] + exported_funcs # must be both referenced, and exported
390404

391405
lib_hdrs = hdrs or []
392406

393407
lib_hdrs.append(generated_header)
394408

395409
default_deps = ["//sandboxed_api/sandbox2"]
396410

397-
sapi_data_deps = [":" + name + ".bin"] if not embed else []
411+
sapi_data_deps = [":" + name + ".bin"] if not embed and not in_process else []
398412

399-
backend_dep = ["//sandboxed_api:sandbox2_backend"]
413+
backend_dep = []
414+
if sandbox_mode == "sandbox2":
415+
backend_dep = ["//sandboxed_api:sandbox2_backend"]
416+
elif sandbox_mode == "passthrough":
417+
backend_dep = ["//sandboxed_api:passthrough_backend", ":" + name + ".lib"]
418+
else:
419+
fail("Unsupported sandbox mode: " + sandbox_mode)
420+
421+
if use_sandboxee_generation:
422+
cc_library(
423+
name = name + ".sandboxee",
424+
srcs = [generated_sandboxee_src],
425+
deps = [
426+
":" + name + ".lib",
427+
"@abseil-cpp//absl/base:core_headers",
428+
"@abseil-cpp//absl/base:no_destructor",
429+
"@abseil-cpp//absl/container:flat_hash_map",
430+
"@abseil-cpp//absl/log",
431+
"@abseil-cpp//absl/strings:string_view",
432+
"//sandboxed_api:call",
433+
"//sandboxed_api:function_call_helper",
434+
],
435+
copts = default_copts,
436+
**common
437+
)
438+
client_message_handler = ":" + name + ".sandboxee"
439+
else:
440+
client_message_handler = "//sandboxed_api:call_message_handler"
400441

401442
# Library that contains generated interface and sandboxed binary as a data
402443
# dependency. Add this as a dependency instead of original library.
@@ -407,6 +448,7 @@ def sapi_library(
407448
hdrs = lib_hdrs,
408449
copts = default_copts + copts,
409450
defines = defines,
451+
linkopts = sandboxee_linkopts if in_process else [],
410452
deps = sort_deps(
411453
[
412454
"@abseil-cpp//absl/base:core_headers",
@@ -418,46 +460,24 @@ def sapi_library(
418460
] + deps +
419461
([":" + name + "_embed"] if embed else []) +
420462
(default_deps if add_default_deps else []) +
463+
([client_message_handler] if in_process else []) +
421464
backend_dep,
422465
),
423466
**common
424467
)
425468

426-
if use_sandboxee_generation:
427-
cc_library(
428-
name = name + ".sandboxee",
429-
srcs = [generated_sandboxee_src],
469+
if not in_process:
470+
cc_binary(
471+
name = name + ".bin",
472+
linkopts = sandboxee_linkopts,
473+
malloc = malloc,
430474
deps = [
431-
"@abseil-cpp//absl/base:core_headers",
432-
"@abseil-cpp//absl/base:no_destructor",
433-
"@abseil-cpp//absl/container:flat_hash_map",
434-
"@abseil-cpp//absl/log",
435-
"@abseil-cpp//absl/strings:string_view",
436-
"//sandboxed_api:call",
437-
"//sandboxed_api:function_call_helper",
438-
],
475+
":" + name + ".lib",
476+
"//sandboxed_api:client",
477+
] + [client_message_handler],
439478
copts = default_copts,
440479
**common
441480
)
442-
client_message_handler = ":" + name + ".sandboxee"
443-
else:
444-
client_message_handler = "//sandboxed_api:call_message_handler"
445-
446-
cc_binary(
447-
name = name + ".bin",
448-
linkopts = [
449-
"-ldl", # For dlopen(), dlsym()
450-
# The sandboxing client must have access to all
451-
"-Wl,-E", # symbols used in the sandboxed library, so these
452-
] + exported_funcs, # must be both referenced, and exported
453-
malloc = malloc,
454-
deps = [
455-
":" + name + ".lib",
456-
"//sandboxed_api:client",
457-
] + [client_message_handler],
458-
copts = default_copts,
459-
**common
460-
)
461481

462482
cc_library(
463483
name = name + ".lib",
@@ -494,6 +514,7 @@ def sapi_library(
494514
api_version = api_version,
495515
generator_version = generator_version,
496516
limit_scan_depth = limit_scan_depth,
517+
sandbox_mode = sandbox_mode,
497518
**common
498519
)
499520

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright 2026 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+
// https://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+
#ifndef SANDBOXED_API_NULL_BACKEND_H_
16+
#define SANDBOXED_API_NULL_BACKEND_H_
17+
18+
#include <memory>
19+
#include <utility>
20+
21+
#include "absl/status/status.h"
22+
#include "absl/status/statusor.h"
23+
#include "absl/time/time.h"
24+
#include "sandboxed_api/passthrough_rpcchannel.h"
25+
#include "sandboxed_api/sandbox_config.h"
26+
27+
namespace sapi {
28+
29+
class SandboxBase;
30+
31+
class PassthroughBackend {
32+
public:
33+
using CallFunctionT = PassthroughRPCChannel::CallFunctionT;
34+
PassthroughBackend(SandboxConfig config, CallFunctionT call_function)
35+
: rpc_channel_(
36+
std::make_unique<PassthroughRPCChannel>(std::move(call_function))) {
37+
}
38+
39+
// Initializes a new sandboxing session.
40+
absl::Status Init() { return absl::OkStatus(); }
41+
42+
// Returns whether the current sandboxing session is active.
43+
bool is_active() const { return true; }
44+
45+
PassthroughRPCChannel* rpc_channel() const { return rpc_channel_.get(); }
46+
47+
absl::Status SetWallTimeLimit(absl::Duration limit) const {
48+
// TODO(sroettger): This should enforce a wall time limit.
49+
return absl::OkStatus();
50+
}
51+
52+
absl::Status AwaitExitStatus() { return absl::OkStatus(); }
53+
54+
absl::StatusOr<int> GetPid() const {
55+
return absl::UnavailableError("In-process sandbox has no pid");
56+
}
57+
58+
void Terminate(bool attempt_graceful_exit = true) {}
59+
60+
private:
61+
std::unique_ptr<PassthroughRPCChannel> rpc_channel_;
62+
};
63+
64+
} // namespace sapi
65+
66+
#endif // SANDBOXED_API_NULL_BACKEND_H_

0 commit comments

Comments
 (0)