ioctl系統調用過程(深入Linux(ARM)內核源碼)

1. 系統調用過程簡述

圖1-1 系統調用過程圖

探究系統調用過程,以ioctl爲例,通俗來說,其實就是探究操作系統實現應用程序的ioctl對應上特定驅動程序的ioctl的過程。由於應用程序的ioctl處於用戶空間,驅動程序的ioctl處於內核空間,所以這兩者之間不屬於簡單的函數調用關係;在者,考慮到內核空間操作的安全性,系統調用過程大量的安全性處理,進而使得系統調用看起來十分複雜,但是瞭解系統調用過程是十分必要的。不僅僅在你的開發過程中更好地找到問題所在,更加深你對Linux系統工作原理的理解!

2. 系統調用過程深入

2.0 提出問題,應用程序的ioctl怎麼對應驅動程序的ioctl

首先我們來看看驅動程序中ioctl的設計代碼:

圖2-2 驅動程序ioctl設計代碼截圖

然後我們來看看應用程序的ioctl的設計代碼:

圖2-2 應用程序ioctl設計代碼截圖

那麼,我們就有這樣的疑問了,驅動程序和應用程序雖說都是ioctl,但是具體的函數名稱或者函數指針的名稱各不相同,那麼他們之間是如何關聯起來的呢?也就是回到標題 應用程序的ioctl怎麼對應驅動程序的ioctl的呢?

2.1 應用程序ioctl

圖2-3 應用程序ioctl設計代碼截圖

應用程序上的 ioctl 是Linux系統提供的系統調用接口,使用 man 工具查詢ioctl介紹:

圖2-4 ioctl介紹

ioctl屬於可變參數函數,對於如上應用程序中的ioctl,第一個爲文件描述符,對應的是驅動文件;第二個是操作命令,這個命令是自行定義,但是具有一套規則;第三個屬於外加參數,我這裏是沒啥意義的。

2.2 中斷過程

驅動程序中的ioctl屬於內核空間,然而應用程序屬於用戶空間,沒有權限訪問內核空間,那麼需要系統需要從用戶態轉爲內核態,在系統調用中,是通過SWI(Software Interrupt)的方式陷入內核態的。(但是我並不清楚如何去窺探這個過程,希望知道的同學們在下面留言交流!)

2.3 根據系統調用號查找系統調用表

在講這部分內容之前,由於接下來要涉及閱覽linux內核源代碼,簡單介紹一下,使用的是linux內核版本是 3.4.39 ,使用的代碼閱覽工具是 source Insight。

首先我們得尋找ioctl的系統調用號,這個系統調用號會在中斷過程中由相對應的寄存器傳遞給內核(對於x86平臺,是eax寄存器,對於ARM平臺,好像是R7傳遞的)。

圖2-4 查看ioctl系統調用號操作圖

找到系統調用表中對應的54號系統調用號對應的操作:

圖2-5 查看系統調用表操作圖

系統調用過程,中斷陷入內核態之後,會根據寄存器傳遞過來的系統調用號(54),執行系統調用表中的(54)操作,就是調用sys_ioctl()函數。

2.4 解析sys_ioctl()一步一步找到驅動程序led_ioctl()

2.4.1 sys_ioctl聲明

source Insight在代碼閱覽時非常好用,他會生成代碼關聯,實現代碼跳轉,這對於我們預覽代碼量非常大的工程是必要的。跳轉 sys_ioctl 聲明:

圖2-6 sys_ioctl函數聲明
asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);

從函數原型來看,和驅動程序函數的原型十分相似,那麼它和驅動函數的ioctl有什麼聯繫呢,我們應該看看函數的定義!

2.4.2 sys_ioctl定義

"奇怪"的是,在整個linux內核源碼中,都沒有找到sys_ioctl的定義。其實,由於 CVE-2010-3301 漏洞的存在,系統在函數定義上又做了一層分裝,過程也顯得繁瑣,後續我會另開一篇博文分析,也可以先看看下面這個博文:

linux內核SYSCALL_DEFINE分析

現在我們只需明白,SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)就是sys_ioctl的定義:

圖2-7 sys_ioctl定義

從函數源代碼來看,fget_light() 以及 security_file_ioctl() 就是檢驗可操作安全性,所以sys_ioctl更多是調用更深一層接口 do_vfs_ioctl()。

2.4.3 分析do_vfs_ioctl

圖2-8 分析do_vfs_ioctl

所以這一步也是調用更深一層接口 vfs_ioctl()。

2.4.4 分析vfs_ioctl

圖2-9 分析vfs_ioctl
圖2-2 驅動程序ioctl設計代碼截圖

到這裏,我們發現應用程序 ioctl() 和驅動程序的 led_ioctl() 也算是"牽手成功"。

總結

其實,總的來說,因爲內核操作的敏感性,纔會有系統調用這麼一個概念,系統調用總結爲下列幾個步驟

1. 應用程序調用系統調用接口;

2. 程序由用戶態通過中斷陷入內核態,同時傳遞系統調用號;

3. 查找系統調用表對應的操作

4. 一系列封裝找到底層的已設計好的接口函數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章