
Rex एक सुरक्षित और उपयोग योग्य कर्नेल एक्सटेंशन फ्रेमवर्क है जो eBPF के स्थान पर रस्ट कर्नेल एक्सटेंशन प्रोग्राम को लोड और निष्पादित करने की अनुमति देता है।
____ _______ __ _____ _ _
| _ \| ____\ \/ / | ____|_ _| |_ ___ _ __ ___(_) ___ _ __ ___
| |_) | _| \ / | _| \ \/ / __/ _ \ '_ \/ __| |/ _ \| '_ \/ __|
| _ <| |___ / \ | |___ > <| || __/ | | \__ \ | (_) | | | \__ \
|_| \_\_____/_/\_\ |_____/_/\_\\__\___|_| |_|___/_|\___/|_| |_|___/
Rex एक सुरक्षित और उपयोगी कर्नेल एक्सटेंशन फ्रेमवर्क है जो eBPF के स्थान पर Rust कर्नेल एक्सटेंशन प्रोग्राम को लोड और निष्पादित करने की अनुमति देता है। eBPF-आधारित फ्रेमवर्क जैसे Aya के विपरीत, Rex प्रोग्राम इन-कर्नेल वेरिफायर से नहीं गुजरते, बल्कि प्रोग्राम Rust के सुरक्षित उपसमूह में कार्यान्वित किए जाते हैं, जिस पर Rust कंपाइलर आवश्यक सुरक्षा जांच करता है और सीधे नेटिव कोड उत्पन्न करता है। यह दृष्टिकोण अत्यधिक प्रतिबंधित सत्यापन आवश्यकताओं (जैसे, प्रोग्राम जटिलता बाधाएं) और परिणामी रहस्यमयी सत्यापन त्रुटियों से बचाता है, जबकि साथ ही नेटिव कंपाइलर बैकएंड (अर्थात LLVM) में eBPF बैकएंड + इन-कर्नेल JIT दृष्टिकोण की तुलना में बेहतर अनुकूलन अवसर प्रदान करता है।
Rex वर्तमान में निम्नलिखित सुविधाओं का समर्थन करता है:
kprobe, perf_event, tracepoint, xdp, और tc।निम्नलिखित उदाहरण एक kprobe प्रोग्राम को लागू करता है जो एक चयनित सिस्टम कॉल से जुड़ता है और एक प्रक्रिया (उसके pid द्वारा निर्दिष्ट) पर सिस्टम कॉल में एक त्रुटि (errno द्वारा निर्दिष्ट) इंजेक्ट करता है। पूरा उदाहरण, लोडर प्रोग्राम सहित, samples/error_injector में पाया जा सकता है।
#![no_std]
#![no_main]
use rex::kprobe::kprobe;
use rex::map::RexHashMap;
use rex::pt_regs::PtRegs;
use rex::rex_kprobe;
use rex::rex_map;
use rex::Result;
#[allow(non_upper_case_globals)]
#[rex_map]
static pid_to_errno: RexHashMap<i32, u64> = RexHashMap::new(1, 0);
#[rex_kprobe]
pub fn err_injector(obj: &kprobe, ctx: &mut PtRegs) -> Result {
obj.bpf_get_current_task()
.map(|t| t.get_pid())
.and_then(|p| obj.bpf_map_lookup_elem(&pid_to_errno, &p).cloned())
.map(|e| obj.bpf_override_return(ctx, e))
.ok_or(0)
}
अधिक नमूना प्रोग्राम samples में पाए जा सकते हैं।
आप विस्तृत मार्गदर्शिका यहाँ पा सकते हैं।
अतिरिक्त डिज़ाइन दस्तावेज़ docs में पाए जा सकते हैं।
मौजूदा eBPF एक्सटेंशन सुरक्षा गारंटी प्रदान करने के लिए इन-कर्नेल eBPF वेरिफायर पर निर्भर करता है। दुर्भाग्य से, इससे उपयोगिता संबंधी समस्याएं उत्पन्न होती हैं जहां सुरक्षित प्रोग्राम वेरिफायर द्वारा अस्वीकार कर दिए जाते हैं, जिनमें निम्नलिखित शामिल हैं लेकिन इन्हीं तक सीमित नहीं:
Rex का उद्देश्य safe Rust से सुरक्षा गारंटी का सीधे लाभ उठाकर इन समस्याओं का समाधान करना है। डेवलपर्स अपने प्रोग्रामों को किसी भी तरह से लागू कर सकते हैं जो कुछ प्रतिबंधों के साथ safe Rust में लिखा जा सकता है, और अब उन्हें प्रोग्राम जटिलता, कोड जनरेटर, या वेरिफायर को संतुष्ट करने के लिए समान तर्क को व्यक्त करने का (कई बार प्रति-सहज) तरीका खोजने की चिंता करने की आवश्यकता नहीं है।
हम इसे BPF Memcached Cache (BMC) के कार्यान्वयन के साथ प्रदर्शित करते हैं, जो Memcached त्वरण के लिए एक अत्याधुनिक एक्सटेंशन प्रोग्राम है। एक जटिल eBPF प्रोग्राम के रूप में, BMC को BPF टेल-कॉल द्वारा जुड़े कई घटकों में विभाजित करने और वेरिफायर को संतुष्ट करने के लिए अजीब लूप/ब्रांच कार्यान्वयन का उपयोग करने के लिए मजबूर किया जाता है, जो इसके Rex कार्यान्वयन में बिल्कुल आवश्यक नहीं हैं।
उदाहरण के लिए, हम BPF-BMC के कैश अमान्यकरण तर्क में कोड दिखाते हैं जो पैकेट पेलोड में SET कमांड की खोज करता है:
// Searches for SET command in payload
for (unsigned int off = 0;
off < BMC_MAX_PACKET_LENGTH && payload + off + 1 <= data_end;
off++) {
if (set_found == 0 && payload[off] == 's' &&
payload + off + 3 <= data_end && payload[off + 1] == 'e' &&
payload[off + 2] == 't') {
off += 3;
set_found = 1;
}
...
}
कोड न केवल लूप में एक अतिरिक्त बाधा (off < BMC_MAX_PACKET_LENGTH) प्रस्तुत करता है जो केवल वेरिफायर को पास करने के लिए है, बल्कि पैकेट के अंत (data_end) की जांच करने और पैकेट में "set" स्ट्रिंग से मिलान करने के लिए बार-बार बॉयलरप्लेट कोड और बोझिल तर्क का उपयोग करता है।
Rex में safe Rust की शक्ति के साथ इनमें से किसी भी बोझ की आवश्यकता नहीं है, जिसमें कोई जटिलता सीमा नहीं है और कार्यान्वयन पर अधिक स्वतंत्रता प्रदान करता है:
let set_iter = payload.windows(4).enumerate().filter_map(|(i, v)| {
if v == b"set " {
Some(i)
} else {
None
}
});
Rex में BMC का पूर्ण कार्यान्वयन samples/bmc पर पाया जा सकता है।
Rex GPLv2 लाइसेंस के तहत लाइसेंस प्राप्त है। इस रेपो में उपमॉड्यूल (Linux, Rust, LLVM) अपनी स्वयं की शर्तों के तहत लाइसेंस प्राप्त हैं। कृपया अधिक जानकारी के लिए संबंधित लाइसेंस फ़ाइलें देखें। इसके अतिरिक्त, memcached बेंचमार्क MIT लाइसेंस के तहत लाइसेंस प्राप्त है।