1. 程式人生 > >Linux檔案的特殊許可權位SUID、SGID作用及程式設計設定/讀取

Linux檔案的特殊許可權位SUID、SGID作用及程式設計設定/讀取

最近在搞android裡面的su(不是為了做root提權,那是別的部門乾的事)。學習了一些新東西,挺有意思。


以下文章假定你的android裝置已經被root了,有獲取root許可權的能力,或者在Linux環境下。


SU這個程式嘛,說簡單一點就是讓你的程式能夠以android/linux裡面最高的root許可權執行。例如通常情況下,在android裡面執行的apk是沒有root許可權的,所以你想以root許可權去啟動一個程序,你得寫程式碼:

runtime.getRuntime().exec("su -c myProgram");

這樣,啟動的myProgram程式就具有root許可權了。SU程式為什麼有這樣的特性呢?能讓普通使用者啟動的程式變成屬於超級使用者root的程式呢?

這就必須得提到Linux的特殊檔案許可權位了。


我們來看一下su程式的屬性:

[email protected]:/data # ls /system/bin/su -l
ls /system/bin/su -l
-rwsr-sr-x root     shell       97385 2014-03-04 11:33 su
rwx我們知道分別代表的是 讀/寫/執行 許可權,可是su這個程式在本來的x位置卻不是寫的x而是 s屬性。s代表什麼意思呢?請看下文介紹。

SUID、SGID和粘滯位說明

以下說明來自鳥哥的論壇(http://phorum.vbird.org/viewtopic.php?t=20256


Set UID 

當 s 這個標誌出現在檔案擁有者的 x 許可權上時,例如 /usr/bin/passwd 這個檔案的許可權狀態:『-rwsr-xr-x』,此時就被稱為 Set UID,簡稱為 SUID 的特殊許可權 

SUID 許可權僅對二進位程式(binary program)有效;  
* 執行者對於該程式需要具有 x 的可執行許可權; 
* 本許可權僅在執行該程式的過程中有效 (run-time); 
* 執行者將具有該程式擁有者 (owner) 的許可權。 

Set GID
 
當 s 標誌在檔案擁有者的 x 專案為 SUID,那 s 在群組的 x 時則稱為 Set GID, SGID 囉! 

與 SUID 不同的是, SGID 可以針對檔案或目錄來設定!  
對檔案 來說, SGID 有如下的功能: 

* SGID 對二進位程式有用; 
* 程式執行者對於該程式來說,需具備 x 的許可權; 
* 執行者在執行的過程中將會獲得該程式群組的支援! 

用在目錄 上,這也是非常常見的一種用途! 
當一個目錄設定了 SGID 的許可權後,他將具有如下的功能: 

* 使用者若對於此目錄具有 r 與 x 的許可權時,該使用者能夠進入此目錄; 
* 使用者在此目錄下的有效群組(effective group)將會變成該目錄的群組; 
* 用途:若使用者在此目錄下具有 w 的許可權(可以新建檔案),則使用者所建立的新檔案,該檔案的群組與此目錄的群組相同。 

Sticky Bit  

這個 Sticky Bit, SBIT 目前 只針對目錄有效 ,對於檔案已經沒有效果了。 SBIT 對於目錄的作用是: 

* 當使用者對於此目錄具有 w, x 許可權,亦即具有寫入的許可權時; 
* 當使用者在該目錄下建立檔案或目錄時,僅有自己與 root 才有權力刪除該檔案 


還有一篇英文(http://www.tutorialspoint.com/unix/unix-file-permission.htm)以passwd程式為例

SUID and SGID File Permission:

Often when a command is executed, it will have to be executed with special privileges in order to accomplish its task.

As an example, when you change your password with the passwd command, your new password is stored in the file /etc/shadow.

As a regular user, you do not have read or write access to this file for security reasons, but when you change your password, you need to have write permission to this file. This means that the passwdprogram has to give you additional permissions so that you can write to the file /etc/shadow.

Additional permissions are given to programs via a mechanism known as the Set User ID ( SUID) and Set Group ID ( SGID) bits.

When you execute a program that has the SUID bit enabled, you inherit the permissions of that program's owner. Programs that do not have the SUID bit set are run with the permissions of the user who started the program.

This is true for SGID as well. Normally programs execute with your group permissions, but instead your group will be changed just for this program to the group owner of the program.

The SUID and SGID bits will appear as the letter "s" if the permission is available. The SUID "s" bit will be located in the permission bits where the owners execute permission would normally reside. For example, the command

$ ls -l /usr/bin/passwd
-r-sr-xr-x  1   root   bin  19031 Feb 7 13:47  /usr/bin/passwd*
$

Which shows that the SUID bit is set and that the command is owned by the root. A capital letter S in the execute position instead of a lowercase s indicates that the execute bit is not set.

If the sticky bit is enabled on the directory, files can only be removed if you are one of the following users:

  • The owner of the sticky directory

  • The owner of the file being removed

  • The super user, root

To set the SUID and SGID bits for any directory try the following:

$ chmod ug+s dirname
$ ls -l
drwsr-sr-x 2 root root  4096 Jun 19 06:45 dirname
$
上文加粗的地方特別提到了,如果owner和group兩個位置的執行許可權沒有設定的話,那麼設定了SUID或者SGID後出現的將是大寫的S,而不是小寫的s.

禮物上文提到了sticky bit的作用,如果sticky bit在某一目錄上有設定,那麼這個目錄裡面的檔案只能被三種使用者所刪除:

1 目錄的所有者

2 檔案的所有者

3 root超級使用者

維基百科的sticky bit詞條也說明了“When the sticky bit is set, only the item's owner, the directory's owner, or the superuser can rename or delete files.”所以上面鳥哥論壇裡面介紹sticky bit作用時少說了一種情況:設定了sticky bit的目錄的所有者也是可以刪除或者重新命名目錄下的檔案的。

程式設計獲取檔案的屬性

只需要一個函式stat就可以了。如下程式碼獲取/system/bin/su程式的屬性(包括特殊許可權位)

    struct stat results;  


    stat("/system/bin/su", &results);


    printf("permission  is %#o\n", results.st_mode);


    printf("user READ   permission: %d\n", (bool)(results.st_mode & S_IRUSR));
    printf("user WRITE  permission: %d\n", (bool)(results.st_mode & S_IWUSR));
    printf("user Exec   permission: %d\n", (bool)(results.st_mode & S_IXUSR));


    printf("group READ  permission: %d\n", (bool)(results.st_mode & S_IRGRP));
    printf("group WRITE permission: %d\n", (bool)(results.st_mode & S_IWGRP));
    printf("group Exec  permission: %d\n", (bool)(results.st_mode & S_IXGRP));


    printf("other READ  permission: %d\n", (bool)(results.st_mode & S_IROTH));
    printf("other WRITE permission: %d\n", (bool)(results.st_mode & S_IWOTH));
    printf("other Exec  permission: %d\n", (bool)(results.st_mode & S_IXOTH));


    printf("SUID        permission: %d\n", (bool)(results.st_mode & S_ISUID));
    printf("SGID        permission: %d\n", (bool)(results.st_mode & S_ISGID));
    printf("Sticky Bit  permission: %d\n", (bool)(results.st_mode & S_ISVTX));

結果如下:

permission  is 0106755
user READ   permission: 1
user WRITE  permission: 1
user Exec   permission: 1
group READ  permission: 1
group WRITE permission: 0
group Exec  permission: 1
other READ  permission: 1
other WRITE permission: 0
other Exec  permission: 1
SUID        permission: 1
SGID        permission: 1
Sticky Bit  permission: 0

其中的8進位制數值0106755對應的就是 -rwsr-sr-x,只看最後的755對應的rwxr-xr-x,755前面的6等於4+2,所以在755中的owner和group的執行位會變成s,也就是變成rwsr-sr-x。


PS:上面的程式碼裡面%#o會在打印出來的8進位制數值前面加0。如果用%#x,那麼打印出來的16進位制前面會自動加0x,這樣我們就不需要用0x%x來格式化輸出了。