前言
本文描述的权限是指文件或目录的基本权限,不涉及selinux。
权限构成
位域表示
位域 | 11 | 10 | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
权限 | S | G | T | r | w | x | r | w | x | r | w | x |
- S位代表可执行文件可提升至所有者权限执行。非可执行文件无效。
- G位代表可执行文件可提升至文件所在组权限执行。非可执行文件无效。
- T位代表目录权限粘滞,只有所有者和root可删除。非目录无效。
设置
- S位
chmod u+s [file/dir]
- G位
chmod g+s [file/dir]
- T位
chmod g+s [file/dir]
注意
S、G和T位都不可复制,就是说具备S、G或T位的文件的拷贝不会保留对应的S、G或T位。
S和G位受所在文件系统挂载方式限制。例如在/dev/shm下面的文件权限不能提升(浪费了笔者不少时间)。
例如
- S位例子
zyitong@Z228M ~ % ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 47032 1月 27 2016 /usr/bin/passwd*
passwd需要修改/etc/passwd文件,普通用户对于/etc/passwd是没有权限的。通过passwd则可以修改。
- G位例子
zyitong@Z228M ~ % ls -l /sbin/unix_chkpwd
-rwxr-sr-x 1 root shadow 35536 3月 17 01:47 /sbin/unix_chkpwd*
- T位例子
zyitong@Z228M /sbin % ls -lh
drwxrwxrwt 13 root root 4.0K 8月 4 18:13 tmp/
用户建立该目录之后,只有该用户才有权限删除。即使目录所在组具有rwx权限,组内的用户也是没有权限删除。但子目录的T位需要重新设置。
字段表示
- 第9位
表示文件类型,可以为p、d、l、s、c、b和-:
p表示命名管道文件
d表示目录文件
l表示符号连接文件
-表示普通文件
s表示socket文件
c表示字符设备文件
b表示块设备文件
- 第8-6位
分别表示所有者对应的读、写、执行权限,表现形式为rwx。如果对应权限没有,该表示为-。如果存在S位且可执行,则执行权限位为s;如果存在S位且不可执行,则执行权限位为S(表示没有生效);
- 第5-3位
分别表示同组用户对应的读、写、执行权限,表现形式为rwx。如果对应权限没有,该表示为-。如果存在G位且可执行,则执行权限位为s;如果存在G位且不可执行,则执行权限位为S(表示没有生效);
- 第2-0位
分别表示其他用户对应的读、写、执行权限,表现形式为rwx。如果对应权限没有,该表示为-。如果存在T位存在且可执行,则执行权限位为t;如果存在粘帖位存在且为不可执行,则执行权限位为T。
例如
% ls -lh /dev/null
crw-rw-rw- 1 root root 1, 3 8月 4 09:02 /dev/null
表示字符设备文件,所有者、文件所在组和其他用户都具有读写权限,都没有执行权限,没有S,G和T位。
附录
C提升权限
- 源码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include "common.h"
static int fileprint(char *path)
{
int ret = 0;
long size;
struct stat status;
int fd = 0;
char *fp = NULL;
#if 0
ret = access(path, R_OK);
if(ret != 0){
VERR("%s access failed(%s)!\n", path, strerror(errno));
return -1;
}
#endif
fd = open(path, O_RDONLY);
if(fd < 0){
VERR("open %s failed(%s)\n", path, strerror(errno));
return -1;
}
ret = fstat(fd, &status);
if(ret != 0){
VERR("%s fstat failed(%s)!\n", path, strerror(errno));
close(fd);
return -1;
}
VDBG("the size of %s is %ld bytes\n", path, status.st_size);
fp = mmap(NULL, status.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if(fp == MAP_FAILED){
VERR("mmap failed(%s)!\n", strerror(errno));
}
close(fd);
vdump(fp, status.st_size);
ret = munmap(fp, status.st_size);
if(ret != 0){
VERR("munmap failed(%s)!", strerror(errno));
}
return ret;
}
int main(int argc, char *argv[])
{
int ret;
ret = getuid();
VINFO("uid %d\n", ret);
ret = geteuid();
VINFO("euid %d\n", ret);
#if 1
ret = seteuid(0);
if(ret != 0){
VERR("setuid failed(%s)!\n", strerror(errno));
exit(-errno);
}
#endif
ret = getuid();
VINFO("uid %d\n", ret);
ret = geteuid();
VINFO("euid %d\n", ret);
ret = fileprint("root.txt");
return ret;
}
- 使用
# root权限下
gcc -c common.c &&\
gcc -c suid.c &&\
gcc -o suid suid.o common.o &&\
chown root:root suid &&\
chmod 4111 suid
在普通用户权限下,可以验证suid能读取只有root权限能读取的文件。也就是说可以提升权限。