Exploiting “BadIRET” vulnerability (CVE-2014-9322, Linux kernel privilege escalation)
from:http://labs.bromium.com/2015/02/02/exploiting-badiret-vulnerability-cve-2014-9322-linux-kernel-privilege-escalation/
POC( 感謝Mickey提供的連結):
https://rdot.org/forum/showthread.php?t=3341
Shawn:對於這個漏洞,本文的結論是SMEP雖然被繞過了,但SMAP是依然奏效的,這裡只想提一下類似PaX/Grsecurity的UDEREF特性和SMAP類似,只是屬於純軟體 實現,大概2006年左右這個特性就已經有了而且被一些anarchy廣泛使用。
0x00 Intro
CVE-2014-9322的描述如下:
linux核心程式碼檔案arch/x86/kernel/entry_64.S在3.17.5之前的版本都沒有正確的處理跟SS(堆疊區)段暫存器相關的錯誤,這可以讓本地使用者透過觸發一個IRET指令從錯誤的地址空間去訪問GS基地址來提權。
這個漏洞於2014年11月23日被社群修復2,至今我並沒有見到公開的利用程式碼和詳細的討論。這篇文章我會嘗試去解釋這個漏洞的本質以及利用的過程。不幸的 是,我無法完全引用Intel白皮書3的所有內容,如果有讀者不熟悉一些術語可以直接查Intel白皮書。所有的實驗都是在Fedora 20 64-bit發行版上完成的,核心是3.11.10-301,所有的討論基於64位進行。
簡單結論概要:
1. 透過測試,這個漏洞可以完全穩定的被利用。
2. SMEP[4]不能阻止任意程式碼執行;SMAP[5]可以阻止任意程式碼執行。
0x01 Digression: kernel, usermode, iret
0x02 漏洞
在一些情況下,linux核心透過iret指令返回使用者空間時會產生一個異常。異常處理程式把執行路徑返回到了bad_iret函式,她做了:
#!bash
/* So pretend we completed the iret and took the #GPF in user mode.*/
pushq $0
SWAPGS
jmp general_protection
正如這行評論所解釋,接下來的程式碼流應該和一般保護異常(General Protection)在使用者空間發生時(轉跳到#GP處理程式)完全相同。這種異常處理情況大多是由iret指令引發的,e.g. #GP。
問題在於#SS異常。如果有漏洞的核心(比如3.17.5)也有"espfix"功能(從3.16引入的特性),之後bad_iret函式會在只讀的棧上執行"push"指令,這會導致頁錯誤(page fault)而會直接引起兩個錯誤。我不考慮這種場景;從現在開始,我們只關注在3.16以前的沒有"espfix"的核心。
這個漏洞根源於#SS的異常處理程式沒有符合“pretend-it-was-#GP-in-userspace”[6]的規劃,與#GP處理程式相比,#SS異常處理會多做一次swapgs指令。如果你對swapgs不瞭解,請不要跳過下面的章節。
0x03 偏題:swapgs指令
當記憶體透過gs段進行訪問時,像這樣:
#!bash
mov %gs:LOGICAL_ADDRESS, %eax
實際會發生以下幾步:
1. BASE_ADDRESS值從段暫存器的隱藏部分取出
2. 記憶體中的線性地址LOGICAL_ADDRESS+BASE_ADDRESS被dereferenced(Shawn:char *p; *p就是deref)。
基地址是從GDT(或者LDT)繼承過來的。無論如何,有一些情況是GS段基地址被修改的動作不需要GDT的參與。
引用自Intel白皮書:
“SWAPGS把當前GS基暫存器值和在MSR地址C0000102H(IA32_KERNEL_GS_BASE)所包含的值進行交換。SWAPGS指令是一個為系統軟體設計的特權指令。(....)核心可以使用GS字首在正常的記憶體引用去訪問[per-cpu]核心資料結構。”
Linux核心為每個CPU在啟動時分配一個固定大小的結構體來存放關鍵資料。之後為每個CPU載入IA32_KERNEL_GS_BASE到相應的結構地址上,因此,通常的情況,比如系統呼叫的處理程式是:
1. swapgs(現在是GS指向核心空間)
2. 透過記憶體指令和gs字首訪問per-cpu核心資料結構
3. swapgs(撤銷之前的swapgs,GS指向使用者空間)
4. 返回使用者空間
0x04 觸發漏洞
現在很明顯可以看到這個漏洞簡直就是墳墓,因為多了一個swapgs指令在有漏洞程式碼路徑裡,核心會嘗試從可能被使用者操控的錯誤GS基地址訪問重要的資料結構。
當iret指令產生了一個#SS異常?有趣的是,Intel白皮書在這方面介紹不完全(Shawn:是陰謀論的話又會想到BIG BROTHER?);描述iret指令時,Intel白皮書這 麼講:
64位模式的異常:
#SS(0)
如果一個嘗試從棧上pop一個值違反了SS限制。
如果一個嘗試從棧上pop一個值引起了non-canonical地址(Shawn: 64-bit下只允許訪問canonical地址)的引用。
沒有一個條件能被強制在核心空間裡發生。無論如何,Intel白皮書裡的iret虛擬碼展示了另外一種情況:when the segment defined by the return frame is not present:
IF stack segment is not present
THEN #SS(SS selector); FI;
所以在使用者空間,我們需要設定ss暫存器為某個值來表示不存在。這不是很直接:
我們不能僅僅使用:
mov $nonpresent_segment_selector, %eax
mov %ax, %ss
第二條指令會引發#GP。透過偵錯程式(任何ptrace)設定ss暫存器是不允許的;類似的,sys_sigreturn系統呼叫不會在64位系統上設定這個暫存器(可能32位能工作)。解決方案是:
1. 執行緒A:透過sys_modify_ldt系統呼叫在LDT裡建立一個定製段X
2. 執行緒B:s:=X_selector
3. 執行緒A:透過sys_modify_ldt使X無效
4. 執行緒B:等待硬體中斷
為什麼需要在一個程式裡使用兩個執行緒的原因是從系統呼叫(包括sys_modify_ldt)返回是透過硬編碼了#ss值的sysret指令。如果我們使X在相同的執行緒中無效就等同於"ss:=X 指令“,ss暫存器會處於未完成設定的狀態。執行以上程式碼會導致核心panic。按照更有意義的做法,我們將需要控制使用者空間的gs基地址;她可以透過系統呼叫arch_prctl(ARCH_SET_GS)被設定。
0x05 Achieving write primitive
如果執行以上程式碼,#SS處理程式會正常的返回bad_iret(意思是沒有觸及到記憶體的GS基地址),之後轉跳到#GP異常處理程式,執行一段時間後就呼叫到了這個函式:
#!cpp
289 dotraplinkage void
290 do_general_protection(struct pt_regs *regs, long error_code)
291 {
292 struct task_struct *tsk;
...
306 tsk = current;
307 if (!user_mode(regs)) {
... it is not reached
317 }
318
319 tsk->thread.error_code = error_code;
320 tsk->thread.trap_nr = X86_TRAP_GP;
321
322 if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
323 printk_ratelimit()) {
324 pr_info("%s[%d] general protection ip:%lx sp:%lx
error:%lx",
325 tsk->comm, task_pid_nr(tsk),
326 regs->ip, regs->sp, error_code);
327 print_vma_addr(" in ", regs->ip);
328 pr_cont("\n");
329 }
330
331 force_sig_info(SIGSEGV, SEND_SIG_PRIV, tsk);
332 exit:
333 exception_exit(prev_state);
334 }
C程式碼不太明顯,但從gs字首讀取到現有宏的值賦給了tsk。第306行是:
#!bash
0xffffffff8164b79d : mov %gs:0xc780,%rbx
這很變得有意思起來了。我們控制了current指標,她指向用於描述整個Linux程式的資料結構。
319 tsk->thread.error_code = error_code;
320 tsk->thread.trap_nr = X86_TRAP_GP;
寫入(從task_struct開始的固定偏移)我們控制的地址。注意值本身不能被控制(分別是0和0xd常量),但這不應該成為一個問題。遊戲結束?
不會,我們想覆蓋一些在X上的重要資料結構。如果我們按照以下的步驟:
1. 準備在FAKE_PERCPU的使用者空間記憶體,設定gs基地址給她
2. 讓地址FAKE_PERCPU+0xc780存著指標FAKE_CURRENT_WITH_OFFSET,以滿足FAKE_CURRENT_WITH_OFFSET= X – offsetof(struct task_struct,thread.error_code)
3. 觸發漏洞
之後do_general_protection會寫入X。但很快就會嘗試再次訪問current task_current的其他成員,e.g.unhandled_signal()函式從task_struct指標解引用。我們沒有依賴X來控制,最終會在核心產生一個頁錯誤。我們怎麼避免這個問題?選項有:
什麼都不做。Linux核心不像Windows,Linux核心是完全允許當一個不是預期的頁錯誤在核心出現,如果可能的話,核心會殺死當前程式之後嘗試繼續執行(Windows會藍色畫面)。這種機制對於大量核心資料汙染就無能為力了。我的猜測是在當前程式被殺死後,swapgs不平衡的保持下來,這會導致其他程式上下文的更多頁錯誤。
使用“tsk->thread.error_code = error_code”覆蓋為頁錯誤處理程式的IDT入口。之後頁錯誤發生(被unhandled_signal()觸發)。這個技術曾經在一些偶然的環境中成功過。但在這裡不會成功,因為有2個原因:
- Linux讓IDT只讀
- 就算IDT可寫,我們也不能控制覆蓋的值 -- 0或者0xd。SMEP/SMAP也會是問題。
我們可以嘗試產生一個競爭。“tsk->thread.error_code = error_code”會促進程式碼執行,比如允許透過系統呼叫控制的程式碼指標P。之後我們可以在CPU 0上觸發漏洞,在同一時間段CPU 1可以迴圈執行一些系統呼叫。這個思路可以在CPU 0被破壞前讓透過CPU 1獲得程式碼執行,比如hook頁錯誤處理程式,這樣CPU 0不會影響更多的地方,我嘗試了這種方法多次,但都失敗了。可能不同的漏洞在時間線上的不同所致。
Throw a towel on “tsk->thread.error_code = error_code” write.
雖然有些噁心,我們會嘗試最後一個選項。我們會讓current指向使用者空間,設定這個指標可以透過讀的deref到我們能控制的記憶體。自然的,我們觀察接下來的程式碼,找找更多的寫deref。
0x06. Achieving write primitive continued, aka life after do_general_protection
下一個機會是do_general_protection()所呼叫的函式:
#!cpp
int
force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
{
unsigned long int flags;
int ret, blocked, ignored;
struct k_sigaction *action;
spin_lock_irqsave(&t->sighand->siglock, flags);
action = &t->sighand->action[sig-1];
ignored = action->sa.sa_handler == SIG_IGN;
blocked = sigismember(&t->blocked, sig);
if (blocked || ignored) {
action->sa.sa_handler = SIG_DFL;
if (blocked) {
sigdelset(&t->blocked, sig);
recalc_sigpending_and_wake(t);
}
}
if (action->sa.sa_handler == SIG_DFL)
t->signal->flags &= ~SIGNAL_UNKILLABLE;
ret = specific_send_sig_info(sig, info, t);
spin_unlock_irqrestore(&t->sighand->siglock, flags);
return ret;
}
task_struct的成員sighand是一個指標,我們可以設定任意值。
action = &t->sighand->action[sig-1];
action->sa.sa_handler = SIG_DFL;
我們無法控制寫的值,SIG_DFL是常量的0。這裡最終能工作了,雖然有些扭曲。假設我們想覆蓋核心地址X。為此我們準備偽造的task_struct,所以X等於t->sighand->action[sig-1].sa.sa_handler的地址。上面還有一行要注意:
#!cpp
spin_lock_irqsave(&t->sighand->siglock, flags);
t->sighand->siglock在t->sighand->action[sig-1].sa.sa_handler的常量偏移上,核心會呼叫spin_local_irqsave在某些地址上,X+SPINLOCK的內容無法控制。這會發生什麼呢?兩種可能性:
- X+SPINLOCK所在的記憶體地址看起來像沒有鎖的spinlock。spin_lock_irqsave會立即完成。最後,spin_unlock_irqrestore會撤銷spin_lock_irqsave的寫操作。
2.X+SPINLOCK所在的記憶體地址看起來像上鎖的spinlock。如果我們不介入的話,spin_lock_irqsave會無線迴圈等待spinlock。有些擔心,要繞過這個障礙我們得需要其他假設 ---|| X+SPINLOCK所在記憶體地址的內容。這是可接受的,我們可以在後面看到在核心.data區域裡設定X。
* 首先,準備FAKE_CURRENT,讓t->sighand->siglock指向使用者空間上鎖的區域,SPINLOCK_USERMODE
* force_sig_info()會掛在spin_lock_irqsave裡
* 這時,另外一個使用者空間的執行緒在另外一個CPU上執行,並且改變了t->sighand,所以t->sighand->action[sig-1.sa.sa_hander成了我們的覆蓋目標,之後解鎖SPINLOCK_USERMODE
* spin_lock_irqsave會返回
* force_sig_info()會重新載入t->sighand,執行期望的寫操作
鼓勵細心的讀者追問為什麼不能使用第2種方案,即X+SPINLOCK在初始時是沒有鎖的。這並不是全部 ---|| 我們需要準備一些FAKE_CURRENT的欄位來讓儘量少的程式碼執行。我不會再透露更多細節 ---|| 這篇BLOG已經夠長了....下一步會發生什麼?force_sig_info()和do_general_protection()返回。接下來iret指令會再次產生#SS異常處理(因為仍然是使用者空間ss的值在棧上引用了一個nonpresent段),但這一次,#SS處理程式裡的額外swapgs指令會返回並取消之前不正確的swapgs。 do_general_protection()會呼叫和操作真正的task_struct,而不是偽造的FAKE_CURRENT。最終,current會發出SIGSEGV訊號,其他程式會被排程來執行。這個系統仍然是穩定的。
0x07 插曲:SMEP
SMEP是Intel處理器從第3代Core(Shawn:酷睿)時加入的硬體特性。如果控制暫存器CR4裡的SMEP位被設定的話,當RING0(Shawn:標準Linux核心是RING0,在XEN下是例外,RING0是Hypervisor)嘗試執行的程式碼來自標記為使用者空間的記憶體頁,CPU就會生成一個錯誤(Shawn:就是拒絕)。如果可能的話,Linux核心會預設開啟SMEP。
0x08 實現程式碼執行
之前的章節講述了一種如何以0在核心記憶體中覆蓋8個連續位元組的方法。如果SMEP開啟的情況下如何實現程式碼執行呢?
直接覆蓋一個核心程式碼的指標是不行的。我們可以清零top bytes( Shawn: MSB)- 但之後的地址會在使用者空間,所以SMEP會阻止這個指標的deref。
換一種方式,我們可以清零幾個low bytes( Shawn: LSB),但是之後能利用這個指標的機率也很低。
我們需要一個核心指標P指向結構X包含了程式碼指標。我們可以覆蓋P的top bytes讓她成為一個使用者空間的地址,這樣P->code_pointer_in_x()呼叫會跳轉到一個我們能選擇的地址。我不確定最好選擇哪個攻擊物件。從我的經驗來看,我選擇核心proc_root變數,這是一個結構體:
#!cpp
struct proc_dir_entry {
...
const struct inode_operations *proc_iops;
const struct file_operations *proc_fops;
struct proc_dir_entry *next, *parent, *subdir;
...
u8 namelen;
char name[];
};
這個結構體是一個proc檔案系統的入口(proc_root是/proc作為proc檔案系統的根目錄)。當一個檔名路徑開始在/proc裡查詢時,subdir指標(從proc_root.subdir開始)會跟進,直到名字被找到。之後proc_iops的指標會被呼叫:
#!cpp
struct inode_operations {
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
void * (*follow_link) (struct dentry *, struct nameidata *);
...many more...
int (*update_time)(struct inode *, struct timespec *, int);
...
} ____cacheline_aligned;
proc_root駐紮在核心程式碼段裡,這意味著漏洞利用需要知道她的地址。這個資訊可以從/proc/kallsyms符號表得到;當然,很多加固過的核心不允許普通使用者讀取這個檔案。但如果核心是一個已知的build(標準的GNU/Linux發行版),這個地址可以輕鬆獲得;和一堆偏移一樣需要構建FAKE_CURRENT。
我們會覆蓋proc_root.subdir,讓她成為一個指向一個在使用者空間能被控制的結構體proc_dir_entry。有點困難在於我們不能覆蓋整個指標。別忘了我們的寫操作是“覆蓋8個0”。如果我們讓proc_root.subdir變成0,我們不會去對映她,因為Linux核心不允許使用者空間對映到地址0上(更確切的說發是,任何低於/proc/sys/vm/mmap_min_addr的地址,預設值一般是4k)。(Shawn:想想哪些0ld good hacking days,每天都有一堆NULL pointer deref是多麼幸福活著無挑戰的時光啊;-))。這意味著我們需要:
1. 對映16MB的記憶體到地址4096
2. 使用類似proc_dir_entry的方式來填充,把inode_operations欄位指向使用者空
間的地址FAKE_IOPS,name欄位為字串"A"。
3. 配置漏洞利用去覆蓋proc_root.subdir的top 5 bytes。
之後,除非proc_root.subdir最低的3 bytes是0,我們可以確定在觸發force_sig_info()覆蓋後,proc_root.subdir會指向被控制的使用者空間記憶體。當我們的程式呼叫open("/proc/A",...)時,FAKE_IOPS的指標會被呼叫。她們應該指向哪裡呢?如果你認為答案是“指向我們的shellcode“,請再讀一遍上面的分析。
我們需要讓FAKE_IOPS指標指向一個stack pivot1序列。這再次假設了具體核心執行的版本情況。通常的"xchg %esp, %eax; ret"程式碼序列(2個位元組,94 c3是在測試核心的地址0xffffffff8119f1ed)很好的可以用於64位核心的ROP。就算沒能控制%rax,這個xchg指令操作32位的暫存器也能清掉%rsp的高32位而讓%rsp著陸在使用者空間的記憶體裡。在最糟糕的情況下,我們可以分配低4GB的虛擬記憶體然後填充ROP鏈條。
在當前測試的核心(Fedora 20)有兩種方法去deref在FAKE_IOPS的指標:
1. %rax:=FAKE_IOPS; call *SOME_OFFSET(%rax)
2. %rax:=FAKE_IOPS; %rax:=SOME_OFFSET(%rax); call *%rax
第1種情況裡,在%rsp和%rax交換值後,她會等於FAKE_IOPS。我們需要ROP鏈條駐紮在FAKE_IOPS的起始位置,這需要類似“add $A_LOT, %rsp; ret”的指令,然後在繼續。
第2種情況裡,%rsp會分配低32位的呼叫目標,即0x8119f1ed。我們需要準備在這個地址上的ROP鏈條。
計算一下%rax值有兩者之一的已知值在特定的時間指向stack pivot序列,我們不需要ROP鏈條填充整個4GB記憶體,只需要上面的兩個地址即可。第2種情況的ROP鏈條自身很簡潔:
#!bash
unsigned long *stack=0x8119f1ed;
*stack++=0xffffffff81307bcdULL; // pop rdi, ret
*stack++=0x407e0; //cr4 with smep bit cleared
*stack++=0xffffffff8104c394ULL; // mov rdi, cr4; pop %rbp; ret
*stack++=0xaabbccdd; // placeholder for rbp
*stack++=actual_shellcode_in_usermode_pages;
0x09 插曲:SMAP
SMAP是Intel從第5代Core處理器推出的一個硬體特性。如果CR4控制暫存器的SMAP位被設定的話,CPU會拒絕使用者空間的頁被RING0訪問(Shawn:個人理解,SMAP和SMEP最大的不同主要是SMEP針對程式碼段,而SMAP針對資料段)。Linux核心通常會預設開啟SMAP。一個測試的核心模組(Core-M 5Y10a CPU)嘗試訪問使用者空間然後crash了:
#!bash
[ 314.099024] running with cr4=0x3407e0
[ 389.885318] BUG: unable to handle kernel paging request at 00007f9d87670000
[ 389.885455] IP: [ffffffffa0832029] test_write_proc+0x29/0x50 [smaptest]
[ 389.885577] PGD 427cf067 PUD 42b22067 PMD 41ef3067 PTE 80000000408f9867
[ 389.887253] Code: 48 8b 33 48 c7 c7 3f 30 83 a0 31 c0 e8 21 c1 f0 e0 44 89 e0 48 8b
正如我們看到的,使用者空間的頁是正常的,但訪問也報了頁錯誤。Windows系統不太支援SMAP;Windows 10技術預覽版build 9926的cr4=0x1506f8(SMEP啟動,SMAP關閉);對比Linux核心(同樣的測試硬體)你可以看到cr4的bit 21是沒有設定的。這不奇怪,在Linux中,訪問使用者空間是透過呼叫copy_from_user(),copy_to_user()和類似函式顯式執行的,所以執行這些操作時臨時關閉SMAP是可行的。在Windows上,核心程式碼直接訪問使用者空間程式碼,只是包裝了一層訪問異常處理程式,所以要讓SMAP工作正常需要調整所有的驅動,這是一項困難的工作。
0x0A SMAP to the rescue!
上面的漏洞利用方法依賴於在使用者空間裡準備特定的資料結構,然後強制核心認為她們是可信的核心資料。這種方法對於開啟SMAP特性的核心不奏效 ---|| CPU會拒絕從使用者空間讀取惡意資料。我們能做的是構造所有需要用的資料結構,然後複製她們到核心。比如:
#!cpp
write(pipe_filedescriptor, evil_data, ...
之後evil_data會被複製到一個核心管道緩衝區裡。我們可能需要猜測她的地址; some sort of heap spraying, combined with the fact that there is no spoon^W effective kernel ASLR[9], could work, although it is likely to be less reliable than exploitation without SMAP.
總之,還有最後一個障礙 ---|| 不要忘了我們需要設定使用者空間的gs base去指向我們的漏洞利用的資料結構。在上面的場景(沒有SMAP),我們使用arch_prctl(ARCH_SET_GS)系統呼叫,她是這樣在核心裡實現的:
#!bash
long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
{
int ret = 0;
int doit = task == current;
int cpu;
switch (code) {
case ARCH_SET_GS:
if (addr >= TASK_SIZE_OF(task))
return -EPERM;
... honour the request otherwise
休斯頓,我們有一個麻煩 ---|| 我們不能使用這個API去設定gs base使用者空間以上的記憶體!
最近的CPU有wrgsbase指令可以直接設定gs base,這是一個非特權級指令,但需要透過核心設定CR4控制暫存器中的FSGSBASE bit( no 16)來開啟。Linux並沒有設定這個位,因此使用者空間不能使用這條指令。
在64位系統上,非系統級的GDT和LDT條目依然是8個位元組長,base field是最大4GB-1,所以根本沒有機會設定一個基地址的段在核心空間裡。所以,除非我漏掉了能在核心裡設定使用者態gs base的其他方法,不然SMAP能保護CVE-2014-9322針對64位Linux核心任意程式碼執行的漏洞利用。
1 CVE-2014-9322 http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-9322
2 Upstream fix http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=6f442be2fb22be02cafa606f1769fa1e6f894441
3 Intel Software Developer’s Manuals, http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html
[4] SMEP http://vulnfactory.org/blog/2011/06/05/smep-what-is-it-and-how-to-beat-it-on-linux/
[5] SMAP http://lwn.net/Articles/517475
[6] "pretend-it-was-#GP-in-userspace" https://lists.debian.org/debian-kernel/2014/12/msg00083.html
[7] Stack Pivoting https://trailofbits.files.wordpress.com/2010/04/practical-rop.pdf
[8] TSX improves timing attacks against KASLR http://labs.bromium.com/2014/10/27/tsx-improves-timing-attacks-against-kaslr/
相關文章
- 基本Linux許可權提升(Basic Linux Privilege Escalation)2018-05-13Linux
- Linux kernel map2018-08-09Linux
- XSS Attacks - Exploiting XSS Filter2020-08-19Filter
- Linux kernel 堆溢位利用方法2024-10-18Linux
- Structure of Linux Kernel Device Driver(Part II)2024-07-16StructLinuxdev
- Linux核心Kernel啟動過程2024-05-28Linux
- Understanding the linux kernel Chapter 6 Timing Measurements2024-03-27LinuxAPTREM
- Linux Boot,Kernel 和 Service 介紹2021-06-29Linuxboot
- Linux動態列印kernel日誌2018-11-20Linux
- THM-Vulnerability Capstone2024-10-17
- 在 Linux Mint 安裝 Linux Kernel 4.12(穩定版)2023-10-19Linux
- Linux kernel 堆溢位利用方法(三)2024-11-27Linux
- Linux kernel 堆溢位利用方法(二)2024-11-11Linux
- 編譯linux kernel預裝工具list2024-04-26編譯Linux
- Linux Kernel 5.9-rc3 釋出了2020-09-13Linux
- 【Linux】kernel.shmmax和shmall設定2020-08-12LinuxHMM
- Open Wifi SSID Broadcast vulnerability2020-08-19WiFiAST
- 2.2.4.1 Principles of Privilege and Role Grants in a CDB2020-03-16
- 2.2.4 Overview of Privilege and Role Grants in a CDB2020-03-16View
- VirtualBox 7.0.8釋出:初步支援Linux Kernel 6.32023-04-24Linux
- linux kernel記憶體碎片防治技術2019-03-06Linux記憶體
- PHP WDDX Serializier Data Injection Vulnerability2020-08-19PHP
- Drupal - pre Auth SQL Injection Vulnerability2020-08-19SQL
- 如何進行Linux CPU中的Kernel space分析2024-10-31Linux
- 淺析Linux Kernel[5.11.0]記憶體管理(一)2022-01-18Linux記憶體
- linux系統關於kernel.sem調優2018-08-21Linux
- 2.2.4.2.1 What Makes a Privilege or Role Grant Local2020-03-16
- Oracle OCP(31):USER & ROLE & PRIVILEGE 其它2019-02-19Oracle
- linux kernel 關於RSS/RPS/RFS/XPS的介紹2018-04-24Linux
- linux 核心 LINUX_VERSION_CODE 和 KERNEL_VERSION 宏定義 版本資訊2024-10-28Linux
- CentOS7/8 安裝 5+ 以上的Linux kernel2023-05-08CentOSLinux
- Fault-Tolerance, Fast and Slow: Exploiting Failure Asynchrony in Distributed Systems2020-08-05ASTAI
- Kernel Method2020-11-08
- [SEEDLab]競態條件漏洞(Race Condition Vulnerability)2021-06-19
- Analyzing and Reproducing the EOS Out-of-Bound Write Vulnerability in nodeos2018-07-15
- PostgreSQL 原始碼解讀(226)- Linux Kernel(虛擬記憶體)2019-09-11SQL原始碼Linux記憶體
- kernel_mktime() 詳解 —— Linux-0.11 學習筆記(四)2020-04-04Linux筆記
- Linux開機流程詳解:BIOS->MBR->GRUB->Kernel2020-12-18LinuxiOS