Linux 下的文件權限管理分為三組:擁有者、組、其它用戶,文件權限分為讀、寫、執行,但其實并不僅僅如此,還有 setuid、setgid、sticky bit 這一組标志,本文通過一個可執行文件的權限 4755 展開介紹 setuid、setgid 和 sticky bit 的概念,希望本文對讀者理解 Linux 文件權限管理能有所幫助。
歡迎訪問我的博客:https://whowin.gitee.io
1. 概述
2. 問題的提出
前不久在折騰 openwrt 時,需要給 openwrt 裝上 sudo(openwrt 默認是不安裝 sudo 的),安裝很成功,用起來也沒什麼問題,但是重啟了以後就不能用了,後來發現原因之一是這個 openwrt 在啟動的時候将 /usr/bin/ 目錄下的所有文件的權限(permission)都改為了 0755,這是一個正常的可執行文件的權限(permission),但是對 sudo 這個可執行文件卻是不行的,sudo 的文件權限(permission)必須是 4755;
解決這個問題倒是不難,在 openwrt 啟動時,執行一下 chmod 4755 /usr/bin/sudo 就行了;
這件事讓我想寫這篇文章,因為我們看慣了諸如 0755、0750等可執行文件屬性,這個 4755 的文件屬性并不多見。
3. 有哪些文件的屬性是4755
ls -al /usr/bin/sudo
圖1:4755的文件屬性怎麼顯示
可以看到平時常見的 rwx 中的 x 變成了 s,這個 s 正是 chmod 4755 /usr/bin/sudo 命令中,那個 “4” 造成的
假定我們有一個用戶 demo,我們已經把這個用戶加入到了 sudoers 中,那麼 demo 用戶使用 sudo 命令就可以提權了;
sudo 這個可執行文件的擁有者(owner)一定是 root,執行這個文件時,至少需要讀取用戶密碼文件 /etc/shadow,這個密碼文件的擁有者是 root,權限是 640,所以讀取這個文件是要有 root 權限,也就是說,執行 sudo 是需要有 root 權限的;
問題是,當我們執行這個文件時,當前用戶是 demo,而 demo 是沒有 root 權限的,隻有執行 sudo 經過提權才能短暫地擁有 root 權限;
這裡産生了一個無法調和的矛盾,demo 用戶需要通過執行 sudo 獲得 root 權限,但執行 sudo 也需要 root 權限;
這就是為什麼 sudo 這個文件的屬性是 4755 的原因了,當一個可執行文件的屬性是 4755 時,任何用戶執行這個文件時,将被以該文件擁有者的權限運行,這個問題後面會有詳細的描述;
下面指令可以顯示 /usr/bin/ 目錄下哪些文件的屬性是 4755
ls -al /usr/bin|grep "^-rws"
在我的 ubuntu 下會顯示出這些文件
圖2:/usr/bin/目錄下4755屬性的文件
圖3:/bin/目錄下4755屬性的文件
還可以用 find 命令查找系統中所有的權限為 4755 的文件
sudo find / -perm 4755 -type f
4. uid、euid、gid、egid
圖4:當前用戶的uid和gid
圖5:root用戶的uid和gid
圖6:whowin用戶執行touch命令
圖7:用戶權限不夠
5. setuid、setgid 和 sticky bit
圖8:Linux文件權限示意圖
程序 open_file.c 的源代碼
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main(int argc, char **argv) {
int fd = 0;
if (argc != 2) {
printf("Usage: %s [filename]\n", argv[0]);
return -1;
}
fd = open(argv[1], O_RDONLY);
if (fd == -1) {
fprintf(stderr, "%s\n", strerror(errno));
return -1;
}
close(fd);
printf("Open file %s successfully.\n", argv[1]);
return 0;
}
建立一個隻有 root 可以讀的文件 rootfile.txt
echo "This file's owner is root.">rootfile.txt
chmod 600 rootfile.txt
sudo chown root:root rootfile.txt
ls -l rootfile.txt cat rootfile.txt
圖9:編譯程序并建立一個隻有root可讀的文件
我們看到當前用戶 whowin 是不能讀取文件 rootfile.txt 的
2. 用程序 open_file 打開 rootfile.txt
./open_file rootfile.txt
圖10:程序open_file無法打開文件rootfile.txt
權限不夠是因為 Linux 在執行 open_file 程序時将當前用戶 whowin 的權限賦予了 open_file 進程,而 whowin 沒有讀取文件 rootfile.txt 的權限;
3. 将程序 open_file 的所有者改為 root 并再次嘗試打開文件 rootfile.txt
sudo chown root:root open_file
ls -l open_file
./open_file rootfile.txt
圖11:将文件所有者改為root并再次執行
權限還是不夠,盡管 open_file 的擁有者變成了 root,whowin 仍有執行 open_file 的權限,但讀取 rootfile.txt 時仍然使用的是 whowin 的權限,也就是說 Linux 在執行 open_file 時将 whowin 的權限賦予了 open_file 進程,而沒有将這個文件的擁有者 root 的權限賦予 open_file 進程;
4. 将 open_file 的權限改為 4755 并再次嘗試打開文件 rootfile.txt
sudo chmod 4755 open_file
ls -l open_file
./open_file rootfile.txt
圖12:将程序的權限改為4755并再次執行
第一個驚喜是,當我們把 open_file 的權限改為 4755 後,ls -l open_file 顯示的權限從 rwx 變成了 rws
第二個驚喜是 open_file 居然可以打開文件 rootfile.txt 了,這說明 open_file 的權限被改為 4755 後,Linux 在執行 open_file 時不像以前一樣把當前用戶 whowin 的權限賦予 open_file 進程,而是把 open_file 的擁有者 root 的權限賦予了 open_file 進程,這才使得 open_file 進程有足夠的權限打開文件 rootfile.txt;
setuidsetuid 是文件權限的一個标志位,當這個标志位置為 1 時,Linux 在執行這個文件時将會把這個文件的所有者的權限賦予這個程序的進程,而不是像普通可執行文件那樣将執行該文件的用戶的權限賦予這個程序的進程;
換句話說,當一個文件設置了 setuid 标志後,用戶執行這個文件時,在這個程序的進程中 uid 為用戶的 uid,euid 為這個文件擁有者的 uid;
chmod u s [文件名]
或者:
chmod 4755 [文件名]
ls -l rootfile.txt
sudo chmod u s rootfile.txt
ls -l rootfile.txt
sudo chmod u-s rootfile.txt
ls -l rootfile.txt
圖13:設置非可執行文件的setuid
理解了 setuid 之後 setgid 就比較容易理解了,setgid 也是文件權限的一個标志位,當設置該标志位後,用戶執行該文件時,将把該文件所在的組的權限賦予這個程序進程的組權限,而不是使用當前用戶的組權限去執行該程序;
換句話說,當一個文件設置了 setgid 标志後,用戶執行這個文件時,在這個程序的進程中 gid 為用戶的 gid,egid 為這個文件擁有者的 gid;
chmod g s [文件名]
或者:
chmod 2755 [文件名]
sticky bit 是一個比較特殊的東西,這個标志隻有用于目錄時才有效,當一個目錄被設置 sticky bit 後,在這個目錄下的所有文件隻有文件的擁有者和 root 可以删除,不管這個文件的權限是什麼(哪怕是 0777 的權限),所以 sticky bit 又可以被稱為 “限制删除标志”
最典型的例子是 /tmp 目錄,每個用戶都可以向這個文件中寫入文件,假定有 whowin 和 demo 用戶都在這個目錄下寫了文件,如果 demo 用戶删除了 whowin 用戶寫入的文件,就有可能出現問題,所以這個目錄被設置了 sticky bit,其中的文件隻有擁有者和 root 可以删除;
設置 sticky bit 可以使用以下命令
chmod t [目錄名]
或者:
chmod 1777 [目錄名]
當一個目錄被設置 sticky bit 後,在其他用戶權限中的可執行位将被改為 t
圖14:顯示設置sticky bit的目錄
圖15:Linux文件權限标志示意圖
圖16:在sticky目錄上同時設置三個标志
chmod u-s [文件名]
chmod g-s [文件名]
chmod -t [目錄名]
圖17:chmod 0755全部無法清除标志
6. uid 和 euid 的實驗
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void) {
uid_t uid;
uid_t euid;
uid = getuid();
euid = geteuid();
printf("uid = %d\neuid = %d\n", uid, euid);
return 0;
}
gcc get_euid.c -o get_euid
圖18:沒有設置setuid時的euid
圖19:設置setuid後的euid
7. 後記
更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!