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程序的属性:

shell@android:/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来格式化输出了。


你可能感兴趣的:(android,linux)