Bắt đầu sử dụng Sandboxed API

Trên trang này, bạn sẽ tìm hiểu cách tạo thư viện C/C++ trong hộp cát của riêng mình bằng API hộp cát (SAPI). Hãy sử dụng hướng dẫn này cùng với các ví dụ và tài liệu về mã trong các tệp tiêu đề.

Phần phụ thuộc của bản dựng

Bạn phải cài đặt các phần phụ thuộc sau đây trên hệ thống:

  • Nhân Linux có hỗ trợ UTS, IPC, người dùng, PID và không gian tên mạng
  • Tiêu đề API không gian người dùng Linux
  • Để biên dịch mã: GCC 6 (ưu tiên phiên bản 7 trở lên) hoặc Clang 7 (trở lên)
  • Để được tạo tự động tệp tiêu đề: Clang Python Bindings
  • Python 3.5 trở lên
  • Bazel phiên bản 2.2.0 hoặc CMake phiên bản 3.12 trở lên.
    • Chỉ dành cho CMake: GNU Make hoặc một phiên bản của tiêu đề thư viện libcap và một công cụ xây dựng như Ninja (nên dùng).

Sử dụng Bazel

Bazel là hệ thống xây dựng được đề xuất và dễ tích hợp nhất.

Tài liệu của chúng tôi sử dụng trình biên dịch Clang. Nếu bạn cần một chuỗi công cụ cụ thể (ví dụ: trình biên dịch, trình liên kết, v.v.), hãy tham khảo tài liệu về Bazel để biết thông tin về cách thay đổi chuỗi công cụ biên dịch mặc định.

Debian 10 (Buster)

Cách cài đặt các phần phụ thuộc của bản dựng:

echo "deb http://storage.googleapis.com/bazel-apt stable jdk1.8" | \
  sudo tee /etc/apt/sources.list.d/bazel.list
wget -qO - https://releases.bazel.build/bazel-release.pub.gpg | sudo apt-key add -
sudo apt-get update
sudo apt-get install -qy build-essential linux-libc-dev bazel python3 \
  python3-pip libclang-dev
pip3 install clang

Gentoo

Các tuỳ chọn bắt buộc về nhân hệ điều hành:

General setup  --->
-*- Namespaces support
[*]   UTS namespace
[*]   IPC namespace
[*]   User namespace (EXPERIMENTAL)
[*]   PID Namespaces
[*]   Network namespace

Cách cài đặt các phần phụ thuộc của bản dựng:

emerge dev-util/bazel dev-python/typing dev-python/clang-python

Sử dụng CMake

CMake là một hệ thống siêu bản dựng nguồn mở phổ biến, giúp tạo tệp dự án cho các công cụ bản dựng như Ninja hoặc Make.

Debian 10 (Buster)

Cách cài đặt các phần phụ thuộc của bản dựng:

sudo apt-get install -qy build-essential linux-libc-dev cmake ninja-build \
  python3 python3-pip libclang-dev libcap-dev
pip3 install absl-py clang

Gentoo

Các tuỳ chọn bắt buộc về nhân hệ điều hành:

General setup  --->
-*- Namespaces support
[*]   UTS namespace
[*]   IPC namespace
[*]   User namespace (EXPERIMENTAL)
[*]   PID Namespaces
[*]   Network namespace

Cách cài đặt các phần phụ thuộc của bản dựng:

emerge sys-kernel/linux-headers dev-util/cmake dev-util/ninja \
dev-python/clang-python

Quy trình phát triển

Để đưa thư viện C/C++ vào hộp cát, bạn sẽ phải chuẩn bị hai mục cho dự án của mình:

Bạn có thể đã quen với zlib trong các ví dụ Sandbox2. Tại đây, toàn bộ chương trình (zpipe.c) đã được đưa vào hộp cát. Trong các bước sau, bạn sẽ tìm hiểu cách sử dụng SAPI để hộp cát thư viện zlib và sử dụng Thư viện hộp cát.

1. Quyết định những hàm cần thiết

Nếu xem mã máy chủ lưu trữ zlib (main_zlib.cc), bạn có thể thấy chức năng của công cụ này là đọc dữ liệu từ stdin và sử dụng hàm deflate() của zlib để nén dữ liệu cho đến khi đọc được điểm đánh dấu EOF. Tổng cộng, chương trình sử dụng ba hàm từ zlib:

  • deflateInit_(): Để khởi động cho quá trình nén
  • deflate(): Để thực hiện thao tác nén trên khối dữ liệu
  • deflateEnd(): Để kết thúc quá trình nén và giải phóng các cấu trúc dữ liệu được phân bổ động

Trong ví dụ thực tế, bạn sẽ xem xét thư viện C/C++ và quyết định những hàm nào cần thiết. Một chiến lược khả thi là bắt đầu bằng Mã lưu trữ và sử dụng thư viện không hộp cát. Sau đó, ở bước thứ hai, bạn có thể tạo Thư viện hộp cát và điều chỉnh Mã lưu trữ để sử dụng các lệnh gọi hàm hộp cát.

2. Viết quy tắc bản dựng sapi_library

Sau khi xác định được 3 hàm zlib cần thiết trong thư viện zlib hộp cát, bạn có thể xác định quy tắc bản dựng trong tệp BUILD. Bạn có thể xem tài liệu về quy tắc xây dựng sapi_library trên trang Quy tắc xây dựng.

Đoạn mã dưới đây cho thấy định nghĩa sapi_library cho ví dụ về SAPI zlib. Khi sử dụng thuộc tính lib, Bazel được hướng dẫn tìm thư viện zlib trong tệp WORKSPACE.

sapi_library(
    name = "zlib-sapi",
    srcs = [],
    hdrs = [],
    functions = [
        "deflateInit_",
        "deflate",
        "deflateEnd",
    ],
    lib = "@net_zlib//:zlib",
    lib_name = "Zlib",
    namespace = "sapi::zlib",
)

Kết quả là thư viện zlib trong hộp cát được tạo. Đầu ra là Đối tượng SAPI có thể được đưa vào Mã máy chủ và dùng để giao tiếp với thư viện trong hộp cát bằng các lệnh gọi RPC.

Ví dụ này sử dụng cấu hình hộp cát mặc định do DefaultConfig (sapi::SandboxConfig::DefaultConfig()) cung cấp.

3. Viết hoặc thay đổi mã của người tổ chức

Bây giờ là lúc kết hợp Thư viện SAPI đã tạo vào Mã máy chủ.

Tạo Hộp cát

Sử dụng sapi::zlib::ZlibSandbox sandbox; để tạo một đối tượng hộp cát.

Sử dụng sapi::zlib::ZlibApi api(&sandbox); để tạo thực thể cho Đối tượng SAPI, từ đó cho phép sử dụng các hàm trong hộp cát.

Để tuỳ chỉnh chính sách, cờ, biến môi trường hoặc giới hạn của hộp cát, hãy bắt đầu từ sapi::SandboxConfig::DefaultConfig(), sửa đổi các trường liên quan (bằng cách sử dụng sapi::Sandbox2Config::DefaultPolicyBuilder(), sapi::SandboxConfig::DefaultFlags() hoặc sapi::SandboxConfig::DefaultEnvironmentVariables() để giữ nguyên chế độ cài đặt cơ sở) và truyền sapi::SandboxConfig đến hàm khởi tạo hộp cát:

sapi::SandboxConfig config = sapi::SandboxConfig::DefaultConfig();
config.sandbox2.policy = sapi::Sandbox2Config::DefaultPolicyBuilder()
                             .AddFile("/path/to/file")
                             .BuildOrDie();
auto flags = sapi::SandboxConfig::DefaultFlags();
flags["my_flag"] = "value";
config.command_line_flags = std::move(flags);

sapi::zlib::ZlibSandbox sandbox(std::move(config));

Sử dụng các loại SAPI

Kiểu SAPI là các kiểu đặc biệt dưới dạng lớp C++ mà SAPI cung cấp vì đôi khi các kiểu C thông thường sẽ không hoạt động.

Bạn có thể thấy lần đầu tiên một loại SAPI được sử dụng trong phần khai báo strm, trong đó một Struct SAPI được sử dụng: sapi::v::Struct<sapi::zlib::z_stream> strm;

Loại mẫu (sapi::zlib::z_stream) là một ví dụ điển hình về mã do quy tắc bản dựng tự động tạo.

Hãy xem trang Biến để biết thêm thông tin chi tiết.

Thực hiện lệnh gọi API

Để gọi đến defalteInit_, deflate hoặc deflateEnd, hãy sử dụng Đối tượng SAPI. Nếu quyết định sử dụng phương pháp "thay đổi", bạn phải đảm bảo rằng các tham số hàm khớp với giá trị dự kiến.

Ví dụ về từng lệnh gọi trong ví dụ về zlib:

  • api.deflateInit_(strm.PtrBoth(), Z_DEFAULT_COMPRESSION,
        version.PtrBefore(), sizeof(sapi::zlib::z_stream));
  • api.deflate(strm.PtrBoth(), flush);
  • api.deflateEnd(strm.PtrBoth()).IgnoreError();

Sử dụng giao dịch SAPI

SAPI tách biệt Mã máy chủ lưu trữ khỏi Thư viện hộp cát và cho phép phương thức gọi khởi động lại hoặc huỷ các yêu cầu xử lý dữ liệu có vấn đề. SAPI Transaction tiến thêm một bước và tự động lặp lại các quy trình không thành công.

Hãy xem Trang giao dịch SAPI để biết thêm thông tin chi tiết.

Ví dụ

Trong phần Ví dụ, bạn có thể tìm thấy một số thư viện do nhóm SAPI chuẩn bị sẵn.