
一、Polkit 是什么
Polkit(PolicyKit)是 Linux 系统中负责细粒度权限控制 的框架。它解决的核心问题是:普通用户如何安全地执行需要特权的操作。
传统的方案只有两个极端:
- sudo:全部放权给 root,粒度太粗
- SUID 二进制:每个程序自己实现权限检查,重复造轮子且容易出错
Polkit 站在中间层,提供一个集中式的策略决策引擎,让系统管理员通过声明式规则(rules)精确控制"谁能做什么"。
二、核心架构:三大组件
#mermaid-svg-AVkCrTYQxFcRStz7{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-AVkCrTYQxFcRStz7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-AVkCrTYQxFcRStz7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-AVkCrTYQxFcRStz7 .error-icon{fill:#552222;}#mermaid-svg-AVkCrTYQxFcRStz7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-AVkCrTYQxFcRStz7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-AVkCrTYQxFcRStz7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-AVkCrTYQxFcRStz7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-AVkCrTYQxFcRStz7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-AVkCrTYQxFcRStz7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-AVkCrTYQxFcRStz7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-AVkCrTYQxFcRStz7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-AVkCrTYQxFcRStz7 .marker.cross{stroke:#333333;}#mermaid-svg-AVkCrTYQxFcRStz7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-AVkCrTYQxFcRStz7 p{margin:0;}#mermaid-svg-AVkCrTYQxFcRStz7 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-AVkCrTYQxFcRStz7 .cluster-label text{fill:#333;}#mermaid-svg-AVkCrTYQxFcRStz7 .cluster-label span{color:#333;}#mermaid-svg-AVkCrTYQxFcRStz7 .cluster-label span p{background-color:transparent;}#mermaid-svg-AVkCrTYQxFcRStz7 .label text,#mermaid-svg-AVkCrTYQxFcRStz7 span{fill:#333;color:#333;}#mermaid-svg-AVkCrTYQxFcRStz7 .node rect,#mermaid-svg-AVkCrTYQxFcRStz7 .node circle,#mermaid-svg-AVkCrTYQxFcRStz7 .node ellipse,#mermaid-svg-AVkCrTYQxFcRStz7 .node polygon,#mermaid-svg-AVkCrTYQxFcRStz7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-AVkCrTYQxFcRStz7 .rough-node .label text,#mermaid-svg-AVkCrTYQxFcRStz7 .node .label text,#mermaid-svg-AVkCrTYQxFcRStz7 .image-shape .label,#mermaid-svg-AVkCrTYQxFcRStz7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-AVkCrTYQxFcRStz7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-AVkCrTYQxFcRStz7 .rough-node .label,#mermaid-svg-AVkCrTYQxFcRStz7 .node .label,#mermaid-svg-AVkCrTYQxFcRStz7 .image-shape .label,#mermaid-svg-AVkCrTYQxFcRStz7 .icon-shape .label{text-align:center;}#mermaid-svg-AVkCrTYQxFcRStz7 .node.clickable{cursor:pointer;}#mermaid-svg-AVkCrTYQxFcRStz7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-AVkCrTYQxFcRStz7 .arrowheadPath{fill:#333333;}#mermaid-svg-AVkCrTYQxFcRStz7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-AVkCrTYQxFcRStz7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-AVkCrTYQxFcRStz7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-AVkCrTYQxFcRStz7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-AVkCrTYQxFcRStz7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-AVkCrTYQxFcRStz7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-AVkCrTYQxFcRStz7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-AVkCrTYQxFcRStz7 .cluster text{fill:#333;}#mermaid-svg-AVkCrTYQxFcRStz7 .cluster span{color:#333;}#mermaid-svg-AVkCrTYQxFcRStz7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-AVkCrTYQxFcRStz7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-AVkCrTYQxFcRStz7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-AVkCrTYQxFcRStz7 .icon-shape,#mermaid-svg-AVkCrTYQxFcRStz7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-AVkCrTYQxFcRStz7 .icon-shape p,#mermaid-svg-AVkCrTYQxFcRStz7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-AVkCrTYQxFcRStz7 .icon-shape .label rect,#mermaid-svg-AVkCrTYQxFcRStz7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-AVkCrTYQxFcRStz7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-AVkCrTYQxFcRStz7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-AVkCrTYQxFcRStz7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 特权服务层
D-Bus 系统总线(中介层)
用户空间(非特权)
调用特权操作
pkexec/dbus-send
D-Bus 查询
D-Bus 查询
请求执行
发送方法调用
转发请求
返回授权结果
调用服务方法
加载规则
解析动作
请求权限检查
根据授权结果
执行/拒绝操作
需要认证时
调用认证代理
用户输入密码
认证代理层
polkit-gnome
图形认证代理
polkit-kde-agent-1
KDE 认证代理
lxqt-policykit-agent
LXQt 认证代理
pkttyagent
文本模式认证代理
系统服务(特权守护进程)
systemd
org.freedesktop.systemd1
udisks2
org.freedesktop.udisks2
NetworkManager
org.freedesktop.NetworkManager
systemd-logind
org.freedesktop.login1
accounts-daemon
org.freedesktop.Accounts
ufw
com.ubuntu.UFW
flatpak-system-helper
org.freedesktop.Flatpak
snapd
io.snapcraft.Snapd
gamemoded
com.feralinteractive.GameMode
systemd-timedated
org.freedesktop.timedate1
systemd-localed
org.freedesktop.locale1
systemd-hostnamed
org.freedesktop.hostname1
Policy 文件解析器
/usr/share/polkit-1/actions/
*.policy(动作定义)
JavaScript 规则引擎
/etc/polkit-1/rules.d/
*.rules(管理员自定义)
/usr/share/polkit-1/rules.d/
*.rules(发行版预设)
应用程序
如电源管理/挂载工具
命令行工具
pkaction
枚举策略
pkcheck
探测权限
pkexec
特权执行
dbus-send
D-Bus 客户端
dbus-daemon
消息路由器
polkitd
策略决策引擎(root/polkitd)
2.1 组件一:polkitd(决策引擎)
polkitd 是以 root 权限运行的系统守护进程,它是整个架构的核心。
职责:
- 启动时加载并解析所有
.rules规则文件 - 维护所有已注册的动作(action)数据库
- 通过 D-Bus 接收客户端的授权查询请求
- 根据规则引擎实时计算授权结果
权限模型:
polkitd 进程权限:
- UID: 0 (root) 或专用系统用户
- 补充组: polkitd
- 能读取 /etc/polkit-1/rules.d/ (drwxr-x--- root polkitd)
这就是为什么普通用户无法直接读取规则文件,却能通过 pkaction 查询策略------真正的文件访问发生在 polkitd 内部。
2.2 组件二:Policy 文件(动作定义)
.policy 文件是 XML 格式的动作声明,定义了"系统有哪些特权操作"。
典型路径:
/usr/share/polkit-1/actions/org.freedesktop.login1.policy
核心结构:
xml
<policyconfig>
<action id="org.freedesktop.login1.reboot">
<description>Reboot the system</description>
<message>Authentication is required to reboot the system.</message>
<defaults>
<allow_any>auth_admin</allow_any> <!-- 任何用户:需管理员认证 -->
<allow_inactive>auth_admin</allow_inactive> <!-- 非活跃会话:需管理员认证 -->
<allow_active>yes</allow_active> <!-- 活跃会话用户:直接允许 -->
</defaults>
</action>
</policyconfig>
三个关键字段:
| 字段 | 含义 | 典型值 |
|---|---|---|
allow_any |
无会话上下文时的默认策略 | no / yes / auth_self / auth_admin |
allow_inactive |
非当前活跃会话的策略 | 同上 |
allow_active |
当前活跃图形会话的策略 | 同上 |
策略值解析:
| 值 | 含义 |
|---|---|
no |
明确拒绝 |
yes |
直接允许,无需认证 |
auth_self |
需要用户自己认证(输入自己的密码) |
auth_admin |
需要管理员认证(输入 root 密码或管理员密码) |
2.3 组件三:Rules 文件(动态规则)
.rules 文件是 JavaScript 代码,用于覆盖和扩展 Policy 文件的静态默认值。
路径与优先级:
/etc/polkit-1/rules.d/ ← 管理员自定义(优先级高)
/usr/share/polkit-1/rules.d/ ← 发行版预设(优先级低)
文件名决定执行顺序:
10-vendor.rules ← 先执行
20-admin.rules ← 后执行(可覆盖前者)
99-custom.rules ← 最后执行(优先级最高)
典型规则示例:
javascript
// /etc/polkit-1/rules.d/10-admin.rules
polkit.addRule(function(action, subject) {
// 如果用户属于 wheel 组,直接允许所有动作
if (subject.isInGroup("wheel")) {
return polkit.Result.YES;
}
});
规则引擎 API:
| 对象 | 属性/方法 | 说明 |
|---|---|---|
action.id |
字符串 | 动作标识符,如 org.freedesktop.systemd1.manage-units |
action.lookup() |
方法 | 获取动作的额外参数 |
subject.user |
字符串 | 用户名 |
subject.isInGroup() |
方法 | 检查用户是否属于某组 |
subject.local |
布尔 | 是否为本地登录 |
subject.active |
布尔 | 是否为活跃会话 |
polkit.Result.YES |
常量 | 允许 |
polkit.Result.NO |
常量 | 拒绝 |
polkit.Result.AUTH_SELF |
常量 | 需用户自身认证 |
polkit.Result.AUTH_ADMIN |
常量 | 需管理员认证 |
三、授权决策流程
认证代理 .policy 文件 .rules 规则引擎 polkitd 系统服务(如accounts-daemon) dbus-daemon 用户/应用程序 认证代理 .policy 文件 .rules 规则引擎 polkitd 系统服务(如accounts-daemon) dbus-daemon 用户/应用程序 #mermaid-svg-7SNKt1yNG4f3THRC{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7SNKt1yNG4f3THRC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7SNKt1yNG4f3THRC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7SNKt1yNG4f3THRC .error-icon{fill:#552222;}#mermaid-svg-7SNKt1yNG4f3THRC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7SNKt1yNG4f3THRC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7SNKt1yNG4f3THRC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7SNKt1yNG4f3THRC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7SNKt1yNG4f3THRC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7SNKt1yNG4f3THRC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7SNKt1yNG4f3THRC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7SNKt1yNG4f3THRC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7SNKt1yNG4f3THRC .marker.cross{stroke:#333333;}#mermaid-svg-7SNKt1yNG4f3THRC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7SNKt1yNG4f3THRC p{margin:0;}#mermaid-svg-7SNKt1yNG4f3THRC .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-7SNKt1yNG4f3THRC text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-7SNKt1yNG4f3THRC .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-7SNKt1yNG4f3THRC .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-7SNKt1yNG4f3THRC .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-7SNKt1yNG4f3THRC .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-7SNKt1yNG4f3THRC #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-7SNKt1yNG4f3THRC .sequenceNumber{fill:white;}#mermaid-svg-7SNKt1yNG4f3THRC #sequencenumber{fill:#333;}#mermaid-svg-7SNKt1yNG4f3THRC #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-7SNKt1yNG4f3THRC .messageText{fill:#333;stroke:none;}#mermaid-svg-7SNKt1yNG4f3THRC .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-7SNKt1yNG4f3THRC .labelText,#mermaid-svg-7SNKt1yNG4f3THRC .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-7SNKt1yNG4f3THRC .loopText,#mermaid-svg-7SNKt1yNG4f3THRC .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-7SNKt1yNG4f3THRC .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-7SNKt1yNG4f3THRC .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-7SNKt1yNG4f3THRC .noteText,#mermaid-svg-7SNKt1yNG4f3THRC .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-7SNKt1yNG4f3THRC .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-7SNKt1yNG4f3THRC .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-7SNKt1yNG4f3THRC .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-7SNKt1yNG4f3THRC .actorPopupMenu{position:absolute;}#mermaid-svg-7SNKt1yNG4f3THRC .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-7SNKt1yNG4f3THRC .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-7SNKt1yNG4f3THRC .actor-man circle,#mermaid-svg-7SNKt1yNG4f3THRC line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-7SNKt1yNG4f3THRC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 场景:用户请求创建新账户 alt认证成功认证失败 alt活跃会话 + allow_active: yes需要认证 alt规则返回 YES规则返回 NO规则返回 AUTH_\* 或 Policy 默认值 dbus-send 调用 CreateUser1转发方法调用2请求权限检查CheckAuthorization3转发到 polkitd4加载并执行 .rules 文件5返回规则计算结果6授权通过7允许执行8创建用户账户9返回结果10操作成功11明确拒绝12拒绝执行13返回错误14权限不足15查询默认策略16返回 allow_any/inactive/active17直接允许18执行操作19请求用户认证20弹出密码输入框21输入密码22验证密码23授权通过24允许执行25拒绝26拒绝执行27
当一个程序需要执行特权操作时,完整的决策链如下:
关键设计:规则覆盖机制
Policy 文件提供的是基线默认值 ,而 .rules 文件通过 JavaScript 逻辑可以:
- 完全覆盖 默认策略(返回
YES或NO) - 条件授权(根据时间、用户组、环境变量等)
- 修改认证方式 (从
auth_admin降级为auth_self)
这意味着 pkaction 显示的 implicit 值不一定等于实际生效值 ------最终决策完全取决于 .rules 中的动态逻辑。
四、与 Polkit 交互的外部程序
Polkit 并非孤立存在,现代 Linux 桌面和服务生态中大量关键组件都依赖它进行权限控制:
#mermaid-svg-KJgXrzv4nNoEIOC2{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-KJgXrzv4nNoEIOC2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-KJgXrzv4nNoEIOC2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-KJgXrzv4nNoEIOC2 .error-icon{fill:#552222;}#mermaid-svg-KJgXrzv4nNoEIOC2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KJgXrzv4nNoEIOC2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-KJgXrzv4nNoEIOC2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KJgXrzv4nNoEIOC2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KJgXrzv4nNoEIOC2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-KJgXrzv4nNoEIOC2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KJgXrzv4nNoEIOC2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KJgXrzv4nNoEIOC2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KJgXrzv4nNoEIOC2 .marker.cross{stroke:#333333;}#mermaid-svg-KJgXrzv4nNoEIOC2 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KJgXrzv4nNoEIOC2 p{margin:0;}#mermaid-svg-KJgXrzv4nNoEIOC2 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-KJgXrzv4nNoEIOC2 .cluster-label text{fill:#333;}#mermaid-svg-KJgXrzv4nNoEIOC2 .cluster-label span{color:#333;}#mermaid-svg-KJgXrzv4nNoEIOC2 .cluster-label span p{background-color:transparent;}#mermaid-svg-KJgXrzv4nNoEIOC2 .label text,#mermaid-svg-KJgXrzv4nNoEIOC2 span{fill:#333;color:#333;}#mermaid-svg-KJgXrzv4nNoEIOC2 .node rect,#mermaid-svg-KJgXrzv4nNoEIOC2 .node circle,#mermaid-svg-KJgXrzv4nNoEIOC2 .node ellipse,#mermaid-svg-KJgXrzv4nNoEIOC2 .node polygon,#mermaid-svg-KJgXrzv4nNoEIOC2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-KJgXrzv4nNoEIOC2 .rough-node .label text,#mermaid-svg-KJgXrzv4nNoEIOC2 .node .label text,#mermaid-svg-KJgXrzv4nNoEIOC2 .image-shape .label,#mermaid-svg-KJgXrzv4nNoEIOC2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-KJgXrzv4nNoEIOC2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-KJgXrzv4nNoEIOC2 .rough-node .label,#mermaid-svg-KJgXrzv4nNoEIOC2 .node .label,#mermaid-svg-KJgXrzv4nNoEIOC2 .image-shape .label,#mermaid-svg-KJgXrzv4nNoEIOC2 .icon-shape .label{text-align:center;}#mermaid-svg-KJgXrzv4nNoEIOC2 .node.clickable{cursor:pointer;}#mermaid-svg-KJgXrzv4nNoEIOC2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-KJgXrzv4nNoEIOC2 .arrowheadPath{fill:#333333;}#mermaid-svg-KJgXrzv4nNoEIOC2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-KJgXrzv4nNoEIOC2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-KJgXrzv4nNoEIOC2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KJgXrzv4nNoEIOC2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-KJgXrzv4nNoEIOC2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KJgXrzv4nNoEIOC2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-KJgXrzv4nNoEIOC2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-KJgXrzv4nNoEIOC2 .cluster text{fill:#333;}#mermaid-svg-KJgXrzv4nNoEIOC2 .cluster span{color:#333;}#mermaid-svg-KJgXrzv4nNoEIOC2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-KJgXrzv4nNoEIOC2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-KJgXrzv4nNoEIOC2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-KJgXrzv4nNoEIOC2 .icon-shape,#mermaid-svg-KJgXrzv4nNoEIOC2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KJgXrzv4nNoEIOC2 .icon-shape p,#mermaid-svg-KJgXrzv4nNoEIOC2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-KJgXrzv4nNoEIOC2 .icon-shape .label rect,#mermaid-svg-KJgXrzv4nNoEIOC2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KJgXrzv4nNoEIOC2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-KJgXrzv4nNoEIOC2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-KJgXrzv4nNoEIOC2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} D-Bus 调用
D-Bus 调用
请求权限检查
系统守护进程
systemd
管理服务/单元
udisks2
磁盘管理
NetworkManager
网络管理
systemd-logind
会话/电源管理
accounts-daemon
用户账户管理
systemd-timedated
时间/时区
systemd-hostnamed
主机名
systemd-localed
区域设置
PackageKit
软件包管理
ufw
防火墙
flatpak-system-helper
应用沙箱
snapd
Snap 包管理
gamemoded
游戏模式
CUPS
打印服务
colord
色彩管理
命令行工具
systemctl
org.freedesktop.systemd1
timedatectl
org.freedesktop.timedate1
hostnamectl
org.freedesktop.hostname1
localectl
org.freedesktop.locale1
loginctl
org.freedesktop.login1
systemd-run
org.freedesktop.systemd1
udisksctl
org.freedesktop.udisks2
nmcli
org.freedesktop.NetworkManager
flatpak
org.freedesktop.Flatpak
snap
io.snapcraft.Snapd
pkexec
org.freedesktop.policykit.exec
桌面应用程序
GNOME Settings
org.gnome.settings-daemon.plugins.power
KDE System Settings
org.kde.ksmserver
XFCE Settings
org.xfce.session
GNOME Disks
org.freedesktop.udisks2
GNOME Software
org.freedesktop.packagekit
polkitd
4.1 systemd 生态
| 程序/服务 | Polkit 动作 | 典型场景 |
|---|---|---|
systemctl |
org.freedesktop.systemd1.manage-units |
启动/停止系统服务 |
systemd-run |
org.freedesktop.systemd1.manage-units |
以特权运行临时单元 |
timedatectl |
org.freedesktop.timedate1.set-time |
修改系统时间 |
hostnamectl |
org.freedesktop.hostname1.set-static-hostname |
修改主机名 |
localectl |
org.freedesktop.locale1.set-locale |
修改区域设置 |
loginctl |
org.freedesktop.login1.power-off |
关机/重启/挂起 |
4.2 存储与设备管理
| 程序/服务 | Polkit 动作 | 典型场景 |
|---|---|---|
udisksctl |
org.freedesktop.udisks2.filesystem-mount |
挂载外部存储 |
| GNOME Disks | org.freedesktop.udisks2.block-format |
格式化磁盘 |
pkexec |
org.freedesktop.policykit.exec |
以 root 执行任意命令 |
4.3 网络管理
| 程序/服务 | Polkit 动作 | 典型场景 |
|---|---|---|
nmcli / nmtui |
org.freedesktop.NetworkManager.settings.modify.system |
修改系统网络配置 |
nmcli |
org.freedesktop.NetworkManager.network-control |
启用/禁用网络 |
| NetworkManager | org.freedesktop.NetworkManager.wifi.scan |
WiFi 扫描 |
4.4 包管理与应用沙箱
| 程序/服务 | Polkit 动作 | 典型场景 |
|---|---|---|
flatpak |
org.freedesktop.Flatpak.app-install |
安装 Flatpak 应用 |
snap |
io.snapcraft.Snapd.login |
Snap 包管理 |
| GNOME Software | org.freedesktop.packagekit.system-update |
系统更新 |
4.5 其他系统服务
| 程序/服务 | Polkit 动作 | 典型场景 |
|---|---|---|
accounts-daemon |
org.freedesktop.accounts.user-administration |
创建/修改用户 |
gamemoded |
com.feralinteractive.GameMode.request |
请求游戏模式优化 |
ufw |
com.ubuntu.UFW.admin |
防火墙配置 |
| CUPS | org.opensuse.cupspkhelper.mechanism.all-edit |
打印机管理 |
colord |
org.freedesktop.color-manager.create-device |
色彩配置文件 |
五、客户端工具解析
Polkit 提供了三个核心命令行工具,分别对应不同的使用场景:
5.1 pkaction --- 策略枚举器
作用: 查询系统中所有已注册的动作及其默认策略。
底层实现:
bash
# pkaction 等价于以下 D-Bus 调用
dbus-send --system --print-reply \
--dest=org.freedesktop.PolicyKit1 \
/org/freedesktop/PolicyKit1/Authority \
org.freedesktop.PolicyKit1.Authority.EnumerateActions \
string:'en_US' string:''
为什么普通用户能执行:
pkaction本身没有 SUID 位- 它只是 D-Bus 客户端,通过 system bus 向 polkitd 发送请求
- polkitd(root 进程)读取规则文件后,将结果返回给客户端
信息暴露面:
能看到的:动作ID、描述、默认策略值(allow_any/inactive/active)
看不到的:.rules 文件中的动态覆盖逻辑
5.2 pkcheck --- 权限探测器
作用: 在不实际执行操作的前提下,测试当前用户是否被授权。
典型用法:
bash
# 测试当前用户是否有权重启系统
pkcheck --action-id org.freedesktop.login1.reboot \
--process $$ \
--allow-user-interaction
返回值:
| 退出码 | 含义 |
|---|---|
| 0 | 已授权(直接允许) |
| 1 | 未授权(明确拒绝) |
| 126 | 需要认证(可交互获取) |
| 127 | 错误(动作不存在等) |
实战价值:
- 绕过
.rules文件的隐藏逻辑 - 直接探测"实际生效的权限"而非"声明的权限"
- 批量扫描潜在提权点
5.3 pkexec --- 特权执行器
作用: 以其他用户身份(默认 root)执行命令,类似于 sudo 但集成 Polkit 策略。
工作流程:
bash
pkexec /usr/bin/some-command
pkexec向 polkitd 请求org.freedesktop.policykit.exec动作的授权- polkitd 根据规则判断是否需要认证
- 如需认证,调用认证代理(如
polkit-agent-gnome)弹出密码框 - 认证通过后,
pkexec以目标 UID 执行命令
与 sudo 的区别:
| 特性 | pkexec | sudo |
|---|---|---|
| 策略引擎 | Polkit(动态规则) | /etc/sudoers(静态配置) |
| 认证方式 | 可集成图形界面 | 纯命令行 |
| 时间窗口 | 默认单次认证 | 可配置 ticket 缓存 |
| 粒度 | 按动作(action)控制 | 按命令路径控制 |
六、认证代理机制
当 polkitd 返回 AUTH_SELF 或 AUTH_ADMIN 时,需要用户输入密码。这个交互过程由认证代理(Authentication Agent)完成。
用户 认证代理 polkitd 应用程序/pkexec 用户 认证代理 polkitd 应用程序/pkexec #mermaid-svg-O9hcise3pGodQ4Tp{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-O9hcise3pGodQ4Tp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-O9hcise3pGodQ4Tp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-O9hcise3pGodQ4Tp .error-icon{fill:#552222;}#mermaid-svg-O9hcise3pGodQ4Tp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-O9hcise3pGodQ4Tp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-O9hcise3pGodQ4Tp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-O9hcise3pGodQ4Tp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-O9hcise3pGodQ4Tp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-O9hcise3pGodQ4Tp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-O9hcise3pGodQ4Tp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-O9hcise3pGodQ4Tp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-O9hcise3pGodQ4Tp .marker.cross{stroke:#333333;}#mermaid-svg-O9hcise3pGodQ4Tp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-O9hcise3pGodQ4Tp p{margin:0;}#mermaid-svg-O9hcise3pGodQ4Tp .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-O9hcise3pGodQ4Tp text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-O9hcise3pGodQ4Tp .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-O9hcise3pGodQ4Tp .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-O9hcise3pGodQ4Tp .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-O9hcise3pGodQ4Tp .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-O9hcise3pGodQ4Tp #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-O9hcise3pGodQ4Tp .sequenceNumber{fill:white;}#mermaid-svg-O9hcise3pGodQ4Tp #sequencenumber{fill:#333;}#mermaid-svg-O9hcise3pGodQ4Tp #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-O9hcise3pGodQ4Tp .messageText{fill:#333;stroke:none;}#mermaid-svg-O9hcise3pGodQ4Tp .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-O9hcise3pGodQ4Tp .labelText,#mermaid-svg-O9hcise3pGodQ4Tp .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-O9hcise3pGodQ4Tp .loopText,#mermaid-svg-O9hcise3pGodQ4Tp .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-O9hcise3pGodQ4Tp .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-O9hcise3pGodQ4Tp .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-O9hcise3pGodQ4Tp .noteText,#mermaid-svg-O9hcise3pGodQ4Tp .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-O9hcise3pGodQ4Tp .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-O9hcise3pGodQ4Tp .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-O9hcise3pGodQ4Tp .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-O9hcise3pGodQ4Tp .actorPopupMenu{position:absolute;}#mermaid-svg-O9hcise3pGodQ4Tp .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-O9hcise3pGodQ4Tp .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-O9hcise3pGodQ4Tp .actor-man circle,#mermaid-svg-O9hcise3pGodQ4Tp line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-O9hcise3pGodQ4Tp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} alt图形会话文本会话(SSH/TTY) alt认证成功认证失败 请求授权(CheckAuthorization)1规则引擎计算结果:AUTH_ADMIN2调用认证代理RegisterAuthenticationAgent3弹出 GUI 密码框4输入管理员密码5提交密码验证6启动 pkttyagent7终端提示输入密码8输入密码9提交密码验证10验证密码11返回 YES(授权通过)12返回 NO(拒绝)13
常见认证代理:
| 代理程序 | 适用环境 |
|---|---|
polkit-gnome-authentication-agent-1 |
GNOME/GTK 桌面 |
polkit-kde-authentication-agent-1 |
KDE Plasma |
lxqt-policykit-agent |
LXQt |
xfce-polkit |
XFCE |
pkttyagent |
纯文本/SSH 会话 |
关键安全点:
- 认证代理必须以当前用户身份运行,不能是 root
- 代理通过 D-Bus 注册到 polkitd,证明自己是"合法"的交互界面
- 如果没有可用的认证代理(如纯 SSH 会话),
AUTH_*类型的请求会直接失败
七、安全模型与攻击面
7.1 权限隔离设计
#mermaid-svg-BJVRw7TAlOuK2gt1{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-BJVRw7TAlOuK2gt1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BJVRw7TAlOuK2gt1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BJVRw7TAlOuK2gt1 .error-icon{fill:#552222;}#mermaid-svg-BJVRw7TAlOuK2gt1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BJVRw7TAlOuK2gt1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BJVRw7TAlOuK2gt1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BJVRw7TAlOuK2gt1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BJVRw7TAlOuK2gt1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BJVRw7TAlOuK2gt1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BJVRw7TAlOuK2gt1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BJVRw7TAlOuK2gt1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BJVRw7TAlOuK2gt1 .marker.cross{stroke:#333333;}#mermaid-svg-BJVRw7TAlOuK2gt1 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BJVRw7TAlOuK2gt1 p{margin:0;}#mermaid-svg-BJVRw7TAlOuK2gt1 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-BJVRw7TAlOuK2gt1 .cluster-label text{fill:#333;}#mermaid-svg-BJVRw7TAlOuK2gt1 .cluster-label span{color:#333;}#mermaid-svg-BJVRw7TAlOuK2gt1 .cluster-label span p{background-color:transparent;}#mermaid-svg-BJVRw7TAlOuK2gt1 .label text,#mermaid-svg-BJVRw7TAlOuK2gt1 span{fill:#333;color:#333;}#mermaid-svg-BJVRw7TAlOuK2gt1 .node rect,#mermaid-svg-BJVRw7TAlOuK2gt1 .node circle,#mermaid-svg-BJVRw7TAlOuK2gt1 .node ellipse,#mermaid-svg-BJVRw7TAlOuK2gt1 .node polygon,#mermaid-svg-BJVRw7TAlOuK2gt1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-BJVRw7TAlOuK2gt1 .rough-node .label text,#mermaid-svg-BJVRw7TAlOuK2gt1 .node .label text,#mermaid-svg-BJVRw7TAlOuK2gt1 .image-shape .label,#mermaid-svg-BJVRw7TAlOuK2gt1 .icon-shape .label{text-anchor:middle;}#mermaid-svg-BJVRw7TAlOuK2gt1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-BJVRw7TAlOuK2gt1 .rough-node .label,#mermaid-svg-BJVRw7TAlOuK2gt1 .node .label,#mermaid-svg-BJVRw7TAlOuK2gt1 .image-shape .label,#mermaid-svg-BJVRw7TAlOuK2gt1 .icon-shape .label{text-align:center;}#mermaid-svg-BJVRw7TAlOuK2gt1 .node.clickable{cursor:pointer;}#mermaid-svg-BJVRw7TAlOuK2gt1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-BJVRw7TAlOuK2gt1 .arrowheadPath{fill:#333333;}#mermaid-svg-BJVRw7TAlOuK2gt1 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-BJVRw7TAlOuK2gt1 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-BJVRw7TAlOuK2gt1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BJVRw7TAlOuK2gt1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-BJVRw7TAlOuK2gt1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BJVRw7TAlOuK2gt1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-BJVRw7TAlOuK2gt1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-BJVRw7TAlOuK2gt1 .cluster text{fill:#333;}#mermaid-svg-BJVRw7TAlOuK2gt1 .cluster span{color:#333;}#mermaid-svg-BJVRw7TAlOuK2gt1 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-BJVRw7TAlOuK2gt1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-BJVRw7TAlOuK2gt1 rect.text{fill:none;stroke-width:0;}#mermaid-svg-BJVRw7TAlOuK2gt1 .icon-shape,#mermaid-svg-BJVRw7TAlOuK2gt1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BJVRw7TAlOuK2gt1 .icon-shape p,#mermaid-svg-BJVRw7TAlOuK2gt1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-BJVRw7TAlOuK2gt1 .icon-shape .label rect,#mermaid-svg-BJVRw7TAlOuK2gt1 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BJVRw7TAlOuK2gt1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-BJVRw7TAlOuK2gt1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-BJVRw7TAlOuK2gt1 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} D-Bus 请求
转发到
授权通过时调用
以 root 执行
Helper 二进制层(提权关键)
xfpm-power-backlight-helper
xfce4-pm-helper
xfsm-shutdown-helper
udisksd
packagekitd
...
特权核心层
polkitd (root/polkitd)
├─ 读 /etc/polkit-1/rules.d/
├─ 读 /usr/share/polkit-1/actions/
└─ JavaScript 规则引擎
D-Bus 中介层(受控接口)
dbus-daemon
system bus
普通用户层(不可读规则文件)
应用程序
pkaction / pkcheck / pkexec
(无 SUID,纯 D-Bus 客户端)
系统操作
设计意图:
- 普通用户永远无法直接接触规则文件
- 所有授权决策必须通过 polkitd 的接口
- 即使客户端被篡改,也只能"请求"而不能"绕过"
7.2 已知攻击面
| 攻击类型 | 典型案例 | 原理 |
|---|---|---|
| Helper 二进制提权 | xfpm-power-backlight-helper |
allow_active: yes + 参数注入 |
| pkexec 本地提权 | CVE-2021-4034 | argv[1] 越界写,SUID 滥用 |
| D-Bus 条件竞争 | CVE-2021-3560 | 请求断开时 UID 验证失败,误认 root |
| 规则逻辑绕过 | 自定义 .rules 配置错误 |
过度宽松的 isInGroup("users") |
| D-Bus 欺骗 | 伪造认证代理 | 拦截认证请求(需配合其他漏洞) |
7.3 审计要点
bash
# 1. 枚举所有免认证动作(直接允许)
pkaction --verbose | grep -B5 "implicit active:.*yes"
# 2. 检查带 exec.path 的 helper
pkaction --verbose | grep -A1 "org.freedesktop.policykit.exec.path"
# 3. 验证实际权限(绕过静态策略)
for action in $(pkaction); do
pkcheck --action-id "$action" --process $$ >/dev/null 2>&1
[ $? -eq 0 ] && echo "[ALLOW] $action"
done
# 4. 检查 helper 二进制权限
find /usr/{lib,libexec,sbin} -name "*helper*" -type f -perm /4000 2>/dev/null
八、演进与现状
| 版本 | 重大变化 |
|---|---|
| PolicyKit 0.1 | 初始版本,使用 .policy + .pkla 文件 |
| Polkit 0.106 | 引入 JavaScript 规则引擎,废弃 .pkla |
| Polkit 0.120+ | 修复 CVE-2021-4034,加强 pkexec 参数校验 |
| 现代发行版 | 默认启用,与 systemd 深度集成 |
当前趋势:
- systemd 生态大量依赖 Polkit 进行特权控制(
systemctl的某些操作、定时器管理、日志访问等) - 容器/Flatpak 场景下,Polkit 与 UID 命名空间的交互仍在演进
- 部分发行版(如 Fedora)探索用 Rust 重写 polkitd 以提高内存安全性
九、总结
Polkit 的核心设计哲学是**"策略与机制分离"**:
| 层级 | 职责 | 文件 |
|---|---|---|
| 机制 | 定义"系统能做什么" | .policy XML 文件 |
| 策略 | 决定"谁能做" | .rules JavaScript 文件 |
| 执行 | 落实决策 | polkitd + helper 二进制 |
| 交互 | 用户认证 | 认证代理(GUI) |
理解这个架构的关键在于把握 D-Bus 中介层 的作用------它既是普通用户与特权服务之间的桥梁,也是安全边界的核心控制点。所有权限检查都收敛到 polkitd 这一个受控进程,避免了传统 SUID 程序分散、难以审计的弊端。
对于安全研究者而言,Polkit 的攻击面主要集中在:
- Helper 二进制的参数处理 (
allow_active: yes的动作) - 规则文件的逻辑漏洞(过度授权)
- pkexec 本身的实现缺陷(历史漏洞频发)
掌握 pkaction、pkcheck 和 D-Bus 接口的底层调用方式,是在现代 Linux 系统上进行权限枚举和提权审计的基本功。