सीपीयू के छल्ले सबसे स्पष्ट अंतर हैं
X86 संरक्षित मोड में, CPU हमेशा 4 रिंग में से एक में होता है। लिनक्स कर्नेल केवल 0 और 3 का उपयोग करता है:
- 0 कर्नेल के लिए
- उपयोगकर्ताओं के लिए 3
यह कर्नेल बनाम उपयोगकर्ताभूमि की सबसे कठिन और तेज़ परिभाषा है।
लिनक्स 1 और 2 के छल्ले का उपयोग क्यों नहीं करता है: https://stackoverflow.com/questions/6710040/cpu-privilege-rings-why-rings-1-and-2-arent-used
वर्तमान रिंग कैसे निर्धारित की जाती है?
वर्तमान रिंग को इसके संयोजन द्वारा चुना गया है:
वैश्विक डिस्क्रिप्टर तालिका: जीडीटी प्रविष्टियों की इन-मेमोरी टेबल और प्रत्येक प्रविष्टि में एक फ़ील्ड होता है Privl
जो रिंग को एनकोड करता है।
LGDT निर्देश पता को वर्तमान डिस्क्रिप्टर टेबल पर सेट करता है।
इसे भी देखें: http://wiki.osdev.org/Global_Descriptor_Table
खंड सीएस, डीएस, आदि को पंजीकृत करता है, जो जीडीटी में एक प्रविष्टि के सूचकांक को इंगित करता है।
उदाहरण के लिए, CS = 0
GDT का पहला प्रवेश वर्तमान में निष्पादन कोड के लिए सक्रिय है।
प्रत्येक अंगूठी क्या कर सकती है?
सीपीयू चिप को भौतिक रूप से बनाया गया है ताकि:
अंगूठी 0 कुछ भी कर सकती है
रिंग 3 कई निर्देश नहीं चला सकता है और कई रजिस्टरों को लिख सकता है, विशेष रूप से:
अपनी खुद की अंगूठी नहीं बदल सकते हैं! अन्यथा, यह खुद को 0 में सेट कर सकता है और रिंग बेकार हो जाएगा।
दूसरे शब्दों में, वर्तमान खंड वर्णनकर्ता को संशोधित नहीं कर सकता है , जो वर्तमान रिंग को निर्धारित करता है।
पृष्ठ तालिकाएँ संशोधित नहीं कर सकते: https://stackoverflow.com/questions/18431261/how-does-x86-aging-work
दूसरे शब्दों में, सीआर 3 रजिस्टर को संशोधित नहीं किया जा सकता है, और पेजिंग स्वयं पेज तालिकाओं के संशोधन को रोकता है।
यह एक प्रक्रिया को सुरक्षा के लिए अन्य प्रक्रियाओं की स्मृति को देखने से रोकता है / प्रोग्रामिंग कारणों में आसानी।
बाधित हैंडलर पंजीकृत नहीं कर सकते। इन्हें स्मृति स्थानों पर लिखकर कॉन्फ़िगर किया जाता है, जिसे पेजिंग द्वारा भी रोका जाता है।
हैंडलर रिंग 0 में दौड़ते हैं, और सुरक्षा मॉडल को तोड़ देंगे।
दूसरे शब्दों में, LGDT और LIDT निर्देशों का उपयोग नहीं कर सकते।
IO जैसे निर्देश in
और नहीं कर सकता out
, और इस तरह मनमाने ढंग से हार्डवेयर एक्सेस है।
अन्यथा, उदाहरण के लिए, यदि किसी प्रोग्राम को डिस्क से सीधे पढ़ा जा सकता है तो फ़ाइल अनुमतियां बेकार हो जाएंगी।
माइकल पेटी के लिए अधिक सटीक धन्यवाद : ओएस के लिए रिंग 3 पर आईओ के निर्देशों की अनुमति देना वास्तव में संभव है, यह वास्तव में टास्क सेक्शन द्वारा नियंत्रित किया जाता है ।
क्या संभव नहीं है रिंग 3 के लिए खुद को ऐसा करने की अनुमति देना अगर यह पहली जगह में नहीं था।
लिनक्स हमेशा इसे नापसंद करता है। इसे भी देखें: https://stackoverflow.com/questions/2711044/why-doesnt-linux-use-the-hardware-context-switch-via-the-ts
रिंगों के बीच प्रोग्राम और ऑपरेटिंग सिस्टम कैसे संक्रमण करते हैं?
जब CPU चालू होता है, तो यह रिंग 0 में प्रारंभिक प्रोग्राम चलाने लगता है (अच्छी तरह का, लेकिन यह एक अच्छा सन्निकटन है)। आप इस प्रारंभिक कार्यक्रम को कर्नेल होने के रूप में सोच सकते हैं (लेकिन यह आमतौर पर एक बूटलोडर है जो तब कर्नेल को अभी भी रिंग 0 में कहता है)।
जब कोई उपयोगकर्ता प्रक्रिया प्रक्रिया कर्नेल को इसके लिए कुछ करना चाहती है जैसे फ़ाइल में लिखना, यह एक निर्देश का उपयोग करता है जो कि एक बाधा उत्पन्न करता है जैसे कि int 0x80
याsyscall
कर्नेल को संकेत देने के लिए। x86-64 लिनक्स syscall हैलो दुनिया उदाहरण:
.data
hello_world:
.ascii "hello world\n"
hello_world_len = . - hello_world
.text
.global _start
_start:
/* write */
mov $1, %rax
mov $1, %rdi
mov $hello_world, %rsi
mov $hello_world_len, %rdx
syscall
/* exit */
mov $60, %rax
mov $0, %rdi
syscall
संकलित करें और चलाएं:
as -o hello_world.o hello_world.S
ld -o hello_world.out hello_world.o
./hello_world.out
गिटहब अपस्ट्रीम ।
जब ऐसा होता है, CPU एक कॉलबैक हैंडलर को कॉल करता है जिसे कर्नेल बूट समय पर पंजीकृत करता है। यहां एक ठोस नंगेपन का उदाहरण है जो एक हैंडलर को पंजीकृत करता है और इसका उपयोग करता है ।
यह हैंडलर रिंग 0 में चलता है, जो तय करता है कि कर्नेल इस क्रिया को करने देगा, एक्शन करेगा, और रिंग में यूजरलैंड प्रोग्राम को पुनः आरंभ करेगा। x86_64
जब exec
सिस्टम कॉल का उपयोग किया जाता है (या जब कर्नेल शुरू हो जाएगा/init
), कर्नेल नए यूजरलैंड प्रक्रिया के रजिस्टरों और मेमोरी को तैयार करता है, तो यह प्रवेश बिंदु पर कूदता है और सीपीयू को रिंग 3 में स्विच करता है
यदि प्रोग्राम कुछ शरारती करने की कोशिश करता है जैसे निषिद्ध रजिस्टर या मेमोरी एड्रेस (पेजिंग के कारण) को लिखने के लिए, सीपीयू रिंग 0 में कुछ कर्नेल कॉलबैक हैंडलर को भी कॉल करता है।
लेकिन चूंकि यूजरलैंड शरारती था, इसलिए कर्नेल इस बार प्रक्रिया को मार सकता है, या इसे सिग्नल के साथ चेतावनी दे सकता है।
जब कर्नेल बूट होता है, तो यह कुछ निश्चित आवृत्ति के साथ एक हार्डवेयर घड़ी को सेटअप करता है, जो समय-समय पर व्यवधान उत्पन्न करता है।
यह हार्डवेयर क्लॉक रिंग 0 को चलाने वाली रुकावट पैदा करता है, और इसे शेड्यूल करने की अनुमति देता है कि कौन सी यूजरलैंड प्रक्रिया को जागृत करता है।
इस तरह, शेड्यूलिंग तब भी हो सकती है, जब प्रक्रियाएं कोई सिस्टम कॉल नहीं कर रही हैं।
एकाधिक वलय होने की बात क्या है?
कर्नेल और उपयोगकर्ताभूमि को अलग करने के दो प्रमुख लाभ हैं:
- प्रोग्राम बनाना आसान है क्योंकि आप अधिक निश्चित हैं कि कोई दूसरे के साथ हस्तक्षेप नहीं करेगा। उदाहरण के लिए, एक उपयोगकर्ता प्रक्रिया में पेजिंग के कारण किसी अन्य प्रोग्राम की मेमोरी को ओवरराइट करने के बारे में चिंता करने की आवश्यकता नहीं है, न ही किसी अन्य प्रक्रिया के लिए अमान्य स्थिति में हार्डवेयर डालने के बारे में।
- यह अधिक सुरक्षित है। उदाहरण के लिए फ़ाइल अनुमतियां और मेमोरी पृथक्करण हैकिंग ऐप को आपके बैंक डेटा को पढ़ने से रोक सकते हैं। यह, ज़ाहिर है, कि आप कर्नेल पर भरोसा करते हैं।
इसके साथ कैसे खेलें?
मैंने एक नंगे धातु सेटअप का निर्माण किया है जो रिंगों को सीधे हेरफेर करने का एक अच्छा तरीका होना चाहिए: https://github.com/cirosantilli/x86-bare-metal-examples
मेरे पास दुर्भाग्य से उपयोगकर्ता के उदाहरण बनाने के लिए धैर्य नहीं था, लेकिन मैं सेटअप पेजिंग के रूप में दूर तक गया, इसलिए उपयोगकर्ताभूमि को व्यवहार्य होना चाहिए। मैं एक पुल अनुरोध देखना पसंद करूंगा।
वैकल्पिक रूप से, लिनक्स कर्नेल मॉड्यूल रिंग 0 में चलते हैं, इसलिए आप उनका उपयोग विशेषाधिकार प्राप्त संचालन को आज़माने के लिए कर सकते हैं, उदाहरण के लिए कंट्रोल रजिस्टर पढ़ें: https://stackoverflow.com/questions/7415515/how-to-access-the-control-registers -cr0-CR2-CR3-से-एक कार्यक्रम-हो रही-segmentà / 7,419,306 # 7,419,306
यहाँ एक सुविधाजनक QEMU + बिल्डरोट सेटअप है जो आपके मेजबान को मारे बिना इसे आज़मा सकता है।
कर्नेल मॉड्यूल का नकारात्मक पक्ष यह है कि अन्य kthreads चल रहे हैं और आपके प्रयोगों में हस्तक्षेप कर सकते हैं। लेकिन सिद्धांत रूप में आप अपने कर्नेल मॉड्यूल के साथ सभी रुकावटों को संभाल सकते हैं और सिस्टम के मालिक हैं, जो वास्तव में एक दिलचस्प परियोजना होगी।
नकारात्मक वलय
जबकि नकारात्मक रिंग्स वास्तव में इंटेल मैनुअल में संदर्भित नहीं होते हैं, वास्तव में सीपीयू मोड हैं जिनके पास रिंग 0 की तुलना में आगे की क्षमता है, और इसलिए "नेगेटिव रिंग" नाम के लिए एक अच्छा फिट है।
एक उदाहरण वर्चुअलाइजेशन में उपयोग किया जाने वाला हाइपरविजर मोड है।
अधिक जानकारी के लिए देखें: https://security.stackexchange.com/questions/129098/what-is-protection-ring-1
एआरएम
एआरएम में, छल्ले को इसके बजाय अपवाद स्तर कहा जाता है, लेकिन मुख्य विचार समान रहते हैं।
ARMv8 में 4 अपवाद स्तर मौजूद हैं, जिनका आमतौर पर उपयोग किया जाता है:
EL0: उपयोगकर्ता भूमि
EL1: कर्नेल (एआरएम शब्दावली में "पर्यवेक्षक")।
svc
निर्देश (सुपरवाइजर कॉल) के साथ दर्ज किया गया , जिसे swi
पहले एकीकृत असेंबली के रूप में जाना जाता था , जो कि लिनक्स सिस्टम कॉल करने के लिए उपयोग किया जाने वाला निर्देश है। नमस्ते दुनिया ARMv8 उदाहरण:
.text
.global _start
_start:
/* write */
mov x0, 1
ldr x1, =msg
ldr x2, =len
mov x8, 64
svc 0
/* exit */
mov x0, 0
mov x8, 93
svc 0
msg:
.ascii "hello syscall v8\n"
len = . - msg
गिटहब अपस्ट्रीम ।
16.04 पर QEMU के साथ इसका परीक्षण करें:
sudo apt-get install qemu-user gcc-arm-linux-gnueabihf
arm-linux-gnueabihf-as -o hello.o hello.S
arm-linux-gnueabihf-ld -o hello hello.o
qemu-arm hello
यहां एक ठोस नंगेपन का उदाहरण है जो एक एसवीसी हैंडलर को पंजीकृत करता है और एक एसवीसी कॉल करता है ।
EL2: हाइपरविजर , उदाहरण के लिए Xen ।
hvc
निर्देश के साथ दर्ज किया गया (हाइपरविजर कॉल)।
एक हाइपरविजर एक OS के लिए है, एक OS क्या है जो उपयोगकर्ता के लिए है।
उदाहरण के लिए, Xen आपको एक ही समय में एक ही सिस्टम पर कई OS जैसे कि Linux या Windows चलाने की अनुमति देता है, और यह OSes को एक दूसरे से सुरक्षा और डिबग की आसानी के लिए अलग करता है, ठीक वैसे ही जैसे कि Linux userland प्रोग्राम के लिए करता है।
Hypervisers आज के क्लाउड बुनियादी ढांचे का एक महत्वपूर्ण हिस्सा हैं: वे कई सर्वरों को एक हार्डवेयर पर चलने की अनुमति देते हैं, हार्डवेयर उपयोग को हमेशा 100% के करीब रखते हैं और बहुत सारे पैसे बचाते हैं।
उदाहरण के लिए AWS ने 2017 तक Xen का उपयोग किया जब इसके KVM के कदम ने खबर बना दी ।
EL3: अभी तक एक और स्तर। TODO उदाहरण।
smc
निर्देश (सुरक्षित मोड कॉल) के साथ दर्ज किया गया
ARMv8 वास्तुकला संदर्भ मॉडल DDI 0487C.a - अध्याय डी 1 - AArch64 सिस्टम स्तर प्रोग्रामर मॉडल - चित्रा D1-1 खूबसूरती से इस दिखाता है:
ध्यान दें कि एआरएम, शायद दृष्टि के लाभ के कारण, नकारात्मक स्तर की आवश्यकता के बिना x86 की तुलना में विशेषाधिकार के स्तर के लिए एक बेहतर नामकरण सम्मेलन है: 0 कम और 3 उच्चतम। उच्च स्तर कम लोगों की तुलना में अधिक बार बनाए जाते हैं।
वर्तमान ईएल को MRS
निर्देश के साथ समझा जा सकता है : https://stackoverflow.com/questions/31787617/what-is-the-current-execution-mode-exception-level-etc
एआरएम को कार्यान्वयन के लिए अनुमति देने के लिए सभी अपवाद स्तरों की आवश्यकता नहीं है जो चिप क्षेत्र को बचाने के लिए सुविधा की आवश्यकता नहीं है। ARMv8 "अपवाद स्तर" कहते हैं:
कार्यान्वयन में अपवाद स्तर शामिल नहीं हो सकते हैं। सभी कार्यान्वयन में EL0 और EL1 शामिल होना चाहिए। EL2 और EL3 वैकल्पिक हैं।
उदाहरण के लिए QEMU EL1 में चूक के लिए, लेकिन EL2 और EL3 को कमांड लाइन विकल्पों के साथ सक्षम किया जा सकता है: https://stackoverflow.com/questions/42824706/qemu-system-aarch64-entering-el1-when-emulating-a53-power-up
कोड स्निपेट्स ने उबंटू 18.10 पर परीक्षण किया।