Sandbox2 ব্যবহার শুরু করা

এই পৃষ্ঠায়, আপনি Sandbox2-এর সাহায্যে কীভাবে নিজের স্যান্ডবক্সড এনভায়রনমেন্ট তৈরি করবেন তা জানতে পারবেন। আপনি কীভাবে Sandbox Policy নির্ধারণ করবেন এবং কিছু উন্নত, কিন্তু সাধারণ, টুইক সম্পর্কে জানবেন। উদাহরণ এবং হেডার ফাইলে কোড ডকুমেন্টেশনের পাশাপাশি, এখানে দেওয়া তথ্যকে গাইড হিসেবে ব্যবহার করুন।

১. স্যান্ডবক্স এক্সিকিউটর পদ্ধতি বেছে নিন

স্যান্ডবক্সিং শুরু হয় এক্সিকিউটর (স্যান্ডবক্স এক্সিকিউটর দেখুন) দিয়ে, যা স্যান্ডবক্সি রান করার জন্য দায়িত্বপ্রাপ্ত। এই উদ্দেশ্যে প্রয়োজনীয় API executor.h হেডার ফাইলে থাকে। API খুবই নমনীয় এবং আপনার ব্যবহারের ক্ষেত্রে কী সবচেয়ে ভালো কাজ করে তা বেছে নিতে দেয়। নিম্নলিখিত বিভাগগুলি ৩টি আলাদা আলাদা পদ্ধতি বর্ণনা করে যেগুলি থেকে আপনি বেছে নিতে পারবেন।

পদ্ধতি ১: স্ট্যান্ড-অ্যালোন – স্যান্ডবক্সিং আগে থেকেই চালু আছে এমন বাইনারি এক্সিকিউট করুন

স্যান্ডবক্সিং ব্যবহার করার এটি হল সবচেয়ে সহজ উপায় এবং আপনি যদি এমন কোনও সম্পূর্ণ বাইনারি স্যান্ডবক্স করতে চান যার সোর্স কোড আপনার কাছে নেই, তাহলে এই পদ্ধতিটি ব্যবহার করার জন্য সাজেস্ট করা হয়। এটি স্যান্ডবক্সিং ব্যবহার করার সবচেয়ে নিরাপদ উপায়ও, কারণ এখানে কোনও আনস্যান্ডবক্সড ইনিশিয়ালাইজেশন নেই যা ক্ষতিকর প্রভাব ফেলতে পারে।

নিচের কোড স্নিপেটে, আমরা স্যান্ডবক্স করা বাইনারির পাথ এবং execve syscall-এ পাস করতে হবে এমন আর্গুমেন্টকে ডিফাইন করি। আপনি যেমন executor.h হেডার ফাইলে দেখতে পাচ্ছেন, আমরা envp-এর জন্য কোনও ভ্যালু নির্দিষ্ট করি না এবং তাই পেরেন্ট প্রসেস থেকে এনভায়রনমেন্ট কপি করি। মনে রাখবেন, প্রথম আর্গুমেন্টটি সবসময়ই এক্সিকিউট করার জন্য প্রোগ্রামের নাম এবং আমাদের স্নিপেট অন্য কোনও আর্গুমেন্ট সংজ্ঞায়িত করে না।

এই এক্সিকিউটর পদ্ধতির উদাহরণ হল: স্ট্যাটিক এবং টুল।

#include "sandboxed_api/sandbox2/executor.h"

std::string path = "path/to/binary";
std::vector<std::string> args = {path};  // args[0] will become the sandboxed
                                         // process' argv[0], typically the
                                         // path to the binary.
auto executor = absl::make_unique<sandbox2::Executor>(path, args);

পদ্ধতি ২: Sandbox2 Forkserver – কখন স্যান্ডবক্স করতে হবে তা এক্সিকিউটরকে বলুন

এই পদ্ধতিটি ইনিশিয়ালাইজেশনের সময় আনস্যান্ডবক্সড থাকার সুবিধা প্রদান করে, এবং তারপর ::sandbox2::Client::SandboxMeHere() কল করে কখন স্যান্ডবক্সিংয়ে প্রবেশ করতে হবে তা বেছে নেয়। আপনি কখন স্যান্ডবক্সিং শুরু করতে চান তা কোডে সংজ্ঞায়িত করতে সক্ষম হতে হবে এবং এটি সিঙ্গেল-থ্রেডেড হতে হবে (কেন তা FAQ-তে পড়ুন)।

নিম্নলিখিত কোড স্নিপেটে, আমরা উপরে পদ্ধতি ১-এ উল্লেখ করা একই কোড ব্যবহার করি। তবে, প্রোগ্রামটি শুরু করার সময় আনস্যান্ডবক্সড পদ্ধতিতে চালানোর অনুমতি দেওয়ার জন্য, আমরা set_enable_sandbox_before_exec(false) কল করি।

#include "sandboxed_api/sandbox2/executor.h"

std::string path = "path/to/binary";
std::vector<std::string> args = {path};
auto executor = absl::make_unique<sandbox2::Executor>(path, args);
executor->set_enable_sandbox_before_exec(false);

যেহেতু এক্সিকিউটরের কাছে এখন একটি বন্ধ করা স্যান্ডবক্স আছে যতক্ষণ না এটি স্যান্ডবক্সির দ্বারা জানানো হয়, আমাদের একটি ::sandbox2::Client ইনস্ট্যান্স তৈরি করতে হবে, এক্সিকিউটর এবং স্যান্ডবক্সির মধ্যে যোগাযোগ সেট-আপ করতে হবে এবং তারপরে এক্সিকিউটরকে জানাতে হবে যে আমাদের ইনিশিয়ালাইজেশন শেষ হয়েছে এবং আমরা এখন sandbox2_client.SandboxMeHere() কল করে স্যান্ডবক্সিং শুরু করতে চাই।

// main() of sandboxee
int main(int argc, char** argv) {
  gflags::ParseCommandLineFlags(&argc, &argv, false);

  // Set-up the sandbox2::Client object, using a file descriptor (1023).
  sandbox2::Comms comms(sandbox2::Comms::kSandbox2ClientCommsFD);
  sandbox2::Client sandbox2_client(&comms);
  // Enable sandboxing from here.
  sandbox2_client.SandboxMeHere();
  …

এই এক্সিকিউটর পদ্ধতির একটি উদাহরণ হল crc4, যেখানে crc4bin.cc হল Sandboxee এবং কখন স্যান্ডবক্সে প্রবেশ করতে হবে তা এক্সিকিউটরকে (crc4sandbox.cc) জানায়।

পদ্ধতি ৩: কাস্টম ফর্কসার্ভার – একটি বাইনারি প্রস্তুত করুন, ফর্ক অনুরোধের জন্য অপেক্ষা করুন এবং আপনার নিজের স্যান্ডবক্স করুন

এই মোড আপনাকে একটি বাইনারি শুরু করতে, স্যান্ডবক্সিংয়ের জন্য এটি প্রস্তুত করতে এবং আপনার বাইনারির লাইফসাইকেলের একটি নির্দিষ্ট মুহূর্তে, এটি এক্সিকিউটরের কাছে উপলভ্য করতে দেয়।

এক্সিকিউটর আপনার বাইনারিতে একটি ফর্ক অনুরোধ পাঠাবে, যা fork() (এর মাধ্যমে ::sandbox2::ForkingClient::EnterForkLook()) করবে। নতুন তৈরি হওয়া প্রসেসটি ::sandbox2::Client::SandboxMeHere()-এর সাথে স্যান্ডবক্স করার জন্য রেডি থাকবে।

#include "sandboxed_api/sandbox2/executor.h"

// Start the custom ForkServer
std::string path = "path/to/binary";
std::vector<std::string> args = {path};
auto fork_executor = absl::make_unique<sandbox2::Executor>(path, args);
fork_executor->StartForkServer();

// Initialize Executor with Comms channel to the ForkServer
auto executor = absl::make_unique<sandbox2::Executor>(
    fork_executor->ipc()->GetComms());

মনে রাখবেন যে এই মোডটি বেশ জটিল এবং শুধুমাত্র কয়েকটি নির্দিষ্ট ক্ষেত্রে প্রযোজ্য; যেমন, আপনার মেমরির প্রয়োজনীয়তা খুব বেশি হলে। আপনি COW থেকে সুবিধা পাবেন তবে এর নেতিবাচক দিক হল যে কোনও আসল ASLR নেই। আরেকটি সাধারণ ব্যবহারের উদাহরণ হল, যখন Sandboxee-এর একটি দীর্ঘ, CPU-ইনটেনসিভ ইনিশিয়ালাইজেশন থাকে যা অবিশ্বস্ত ডেটা প্রসেস করার আগে চালানো যেতে পারে।

এই এক্সিকিউটর পদ্ধতির একটি উদাহরণ দেখতে, custom_fork দেখুন।

২. স্যান্ডবক্স নীতি তৈরি করুন

আপনার কাছে এক্সিকিউটর থাকলে, আপনি সম্ভবত Sandboxee-এর জন্য একটি Sandbox নীতি নির্ধারণ করতে চাইবেন। অন্যথায়, Sandboxee শুধুমাত্র ডিফল্ট Syscall নীতি দ্বারা সুরক্ষিত থাকে।

স্যান্ডবক্স নীতির মাধ্যমে, স্যান্ডবক্সী যেসব সিসকল ও আর্গুমেন্ট করতে পারে এবং যেসব ফাইল অ্যাক্সেস করতে পারে, সেগুলি সীমিত করাই হল উদ্দেশ্য। আপনি যে কোড স্যান্ডবক্স করতে চান সেটির জন্য প্রয়োজনীয় সিসকল সম্পর্কে আপনার বিস্তারিত জ্ঞান থাকতে হবে। syscalls পর্যবেক্ষণ করার একটি উপায় হল, Linux-এর কমান্ড-লাইন টুল strace-এর মাধ্যমে কোড রান করানো।

সিস্টেম কলের তালিকা পাওয়ার পরে, আপনি নীতি নির্ধারণ করতে PolicyBuilder ব্যবহার করতে পারবেন।

PolicyBuilder-এ অনেক সুবিধা এবং হেল্পার ফাংশন আছে যা অনেক সাধারণ অপারেশন করতে দেয় (যার মধ্যে অনেক আগেই DefaultPolicyBuilder()-এ অন্তর্ভুক্ত করা হয়েছে)। নিম্নলিখিত তালিকাটি উপলভ্য ফাংশনের একটি ছোট উদ্ধৃতি মাত্র:

  • প্রসেস স্টার্টআপের জন্য যেকোনও syscall-কে সাদাতালিকায় যোগ করুন:
    • AllowStaticStartup();
    • AllowDynamicStartup();
  • যেকোনও open/read/write* syscall-কে শ্বেত তালিকাভুক্ত করুন:
    • AllowOpen();
    • AllowRead();
    • AllowWrite();
  • যেকোনও এক্সিট/অ্যাক্সেস/স্টেট সম্পর্কিত syscall-কে শ্বেত তালিকাভুক্ত করুন:
    • AllowExit();
    • AllowStat();
    • AllowAccess();
  • ঘুম/সময় সম্পর্কিত যেকোনও syscall-কে শ্বেত তালিকাভুক্ত করুন:
    • AllowTime();
    • AllowSleep();

এইসব সুবিধাজনক ফাংশন যেকোনও প্রাসঙ্গিক syscall-কে সাদাতালিকাভুক্ত করে। এটির সুবিধা হল, একই নীতি বিভিন্ন আর্কিটেকচারে ব্যবহার করা যেতে পারে যেখানে নির্দিষ্ট কিছু syscall উপলভ্য নয় (যেমন, ARM64-এ কোনও OPEN syscall নেই), তবে প্রয়োজনের চেয়ে বেশি syscall চালু করার সামান্য নিরাপত্তা ঝুঁকি থাকে। যেমন, AllowOpen() স্যান্ডবক্সিকে যেকোনও ওপেন সম্পর্কিত সিসকল কল করার অনুমতি দেয়। আপনি যদি শুধুমাত্র একটি নির্দিষ্ট syscall সাদাতালিকাভুক্ত করতে চান, তাহলে আপনি AllowSyscall(); ব্যবহার করতে পারেন একসাথে একাধিক syscall-এর অনুমতি দিতে আপনি AllowSyscalls() ব্যবহার করতে পারেন।

এখনও পর্যন্ত নীতিটি শুধুমাত্র syscall শনাক্তকারী চেক করে। আপনি যদি নীতিকে আরও শক্তিশালী করতে চান এবং এমন একটি নীতি নির্ধারণ করতে চান যেখানে আপনি শুধুমাত্র নির্দিষ্ট আর্গুমেন্ট সহ একটি syscall-কে অনুমতি দেন, তাহলে আপনাকে AddPolicyOnSyscall() বা AddPolicyOnSyscalls() ব্যবহার করতে হবে। এইসব ফাংশন শুধু আর্গুমেন্ট হিসেবে syscall ID নেয় না, এর সাথে Linux kernel থেকে bpf helper macros ব্যবহার করে একটি কাঁচা seccomp-bpf ফিল্টারও নেয়। BPF সম্পর্কে আরও তথ্যের জন্য কার্নেল ডকুমেন্টেশন দেখুন। আপনি যদি দেখেন যে আপনাকে বারবার BPF কোড লিখতে হচ্ছে এবং আপনার মনে হয় যে এর জন্য একটি ইউজেবিলিটি-র‍্যাপার থাকা উচিত, তাহলে ফিচার অনুরোধ জমা দিতে দ্বিধা করবেন না।

syscall-সম্পর্কিত ফাংশন ছাড়াও, PolicyBuilder, স্যান্ডবক্সে কোনও ফাইল/ডিরেক্টরি বাইন্ড-মাউন্ট করার জন্য AddFile() বা AddDirectory()-এর মতো ফাইলের সাথে সম্পর্কিত ফাংশনের একটি সংখ্যাও প্রদান করে। স্যান্ডবক্সের মধ্যে সাময়িক ফাইল স্টোরেজ যোগ করতে AddTmpfs() হেল্পার ব্যবহার করা যেতে পারে।

AddLibrariesForBinary() হল একটি বিশেষ উপযোগী ফাংশন যা লাইব্রেরি ও বাইনারির প্রয়োজনীয় লিঙ্কার যোগ করে।

সাদাতালিকায় যোগ করার জন্য syscall এখনও কিছুটা ম্যানুয়ালি করতে হয় দুর্ভাগ্যবশত। আপনার বাইনারির প্রয়োজন আছে এমন syscalls দিয়ে একটি নীতি তৈরি করুন এবং সাধারণ ওয়ার্কলোড দিয়ে এটি রান করুন। কোনও লঙ্ঘন ট্রিগার হলে, syscall অনুমতি তালিকায় যোগ করুন এবং প্রসেসটি আবার করুন। আপনি যদি এমন কোনও লঙ্ঘনের সম্মুখীন হন যা আপনি মনে করেন যে শ্বেততালিকাভুক্ত করার জন্য ঝুঁকিপূর্ণ হতে পারে এবং প্রোগ্রামটি ত্রুটিগুলি সাবলীলভাবে পরিচালনা করে, তাহলে আপনি BlockSyscallWithErrno()-এর মাধ্যমে এর পরিবর্তে একটি ত্রুটি রিটার্ন করার চেষ্টা করতে পারেন।

নিম্নলিখিত উদাহরণটি সরাসরি sandbox2::PolicyBuilder তৈরি করে write এবং mprotect আর্গুমেন্ট সীমাবদ্ধ করা এবং openat ব্লক করা দেখানোর জন্য (যা DefaultPolicyBuilder() অন্যথায় অনুমতি দেবে):

#include "sandboxed_api/sandbox2/policy.h"
#include "sandboxed_api/sandbox2/policybuilder.h"
#include "sandboxed_api/sandbox2/util/bpf_helper.h"

std::unique_ptr<sandbox2::Policy> CreatePolicy() {
  return sandbox2::PolicyBuilder()
    .AllowSyscall(__NR_read)  // See also AllowRead()
    .AllowTime()              // Allow time, gettimeofday and clock_gettime
    .AddPolicyOnSyscall(__NR_write, {
        ARG(0),        // fd is the first argument of write (argument #0)
        JEQ(1, ALLOW), // allow write only on fd 1
        KILL,          // kill if not fd 1
    })
    .AddPolicyOnSyscall(__NR_mprotect, {
        ARG_32(2), // prot is a 32-bit wide argument, so it's OK to use *_32
                   // macro here
        JNE32(PROT_READ | PROT_WRITE, KILL), // prot must be the RW, otherwise
                                             // kill the process
        ARG(1), // len is a 64-bit argument
        JNE(0x1000, KILL),  // Allow single page syscalls only, otherwise kill
                            // the process
        ALLOW,              // Allow for the syscall to proceed, if prot and
                            // size match
    })
    // Allow the openat() syscall but always return "not found".
    .BlockSyscallWithErrno(__NR_openat, ENOENT)
    .BuildOrDie();
}

৩. সীমা অ্যাডজাস্ট করা

স্যান্ডবক্স নীতি স্যান্ডবক্সিকে নির্দিষ্ট সিসকল কল করা থেকে আটকায় এবং এর ফলে অ্যাটাক সারফেস কম হয়। তবে, কোনও আক্রমণকারী এখনও অনির্দিষ্টকালের জন্য একটি প্রসেস চালিয়ে বা RAM এবং অন্যান্য রিসোর্স শেষ করে অবাঞ্ছিত প্রভাব ফেলতে পারে।

এই হুমকি মোকাবিলা করতে, Sandboxee ডিফল্ট হিসেবে কঠোর এক্সিকিউশন সীমা মেনে চলে। এই ডিফল্ট সীমা আপনার প্রোগ্রামের বৈধ এক্সিকিউশনে সমস্যা সৃষ্টি করলে, আপনি এক্সিকিউটর অবজেক্টে limits() কল করে sandbox2::Limits ক্লাস ব্যবহার করে সেগুলি অ্যাডজাস্ট করতে পারেন।

নিচের কোড স্নিপেটে সীমা অ্যাডজাস্ট করার কিছু উদাহরণ দেখানো হয়েছে। উপলভ্য সব বিকল্প limits.h হেডার ফাইলে ডকুমেন্ট করা আছে।

// Restrict the address space size of the sandboxee to 4 GiB.
executor->limits()->set_rlimit_as(4ULL << 30);
// Kill sandboxee with SIGXFSZ if it writes more than 1 GiB to the filesystem.
executor->limits()->set_rlimit_fsize(1ULL << 30);
// Number of file descriptors which can be used by the sandboxee.
executor->limits()->set_rlimit_nofile(1ULL << 10);
// The sandboxee is not allowed to create core files.
executor->limits()->set_rlimit_core(0);
// Maximum 300s of real CPU time.
executor->limits()->set_rlimit_cpu(300);
// Maximum 120s of wall time.
executor->limits()->set_walltime_limit(absl::Seconds(120));

sandbox2::Limits ক্লাস ব্যবহারের উদাহরণ দেখতে, টুল উদাহরণ দেখুন।

৪. স্যান্ডবক্স চালান

আগের বিভাগে, আপনি স্যান্ডবক্স এনভায়রনমেন্ট, নীতি, এক্সিকিউটর ও Sandboxee প্রস্তুত করেছেন। পরবর্তী ধাপ হল Sandbox2 অবজেক্ট তৈরি করে সেটি রান করানো।

সিঙ্ক্রোনাসভাবে চালান

স্যান্ডবক্স সিঙ্ক্রোনাসভাবে চলতে পারে, তাই ফলাফল না পাওয়া পর্যন্ত ব্লক করে। নিচে দেওয়া কোড স্নিপেট থেকে Sandbox2 অবজেক্টের ইনস্ট্যান্টিয়েশন এবং তার সিঙ্ক্রোনাস এক্সিকিউশন সম্পর্কে জানা যাবে। আরও বিস্তারিত উদাহরণের জন্য, static দেখুন।

#include "sandboxed_api/sandbox2/sandbox2.h"

sandbox2::Sandbox2 s2(std::move(executor), std::move(policy));
sandbox2::Result result = s2.Run();  // Synchronous
LOG(INFO) << "Result of sandbox execution: " << result.ToString();

অ্যাসিঙ্ক্রোনাসভাবে চালান

এছাড়াও, আপনি স্যান্ডবক্স অ্যাসিঙ্ক্রোনাসভাবে চালাতে পারেন, যার ফলে কোনও ফলাফল না পাওয়া পর্যন্ত এটি ব্লক করা হয় না। যেমন, Sandboxee-এর সাথে যোগাযোগ করার সময় এটি কাজে লাগে। নিচের কোড স্নিপেট এই ব্যবহারের উদাহরণ দেখায়, আরও বিস্তারিত উদাহরণের জন্য crc4 এবং tool দেখুন।

#include "sandboxed_api/sandbox2/sandbox2.h"

sandbox2::Sandbox2 s2(std::move(executor), std::move(policy));
if (s2.RunAsync()) {
  // Communicate with sandboxee, use s2.Kill() to kill it if needed
  // ...
}
Sandbox2::Result result = s2.AwaitResult();
LOG(INFO) << "Final execution status: " << result.ToString();

৫. স্যান্ডবক্সির সাথে যোগাযোগ করা

ডিফল্ট হিসেবে, ফাইল ডেসক্রিপ্টরের মাধ্যমে এক্সিকিউটর স্যান্ডবক্সির সাথে যোগাযোগ করতে পারে। আপনার শুধু এটিই প্রয়োজন হতে পারে, যেমন আপনি যদি শুধু Sandboxee-এর সাথে ফাইল শেয়ার করতে চান অথবা Sandboxee-এর স্ট্যান্ডার্ড আউটপুট পড়তে চান।

তবে, এক্সিকিউটর ও স্যান্ডবক্সির মধ্যে আরও জটিল কমিউনিকেশন লজিকের প্রয়োজন আপনার হতে পারে। পূর্ণসংখ্যা, স্ট্রিং, বাইট বাফার, protobuf বা ফাইল ডেসক্রিপ্টর পাঠাতে comms API (দেখুন comms.h হেডার ফাইল) ব্যবহার করা যেতে পারে।

ফাইল ডেসক্রিপটর শেয়ার করা

ইন্টার-প্রসেস কমিউনিকেশন API ব্যবহার করে (দেখুন ipc.h), আপনি MapFd() বা ReceiveFd() ব্যবহার করতে পারবেন:

  • এক্সিকিউটর থেকে Sandboxee-তে ফাইল ডেসক্রিপটর ম্যাপ করতে MapFd() ব্যবহার করুন। এক্সিকিউটর থেকে খোলা ফাইল শেয়ার করার জন্য এটি ব্যবহার করা যেতে পারে, যাতে সেটি Sandboxee-তে ব্যবহার করা যায়। এর ব্যবহারের একটি উদাহরণ স্ট্যাটিক-এ দেখা যেতে পারে।

    // The executor opened /proc/version and passes it to the sandboxee as stdin
    executor->ipc()->MapFd(proc_version_fd, STDIN_FILENO);
    
  • সকেটপেয়ার এন্ডপয়েন্ট তৈরি করতে ReceiveFd() ব্যবহার করুন। এটি Sandboxee-এর স্ট্যান্ডার্ড আউটপুট বা স্ট্যান্ডার্ড এরর পড়ার জন্য ব্যবহার করা যেতে পারে। টুলে ব্যবহারের একটি উদাহরণ দেখা যেতে পারে।

    // The executor receives a file descriptor of the sandboxee stdout
    int recv_fd1 = executor->ipc())->ReceiveFd(STDOUT_FILENO);
    

comms API ব্যবহার করা

Sandbox2 একটি সুবিধাজনক comms API প্রদান করে। এটি হল এক্সিকিউটর ও স্যান্ডবক্সির মধ্যে পূর্ণসংখ্যা, স্ট্রিং বা বাইট বাফার শেয়ার করার একটি সহজ ও সরল উপায়। নিচে কিছু কোড স্নিপেট দেওয়া হল যা আপনি crc4 উদাহরণে দেখতে পাবেন।

Comms API ব্যবহার শুরু করতে, আপনাকে প্রথমে Sandbox2 অবজেক্ট থেকে Comms অবজেক্ট পেতে হবে:

sandbox2::Comms* comms = s2.comms();

কম্যুনিকেশন অবজেক্ট উপলভ্য হলে, Send* ফাংশনের কোনও একটি ফ্যামিলি ব্যবহার করে Sandboxee-তে ডেটা পাঠানো যেতে পারে। crc4 উদাহরণে আপনি comms API-এর একটি উদাহরণ দেখতে পাবেন। নিচে দেখানো কোড স্নিপেট সেই উদাহরণের একটি উদ্ধৃতি। অছি SendBytes(buf, size)-এর সাথে unsigned char buf[size] পাঠান:

if (!(comms->SendBytes(static_cast<const uint8_t*>(buf), sz))) {
  /* handle error */
}

Sandboxee থেকে ডেটা পেতে, Recv* ফাংশনগুলির মধ্যে একটি ব্যবহার করুন। নিচের কোড স্ন্যাপশটটি crc4 উদাহরণের একটি উদ্ধৃতি। এক্সিকিউটর একটি ৩২-বিট আনসাইনড পূর্ণসংখ্যায় চেকসাম পায়: uint32_t crc4;

if (!(comms->RecvUint32(&crc4))) {
  /* handle error */
}

বাফারের সাথে ডেটা শেয়ার করা

ডেটা শেয়ার করার আরেকটি ফাংশন হল, প্রচুর পরিমাণে ডেটা শেয়ার করতে এবং এক্সিকিউটর ও স্যান্ডবক্সির মধ্যে বারবার পাঠানো ব্যয়বহুল কপি এড়াতে বাফার API ব্যবহার করা।

এক্সিকিউটর, সাইজ এবং পাস করা ডেটা অথবা সরাসরি ফাইল ডেসক্রিপটর থেকে বাফার তৈরি করে এবং comms->SendFD() এক্সিকিউটরে এবং comms->RecvFD() স্যান্ডবক্সিতে ব্যবহার করে স্যান্ডবক্সিতে পাস করে।

নিচের কোড স্নিপেটে, আপনি এক্সিকিউটরের দিকটি দেখতে পাবেন। স্যান্ডবক্স অ্যাসিঙ্ক্রোনাসভাবে রান করে এবং স্যান্ডবক্সির সাথে বাফারের মাধ্যমে ডেটা শেয়ার করে:

// start the sandbox asynchronously
s2.RunAsync();

// instantiate the comms object
sandbox2::Comms* comms = s2.comms();

// random buffer data we want to send
constexpr unsigned char buffer_data[] = /* random data */;
constexpr unsigned int buffer_dataLen = 34;

// create sandbox2 buffer
absl::StatusOr<std::unique_ptr<sandbox2::Buffer>> buffer =
     sandbox2::Buffer::CreateWithSize(1ULL << 20 /* 1Mib */);
std::unique_ptr<sandbox2::Buffer> buffer_ptr = std::move(buffer).value();

// point to the sandbox2 buffer and fill with data
uint8_t* buf = buffer_ptr‑>data();
memcpy(buf, buffer_data, buffer_data_len);

// send the data to the sandboxee
comms‑>SendFd(buffer_ptr‑>fd());

Sandboxee-এর দিকে, আপনাকে একটি বাফার অবজেক্ট তৈরি করতে হবে এবং এক্সিকিউটরের পাঠানো ফাইল ডেসক্রিপটর থেকে ডেটা পড়তে হবে:

// establish the communication with the executor
int fd;
comms.RecvFD(&fd);

// create the buffer
absl::StatusOr<std::unique_ptr<sandbox2::Buffer>> buffer =
     sandbox2::Buffer::createFromFd(fd);

// get the data
auto buffer_ptr = std::move(buffer).value();
uint8_t* buf = buffer_ptr‑>data();

/* work with the buf object */

৬. স্যান্ডবক্স থেকে বেরিয়ে আসা

আপনি কীভাবে স্যান্ডবক্স রান করান তার উপর নির্ভর করে (এই ধাপ দেখুন), আপনাকে স্যান্ডবক্স বন্ধ করার পদ্ধতি অ্যাডজাস্ট করতে হবে এবং এর ফলে স্যান্ডবক্সির ক্ষেত্রেও তাই করতে হবে।

সিঙ্ক্রোনাসভাবে চলা স্যান্ডবক্স থেকে বেরিয়ে আসা

স্যান্ডবক্স সিঙ্ক্রোনাসভাবে চলতে থাকলে, স্যান্ডবক্সি শেষ হলেই রান ফিরে আসবে। তাই, বন্ধ করার জন্য অতিরিক্ত কোনও পদক্ষেপের প্রয়োজন নেই। নিচের কোড স্নিপেটে এই পরিস্থিতি দেখানো হয়েছে:

Sandbox2::Result result = s2.Run();
LOG(INFO) << "Final execution status: " << result.ToString();

অ্যাসিঙ্ক্রোনাসভাবে চলা স্যান্ডবক্স থেকে বেরিয়ে আসা

স্যান্ডবক্স অ্যাসিঙ্ক্রোনাসভাবে চলতে থাকলে, বন্ধ করার জন্য দুটি বিকল্প উপলভ্য থাকে। প্রথমে, আপনি Sandboxee সম্পূর্ণ হওয়ার জন্য অপেক্ষা করতে পারেন এবং এক্সিকিউশনের চূড়ান্ত স্ট্যাটাস পেতে পারেন:

sandbox2::Result result = s2.AwaitResult();
LOG(INFO) << "Final execution status: " << result.ToString();

অথবা, আপনি যেকোনও সময় Sandboxee বন্ধ করে দিতে পারেন, তবে AwaitResult()-এ কল করার পরামর্শ দেওয়া হয়, কারণ Sandboxee অন্য কোনও কারণে বন্ধ হয়ে যেতে পারে:

s2.Kill();
sandbox2::Result result = s2.AwaitResult();
LOG(INFO) << "Final execution status: " << result.ToString();

৭. পরীক্ষা

অন্য যেকোনও কোডের মতো, আপনার স্যান্ডবক্স প্রয়োগে টেস্ট থাকতে হবে। স্যান্ডবক্স টেস্টের উদ্দেশ্য হল প্রোগ্রামের সঠিকতা পরীক্ষা করা নয়, বরং স্যান্ডবক্স লঙ্ঘন সংক্রান্ত সমস্যার মতো কোনও সমস্যা ছাড়াই স্যান্ডবক্স করা প্রোগ্রাম রান করতে পারে কিনা তা চেক করা। এটি স্যান্ডবক্স নীতি সঠিক কিনা তাও নিশ্চিত করে।

স্যান্ডবক্স করা প্রোগ্রামটি আপনি প্রোডাকশনে যেভাবে চালাবেন ঠিক সেইভাবেই পরীক্ষা করা হয়, আর্গুমেন্ট এবং ইনপুট ফাইলের সাথে এটি সাধারণত প্রসেস করে।

এই টেস্টগুলি শেল টেস্ট বা সাব-প্রসেস ব্যবহার করে C++ টেস্টের মতো সহজ হতে পারে। অনুপ্রেরণা পেতে উদাহরণ দেখুন।

উপসংহার

এতক্ষণ ধরে পড়ার জন্য ধন্যবাদ, আশা করি আমাদের গাইড আপনার ভালো লেগেছে এবং এখন আপনি নিজের ব্যবহারকারীদের সুরক্ষিত রাখার জন্য নিজের স্যান্ডবক্স তৈরি করতে পারবেন।

স্যান্ডবক্স ও নীতি তৈরি করা কঠিন কাজ এবং এতে সামান্য ভুল হওয়ার সম্ভাবনা থাকে। নিরাপদ থাকতে, আমরা সাজেস্ট করি যে কোনও নিরাপত্তা বিশেষজ্ঞকে দিয়ে আপনার নীতি ও কোড পর্যালোচনা করিয়ে নিন।