เริ่มต้นใช้งาน API ที่แซนด์บ็อกซ์

ในหน้านี้ คุณจะได้เรียนรู้วิธีสร้างไลบรารี C/C++ ที่อยู่ในแซนด์บ็อกซ์ของคุณเองด้วย Sandboxed API (SAPI) ใช้เป็นแนวทางควบคู่ไปกับ ตัวอย่างและเอกสารประกอบโค้ดใน ไฟล์ส่วนหัว

สร้างความสัมพันธ์

คุณต้องติดตั้งความสัมพันธ์ต่อไปนี้ในระบบ

  • เคอร์เนล Linux ที่รองรับเนมสเปซ UTS, IPC, ผู้ใช้, PID และเครือข่าย
  • ส่วนหัว API ของพื้นที่ผู้ใช้ Linux
  • หากต้องการคอมไพล์โค้ด ให้ใช้ GCC 6 (แนะนำให้ใช้เวอร์ชัน 7 ขึ้นไป) หรือ Clang 7 (ขึ้นไป)
  • หากต้องการสร้างไฟล์ส่วนหัวโดยอัตโนมัติ ให้ใช้ Clang Python Bindings
  • Python 3.5 ขึ้นไป
  • Bazel เวอร์ชัน 2.2.0 หรือ CMake เวอร์ชัน 3.12 ขึ้นไป
    • CMake เท่านั้น: GNU Make หรือเวอร์ชัน ของส่วนหัวของไลบรารี libcap และเครื่องมือบิลด์ เช่น Ninja (แนะนำ)

การใช้ Bazel

Bazel เป็นระบบบิลด์ที่แนะนำและผสานรวมได้ง่ายที่สุด

เอกสารประกอบของเราใช้คอมไพเลอร์ Clang หากต้องการ Toolchain เฉพาะ (เช่น คอมไพเลอร์, Linker ฯลฯ) โปรดดูเอกสารประกอบของ Bazel เพื่อดูข้อมูลเกี่ยวกับวิธีเปลี่ยน Toolchain คอมไพเลอร์เริ่มต้น

Debian 10 (Buster)

วิธีติดตั้งความสัมพันธ์ในการบิลด์

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

ตัวเลือกเคอร์เนลที่จำเป็น

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

วิธีติดตั้งความสัมพันธ์ในการบิลด์

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

การใช้ CMake

CMake เป็นระบบเมตาบิลด์แบบโอเพนซอร์สยอดนิยมที่ สร้างไฟล์โปรเจ็กต์สำหรับเครื่องมือบิลด์ เช่น Ninja หรือ Make

Debian 10 (Buster)

วิธีติดตั้งความสัมพันธ์ในการบิลด์

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

ตัวเลือกเคอร์เนลที่จำเป็น

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

วิธีติดตั้งความสัมพันธ์ในการบิลด์

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

กระบวนการพัฒนา

หากต้องการใส่ไลบรารี C/C++ ไว้ในแซนด์บ็อกซ์ คุณจะต้องเตรียม 2 รายการสำหรับโปรเจ็กต์

  • ไลบรารีที่อยู่ในแซนด์บ็อกซ์
  • โค้ดโฮสต์ที่จะ ใช้ฟังก์ชันการทำงานที่ไลบรารีที่อยู่ในแซนด์บ็อกซ์แสดง SAPI จะสร้าง ออบเจ็กต์ SAPI และ RPC Stub ให้คุณโดยอัตโนมัติในระหว่างกระบวนการบิลด์

คุณอาจคุ้นเคยกับ zlib จาก ตัวอย่าง Sandbox2 ที่นี่ ซึ่งมีการใส่โปรแกรมทั้งหมด (zpipe.c) ไว้ในแซนด์บ็อกซ์ ในขั้นตอนต่อไปนี้ คุณจะได้เรียนรู้วิธีใช้ SAPI เพื่อ ใส่ไลบรารี zlib ไว้ในแซนด์บ็อกซ์และ ใช้ประโยชน์จากไลบรารีที่อยู่ในแซนด์บ็อกซ์

1. ตัดสินใจว่าต้องการฟังก์ชันใด

หากดูโค้ดโฮสต์ zlib (main_zlib.cc) คุณจะเห็นว่าฟังก์ชันการทำงานของเครื่องมือคือการอ่านข้อมูลจาก stdin และใช้ ฟังก์ชัน deflate() ของ zlib เพื่อบีบอัดข้อมูลจนกว่าจะอ่านเครื่องหมาย EOF โดยรวมแล้ว โปรแกรมจะใช้ฟังก์ชัน 3 ฟังก์ชันจาก zlib ดังนี้

  • deflateInit_(): เพื่อเริ่มต้นการบีบอัด
  • deflate(): เพื่อดำเนินการบีบอัดในส่วนข้อมูล
  • deflateEnd(): เพื่อสิ้นสุดการบีบอัดและปล่อยโครงสร้างข้อมูลที่จัดสรรแบบไดนามิก

ในตัวอย่างการใช้งานจริง คุณจะต้องตรวจสอบไลบรารี C/C++ และตัดสินใจว่าต้องการฟังก์ชันใด กลยุทธ์ที่เป็นไปได้คือเริ่มต้นด้วยโค้ดโฮสต์และใช้ไลบรารีที่ไม่ได้อยู่ในแซนด์บ็อกซ์ จากนั้นในขั้นตอนที่ 2 คุณสามารถสร้างไลบรารีที่อยู่ในแซนด์บ็อกซ์และปรับโค้ดโฮสต์เพื่อใช้การเรียกใช้ฟังก์ชันที่อยู่ในแซนด์บ็อกซ์

2. เขียนกฎบิลด์ sapi_library

หลังจากระบุฟังก์ชัน zlib 3 ฟังก์ชันที่ต้องการจาก ไลบรารี zlib ที่อยู่ในแซนด์บ็อกซ์แล้ว คุณสามารถกำหนดกฎบิลด์ใน ไฟล์ BUILD ได้ เอกสารประกอบสำหรับกฎบิลด์ sapi_library จะอยู่ในหน้า กฎบิลด์

ข้อมูลโค้ดด้านล่างแสดงคำจำกัดความ sapi_library สำหรับตัวอย่าง SAPI zlib การใช้แอตทริบิวต์ lib จะสั่งให้ Bazel ค้นหาไลบรารี zlib ในไฟล์ WORKSPACE

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

ผลลัพธ์ที่ได้คือการสร้างไลบรารี zlib ที่อยู่ในแซนด์บ็อกซ์ เอาต์พุตคือออบเจ็กต์ SAPI ซึ่งสามารถรวมไว้ในโค้ดโฮสต์และใช้เพื่อสื่อสารกับไลบรารีที่อยู่ในแซนด์บ็อกซ์โดยใช้การเรียก RPC

ตัวอย่างนี้ใช้การกำหนดค่าแซนด์บ็อกซ์เริ่มต้นที่ DefaultConfig (sapi::SandboxConfig::DefaultConfig())

3. เขียนหรือเปลี่ยนโค้ดโฮสต์

ตอนนี้ได้เวลาที่จะรวมไลบรารี SAPI ที่สร้างขึ้นไว้ในโค้ดโฮสต์แล้ว

สร้างแซนด์บ็อกซ์

ใช้ sapi::zlib::ZlibSandbox sandbox; เพื่อสร้างออบเจ็กต์แซนด์บ็อกซ์

ใช้ sapi::zlib::ZlibApi api(&sandbox); เพื่อสร้างอินสแตนซ์ออบเจ็กต์ SAPI และทำให้ ฟังก์ชันที่อยู่ในแซนด์บ็อกซ์พร้อมใช้งาน

หากต้องการปรับแต่งนโยบาย แฟล็ก ตัวแปรสภาพแวดล้อม หรือขีดจำกัดของแซนด์บ็อกซ์ ให้เริ่ม จาก sapi::SandboxConfig::DefaultConfig() แก้ไขช่องที่เกี่ยวข้อง (โดยใช้ sapi::Sandbox2Config::DefaultPolicyBuilder() sapi::SandboxConfig::DefaultFlags() หรือ sapi::SandboxConfig::DefaultEnvironmentVariables() เพื่อให้ระบบรักษาการตั้งค่าพื้นฐานไว้) และส่ง sapi::SandboxConfig ไปยังตัวสร้างแซนด์บ็อกซ์ ดังนี้

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));

ใช้ประเภท SAPI

ประเภท SAPI เป็นประเภทพิเศษ ในรูปแบบคลาส C++ ที่ SAPI มีให้เนื่องจากบางครั้งประเภท C ปกติ จะใช้ไม่ได้

การใช้ประเภท SAPI ครั้งแรกจะเห็นได้ในการประกาศ strm ซึ่ง ใช้ Struct SAPI ดังนี้ sapi::v::Struct<sapi::zlib::z_stream> strm;

ประเภทเทมเพลต (sapi::zlib::z_stream) เป็นตัวอย่างที่ดีของโค้ดที่กฎบิลด์สร้างขึ้นโดยอัตโนมัติ

ดูรายละเอียดเพิ่มเติมได้ที่หน้าตัวแปร

ทำการเรียก API

หากต้องการทำการเรียก defalteInit_, deflate หรือ deflateEnd ให้ใช้ออบเจ็กต์ SAPI หากตัดสินใจใช้แนวทาง "เปลี่ยน" คุณต้องตรวจสอบว่าพารามิเตอร์ฟังก์ชันตรงกับค่าที่คาดไว้

ตัวอย่างการเรียกแต่ละรายการในตัวอย่าง 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();

การใช้ธุรกรรม SAPI

SAPI แยกโค้ดโฮสต์ออกจากไลบรารีที่อยู่ในแซนด์บ็อกซ์และช่วยให้ผู้เรียกสามารถรีสตาร์ทหรือยกเลิกคำขอการประมวลผลข้อมูลที่มีปัญหาได้ ธุรกรรม SAPI ทำงานได้มากกว่านั้นและจะทำซ้ำกระบวนการที่ล้มเหลวโดยอัตโนมัติ

ดูรายละเอียดเพิ่มเติมได้ที่หน้าธุรกรรม SAPI

ตัวอย่าง

ในส่วนตัวอย่าง คุณจะเห็นไลบรารี 2-3 รายการ ที่ทีม SAPI เตรียมไว้แล้ว