5. सैंडबॉक्स में शामिल ऐप्लिकेशन से कम्यूनिकेट करना

डिफ़ॉल्ट रूप से, एक्ज़ीक्यूटर, फ़ाइल डिस्क्रिप्टर के ज़रिए सैंडबॉक्स वाले प्रोग्राम से कम्यूनिकेट कर सकता है. यह आपके लिए काफ़ी हो सकता है. उदाहरण के लिए, अगर आपको सिर्फ़ सैंडबॉक्सी के साथ कोई फ़ाइल शेयर करनी है या सैंडबॉक्सी के स्टैंडर्ड आउटपुट को पढ़ना है.

हालांकि, आपको एक्ज़ीक्यूटर और सैंडबॉक्सी के बीच ज़्यादा जटिल कम्यूनिकेशन लॉजिक की ज़रूरत पड़ सकती है. comms API (comms.h हेडर फ़ाइल देखें) का इस्तेमाल करके, पूर्णांक, स्ट्रिंग, बाइट बफ़र, प्रोटोबफ़ या फ़ाइल डिस्क्रिप्टर भेजे जा सकते हैं.

फ़ाइल की जानकारी देने वाले शेयर करना

इंटर-प्रोसेस कम्यूनिकेशन एपीआई (ipc.h देखें) का इस्तेमाल करके, MapFd() या ReceiveFd() का इस्तेमाल किया जा सकता है:

  • एक्ज़ीक्यूटर से सैंडबॉक्सी में फ़ाइल डिस्क्रिप्टर को मैप करने के लिए, MapFd() का इस्तेमाल करें. इसका इस्तेमाल, एक्ज़ीक्यूटर से खोली गई फ़ाइल को Sandboxee में इस्तेमाल करने के लिए शेयर करने के लिए किया जा सकता है. इसके इस्तेमाल का उदाहरण static में देखा जा सकता है.

    // The executor opened /proc/version and passes it to the sandboxee as stdin
    executor->ipc()->MapFd(proc_version_fd, STDIN_FILENO);
    
  • सॉकेटपेयर एंडपॉइंट बनाने के लिए, ReceiveFd() का इस्तेमाल करें. इसका इस्तेमाल, सैंडबॉक्स के स्टैंडर्ड आउटपुट या स्टैंडर्ड गड़बड़ियों को पढ़ने के लिए किया जा सकता है. इसके इस्तेमाल का उदाहरण टूल में देखा जा सकता है.

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

comms ऑब्जेक्ट उपलब्ध होने के बाद, Send* फ़ंक्शन के परिवार के किसी एक फ़ंक्शन का इस्तेमाल करके, सैंडबॉक्स किए गए प्रोग्राम को डेटा भेजा जा सकता है. comms API के इस्तेमाल का उदाहरण, crc4 उदाहरण में देखा जा सकता है. नीचे दिया गया कोड स्निपेट, उस उदाहरण का एक हिस्सा दिखाता है. मैनेजर, SendBytes(buf, size) के साथ unsigned char buf[size] भेजता है:

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

Sandboxee से डेटा पाने के लिए, इनमें से किसी एक Recv* फ़ंक्शन का इस्तेमाल करें. नीचे दिया गया कोड स्निपेट, crc4 के उदाहरण का एक हिस्सा है. एक्ज़ीक्यूटर को 32-बिट के बिना हस्ताक्षर वाले पूर्णांक में चेकसम मिलता है: uint32_t crc4;

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

बफ़र के साथ डेटा शेयर करना

डेटा शेयर करने की एक और सुविधा यह है कि buffer 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());

सैंडबॉक्सी के लिए, आपको एक बफ़र ऑब्जेक्ट भी बनाना होगा. साथ ही, एक्ज़ीक्यूटर से भेजे गए फ़ाइल डिस्क्रिप्टर से डेटा पढ़ना होगा:

// 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 */