شروع به کار کردن با Sandboxed API

در این صفحه، با نحوه ایجاد کتابخانه C/C++‎ در محیط امن خودتان بااستفاده از Sandboxed API (SAPI) آشنا خواهید شد. از آن به‌عنوان راهنما در کنار مثال‌ها و مستندات کد در فایل‌های سرصفحه استفاده کنید.

وابستگی‌های ساخت

وابستگی‌های زیر باید روی سیستم نصب شوند:

  • هسته Linux با پشتیبانی از UTS،‏ IPC، کاربر، PID، و فضاهای نام شبکه
  • سراینده‌های API فضای کاربر Linux
  • برای کامپایل کردن کد: GCC 6 (نسخه ۷ یا بالاتر ترجیح داده می‌شود) یا Clang 7 (یا بالاتر)
  • برای تولید خودکار فایل‌های سرایند: Clang Python Bindings
  • ‫Python 3.5 یا نسخه‌های جدیدتر
  • نسخه Bazel‏ ۲.۲.۰ یا CMake نسخه ۳.۱۲ یا بالاتر.
    • فقط CMake: GNU Make یا نسخه‌ای از سرصفحه‌های کتابخانه libcap و ابزار ساخت مانند Ninja (توصیه‌شده).

استفاده از Bazel

‫Bazel سیستم ساخت توصیه‌شده است و ادغام با آن از همه آسان‌تر است.

اسناد ما از کامپایلر Clang استفاده می‌کند. اگر به زنجیره ابزار خاصی نیاز دارید (مثلاً، گردآورنده، پیونددهنده، و غیره)، برای اطلاعات درباره نحوه تغییر زنجیره ابزار گردآورنده پیش‌فرض، به مستندات Bazel مراجعه کنید.

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++‎ در جعبه امن، باید دو مورد را برای پروژه‌تان آماده کنید:

ممکن است با zlib از نمونه‌های Sandbox2 آشنا باشید در اینجا یک برنامه کامل (zpipe.c) در محیط امن اجرا شده است. در مراحل زیر، با نحوه استفاده از SAPI برای قراردادن کتابخانه zlib در محیط امن و استفاده از «کتابخانه در محیط امن» آشنا خواهید شد.

۱. تصمیم بگیرید کدام توابع موردنیاز هستند

اگر به کد میزبان zlib نگاه کنید (main_zlib.cc)، می‌بینید که عملکرد ابزار خواندن داده‌ها از stdin و استفاده از تابع deflate() zlib برای فشرده کردن داده‌ها تا زمانی است که نشانگر EOF خوانده شود. درمجموع، این برنامه از سه تابع zlib استفاده می‌کند:

  • ‫deflateInit_(): برای مقداردهی اولیه فشرده‌سازی
  • deflate(): برای انجام عملیات فشرده‌سازی روی بخش داده
  • deflateEnd(): برای پایان دادن به فشرده‌سازی و آزاد کردن ساختارهای داده تخصیص‌یافته به‌صورت پویا

در یک مثال واقعی، کتابخانه C/C++‎ را مرور می‌کنید و تصمیم می‌گیرید که کدام تابع‌ها موردنیاز است. یک راهبرد احتمالی این است که با «کد میزبان» شروع کنید و از کتابخانه بدون جعبه امن استفاده کنید. سپس، در مرحله دوم، می‌توانید «کتابخانه جعبه امن» را تولید کنید و «کد میزبان» را برای استفاده از فراخوانی‌های تابع جعبه امن تطبیق دهید.

۲. نوشتن قانون ساخت sapi_library

پس‌از شناسایی سه تابع zlib موردنیاز از کتابخانه zlib جعبه ایمنی، می‌توانید قانون ساخت را در فایل BUILD تعریف کنید. اسناد مربوط به قانون ساخت sapi_library را می‌توانید در صفحه قوانین ساخت پیدا کنید.

تکه‌کد زیر تعریف sapi_library را برای نمونه zlib SAPI نشان می‌دهد. بااستفاده از مشخصه lib، به Bazel دستور داده می‌شود که در فایل WORKSPACE به‌دنبال کتابخانه zlib بگردد.

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()) استفاده می‌کند.

۳. نوشتن یا تغییر دادن کد میزبان

اکنون زمان آن است که «کتابخانه 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 مشاهده کرد، جایی که از SAPI Struct استفاده می‌شود: sapi::v::Struct<sapi::zlib::z_stream> strm;

نوع الگو (sapi::zlib::z_stream) نمونه خوبی از کد تولیدشده خودکار توسط قانون ساخت است.

برای جزئیات بیشتر، به صفحه متغیرها نگاهی بیندازید.

برقراری تماس‌های میانای برنامه‌سازی کاربردی

برای برقراری تماس با defalteInit_، deflate، یا deflateEnd، از SAPI Object استفاده کنید. اگر تصمیم گرفتید از رویکرد «تغییر» استفاده کنید، باید مطمئن شوید که پارامترهای تابع با مقادیر موردانتظار مطابقت داشته باشند.

مثالی از هریک از فراخوانی‌ها در zlib example:

  • 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 نگاهی بیندازید.

مثال‌ها

در بخش نمونه‌ها می‌توانید چند کتابخانه را که قبلاً توسط تیم SAPI آماده شده است پیدا کنید.