国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 操作系統 > 正文

SUID或SGID程序中能不能用system函數

2024-06-28 13:22:23
字體:
來源:轉載
供稿:網友
SUID或SGID程序中能不能用system函數

  system()函數的聲明和說明如下:

  

  注意它的描述那里,system()執行一個由command參數定義的命令,通過調用/bin/sh -c命令來實現這個功能。也就是說它的邏輯是這樣的!

  進程調用system函數,system函數調用fork創建一個子進程,然后再調用exec函數來把這個子進程的正文段替換成/bin/sh命令的正文段。然后再由sh來執行exec將程序的正文段替換成command參數所代表的命令的正文段,例如,我的一個程序a.out來調用system函數來執行sleep 20命令,它的進程示意圖如下所示:

  

  可以參考下面這個例子,如下圖所示:

  這里我執行了一個system文件,產生了兩個進程,3994和3995(右邊那個終端所示,第一列是PPID,第二列是PID),這兩個進程是父子關系,值得注意的是這兩個進程進程ID是連著的,也就是說在這兩個進程執行的時候沒有新的進程產生。

  接下來開始扯正題,在《APUE》(UNIX環境高級編程,下文不再贅述)的8.13節中,作者強調SUID和SGID程序中不應該調用system函數。為什么呢,我個人的理解是這樣的。

  以SUID權限為例,SUID這種權限設立的目的是什么,就是提供一種可控的超級權限。比如passwd命令,運行passwd這個程序后,進程的有效用戶ID是root,理論上可以為所欲為(即對shadow這個文件想怎么改就怎么改),但是passwd程序的代碼已經被寫死了,用戶所做的操作都要經過passwd這個程序的檢驗,符合標準了才能夠進行,否則程序就會提示出錯!(也就是說不能像vim那樣隨意對shadow文件進行更改,只能在某種規范下進行更改)。

  同時,這種權限應該是有限制的,不能夠進行任意傳播。比如,像man這種能夠執行shell命令的程序,它執行shell命令就是通過fork-exec機制來執行了,在某些distribution中有一個man用戶,man程序屬于這個用戶,并且設置了SUID位。也就是說我任意一個普通用戶運行man程序后的有效用戶都是man,如果此時這個普通用戶在man程序中執行shell命令的話,這個shell命令進程的有效用戶應不應該是man呢,設置用戶ID應不應該繼續保留呢,當然不行啦,這樣的話一個普通用戶不就能夠通過這種方式來具有了man用戶的權限了!(如果保留了設置用戶ID,那么在子進程中可以調用setuid函數來使進程的有效用戶ID變成設置用戶ID,同樣能達到上面所說的目的)

  OK,上面說的這么一大串,就是為啥SUID或者SGID程序不應該調用system函數來執行一個shell命令,因為這樣會傳播進程的設置用戶ID和有效用戶ID,將它傳遞給子進程,這樣就會產生bug了。理論上是這樣的,但是實際中我發現貌似不行,我的centos6.6上就不能模擬出這個bug來,比如我有這么一段程序:

  getresuid程序的代碼如下:

 1 /*  這個程序的作用是獲取進程的三個用戶ID,它的可執行文件被做了一個軟鏈接到/home/michael/bin下面 2  * */ 3 #include<errno.h> 4 #include<string.h> 5 #include<stdlib.h> 6 #include<stdarg.h> 7 #include<stdio.h> 8 #include<sys/types.h> 9 #include<unistd.h>10 #define BUFSIZE 51211 void err_exit(char *fmt,...);12 int main(int argc,char *argv[])13 {14     uid_t ruid,euid,suid;15 16     if(-1 == getresuid(&ruid,&euid,&suid))17     err_exit("[getresuid]: ");18     PRintf("real:%d/teffective:%d/tset-user:%d/n",ruid,euid,suid);19 20     return 0;21 }

  system程序的代碼如下:

 1 #include<stdlib.h> 2 #include<stdio.h> 3 int main(int argc,char *argv[]) 4 { 5     uid_t ruid,euid,suid; 6  7     if(-1 == getresuid(&ruid,&euid,&suid)) 8     err_exit("[getresuid]: "); 9     printf("real:%d/teffective:%d/tset-user:%d/n",ruid,euid,suid);10 11     system("getresuid");12     return 0;13 }

  這個system程序的功能就是首先輸出進程的real uid,effective uid,和set-user id,然后再來通過system函數調用getresuid程序再來把這三個uid輸出一遍,我把system這個可執行文件變成root所有,并加上suid權限,執行的結果如下圖:

  

  第一個uid的輸出結果是符合預期的,即由于SUID權限位的設置,有效用戶ID是0。但是后面第二個uid的輸出卻和想象的有點不同,理論上,system函數應該是能夠傳遞set-user ID和有效用戶ID給子進程的,但是這里三個UID全部都變成了500,沒一個是root,這個可能是因為system函數在exec之前將所有三個UID都變成了實際用戶ID,或者是sh命令在exec之前將所有三個UID都變成了實際用戶ID。

  照這么看來,貌似在SUID程序中調用system函數也未嘗不可,但是為了保險起見,還是自己通過fork和exec動手來實現一個system吧,然后在exec之前把三個UID都設置成實際用戶ID。


上一篇:主引導記錄MBR

下一篇:git教程

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 来安县| 英德市| 南部县| 新绛县| 柳州市| 荆门市| 庆城县| 聊城市| 隆德县| 平陆县| 日土县| 渭南市| 伊宁县| 全州县| 卓资县| 屏东县| 永顺县| 象山县| 比如县| 武定县| 无棣县| 奉节县| 富川| 乌拉特后旗| 虞城县| 涞水县| 长葛市| 武鸣县| 揭东县| 赣榆县| 上栗县| 桃源县| 福建省| 阿鲁科尔沁旗| 吴川市| 湘西| 芜湖市| 黔西县| 莎车县| 府谷县| 汶上县|