CPU halkaları en belirgin ayrımdır
X86 korumalı modda, CPU her zaman 4 zilden birindedir. Linux çekirdeği yalnızca 0 ve 3 kullanır:
- Çekirdek için 0
- Kullanıcılar için 3
Bu çekirdek vs userland en sert ve hızlı tanımıdır.
Linux neden 1. ve 2. halkaları kullanmıyor: https://stackoverflow.com/questions/6710040/cpu-privilege-rings-why-rings-1-and-2-arent-used
Mevcut halka nasıl belirlenir?
Geçerli halka aşağıdakilerden oluşan bir kombinasyonla seçilir:
genel tanımlayıcı tablosu: GDT girişlerinin bellekteki bir tablosu ve her girişin Privl
halkayı kodlayan bir alanı vardır.
LGDT talimatı adresi geçerli tanımlayıcı tablosuna ayarlar.
Ayrıca bakınız: http://wiki.osdev.org/Global_Descriptor_Table
segment, GDT’deki bir girişin dizinine işaret eden CS, DS, vb. kaydeder.
Örneğin CS = 0
, GDT'nin ilk girişinin yürütme kodu için şu anda aktif olduğu anlamına gelir.
Her halka ne yapabilir?
İşlemci yongası fiziksel olarak şöyle yapılır:
0 halkası her şeyi yapabilir
3. halka, çok sayıda komut çalıştıramaz ve en önemlisi birkaç kayıt listesine yazamaz:
kendi yüzüğünü değiştiremez! Aksi takdirde, 0 çalmaya ayarlanmış ve yüzükler işe yaramaz.
Başka bir deyişle, geçerli halkayı belirleyen mevcut segment tanımlayıcısını değiştiremezsiniz .
sayfa tablolarını değiştiremiyorum: https://stackoverflow.com/questions/18431261/how-does-x86-paging-work
Başka bir deyişle, CR3 kaydını değiştiremez ve sayfalamanın kendisi sayfa tablolarının değiştirilmesini önler.
Bu, bir işlemin güvenlik / programlama kolaylığı açısından diğer işlemlerin belleğini görmesini önler.
kesme işleyicilerini kaydedemiyorum. Bunlar, disk belleği tarafından da engellenen bellek konumlarına yazılarak yapılandırılır.
İşleyiciler 0 halkasında çalıştırılır ve güvenlik modelini bozar.
Başka bir deyişle, LGDT ve LIDT talimatlarını kullanamazsınız.
in
ve benzeri IO komutlarını yapamaz out
ve bu nedenle isteğe bağlı donanım erişimine sahip olur.
Aksi takdirde, örneğin, herhangi bir program doğrudan diskten okuyabiliyorsa, dosya izinleri kullanılamaz.
Daha doğrusu Michael Petch sayesinde : OS'nin halka 3'teki IO talimatlarına izin vermesi aslında mümkün, bu aslında Görev durumu segmenti tarafından kontrol ediliyor .
Mümkün değil, halka 3'ün ilk etapta olmasaydı, buna izin vermesidir.
Linux her zaman buna izin vermez. Ayrıca bakınız: https://stackoverflow.com/questions/2711044/why-doesnt-linux-use-the-hardware-context-switch-via-the-ts
Programlar ve işletim sistemleri halkalar arasında nasıl geçiş yapar?
CPU açıldığında, ilk programı 0 halkasında çalıştırmaya başlar (iyi, ancak bu iyi bir yaklaşımdır). Bu başlangıç programının çekirdek olduğunu düşünebilirsiniz (ancak normalde çekirdek hala 0 halkasında olan bir önyükleyicidir).
Bir kullanıcı alanı süreci, çekirdeğin bir dosyaya yazmak gibi bir şey yapmasını istediğinde, çekirdeği işaret etmek int 0x80
veyasyscall
kesmek gibi bir kesinti oluşturan bir komut kullanır . x86-64 Linux sistem çağrısı merhaba dünya örneği:
.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
derleyin ve çalıştırın:
as -o hello_world.o hello_world.S
ld -o hello_world.out hello_world.o
./hello_world.out
GitHub yukarı akış .
Bu olduğunda, CPU, çekirdeğin önyükleme sırasında kayıtlı olduğu bir kesme geri çağrı işleyicisini çağırır. İşte bir işleyiciyi kaydeden ve kullanan somut bir yardımcı örnek .
Bu işleyici, 0 halkasında çalışır; bu, çekirdeğin bu eyleme izin verip vermeyeceğine, eylemi gerçekleştirip kullanıcı halkası programını 3. halkada yeniden başlatıp başlatmayacağına karar verir. X86_64
zaman exec
sistem çağrısı kullanılır (veya çekirdek zaman başlar/init
), çekirdek kaydeder ve hafıza hazırlar yeni kullanım alanı işleminin, o zaman giriş noktası atlar ve 3 halka CPU anahtarları
Program yasaklanmış bir sicile veya hafıza adresine (çağrı nedeniyle) yazmaya yaramaz bir şey yapmaya çalışırsa, CPU ayrıca 0 halkasında bazı çekirdek geri çağırma işleyicisini çağırır.
Ancak kullanıcı yaramaz olduğu için, çekirdek bu kez süreci öldürebilir ya da bir işaret ile uyarı verebilir.
Çekirdek önyüklendiğinde, belirli aralıklarla kesilen bazı sabit frekanslı bir donanım saati ayarlar.
Bu donanım saati, 0 halkasını çalıştıran kesintileri üretir ve hangi kullanıcı alanını uyandırmak için programlamasına izin verir.
Bu yolla, süreçler herhangi bir sistem çağrısı yapmasa bile zamanlama gerçekleşebilir.
Çoklu halkalara sahip olmanın amacı nedir?
Çekirdeği ve kullanıcı alanını ayırmanın iki büyük avantajı vardır:
- Birisinin diğerini etkilemeyeceğinden emin olduğunuz için programlar yapmak daha kolaydır. Örneğin, bir kullanıcı süreci, çağrı nedeniyle başka bir programın belleğinin üzerine yazmaktan veya başka bir işlem için donanımı geçersiz duruma getirmek konusunda endişelenmek zorunda değildir.
- daha güvenli. Örneğin, dosya izinleri ve hafıza ayrımı, bilgisayar korsanlığı uygulamalarının banka verilerinizi okumasını engelleyebilir. Bu, elbette, çekirdeğe güvendiğinizi varsayar.
Bununla nasıl oynanır?
Doğrudan halkaları işlemek için iyi bir yol olması gereken çıplak bir metal kurulum oluşturdum: https://github.com/cirosantilli/x86-bare-metal-examples
Ne yazık ki bir kullanıcı örneği örneği verme sabrım yoktu, ancak çağrı kurulumuna kadar gittim, bu yüzden kullanıcı alanı uygulanabilir olmalıdır. Çekme isteği görmek isterim.
Alternatif olarak, Linux çekirdek modülleri 0 halkasında çalışır, bu nedenle ayrıcalıklı işlemleri denemek için kullanabilirsiniz, örneğin kontrol kayıtlarını oku: https://stackoverflow.com/questions/7415515/how-to-access-the-control-registers -cr0-CR2-cr3-dan-bir-program alma-segmenta / 7419306 # 7419306
İşte sunucunuzu öldürmeden denemek için uygun bir QEMU + Buildroot kurulumu .
Çekirdek modüllerinin dezavantajı, diğer taban çizgilerinin çalışıyor olması ve denemenizi engelleyebilmesidir. Fakat teoride, çekirdek modülünüzle tüm kesme işleyicilerini devralabilir ve sistemin sahibi olabilirsiniz, bu aslında ilginç bir proje olacaktır.
Negatif halkalar
Negatif zil sesleri aslında Intel el kitabında referans gösterilmese de, Zil halkasının 0'dan daha fazla özelliğe sahip CPU modları vardır ve bu nedenle "negatif zil" adı için iyi bir seçimdir.
Bir örnek sanallaştırmada kullanılan hiper yönetici modudur.
Daha fazla ayrıntı için bakınız: https://security.stackexchange.com/questions/129098/what-is-protection-ring-1
KOL
ARM'de, halkalara bunun yerine İstisna Seviyeleri denir, ancak ana fikirler aynı kalır.
ARMv8'de yaygın olarak kullanılan 4 istisna seviyesi vardır:
EL0: kullanıcı ülkesi
EL1: çekirdek (ARM terminolojisinde "denetleyici").
Linux sistem çağrıları yapmak için kullanılan talimat olan svc
, daha swi
önce birleşik birleştirme olarak bilinen talimatla (SuperVisor Call) girildi . Merhaba dünya ARMv8 örneği:
.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
GitHub yukarı akış .
Ubuntu 16.04'teki QEMU ile test edin:
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
İşte bir SVC işleyicisini kaydeden ve bir SVC çağrısı yapan somut bir yardımcı örnek .
EL2: hipervizörler , örneğin Xen .
hvc
Talimatla girildi (HyperVisor Call).
Bir hipervizör bir işletim sistemine, bir işletim sisteminin kullanıcı alanına göre ne olduğunu.
Örneğin, Xen, aynı sistemde aynı anda Linux veya Windows gibi birden fazla işletim sistemi çalıştırmanıza izin verir ve işletim sistemlerini, Linux'un kullanıcı programları için yaptığı gibi güvenlik ve hata ayıklama kolaylığı için birbirinden ayırır.
Hiper yöneticiler bugünün bulut altyapısının önemli bir parçasıdır: birden fazla sunucunun tek bir donanımda çalışmasına izin verir, donanım kullanımını her zaman% 100'e yakın tutar ve çok para tasarrufu sağlar.
Örneğin AWS, KVM'ye taşınması haberi yaptığında 2017 yılına kadar Xen'i kullandı .
EL3: başka bir seviye. TODO örneği.
smc
Talimatla girildi (Güvenli Mod Araması)
ARMv8 Mimarlık Referans Modeli DDI 0487C.a - Bölüm D1 - AArch64 Sistemi Seviye Programcı Modeli - Şekil D1-1 güzelce bunu göstermektedir:
ARM, rüzgârın yararına bağlı olarak, ayrıcalık seviyeleri için x86'dan daha iyi bir adlandırma kuralına sahip olduğunu, negatif seviyelere ihtiyaç duyulmadığını unutmayın: 0 düşük ve 3 en yüksek. Yüksek seviyeler düşük seviyelerden daha sık yaratılma eğilimindedir.
Mevcut EL MRS
talimatı ile sorgulanabilir : https://stackoverflow.com/questions/31787617/what-is-the-current-execution-mode-exception-level-etc
ARM, çip alanından tasarruf etme özelliğine ihtiyaç duymayan uygulamalara izin vermek için tüm istisna seviyelerinin bulunmasını gerektirmez. ARMv8 "İstisna seviyeleri" diyor:
Bir uygulama, İstisna seviyelerinin tümünü içermeyebilir. Tüm uygulamalar EL0 ve EL1'i içermelidir. EL2 ve EL3 isteğe bağlıdır.
Örneğin, QEMU EL1'e varsayılandır, ancak EL2 ve EL3 komut satırı seçenekleriyle etkinleştirilebilir: https://stackoverflow.com/questions/42824706/qemu-system-aarch64-entering-el1-wulating-emulating-a53-power-up
Ubuntu 18.10'da test edilen kod parçacıkları.