2. একটি স্যান্ডবক্স নীতি তৈরি করুন৷

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

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

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

  • প্রসেস স্টার্টআপের জন্য যেকোনও সিস্ক্যালের অনুমতি দিন:
    • AllowStaticStartup();
    • AllowDynamicStartup();
  • যেকোন খোলা /পড়া /লেখা* সিস্কালগুলিকে অনুমতি দিন:
    • AllowOpen();
    • AllowRead();
    • AllowWrite();
  • যেকোন প্রস্থান/অ্যাক্সেস/স্টেট সম্পর্কিত সিস্ক্যালগুলিকে অনুমতি দিন:
    • AllowExit();
    • AllowStat();
    • AllowAccess();
  • যেকোন ঘুম/সময় সম্পর্কিত সিস্ক্যালের অনুমতি দিন:
    • AllowTime();
    • AllowSleep();

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

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

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

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

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

#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();
}
,

2. একটি স্যান্ডবক্স নীতি তৈরি করুন৷

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

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

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

  • প্রসেস স্টার্টআপের জন্য যেকোনও সিস্ক্যালের অনুমতি দিন:
    • AllowStaticStartup();
    • AllowDynamicStartup();
  • যেকোন খোলা /পড়া /লেখা* সিস্কালগুলিকে অনুমতি দিন:
    • AllowOpen();
    • AllowRead();
    • AllowWrite();
  • যেকোন প্রস্থান/অ্যাক্সেস/স্টেট সম্পর্কিত সিস্ক্যালগুলিকে অনুমতি দিন:
    • AllowExit();
    • AllowStat();
    • AllowAccess();
  • যেকোন ঘুম/সময় সম্পর্কিত সিস্ক্যালের অনুমতি দিন:
    • AllowTime();
    • AllowSleep();

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

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

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

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

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

#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();
}