linux权限检查机制

1.文件权限 

static inline int do_inode_permission(struct vfsmount *mnt, struct inode *inode, int mask)
  {
      if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) {
          if (likely(mnt && inode->i_op->permission2))
              return inode->i_op->permission2(mnt, inode, mask);
          if (likely(inode->i_op->permission))
              return inode->i_op->permission(inode, mask);
  
          /* This gets set once for the inode lifetime */
          spin_lock(&inode->i_lock);
          inode->i_opflags |= IOP_FASTPERM;
          spin_unlock(&inode->i_lock);
      }    
      return generic_permission(inode, mask);                                                                                                                            
  }

int generic_permission(struct inode *inode, int mask)
  {
      int ret; 
  
      /*   
       * Do the basic permission checks.
       */
      ret = acl_permission_check(inode, mask);   //基本权限检查
      if (ret != -EACCES)
          return ret; 
  
      if (S_ISDIR(inode->i_mode)) {
          /* DACs are overridable for directories */
          if (capable_wrt_inode_uidgid(inode, CAP_DAC_OVERRIDE))    //CAP_DAC_OVERRIDE是CAP_DAC_READ_SEARCH的超集,不管读写都可以
              return 0;
          if (!(mask & MAY_WRITE))
              if (capable_wrt_inode_uidgid(inode,
                               CAP_DAC_READ_SEARCH))   //不是写
                  return 0;
          return -EACCES;
      }    
      /*   
       * Read/write DACs are always overridable.
       * Executable DACs are overridable when there is
       * at least one exec bit set.
       */
      if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO))//如果是执行,则有些不同,至少要有一个执行权限
          if (capable_wrt_inode_uidgid(inode, CAP_DAC_OVERRIDE))
              return 0;
  
      /*   
       * Searching includes executable on directories, else just read.
       */
      mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
      if (mask == MAY_READ)
          if (capable_wrt_inode_uidgid(inode, CAP_DAC_READ_SEARCH))
              return 0;                                                                                                                                                  
  
      return -EACCES;
  }

static int acl_permission_check(struct inode *inode, int mask)
  {
      unsigned int mode = inode->i_mode;
  
      if (likely(uid_eq(current_fsuid(), inode->i_uid)))  //同一个用户, 使用的是进程的fsuid
          mode >>= 6;
      else {
          if (IS_POSIXACL(inode) && (mode & S_IRWXG)) {    //注意看acl是如何工作的
              int error = check_acl(inode, mask); 
              if (error != -EAGAIN)
                  return error;
          }
  
          if (in_group_p(inode->i_gid))  //同一组
              mode >>= 3;

            //否则是other,不用移位
      }
  
      /*
       * If the DACs are ok we don't need any capability check.
       */
      if ((mask & ~mode & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
          return 0;
      return -EACCES;
  }

2.能力的检查

 bool ns_capable(struct user_namespace *ns, int cap)
  {   
      return ns_capable_common(ns, cap, true);                                                                                                                           
  }

  static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit)                                                                                          
  {
      int capable;
  
      if (unlikely(!cap_valid(cap))) {
          pr_crit("capable() called with invalid cap=%u\n", cap);
          BUG();
      }
  
      capable = audit ? security_capable(current_cred(), ns, cap) :
                security_capable_noaudit(current_cred(), ns, cap);
      if (capable == 0) {
          current->flags |= PF_SUPERPRIV;
          return true;
      }
      return false;
  }

 struct security_hook_list capability_hooks[] = {
      LSM_HOOK_INIT(capable, cap_capable),

.....}

*int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,                                                                                               
          int cap, int audit)
  {
    int ret = __cap_capable(cred, targ_ns, cap, audit);
  }

int __cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
          int cap, int audit)
  {
      struct user_namespace *ns = targ_ns;
  
      /* See if cred has the capability in the target user namespace
       * by examining the target user namespace and all of the target
       * user namespace's parents.
       */
      for (;;) {
          /* Do we have the necessary capabilities? */
          if (ns == cred->user_ns)
              return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;
                                                                                                                                                                         
          /* Have we tried all of the parent namespaces? */
          if (ns == &init_user_ns)
              return -EPERM;
  
          /* 
           * The owner of the user namespace in the parent of the
           * user namespace has all caps.
           */
         if ((ns->parent == cred->user_ns) && uid_eq(ns->owner, cred->euid))
              return 0;
  
          /* 
           * If you have a capability in a parent user ns, then you have
           * it over all children user namespaces as well.
           */ 
         ns = ns->parent;
      }   
      
      /* We never get here */
  } 

如果是root,则默认具有所有能力,即CapInh,CapPrm,CapEff,CapBnd所有bit都是1,包括CAP_DAC_OVERRIDE,所有root可以操作任何文件,通过setuid()和setgid()可以切换到非root用户,此时CapInh,CapPrm,CapEff都变为0,CapBnd维持不变,即默认非root用户失去所有的能力。

通过设置程序文件的能力bit,可以给普通用户授予某项能力

setcap  cap_net_raw=eip /bin/ping

此时任何用户都可以ping,这是比suid更安全的一种做法,只授予需要的权限,而不像suid授予所有的权限(everything or nothing),文件能力存储在文件系统的xattr中,并且挂载时不能指定nosuid选项,否则文件能力失效。

如果文件设置了能力,程序能力具体的规则如下:

我们使用P代表执行exec前的capabilities,P’代表执行exec后的capabilities,F代表exec执行的文件的capabilities。那么:

P’(Permitted) = (P(Inheritable) & F(Inheritable)) | (F(Permitted) & cap_bset)

P’(Effective) = F(Effective) ? P’(Permitted) : 0

P’(Inheritable) = P(Inheritable)

其中的cap_bset是capability bounding set。通过与文件的Permitted集合计算交集,可进一步限制某些capabilities的获取,从而降低了风险

对于文件没有设置能力,则按如下规则:

P’(Permitted) =P(Inheritable)

P’(Effective)=P(Effective)

P’(Inheritable) = P(Inheritable)

如果某个程序文件具有cap_setuid,cap_setgid的能力,则非root用户可以通过setuid()和setgid()可以切换到root用户,此时:

CapInh,CapPrm,CapEff=CapBnd

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux系统的Shell检查脚本是一种用于检查和测试Shell脚本的工具。它可以帮助开发人员和系统管理员发现脚本中的错误和问题,以确保脚本的正确性和可靠性。Shell检查脚本可以检查脚本中的语法错误、变量使用、函数定义、文件操作等方面的问题,并提供详细的错误信息和建议。使用Shell检查脚本可以提高脚本的质量和可维护性,减少错误和故障的发生。 ### 回答2: Linux系统中有一种特殊的脚本称为shell脚本,它可以用来进行一些自动化的检查和处理操作。通过shell脚本,我们可以灵活地进行各种检查任务,节约时间和人力成本。 首先,在创建shell脚本之前,我们需要确定要进行的具体检查任务。可以是检查系统的硬件配置、软件版本、服务状态、文件和目录权限等。然后,我们可以利用shell脚本语言来编写具体的检查脚本。 在Shell脚本中,我们可以使用各种命令和工具来完成检查任务。例如,可以使用grep命令来搜索特定的关键词,使用awk命令来解析文本数据,使用find命令来查找文件和目录等。通过这些命令和工具的组合和使用,我们可以灵活地进行各种检查操作。 此外,我们还可以使用条件语句和循环语句来实现更复杂的检查逻辑。例如,我们可以使用if语句来判断某个条件是否满足,根据不同的情况执行不同的命令。我们还可以使用for循环来遍历某个范围内的数据,执行相同的检查任务。 最后,在运行shell检查脚本之前,我们需要给予执行权限。可以使用chmod命令来修改脚本文件的权限,使其可以执行。然后,我们可以使用./命令来运行脚本。 总之,Linux系统中的shell脚本可以用于进行各种检查任务,通过灵活使用各种命令和工具,结合条件语句和循环语句,可以实现复杂的检查逻辑。这样,我们可以方便地进行系统检查,提高效率和准确性。 ### 回答3: Linux系统中的shell检查脚本是一段用于自动化执行任务和检查系统状态的代码。它可以通过命令行或者定时任务的方式运行,以达到自动监控和报告系统运行情况的目的。 shell检查脚本可以包含各种命令和逻辑判断,用于检查系统的各种指标和状态。比如,可以通过检查磁盘空间占用率、进程运行状态、网络连接情况等来监控系统的健康度。当某个指标或状态达到预设的阈值时,脚本可以发出警报、记录日志或者采取其他预定的操作,以提醒系统管理员或采取相应的处理措施。 shell检查脚本的编写需要掌握相应的shell脚本语法和命令。可以使用if语句、for循环、while循环等控制结构来实现各种判断和循环操作。同时,还可以使用一些命令行工具如grep、awk、sed等来处理和过滤命令的输出。 一个好的shell检查脚本应该具备以下特点:简洁明了的逻辑结构、充分的错误处理机制、适当的日志输出和报警机制、良好的可读性和可维护性等。此外,还可以使用一些第三方工具或库来增强脚本的功能和易用性,如nagios、zabbix等监控系统。 总之,shell检查脚本在Linux系统中具有重要的作用,通过自动化的方式检查系统状态和运行情况,可以提高系统的可靠性和可维护性,减少系统管理员的工作压力,并及时发现和解决系统问题,保障系统的稳定运行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值