২. স্যান্ডবক্স নীতি তৈরি করুন
আপনার কাছে এক্সিকিউটর থাকলে, আপনি সম্ভবত Sandboxee-এর জন্য একটি Sandbox নীতি নির্ধারণ করতে চাইবেন। অন্যথায়, Sandboxee শুধুমাত্র ডিফল্ট Syscall নীতি দ্বারা সুরক্ষিত থাকে।
স্যান্ডবক্স নীতির মাধ্যমে, স্যান্ডবক্সী যেসব সিসকল ও আর্গুমেন্ট করতে পারে এবং যেসব ফাইল অ্যাক্সেস করতে পারে, সেগুলি সীমিত করাই হল উদ্দেশ্য। আপনি যে কোড স্যান্ডবক্স করার পরিকল্পনা করছেন, তার জন্য প্রয়োজনীয় syscalls সম্পর্কে আপনার বিস্তারিত ধারণা থাকতে হবে। সিসকল পর্যবেক্ষণ করার একটি উপায় হল Linux-এর কমান্ড-লাইন টুল strace-এর মাধ্যমে কোড রান করা।
আপনার কাছে syscall-এর তালিকা থাকলে, আপনি PolicyBuilder ব্যবহার করে নীতি নির্ধারণ করতে পারবেন।
PolicyBuilder-এ অনেক সুবিধা এবং হেল্পার ফাংশন আছে যা অনেক
সাধারণ অপারেশন করতে দেয় (যার মধ্যে অনেক আগেই
DefaultPolicyBuilder()-এ অন্তর্ভুক্ত করা হয়েছে)। নিম্নলিখিত তালিকাটি উপলভ্য ফাংশনের
একটি ছোট উদ্ধৃতি মাত্র:
- প্রসেস স্টার্টআপের জন্য যেকোনও syscall-কে সাদাতালিকায় যোগ করুন:
AllowStaticStartup();AllowDynamicStartup();
- যেকোনও open/read/write* syscalls সাদাতালিকাভুক্ত করুন:
AllowOpen();AllowRead();AllowWrite();
- যেকোনও এক্সিট/অ্যাক্সেস/স্টেট সম্পর্কিত syscall-কে শ্বেত তালিকাভুক্ত করুন:
AllowExit();AllowStat();AllowAccess();
- ঘুম/সময় সম্পর্কিত যেকোনও syscall-কে অনুমতি তালিকায় যোগ করুন:
AllowTime();AllowSleep();
এইসব কনভেনিয়েন্স ফাংশন যেকোনও প্রাসঙ্গিক সিসকলকে হোয়াইটলিস্ট করে। এটির সুবিধা হল,
একই নীতি বিভিন্ন আর্কিটেকচারে ব্যবহার করা যেতে পারে যেখানে
নির্দিষ্ট কিছু syscall উপলভ্য নয় (যেমন, ARM64-এ কোনও OPEN syscall নেই), তবে
প্রয়োজনের চেয়ে বেশি syscall চালু করার সামান্য নিরাপত্তা ঝুঁকি থাকে। যেমন, AllowOpen() স্যান্ডবক্সিকে যেকোনও ওপেন সম্পর্কিত সিসকল কল করার অনুমতি দেয়। আপনি
যদি শুধুমাত্র একটি নির্দিষ্ট syscall-কে সাদাতালিকাভুক্ত করতে চান, তাহলে আপনি AllowSyscall(); ব্যবহার করতে পারেন
এবং একাধিক syscall-কে একসাথে সাদাতালিকাভুক্ত করতে, আপনি AllowSyscalls() ব্যবহার করতে পারেন।
এখনও পর্যন্ত নীতিটি শুধুমাত্র syscall শনাক্তকারী চেক করে। আপনার যদি নীতিটি আরও শক্তিশালী করার প্রয়োজন হয় এবং এমন একটি নীতি সংজ্ঞায়িত করতে চান যেখানে আপনি শুধুমাত্র নির্দিষ্ট আর্গুমেন্ট সহ একটি সিসকলের অনুমতি দেন, তাহলে আপনাকে AddPolicyOnSyscall() বা AddPolicyOnSyscalls() ব্যবহার করতে হবে। এই ফাংশনগুলি আর্গুমেন্ট হিসেবে শুধু syscall ID নেয় না, তার সাথে Linux কার্নেল থেকে bpf হেল্পার ম্যাক্রো ব্যবহার করে
র 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();
}