解读linux文件权限管理如何实现

1 linux内核中的文件读写简介

通常,编程的主要工作就是IO,在linux中一切皆文件,那么了解文件的读写以及它们的权限管理就很重要,我们这几个部分企图一窥其貌。

对于 Linux 系统,所有输入输出都是通过读写文件完成的。因为所有的外围设备都是以文件形式在系统中呈现,这样使用统一的文件句柄就可以处理程序与外设之间的所有访问操作。

实际运行中的应用程序一般不直接调用 Liux 的系统调用 (System Calls),而是通过调用函数库(例如 libc.a)中的子程序进行操作的。

但是若为了提高一些效率,当然也是可以直接进行调用的。对于一个基本的函数库来讲,通常需要提供以下一些基本函数或子程序的集合:

复制代码
系统调用接口函数
内存分配管理函数
信号处理函数集
字符串处理函数
标准输入输出函数,
其他函数集,

如 bsd 函数、加解密函数、算术运算函数、终端操作函数和网络套接字函数集等。在这些函数集中,系统调用函数是操作系统的底层接口函数。

许多牵涉到系统调用的函数都会调用系统调用接口函数集中具有标准名称的系统函数,而不是直接使用 Linux 的系统终端调用接口。

这样做的好处是可以很大程度上让一个函数库与其所在的操作系统无关,让函数库有较高的可移植性。对于一个新的函数源代码,只要将其中涉及系统调用的部分(系统接口部分) 替换成新操作系统的系统调用,就基本上能完成该函数库的移植工作。

函数库中的子程序可以看作是应用程序与内核系统之间的中间层,它的主要作用除了提供一些不属于内核的计算函数等功能函数外,还为应用程序执行系统调用提供"包裹函数"。

这样做一来可以简化调用接口,使得接口更简单容易记忆,也可以在这些包裹函数中进行一些参数验证,出错处理,因此能使得程序更加可靠稳定。

2 读取文件是如何实现的

在通常情况下,在读写一个文件之前我们需要首先使用打开文件 (open file)操作来通知操作系统将要开始的行动。

如果想在一个文件上执行写操作,那么你首先可能需要先创建这个文件或者将文件中以前的内容删除。

操作系统还需要检查你是否有权限来执行这些操作。

如果一切正常的话,打开操作会向程序返回一个文件描述符(file escriptor),文件描述符将替代文件名来确定所访问的文件,它与 MS-DOS 中文件柄(flehandle) 作用一样。

此时一个打开着的文件的所有信息都由系统来维护,用户程序只需要使用文件描述符来访问文件。

文件读写分别使用read 和 write 系统调用,用户程序一般通过访问函数库中的 read 和 write函数来执行这两个系统调用。例如在linux内核 0.1* 版本这两个函数在系统的实现代码定义如下:

java 复制代码
int read(int fd, char *buf, int n);
int write(int fd, char *buf, int n):

这两个函数的头一个参数是文件描述符。第二个参数是一个字符缓冲阵列,用于存放读取或被写出的数据。第三个参数是需要读写的数据字节数。

函数返回值是一次调用时传输的字节计数值。对于读文件操作,返回的值可能会比想要读的数据小。如果返回值是 0,则表示已经读到文件尾。如果返回-1,则表示读操作遇到错误。对于写操作,返回的值是实际写入的字节数,如果该值与第三个参数指定的值不等,这表示写操作遇到了错误。

3 文件读取的系统调用执行过程

在 Linux 内核中,读操作在文件系统的 read_write.c 文件中实现。

当执行了上述系统中断调用时,在该系统中断程序中就会去调用执行 read_write.c 文件中的 sys read函数。sys_read()函数的原型定义如下:

arduino 复制代码
int sys_read(unsigned int fd, char *buf, int count)

该函数首先判断参数的有效性。如果文件描述符值大于系统最多同时打开的最大文件数,或者需要读取的字节数值小于 0,或者该文件还没有执行过打开操作(此时文件描述符所索引的文件结构项指针为空),这返回一个负的出错代码。

接着内核程序验证将要存放读取数据的缓冲区大小是否合适。在验证过程中,内核程序会根据指定的读取字节数对缓冲区 buf的大小进行验证,如果 buf 太小,系统会对其进行扩充。

因此,若用户程序开辟的内存缓冲区太小的话就有可能冲毁后面的数据。

随后内核代码会从文件描述符对应的内部文件表结构中获得该文件的节点结构,

并根据节点中的标志信息对该文件进行分类判断,调用下面对应类型的读操作函数,并返回所读取的实际字节数。

scss 复制代码
* 如果该文件是管道文件,
    则调用读管道函数 read_pipe()(在 fs/pipe.c 中实现) 进行操作。
* 如果是字符设备文件
    则调用读字符设备操作函数rw_char()(在 fs/char_dev.c 中实现)。
    该函数再会根据具体的字符设备子类型调用字符设备驱动程序或对内存字符设备进行操作。
* 如果是块设备文件,
    则调用块设备读操作函数 block_read() (在 fs/block_dev.c 中实现)。
    该函数则调用内存高速缓冲管理程序 fs/bufferc 中的读块函数 bread(),
    最后调用到块设备驱动程序中的l1_rw_block()函数执行实际的块设备读操作。
* 如果该文件是一般普通常规文件,
    则调用常规文件读函数 file_read()(在 fs/file_read.c 中实现)进行读数据操作。
    该函数与读块设备操作类似,
    最后也会去调用执行文件系统所在块设备的底层驱动程序访问函数 ll_rw_block(),
    但是 file_read()还需要维护相关的内部文件表结构中的信息,例如移动文件当前指针。

当读操作的系统调用返回时,函数库中的 read()函数就可以根据系统调用返回值来判断此次操作是否正确。

若返回的值小于 0,则表示此次读操作出错,于是将出错号取反后存入全局变量 errno 中,并向应用程序返回-1 值。从用户程序执行 read()函数到进入内核中进行实际操作的整个过程如下图 所示。

4 Linux文件权限管理解读

最新的 Linux 发行版通常遵循传统的 Unix 文件权限模型,该模型使用权限位来定义文件和目录的访问权限。

在 Linux 中,每个文件和目录都有一个所有者(owner)、一个所属组(group)和其他用户(others)的权限设置。以下是 Linux 中常见的文件权限级别及其含义:

sql 复制代码
读取权限(Read)(代号为 "r"):允许查看文件内容及目录内容的权限。
写入权限(Write)(代号为 "w"):允许修改文件内容或向目录添加、删除、重命名文件或目录的权限。
执行权限(Execute)(代号为 "x"):对于文件,允许执行文件,对于目录,允许进入该目录。

每个文件和目录都有一个权限字符串,如 "rwxr-xr--"。这个字符串表示了文件所有者、所属组和其他用户的权限设置,具体顺序是:

复制代码
前三位代表文件所有者的权限;
接下来的三位代表所属组的权限;
最后三位代表其他用户的权限。
  • 文件权限的功能

文件的权限是 linux 系统安全的第一道防线。linux 权限的基本构建块是读取、写入和执行权限用于控制用户对文件和目录的访问。

它通过将权限分配给三个类别来实现:所有者、组和其他用户。例如,权限 755 表示所有者拥有所有权限(rwx),组拥有读和执行权限(rx),其他用户只有读取权限(r)。

文件权限之所以重要,原因有以下几点:

  • 保护关键系统文件:

通过限制对关键系统文件的访问,可以防止有漏洞的程序或恶意程序破坏系统。例如,可以将 /etc 目录的权限设置为 700,这样只有 root 用户才能读取和修改这些文件。

  • 提高安全性:

通过限制用户对文件的访问,可以降低安全风险。例如,可以将用户主目录的权限设置为 750,这样只有用户本人才能读取和修改其文件。

  • 组织文件系统:

文件权限可以用于组织文件系统并使其更易于管理。例如,可以将所有 Web 服务器文件的组设置为 www-data,这样所有这些文件都将由同一个用户组拥有,并且可以轻松地为它们分配权限。

5 文件权限的示例和设置

文件权限的示例,以下是一些常见的 Unix 文件权限示例:

复制代码
644: 此权限授予所有者读写权限,授予组成员读取权限,授予其他用户无权限。这通常用于文本文件和脚本。
755: 此权限授予所有者读写执行权限,授予组成员读执行权限,授予其他用户读权限。这通常用于可执行文件和目录。
700: 此权限授予所有者读写执行权限,授予组成员和其他人无权限。这通常用于需要高度安全性的文件,例如系统配置文件。
  • 如何设置 如何设置 Unix 文件权限,可以使用 chmod 命令设置 Unix 文件权限。该命令接受以下参数:

    权限: 要设置的权限,可以是数字或字母表示法。

    文件或目录:是要设置权限的文件或目录的路径。

例如,以下命令将 /my_file.txt 文件的权限设置为 644:

bash 复制代码
chmod 644 /my_file.txt

有关 chmod 命令的更多信息,请参阅手册页:

bash 复制代码
man chmod

6 如何做才是安全正确

以下是一些有关 Unix 文件权限的常见安全最佳做法:

  • 尽量限制文件权限:

只授予用户完成其工作所需的最少权限。例如,如果用户不需要修改文件,请不要授予他们写权限。

  • 使用 umask 命令:

umask 命令可用于设置新创建文件的默认权限。这可以帮助确保所有新文件都具有安全的默认权限。

  • 定期检查文件权限:

定期检查文件权限以确保它们是最新的很重要。这可以帮助识别和修复任何潜在的安全漏洞。

除了上述内容之外,还有一些更高级的 Unix 文件权限功能可用于提高安全性。例如,您可以使用 setuid 和 setgid 位来允许非 root 用户以 root 用户的身份运行程序,而无需授予他们完整的 root 权限。您还可以使用 粘滞位 来防止用户删除或重命名不属于他们的文件。

文件权限是一种重要的安全机制,用于控制用户对文件和目录的访问。它通过将权限授予文件的所有者、组成员和其他用户来实现这一点。每个权限都允许或阻止对文件的特定操作,例如读取、写入或执行。

相关推荐
ai小鬼头23 分钟前
AIStarter最新版怎么卸载AI项目?一键删除操作指南(附路径设置技巧)
前端·后端·github
Touper.29 分钟前
SpringBoot -- 自动配置原理
java·spring boot·后端
一只叫煤球的猫1 小时前
普通程序员,从开发到管理岗,为什么我越升职越痛苦?
前端·后端·全栈
一只鹿鹿鹿1 小时前
信息化项目验收,软件工程评审和检查表单
大数据·人工智能·后端·智慧城市·软件工程
M4K01 小时前
Linux百度网盘优化三板斧
linux
好奇的菜鸟2 小时前
如何在 Ubuntu 24.04 (Noble) 上使用阿里源
linux·运维·ubuntu
专注VB编程开发20年2 小时前
开机自动后台运行,在Windows服务中托管ASP.NET Core
windows·后端·asp.net
程序员岳焱2 小时前
Java 与 MySQL 性能优化:MySQL全文检索查询优化实践
后端·mysql·性能优化
bcbobo21cn2 小时前
初步了解Linux etc/profile文件
linux·运维·服务器·shell·profile
一只叫煤球的猫2 小时前
手撕@Transactional!别再问事务为什么失效了!Spring-tx源码全面解析!
后端·spring·面试