Linux Capabilities 入门

news2024/9/20 22:35:32

目录

Linux capabilities 是什么?

capabilities 的赋予和继承

线程的 capabilities

Permitted

Effective

Inheritable

Bounding

Ambient

文件的 capabilities

Permitted

Inheritable

Effective

运行 execve() 后 capabilities 的变化

案例


Linux capabilities 是什么?

Capabilities 机制是在 Linux 内核 2.2 之后引入的,原理很简单,就是将之前与超级用户 root(UID=0)关联的特权细分为不同的功能组,Capabilites 作为线程(Linux 并不真正区分进程和线程)的属性存在,每个功能组都可以独立启用和禁用。其本质上就是将内核调用分门别类,具有相似功能的内核调用被分到同一组中。

这样一来,权限检查的过程就变成了:在执行特权操作时,如果线程的有效身份不是 root,就去检查其是否具有该特权操作所对应的 capabilities,并以此为依据,决定是否可以执行特权操作。

Capabilities 可以在进程执行时赋予,也可以直接从父进程继承。所以理论上如果给 nginx 可执行文件赋予了 CAP_NET_BIND_SERVICE(允许绑定到小于 1024 的端口 capabilities,那么它就能以普通用户运行并监听在 80 端口上。

capability 名称描述
CAP_AUDIT_CONTROL启用和禁用内核审计;改变审计过滤规则;检索审计状态和过滤规则
CAP_AUDIT_READ允许通过 multicast netlink 套接字读取审计日志
CAP_AUDIT_WRITE将记录写入内核审计日志
CAP_BLOCK_SUSPEND使用可以阻止系统挂起的特性
CAP_CHOWN修改文件所有者的权限
CAP_DAC_OVERRIDE忽略文件的 DAC 访问限制
CAP_DAC_READ_SEARCH忽略文件读及目录搜索的 DAC 访问限制
CAP_FOWNER忽略文件属主 ID 必须和进程用户 ID 相匹配的限制
CAP_FSETID允许设置文件的 setuid 位
CAP_IPC_LOCK允许锁定共享内存片段
CAP_IPC_OWNER忽略 IPC 所有权检查
CAP_KILL允许对不属于自己的进程发送信号
CAP_LEASE允许修改文件锁的 FL_LEASE 标志
CAP_LINUX_IMMUTABLE允许修改文件的 IMMUTABLE 和 APPEND 属性标志
CAP_MAC_ADMIN允许 MAC 配置或状态更改
CAP_MAC_OVERRIDE忽略文件的 DAC 访问限制
CAP_MKNOD允许使用 mknod() 系统调用
CAP_NET_ADMIN允许执行网络管理任务
CAP_NET_BIND_SERVICE允许绑定到小于 1024 的端口
CAP_NET_BROADCAST允许网络广播和多播访问
CAP_NET_RAW允许使用原始套接字
CAP_SETGID允许改变进程的 GID
CAP_SETFCAP允许为文件设置任意的 capabilities
CAP_SETPCAP参考 capabilities man page
CAP_SETUID允许改变进程的 UID
CAP_SYS_ADMIN允许执行系统管理任务,如加载或卸载文件系统、设置磁盘配额等
CAP_SYS_BOOT允许重新启动系统
CAP_SYS_CHROOT允许使用 chroot() 系统调用
CAP_SYS_MODULE允许插入和删除内核模块
CAP_SYS_NICE允许提升优先级及设置其他进程的优先级
CAP_SYS_PACCT允许执行进程的 BSD 式审计
CAP_SYS_PTRACE允许跟踪任何进程
CAP_SYS_RAWIO允许直接访问 /devport、/dev/mem、/dev/kmem 及原始块设备
CAP_SYS_RESOURCE忽略资源限制
CAP_SYS_TIME允许改变系统时钟
CAP_SYS_TTY_CONFIG允许配置 TTY 设备
CAP_SYSLOG允许使用 syslog() 系统调用
CAP_WAKE_ALARM允许触发一些能唤醒系统的东西(比如 CLOCK_BOOTTIME_ALARM 计时器)

capabilities 的赋予和继承

Linux capabilities 分为进程 capabilities 和文件 capabilities。对于进程来说,capabilities 是细分到

线程的,即每个线程可以有自己的capabilities。对于文件来说,capabilities 保存在文件的扩展属

性中。

下面分别介绍线程(进程)的 capabilities 和文件的 capabilities。

线程的 capabilities

每一个线程,具有 5 个 capabilities 集合,每一个集合使用 64 位掩码来表示,显示为 16 进制格式。这 5 个 capabilities 集合分别是:

  • Permitted

  • Effective

  • Inheritable

  • Bounding

  • Ambient

Permitted

定义了线程能够使用的 capabilities 的上限。它并不使用线程的 capabilities,而是作为一个规定。也就是说,线程可以通过系统调用 capset() 来从 EffectiveInheritable 集合中添加或删除 capability,前提是添加或删除的 capability 必须包含在 Permitted 集合中(其中 Bounding 集合也会有影响,具体参考下文)。 如果某个线程想向 Inheritable 集合中添加或删除 capability,首先它的 Effective 集合中得包含 CAP_SETPCAP 这个 capabiliy。

Effective

内核检查线程是否可以进行特权操作时,检查的对象便是 Effective 集合。如之前所说,Permitted 集合定义了上限,线程可以删除 Effective 集合中的某 capability,随后在需要时,再从 Permitted 集合中恢复该 capability,以此达到临时禁用 capability 的功能。

Inheritable

当执行exec() 系统调用时,能够被新的可执行文件继承的 capabilities,被包含在 Inheritable 集合中。这里需要说明一下,包含在该集合中的 capabilities 并不会自动继承给新的可执行文件,即不会添加到新线程的 Effective 集合中,它只会影响新线程的 Permitted 集合。

Bounding

Bounding 集合是 - 集合的超集,如果某个 capability 不在 Bounding 集合中,即使它在 Permitted 集合中,该线程也不能将该 capability 添加到它的 Inheritable 集合中。

Bounding 集合的 capabilities 在执行 fork() 系统调用时会传递给子进程的 Bounding 集合,并且在执行 execve 系统调用后保持不变。

  • 当线程运行时,不能向 Bounding 集合中添加 capabilities。

  • 一旦某个 capability 被从 Bounding 集合中删除,便不能再添加回来。

  • 将某个 capability 从 Bounding 集合中删除后,如果之前 Inherited 集合包含该 capability,将继续保留。但如果后续从 Inheritable 集合中删除了该 capability,便不能再添加回来。

Ambient

Linux 4.3 内核新增了一个 capabilities 集合叫 Ambient ,用来弥补 Inheritable 的不足。Ambient 具有如下特性:

  • PermittedInheritable 未设置的 capabilities,Ambient 也不能设置。

  • PermittedInheritable 关闭某权限(比如 CAP_SYS_BOOT)后,Ambient 也随之关闭对应权限。这样就确保了降低权限后子进程也会降低权限。

  • 非特权用户如果在 Permitted 集合中有一个 capability,那么可以添加到 Ambient 集合中,这样它的子进程便可以在 AmbientPermittedEffective 集合中获取这个 capability。现在不知道为什么也没关系,后面会通过具体的公式来告诉你。

Ambient 的好处显而易见,举个例子,如果你将 CAP_NET_ADMIN 添加到当前进程的 Ambient 集合中,它便可以通过 fork()execve() 调用 shell 脚本来执行网络管理任务,因为 CAP_NET_ADMIN 会自动继承下去。

文件的 capabilities

文件的 capabilities 被保存在文件的扩展属性中。如果想修改这些属性,需要具有 CAP_SETFCAP 的 capability。文件与线程的 capabilities 共同决定了通过 execve() 运行该文件后的线程的 capabilities。

文件的 capabilities 功能,需要文件系统的支持。如果文件系统使用了 nouuid 选项进行挂载,那么文件的 capabilities 将会被忽略。

类似于线程的 capabilities,文件的 capabilities 包含了 3 个集合:

  • Permitted

  • Inheritable

  • Effective

这3个集合的具体含义如下:

Permitted

这个集合中包含的 capabilities,在文件被执行时,会与线程的 Bounding 集合计算交集,然后添加到线程的 Permitted 集合中。

Inheritable

这个集合与线程的 Inheritable 集合的交集,会被添加到执行完 execve() 后的线程的 Permitted 集合中。

Effective

这不是一个集合,仅仅是一个标志位。如果设置开启,那么在执行完 execve() 后,线程 Permitted 集合中的 capabilities 会自动添加到它的 Effective 集合中。对于一些旧的可执行文件,由于其不会调用 capabilities 相关函数设置自身的 Effective 集合,所以可以将可执行文件的 Effective bit 开启,从而可以将 Permitted 集合中的 capabilities 自动添加到 Effective 集合中。

详情请参考 Linux capabilities 的 man pageicon-default.png?t=N176http://man7.org/linux/man-pages/man7/capabilities.7.html

运行 execve() 后 capabilities 的变化

上面介绍了线程和文件的 capabilities,你们可能会觉得有些抽象难懂。下面通过具体的计算公式,来说明执行 execve() 后 capabilities 是如何被确定的。

我们用 P 代表执行 execve() 前线程的 capabilities,P' 代表执行 execve() 后线程的 capabilities,F 代表可执行文件的 capabilities。那么:

P'(ambient)     = (file is privileged) ? 0 : P(ambient)
​
P'(permitted)   = (P(inheritable) & F(inheritable)) |
                          (F(permitted) & P(bounding)) | P'(ambient)
​
P'(effective)   = F(effective) ? P'(permitted) : P'(ambient)
​
P'(inheritable) = P(inheritable)    [i.e., unchanged]
​
P'(bounding)    = P(bounding)       [i.e., unchanged]

我们一条一条来解释:

  • 如果用户是 root 用户,那么执行 execve() 后线程的 Ambient 集合是空集;如果是普通用户,那么执行 execve() 后线程的 Ambient 集合将会继承执行 execve() 前线程的 Ambient 集合。

  • 执行 execve() 前线程的 Inheritable 集合与可执行文件的 Inheritable 集合取交集,会被添加到执行 execve() 后线程的 Permitted 集合;线程执行前 bounding 集合与可执行文件的 Permitted 集合取交集,也会被添加到执行 execve() 后线程的 Permitted 集合;同时执行 execve() 后线程的 Ambient 集合中的 capabilities 会被自动添加到该线程的 Permitted 集合中。

  • 如果可执行文件开启了 Effective 标志位,那么在执行完 execve() 后,线程 Permitted 集合中的 capabilities 会自动添加到它的 Effective 集合中。

  • 执行 execve() 前线程的 Inheritable 集合会继承给执行 execve() 后线程的 Inheritable 集合。

这里有几点需要着重强调:

  1. 上面的公式是针对系统调用 execve() 的,如果是 fork(),那么子线程的 capabilities 信息完全复制父进程的 capabilities 信息。

  2. 可执行文件的 Inheritable 集合与线程的 Inheritable 集合并没有什么关系,可执行文件 Inheritable 集合中的 capabilities 不会被添加到执行 execve() 后线程的 Inheritable 集合中。如果想让新线程的 Inheritable 集合包含某个 capability,只能通过 capset() 将该 capability 添加到当前线程的 Inheritable 集合中(因为 P’(inheritable) = P(inheritable))。

  3. 如果想让当前线程 Inheritable 集合中的 capabilities 传递给新的可执行文件,该文件的 Inheritable 集合中也必须包含这些 capabilities(因为 P’(permitted) = (P(inheritable) & F(inheritable))|…)。

  4. 将当前线程的 capabilities 传递给新的可执行文件时,仅仅只是传递给新线程的 Permitted 集合。如果想让其生效,新线程必须通过 capset() 将 capabilities 添加到 Effective 集合中。或者开启新的可执行文件的 Effective 标志位(因为 P’(effective) = F(effective) ? P’(permitted) : P’(ambient))。

  5. 在没有 Ambient 集合之前,如果某个脚本不能调用 capset(),但想让脚本中的线程都能获得该脚本的 Permitted 集合中的 capabilities,只能将 Permitted 集合中的 capabilities 添加到 Inheritable 集合中(P’(permitted) = P(inheritable) & F(inheritable)|…),同时开启 Effective 标志位(P’(effective) = F(effective) ? P’(permitted) : P’(ambient))。有 Ambient 集合之后,事情就变得简单多了,后续的文章会详细解释。

  6. 如果某个 UID 非零(普通用户)的线程执行了 execve(),那么 PermittedEffective 集合中的 capabilities 都会被清空。

  7. 从 root 用户切换到普通用户,那么 PermittedEffective 集合中的 capabilities 都会被清空,除非设置了 SECBIT_KEEP_CAPS 或者更宽泛的 SECBIT_NO_SETUID_FIXUP。

案例


最后拿 docker 举例,如果你使用普通用户来启动官方的 nginx 容器,会出现以下错误:

bind() to 0.0.0.0:80 failed (13: Permission denied)

因为 nginx 进程的 Effective 集合中不包含 CAP_NET_BIND_SERVICE capability,且不具有 capabilities 感知能力(普通用户),所以启动失败。要想启动成功,至少需要将该 capability 添加到 nginx 文件的 Inheritable 集合中,同时开启 Effective 标志位,并且在 Kubernetes Pod 的部署清单中的 securityContext –> capabilities 字段下面添加 NET_BIND_SERVICE(这个 capability 会被添加到 nginx 进程的 Bounding 集合中),最后还要将 capability 添加到 nginx 文件的 Permitted 集合中。如此一来就大功告成了,参考公式:P’(permitted) = …|(F(permitted) & P(bounding)))|…,P’(effective) = F(effective) ? P’(permitted) : P’(ambient)。

如果容器开启了 securityContext/allowPrivilegeEscalation,上述设置仍然可以生效。如果 nginx 文件具有 capabilities 感知能力,那么只需要将 CAP_NET_BIND_SERVICE capability 添加到它的 Inheritable 集合中就可以正常工作了。

当然了,除了上述使用文件扩展属性的方法外,还可以使用 Ambient 集合来让非 root 容器进程正常工作,但 Kubernetes 目前还不支持这个属性,具体参考 Kubernetes 项目的 issueicon-default.png?t=N176https://github.com/kubernetes/kubernetes/issues/56374

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/343676.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

黑马】后台管理183-

一、添加时间线组件时间线组件在element2.6.0的版本中才可以找到项目中用到的插件早于时间线插件发布的,所以需要用到素材中的,timeline 和timeline-item复制到\code\shop-hou\src\plugins\1,在element.js中导入timeline等组件import Timeline from ./ti…

20230213在AIO-3568J开发板在原厂Android12下跑通ap6275s

20230213在AIO-3568J开发板在原厂Android12下跑通ap6275s 2023/2/13 8:59 一、从AIO-3568的Android11的kernel中抠出来AP6275S的驱动: 1、 Z:\android12-rk3588-new\kernel-4.19\arch\arm64\configs\rockchip_defconfig # CONFIG_WLAN_VENDOR_QUANTENNA is not set …

电路中的过压(OVP)过流(OCP)保护电路

电路中的过压(OVP)过流(OCP)保护电路 我们在学习电路设计的过程中,总会发现电路在过压或者过流时遭到不可逆的损坏, 下面分享几例过压过流保护电路, 希望对朋友们有所帮助, 个人能力有限, 如有不当之处还请多多指教: 例 1:OVP(过压保护) 1).当VCC_IN小于28V时&…

spring(三)-----------什么是beanDefinition?

上篇我们以mybatis如何注入mapper对象为引,发现mybatis使用了FactoryBean(动态代理)动态注册beanDefinition 的方式实现了对多个bean进行注入。 这篇我们延续上篇的问题,什么是beanDefinition?动态注入beanDefinition…

yum安装

仓库安装[rootlocalhost ~]# rpm -ivh https://repo.mysql.com//mysql80-community-release-el9-1.noarch.rpm[roothezhihao ~]# dnf install mysql-server -y本地安装wget https://cdn.mysql.com//Downloads/MySQL-8.0/mysql-8.0.32-1.el9.x86_64.rpm-bundle.tartar xvf mysql…

STK + C# + Cesium联合编程(二):CZML文件生成及加载

概述本文续上一篇博文,上一篇文章中验证了C# .NET Framework (Web Service) STK Cesium前端显示的相关技术,本篇通过STK安装附带的Pro Tutorial实例以及Export CZML插件演示如何创建STK场景,创建对象,计算Access,并通…

【软件测试】8年测试老兵的突破之路,一路升级打怪......

目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 目前几乎所有的大厂…

网络基础-基础网络命令

文章目录路由命令查询添加路由1.添加访问某台主机的静态路由2.添加访问某个网络的静态路由3.添加默认网关:删除设计关键字路由2参考路由 命令查询 通过 route --help 或man route 查询 添加路由 1.添加访问某台主机的静态路由 route add -host [目标主机IP地址…

为什么优秀的人总能拥有开挂的人生

时间不会辜负一个自信之人。坚持不懈的努力,如果好的回报尚未到来,那一定是时间还不够长,努力还不够多。 来自尚学堂毕业学生的感悟 我从未接触过编程,来到北京尚学堂学Java的,学习难度自然要比计算机专业的同学大很多…

OpenHarmony使用Socket实现一个UDP客户端详解

一、前言 我们在这里介绍Socket的使用,是为了后面的一篇文章实现设备配网做铺垫。 二、示例详解 点击获取BearPi-HM_Nano源码 ,以D3_iot_udp_client为例: 示例本身很简单,只需要修改 udp_client_demo.c 的2处代码,就能测试了: //连接WIFI,参数1是:WIFI名称,参数2是:…

【ChatGPT】AI 人工智能将使中国教育优势荡然无存

中国的教育现状 论述1: 上小学的时候,老师天天检查你有没有戴红领巾,不带就要体罚,大人告诉你,等到上中学老师就不管这些杂事了。上中学的时候,学习非常辛苦,周末还要补课,大人们又…

人工智能为PMO提供支持的4种方式

许多企业已经认识到 PMO (项目管理办公室)和 PPM (项目组合管理)在推动增长、提高组织敏捷性和交付更好的业务成果方面的力量。今天的PMO被期望用更少的钱做更多的事,而且做得更快。 虽然PMO的工作很繁重,…

ChIP-seq 分析:数据比对(3)

读取 reads(二者含义相同,下文不做区分)1. ChIPseq reads 比对 在评估读取质量和我们应用的任何读取过滤之后,我们将希望将我们的读取与基因组对齐,以便识别任何基因组位置显示比对读取高于背景的富集。 由于 ChIPseq…

DNS 原理入门指南(三)

六、分级查询的实例 dig命令的trace参数可以显示DNS的整个分级查询过程。 $ dig trace math.stackexchange.com 上面命令的第一段列出根域名.的所有NS记录,即所有根域名服务器。 根据内置的根域名服务器IP地址,DNS服务器向所有这些IP地址发出查询请求&…

LeetCode题目笔记——2563. 统计公平数对的数目

文章目录题目描述题目链接题目难度——中等方法一:排序双指针代码/Python代码/C方法二代码/Python总结题目描述 这是前天周赛的第二题。 统计公平数对的数目 - 给你一个下标从 0 开始、长度为 n 的整数数组 nums ,和两个整数 lower 和 upper &#xff0c…

【Spring Cloud】如何使用Feign实现远程调用

本期目录前言1. 导入依赖坐标2. 开启Feign自动装配3. 声明远程调用4. 替代RestTemplate5. 测试前言 本次示例代码的文件结构如下图所示。 1. 导入依赖坐标 在 order-service 的 pom.xml 文件中导入 Feign 的依赖坐标。 <!-- Feign远程调用客户端 --> <dependency&…

FastAPI(二)路由映射

目录 一、在根目录-新建apps文件夹 二、在apps文件夹下-新建user文件夹和menu文件夹 三、编写API 四、 将子路由导入根路由中 五、改造main.py 六、启动并访问接口文档 一、在根目录-新建apps文件夹 编辑__init__.py文件如下&#xff1a; from fastapi import APIRoute…

动态规划专题——背包问题

&#x1f9d1;‍&#x1f4bb; 文章作者&#xff1a;Iareges &#x1f517; 博客主页&#xff1a;https://blog.csdn.net/raelum ⚠️ 转载请注明出处 目录前言一、01背包1.1 使用滚动数组优化二、完全背包2.1 使用滚动数组优化三、多重背包3.1 使用二进制优化四、分组背包总结…

Spring基础入门(一)之 理论基础概念

文章目录前言Spring 体系结构IOC&DI1.Ioc控制反转2.DI依赖注入3.目标IOC相关之bean1.bean的基础配置2.bean的实例化3.bean的生命周期4.IOC管理第三方beanDI相关之注入注解开发1.介绍2.注解之bean&DI3.注解管理第三方bean4.常见注解的含义AOP1.介绍2.核心概念3.常见注解…

机械革命z2黑苹果双系统改造计划

原来的系统硬盘才256G实在太小了&#xff0c;趁固态便宜搞了一块大华C900Plus-b 1T固态&#xff0c;加上之前电脑里后加的一块海康威视c2000pro 1T准备搞一个winmac双系统生产力工具 黑苹果的详细教程b站上有很多&#xff0c;也可以看下国光师傅的博客&#xff0c;https://app…