当前位置: 首页 > news >正文

Linux中系统调用sys_access函数的实现

Linux 权限检查sys_access函数概览

核心组件层次结构

用户空间系统调用↓
sys_access() / 其他文件操作↓
__user_walk() → 用户/内核空间路径名传递↓  
path_lookup() → 路径解析起点↓
link_path_walk() → 路径组件遍历├── do_lookup() → 目录项查找├── follow_dotdot() → 父目录处理├── follow_mount() → 挂载点处理└── do_follow_link() → 符号链接解析↓
permission() → 权限验证├── 文件系统特定检查├── generic_permission() → 通用检查└── LSM安全模块检查

权限检查分层模型

传统DAC检查 (Unix权限位)↓
POSIX ACL扩展检查  ↓
能力机制覆盖 (Capabilities)↓
LSM强制访问控制 (SELinux/AppArmor)

安全体系设计

身份与权限管理

// access()系统调用的真实身份检查
current->fsuid = current->uid;    // 使用真实UID
current->fsgid = current->gid;    // 使用真实GID// 能力集调整
if (current->uid)cap_clear(current->cap_effective);  // 非root用户清空能力

能力机制精细化控制

// CAP_DAC_OVERRIDE - 完全权限覆盖
if (capable(CAP_DAC_OVERRIDE))return 0;// CAP_DAC_READ_SEARCH - 只读权限覆盖  
if (mask == MAY_READ || (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE)))if (capable(CAP_DAC_READ_SEARCH))return 0;

只有root用户才能有能力覆盖的可能,普通用户会清空能力集

检查当前进程是否有权按指定模式访问文件sys_access

asmlinkage long sys_access(const char __user * filename, int mode)
{struct nameidata nd;int old_fsuid, old_fsgid;kernel_cap_t old_cap;int res;if (mode & ~S_IRWXO)	/* where's F_OK, X_OK, W_OK, R_OK? */return -EINVAL;old_fsuid = current->fsuid;old_fsgid = current->fsgid;old_cap = current->cap_effective;current->fsuid = current->uid;current->fsgid = current->gid;/** Clear the capabilities if we switch to a non-root user** FIXME: There is a race here against sys_capset.  The* capabilities can change yet we will restore the old* value below.  We should hold task_capabilities_lock,* but we cannot because user_path_walk can sleep.*/if (current->uid)cap_clear(current->cap_effective);elsecurrent->cap_effective = current->cap_permitted;res = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);if (!res) {res = permission(nd.dentry->d_inode, mode, &nd);/* SuS v2 requires we report a read only fs too */if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode)&& !special_file(nd.dentry->d_inode->i_mode))res = -EROFS;path_release(&nd);}current->fsuid = old_fsuid;current->fsgid = old_fsgid;current->cap_effective = old_cap;return res;
}

函数功能概述

sys_access 函数检查当前进程是否有权按指定模式访问文件,用于实现POSIX标准的access()系统调用

代码详细解析

asmlinkage long sys_access(const char __user * filename, int mode)
{

函数声明:

  • asmlinkage: 表示函数参数通过栈传递,用于系统调用
  • long: 返回类型,系统调用通常返回long
  • sys_access: 系统调用函数名
  • const char __user * filename: 用户空间文件名指针
  • int mode: 访问模式标志

变量定义

	struct nameidata nd;int old_fsuid, old_fsgid;kernel_cap_t old_cap;int res;
  • struct nameidata nd: 用于存储路径查找结果的数据结构
  • int old_fsuid, old_fsgid: 保存原来的文件系统用户ID和组ID
  • kernel_cap_t old_cap: 保存原来的有效能力集
  • int res: 操作结果返回值

模式参数验证

	if (mode & ~S_IRWXO)	/* where's F_OK, X_OK, W_OK, R_OK? */return -EINVAL;
  • if (mode & ~S_IRWXO): 检查mode参数是否包含非法标志
  • S_IRWXO: 其他用户的读、写、执行权限位掩码(0007)
  • ~S_IRWXO: 取反后得到所有非法位的掩码
  • return -EINVAL: 如果包含非法标志,返回无效参数错误

保存原始安全上下文

	old_fsuid = current->fsuid;old_fsgid = current->fsgid;old_cap = current->cap_effective;
  • current->fsuid: 当前进程的文件系统用户ID
  • current->fsgid: 当前进程的文件系统组ID
  • current->cap_effective: 当前进程的有效能力集
  • 作用: 保存当前安全状态,以便后续恢复

设置真实身份

	current->fsuid = current->uid;current->fsgid = current->gid;
  • current->fsuid = current->uid: 将文件系统UID设置为真实UID
  • current->fsgid = current->gid: 将文件系统GID设置为真实GID
  • access系统调用语义: 使用进程的真实用户ID进行检查

能力集调整

	/** Clear the capabilities if we switch to a non-root user** FIXME: There is a race here against sys_capset.  The* capabilities can change yet we will restore the old* value below.  We should hold task_capabilities_lock,* but we cannot because user_path_walk can sleep.*/if (current->uid)cap_clear(current->cap_effective);elsecurrent->cap_effective = current->cap_permitted;
  • 非root用户处理

    • if (current->uid): 如果当前用户不是root(uid != 0
    • cap_clear(current->cap_effective): 清空有效能力集
  • root用户处理:

    • else: 如果是root用户
    • current->cap_effective = current->cap_permitted: 设置有效能力集为允许的能力集

路径查找

	res = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
  • __user_walk(): 从用户空间文件名解析到内核文件对象
  • filename: 用户空间文件名指针
  • LOOKUP_FOLLOW: 跟随符号链接
  • LOOKUP_ACCESS: 为权限检查进行路径查找
  • &nd: 存储查找结果的nameidata结构
  • res: 返回查找结果,0表示成功

权限检查

	if (!res) {res = permission(nd.dentry->d_inode, mode, &nd);
  • if (!res): 如果路径查找成功
  • permission(nd.dentry->d_inode, mode, &nd): 检查文件访问权限
    • nd.dentry->d_inode: 文件的inode对象
    • mode: 请求的访问模式
    • &nd: 路径查找上下文

只读文件系统检查

		/* SuS v2 requires we report a read only fs too */if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode)&& !special_file(nd.dentry->d_inode->i_mode))res = -EROFS;
  • 条件检查:
    • !res: 之前的权限检查通过
    • (mode & S_IWOTH): 请求写权限(其他用户写权限位)
    • IS_RDONLY(nd.dentry->d_inode): 文件所在文件系统是只读的
    • !special_file(...): 不是特殊文件(设备文件等)
  • res = -EROFS: 如果满足条件,返回只读文件系统错误

释放路径资源

		path_release(&nd);}
  • path_release(&nd): 释放路径查找过程中获取的引用和锁
  • 无论权限检查结果如何,都需要释放资源

恢复原始上下文

	current->fsuid = old_fsuid;current->fsgid = old_fsgid;current->cap_effective = old_cap;
  • 恢复原来的文件系统用户ID
  • 恢复原来的文件系统组ID
  • 恢复原来的有效能力集
  • 重要性: 确保系统调用不会永久改变进程的安全状态

返回结果

	return res;
}
  • res: 包含整个操作的最终结果
  • 成功返回0,失败返回负的错误代码

函数功能总结

主要功能:检查真实用户对指定文件的访问权限

核心特性

  1. 真实身份检查 - 使用真实用户ID而非有效用户ID
  2. 完整权限验证 - 考虑文件权限、文件系统状态、能力集
  3. 资源安全管理 - 正确保存和恢复进程安全上下文
  4. 错误全面处理 - 处理各种边界条件和错误情况

安全设计

  • 凭据隔离 - 临时修改凭据并在完成后恢复

  • 能力控制 - 根据用户身份调整能力集

  • 资源清理 - 确保路径查找资源正确释放

  • 真实用户ID:表明"你是谁" - 进程的真实所有者

  • 有效用户ID:决定"你能做什么" - 实际的权限级别,用于临时提权

解析用户空间提供的路径名__user_walk

int fastcall __user_walk(const char __user *name, unsigned flags, struct nameidata *nd)
{char *tmp = getname(name);int err = PTR_ERR(tmp);if (!IS_ERR(tmp)) {err = path_lookup(tmp, flags, nd);putname(tmp);}return err;
}
int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd)
{int retval;nd->last_type = LAST_ROOT; /* if there are only slashes... */nd->flags = flags;nd->depth = 0;read_lock(&current->fs->lock);if (*name=='/') {if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) {nd->mnt = mntget(current->fs->altrootmnt);nd->dentry = dget(current->fs->altroot);read_unlock(&current->fs->lock);if (__emul_lookup_dentry(name,nd))return 0;read_lock(&current->fs->lock);}nd->mnt = mntget(current->fs->rootmnt);nd->dentry = dget(current->fs->root);} else {nd->mnt = mntget(current->fs->pwdmnt);nd->dentry = dget(current->fs->pwd);}read_unlock(&current->fs->lock);current->total_link_count = 0;retval = link_path_walk(name, nd);if (unlikely(current->audit_context&& nd && nd->dentry && nd->dentry->d_inode))audit_inode(name,nd->dentry->d_inode->i_ino,nd->dentry->d_inode->i_rdev);return retval;
}

函数功能概述

这两个函数协同工作,用于解析用户空间提供的路径名,将其转换为内核中的目录项(dentry)和挂载点(mnt)结构,是Linux内核VFS层路径解析的核心组件

代码详细解释

第一部分:__user_walk函数

int fastcall __user_walk(const char __user *name, unsigned flags, struct nameidata *nd)
{char *tmp = getname(name);int err = PTR_ERR(tmp);
  • fastcall:编译器优化,表示使用寄存器传递参数
  • __user *name:指向用户空间的路径名字符串
  • getname(name)关键函数,从用户空间复制路径名到内核空间
  • PTR_ERR(tmp):将指针转换为错误码,如果getname失败会返回错误指针
	if (!IS_ERR(tmp)) {err = path_lookup(tmp, flags, nd);putname(tmp);}return err;
  • IS_ERR(tmp):检查getname是否成功(返回的不是错误指针)
  • 如果成功:调用path_lookup进行实际的路径查找
  • putname(tmp):释放getname分配的内核空间内存
  • 返回错误码或查找结果

第二部分:path_lookup函数 - 初始化

int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd)
{int retval;nd->last_type = LAST_ROOT; /* if there are only slashes... */nd->flags = flags;nd->depth = 0;
  • nameidata *nd:输出参数,存储查找结果(dentry, mnt等)
  • last_type = LAST_ROOT:初始化最后组件类型为根目录
  • flags:查找标志(如LOOKUP_FOLLOW等)
  • depth = 0:符号链接深度计数器,防止无限递归

第三部分:路径起点确定

	read_lock(&current->fs->lock);if (*name=='/') {if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) {nd->mnt = mntget(current->fs->altrootmnt);nd->dentry = dget(current->fs->altroot);read_unlock(&current->fs->lock);if (__emul_lookup_dentry(name,nd))return 0;read_lock(&current->fs->lock);}nd->mnt = mntget(current->fs->rootmnt);nd->dentry = dget(current->fs->root);} else {nd->mnt = mntget(current->fs->pwdmnt);nd->dentry = dget(current->fs->pwd);}read_unlock(&current->fs->lock);
  1. 读锁保护

    read_lock(&current->fs->lock);
    
    • 保护进程的文件系统状态(current->fs)不被并发修改
  2. 绝对路径处理 (/开头):

    if (*name=='/') {
    
    • 检查是否是绝对路径
  3. 替代根目录检查

    if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
    
    • altroot:chroot环境的替代根目录
    • LOOKUP_NOALT:标志位,表示不使用替代根目录
  4. 设置替代根目录

    nd->mnt = mntget(current->fs->altrootmnt);
    nd->dentry = dget(current->fs->altroot);
    
    • mntget():增加挂载点的引用计数
    • dget():增加目录项的引用计数
  5. 尝试在替代根中查找

    read_unlock(&current->fs->lock);
    if (__emul_lookup_dentry(name,nd))return 0;
    read_lock(&current->fs->lock);
    
    • 临时释放锁(__emul_lookup_dentry可能需要睡眠)
    • 如果找到则直接返回成功
    • 重新获取锁继续处理
  6. 设置正常根目录

    nd->mnt = mntget(current->fs->rootmnt);
    nd->dentry = dget(current->fs->root);
    
    • 使用进程的根目录"/"
  7. 相对路径处理

    } else {nd->mnt = mntget(current->fs->pwdmnt);nd->dentry = dget(current->fs->pwd);
    }
    
    • 使用进程的当前工作目录
  8. 释放读锁

    read_unlock(&current->fs->lock);
    

第四部分:路径遍历和审计

	current->total_link_count = 0;retval = link_path_walk(name, nd);
  • total_link_count = 0:重置符号链接计数器
  • link_path_walk(name, nd):实际遍历路径的每个组件
	if (unlikely(current->audit_context&& nd && nd->dentry && nd->dentry->d_inode))audit_inode(name,nd->dentry->d_inode->i_ino,nd->dentry->d_inode->i_rdev);return retval;
  • unlikely():编译器优化,提示条件 unlikely 成立
  • 审计检查:如果启用了内核审计且找到了有效的inode,记录审计信息
  • audit_inode():记录inode访问审计信息(inode号、设备号)
  • 返回路径查找的结果

函数功能总结

  1. 用户空间接口__user_walk处理用户空间到内核空间的数据传输
  2. 安全复制:使用getname/putname安全地复制用户路径
  3. 路径起点解析:根据绝对/相对路径确定查找起点
  4. chroot支持:处理替代根目录情况
  5. 引用计数管理:正确管理dentryvfsmount的引用计数
  6. 并发保护:使用读写锁保护进程文件系统状态
  7. 路径遍历:委托给link_path_walk进行组件级遍历
  8. 审计支持:集成内核审计功能

在替代根目录中进行路径查找__emul_lookup_dentry

static int __emul_lookup_dentry(const char *name, struct nameidata *nd)
{if (path_walk(name, nd))return 0;		/* something went wrong... */if (!nd->dentry->d_inode || S_ISDIR(nd->dentry->d_inode->i_mode)) {struct dentry *old_dentry = nd->dentry;struct vfsmount *old_mnt = nd->mnt;struct qstr last = nd->last;int last_type = nd->last_type;/** NAME was not found in alternate root or it's a directory.  Try to find* it in the normal root:*/nd->last_type = LAST_ROOT;read_lock(&current->fs->lock);nd->mnt = mntget(current->fs->rootmnt);nd->dentry = dget(current->fs->root);read_unlock(&current->fs->lock);if (path_walk(name, nd) == 0) {if (nd->dentry->d_inode) {dput(old_dentry);mntput(old_mnt);return 1;}path_release(nd);}nd->dentry = old_dentry;nd->mnt = old_mnt;nd->last = last;nd->last_type = last_type;}return 1;
}

函数功能概述

这个函数用于在chroot环境中进行路径查找,当在替代根目录中找不到目标文件时,自动回退到正常根目录中继续查找,主要用于支持某些特殊系统调用

代码详细解释

第一部分:在替代根目录中查找

static int __emul_lookup_dentry(const char *name, struct nameidata *nd)
{if (path_walk(name, nd))return 0;		/* something went wrong... */
  • 函数参数
    • name: 要查找的路径名
    • nd: 已经指向替代根目录的nameidata结构
  • 在替代根目录中查找path_walk(name, nd)
    • 在当前的替代根目录环境中解析路径
  • 错误处理:如果查找失败(返回非零),直接返回0表示失败,查找成功则继续执行

第二部分:检查查找结果

	if (!nd->dentry->d_inode || S_ISDIR(nd->dentry->d_inode->i_mode)) {
  • 结果检查条件
    • !nd->dentry->d_inode: 找到的目录项没有对应的inode
    • S_ISDIR(nd->dentry->d_inode->i_mode): 找到的是目录
  • 逻辑含义:如果没有找到文件或者找到的是目录,需要尝试在正常根目录中查找
		struct dentry *old_dentry = nd->dentry;struct vfsmount *old_mnt = nd->mnt;struct qstr last = nd->last;int last_type = nd->last_type;
  • 保存当前状态
    • old_dentry: 保存替代根目录中找到的目录项
    • old_mnt: 保存替代根目录的挂载点
    • last: 保存最后一个路径组件信息
    • last_type: 保存最后一个组件类型
  • 目的:为了在回退查找失败时能够恢复状态

第三部分:切换到正常根目录

		/** NAME was not found in alternate root or it's a directory.  Try to find* it in the normal root:*/nd->last_type = LAST_ROOT;read_lock(&current->fs->lock);nd->mnt = mntget(current->fs->rootmnt);nd->dentry = dget(current->fs->root);read_unlock(&current->fs->lock);
  • 重置查找状态
    • nd->last_type = LAST_ROOT: 标记为从根目录开始
  • 切换到正常根目录
    • 获取读锁保护current->fs结构
    • nd->mnt = mntget(current->fs->rootmnt): 设置正常根目录挂载点,增加引用计数
    • nd->dentry = dget(current->fs->root): 设置正常根目录dentry,增加引用计数
    • 释放读锁

第四部分:在正常根目录中查找

		if (path_walk(name, nd) == 0) {if (nd->dentry->d_inode) {dput(old_dentry);mntput(old_mnt);return 1;}path_release(nd);}
  • 在正常根目录中查找path_walk(name, nd) == 0

    • 在正常根目录环境中解析相同路径
    • 如果返回0表示查找成功(没有错误)
  • 成功找到非目录文件

    if (nd->dentry->d_inode) {dput(old_dentry);mntput(old_mnt);return 1;
    }
    
    • 检查找到的目录项有对应的inode(不是目录)
    • 释放之前替代根目录的资源:
      • dput(old_dentry): 减少替代根dentry的引用计数
      • mntput(old_mnt): 减少替代根挂载点的引用计数
    • 返回1表示成功(在正常根目录中找到)
  • 查找失败处理

    path_release(nd);
    
    • 如果正常根目录查找失败或者找到的是目录,释放当前查找资源

第五部分:恢复状态和返回

		nd->dentry = old_dentry;nd->mnt = old_mnt;nd->last = last;nd->last_type = last_type;}return 1;
}
  • 恢复替代根目录状态
    • nameidata恢复为替代根目录的查找结果
    • 恢复dentrymnt、last、last_type等所有状态
  • 直接使用替代根查找的结果

函数功能总结

  1. chroot环境支持:专门为替代根目录环境设计的查找函数

  2. 智能回退机制:在替代根中找不到时自动尝试正常根目录

  3. 状态保存恢复:完整保存和恢复查找状态,确保操作原子性

  4. 资源管理:正确管理dentryvfsmount的引用计数

  5. 并发保护:使用读锁保护进程文件系统状态

  6. 目录特殊处理:对目录和文件采用不同的查找策略

权限检查函数permission

int permission(struct inode * inode,int mask, struct nameidata *nd)
{int retval;int submask;/* Ordinary permission routines do not understand MAY_APPEND. */submask = mask & ~MAY_APPEND;if (inode->i_op && inode->i_op->permission)retval = inode->i_op->permission(inode, submask, nd);elseretval = generic_permission(inode, submask, NULL);if (retval)return retval;return security_inode_permission(inode, mask, nd);
}
int generic_permission(struct inode *inode, int mask,int (*check_acl)(struct inode *inode, int mask))
{umode_t			mode = inode->i_mode;if (mask & MAY_WRITE) {/** Nobody gets write access to a read-only fs.*/if (IS_RDONLY(inode) &&(S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))return -EROFS;/** Nobody gets write access to an immutable file.*/if (IS_IMMUTABLE(inode))return -EACCES;}if (current->fsuid == inode->i_uid)mode >>= 6;else {if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) {int error = check_acl(inode, mask);if (error == -EACCES)goto check_capabilities;else if (error != -EAGAIN)return error;}if (in_group_p(inode->i_gid))mode >>= 3;}/** If the DACs are ok we don't need any capability check.*/if (((mode & mask & (MAY_READ|MAY_WRITE|MAY_EXEC)) == mask))return 0;check_capabilities:/** Read/write DACs are always overridable.* Executable DACs are overridable if at least one exec bit is set.*/if (!(mask & MAY_EXEC) ||(inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode))if (capable(CAP_DAC_OVERRIDE))return 0;/** Searching includes executable on directories, else just read.*/if (mask == MAY_READ || (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE)))if (capable(CAP_DAC_READ_SEARCH))return 0;return -EACCES;
}

函数功能概述

这两个函数协同工作,实现了Linux内核完整的文件权限检查机制,包括传统Unix权限、POSIX ACL、文件属性检查和能力(capability)覆盖机制

代码详细解释

第一部分:permission函数 - 入口处理

int permission(struct inode * inode,int mask, struct nameidata *nd)
{int retval;int submask;/* Ordinary permission routines do not understand MAY_APPEND. */submask = mask & ~MAY_APPEND;
  • 函数参数
    • inode: 要检查权限的文件inode
    • mask: 请求的权限掩码(MAY_READ, MAY_WRITE, MAY_EXEC, MAY_APPEND)
    • nd: 路径查找数据
  • MAY_APPEND处理submask = mask & ~MAY_APPEND
    • 传统Unix权限检查没有MAY_APPEND标志,只进行MAY_READ, MAY_WRITE, MAY_EXEC检查
    • 避免将append权限错误地映射为write权限
    • 有些文件系统也不支持append-only语义
    • 先过滤掉这个标志,后续检查使用submask
	if (inode->i_op && inode->i_op->permission)retval = inode->i_op->permission(inode, submask, nd);elseretval = generic_permission(inode, submask, NULL);
  • 文件系统特定检查
    • 如果inode操作集存在且有permission方法,优先调用文件系统特定的权限检查
    • 否则回退到通用权限检查generic_permission
	if (retval)return retval;return security_inode_permission(inode, mask, nd);
  • 错误处理:如果前面的检查返回非零(错误),直接返回
  • LSM安全钩子:调用Linux安全模块的权限检查
    • 支持SELinuxAppArmor等安全模块
    • 使用原始的mask(包含MAY_APPEND)

第二部分:generic_permission - 基础属性检查

int generic_permission(struct inode *inode, int mask,int (*check_acl)(struct inode *inode, int mask))
{umode_t			mode = inode->i_mode;
  • 函数参数
    • inode: 文件inode
    • mask: 请求的权限(已过滤MAY_APPEND)
  • 获取文件模式mode = inode->i_mode - 文件的权限和类型信息
	if (mask & MAY_WRITE) {/** Nobody gets write access to a read-only fs.*/if (IS_RDONLY(inode) &&(S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))return -EROFS;
  • 写权限特殊检查:如果请求包含写权限
  • 只读文件系统检查
    • IS_RDONLY(inode): 检查文件系统是否只读
    • 影响普通文件(S_ISREG)、目录(S_ISDIR)、符号链接(S_ISLNK)
    • 如果只读,返回-EROFS(Read-only file system)
		/** Nobody gets write access to an immutable file.*/if (IS_IMMUTABLE(inode))return -EACCES;}
  • 不可变文件检查
    • IS_IMMUTABLE(inode): 检查文件是否被标记为不可变(immutable)
    • 如果不可变,返回-EACCES(Permission denied)

第三部分:用户身份和权限位选择

	if (current->fsuid == inode->i_uid)mode >>= 6;
  • 文件所有者检查
    • current->fsuid == inode->i_uid: 当前进程的文件系统UID等于文件所有者UID
    • mode >>= 6: 将权限位右移6位,从rwxrwxrwx变为只看前3位rwx(所有者权限)
	else {if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) {int error = check_acl(inode, mask);if (error == -EACCES)goto check_capabilities;else if (error != -EAGAIN)return error;}
  • 非文件所有者路径
    • POSIX ACL检查
      • IS_POSIXACL(inode): 文件系统支持ACL
      • (mode & S_IRWXG): 文件有组权限位设置
      • check_acl: 提供了ACL检查函数
    • ACL结果处理
      • -EACCES: ACL拒绝访问,跳转到能力检查
      • 其他错误(非-EAGAIN):直接返回
      • -EAGAIN: 继续后续的传统权限检查
		if (in_group_p(inode->i_gid))mode >>= 3;}
  • 组用户检查
    • in_group_p(inode->i_gid): 当前进程在文件所属组中
    • mode >>= 3: 右移3位,查看中间3位组权限
  • 其他用户:如果既不是所有者也不在组中,使用原始mode的最后3位(其他用户权限)

第四部分:传统DAC权限验证

	/** If the DACs are ok we don't need any capability check.*/if (((mode & mask & (MAY_READ|MAY_WRITE|MAY_EXEC)) == mask))return 0;
  • 传统DAC权限检查
    • mode & mask & (MAY_READ|MAY_WRITE|MAY_EXEC): 实际权限与请求权限的交集
    • 过滤掉非基本权限标志,只比较READ/WRITE/EXEC
    • 如果等于请求的mask,说明传统Unix权限足够,返回0(成功)

第五部分:能力机制覆盖检查

 check_capabilities:/** Read/write DACs are always overridable.* Executable DACs are overridable if at least one exec bit is set.*/if (!(mask & MAY_EXEC) ||(inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode))if (capable(CAP_DAC_OVERRIDE))return 0;
  • CAP_DAC_OVERRIDE检查
    • 条件1:不需要执行权限(!(mask & MAY_EXEC)
    • 条件2:文件有任何执行位设置(inode->i_mode & S_IXUGO)- 用户、组或其他用户的执行位
    • 条件3:是目录(S_ISDIR(inode->i_mode)
    • capable(CAP_DAC_OVERRIDE): 检查进程是否有忽略DAC限制的能力
    • 如果条件满足且有该能力,返回0(成功)
	/** Searching includes executable on directories, else just read.*/if (mask == MAY_READ || (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE)))if (capable(CAP_DAC_READ_SEARCH))return 0;
  • CAP_DAC_READ_SEARCH检查
    • 条件1:只需要读权限(mask == MAY_READ
    • 条件2:目录搜索(是目录且不需要写权限)
    • capable(CAP_DAC_READ_SEARCH): 检查进程是否有读取和搜索覆盖的能力
    • 如果条件满足且有该能力,返回0(成功)
  • CAP_DAC_READ_SEARCH允许进程绕过读和搜索相关的自主访问控制检查
	return -EACCES;
  • 最终拒绝:所有检查都失败,返回-EACCES(Permission denied)

CAP_DAC_OVERRIDE: 覆盖 读 + 写 + 执行 权限
CAP_DAC_READ_SEARCH:只覆盖 读 + 搜索 权限,具有CAP_DAC_READ_SEARCH就可以扫描所有用户的文件

关键权限标志说明

标志含义
MAY_READ4读权限
MAY_WRITE2写权限
MAY_EXEC1执行权限
MAY_APPEND8追加权限
S_IRWXU00700用户读写执行
S_IRWXG00070组读写执行
S_IRWXO00007其他用户读写执行

函数功能总结

  1. 统一入口permission提供统一的权限检查接口
  2. 标志处理:正确处理MAY_APPEND特殊标志
  3. 文件系统扩展:支持文件系统特定的权限检查方法
  4. 基础属性检查:只读文件系统和不可变文件保护
  5. 用户身份识别:正确区分文件所有者、组用户和其他用户
  6. ACL支持:集成POSIX ACL扩展权限机制
  7. 传统DAC检查:标准的Unix权限位检查
  8. 能力覆盖:支持capabilities机制覆盖传统权限限制
  9. 安全模块集成:LSM钩子支持强制访问控制
http://www.dtcms.com/a/528187.html

相关文章:

  • 微波加热内部温度场的电磁−热耦合模拟
  • 2024ICPC上海
  • 专业制作网站多少钱成品网页网站
  • Linux(LDAP服务)
  • 安卓旧机变服务器,KSWEB部署Typecho博客并实现远程访问:cpolar内网穿透实验室第645个成功挑战
  • 无需云服务的家庭相册:OpenHarmony 上的 Rust 实践
  • OpenHarmony后台服务开发指南:ServiceAbility与ServiceExtensionAbility全解析
  • ARM Cortex-M 向量表详解
  • 网站优化免费软件游戏推广话术
  • wxPython下载和安装教程(附安装包)
  • IOT项目——电源入门系列-第三章
  • 情绪合集 | 以往高分文献分析,揭示情绪研究热点
  • Vue中data和props数据代理的区别
  • C++容器queue
  • 运转灵活小企业网站建设wordpress文章布局
  • 网站网页框架构架图怎么做大理网站开发
  • Cliproxy与Adspower指纹浏览器:跨境业务安全与效率的双重引擎
  • 在线观看免费网站网址开源之家
  • AI降重软件开发方案:基于Python的文本语义重构系统
  • 小杰-自然语言处理(seven)——transformer系列——自注意力(self-attention)
  • 带代码示例的 HTML 标签实操手册
  • fastapi 前端文件配置 python fastapi服务添加前端打包好的静态文件
  • 计算机网络自顶向下方法3——详解分组交换时延、丢包、吞吐量
  • 外贸 网站推广青岛胶南市城乡建设局网站
  • GitHub等平台形成的开源文化正在重塑推荐人
  • webrtc代码走读(六)-QOS-FEC冗余度配置
  • F036 vue+flask中医热性药知识图谱可视化系统vue+flask+echarts+mysql
  • 电脑效能跃升利器 金士顿KVR内存焕新机
  • Bootstrap UI 编辑器
  • MySQL联合查询详解