| 32 |
32 |
|
# property anyone cares about and no amount of label-reading proves
|
| 33 |
33 |
|
# it as directly as running one.
|
| 34 |
34 |
|
#
|
|
35 |
+ |
# A third check answers a different standing question, and is separate because
|
|
36 |
+ |
# it needs no root and reports rather than passes or fails:
|
|
37 |
+ |
#
|
|
38 |
+ |
# policy what polkit's *implicit* defaults actually are on this machine,
|
|
39 |
+ |
# for every action the console depends on.
|
|
40 |
+ |
#
|
|
41 |
+ |
# Wiki `alloy-privilege` records that table, and every reading in it was taken
|
|
42 |
+ |
# on fw13, which is Pop!_OS. The note says so and asks for it to be re-read on
|
|
43 |
+ |
# a booted Alloy image, because the whole privilege ladder is built on those
|
|
44 |
+ |
# values: tier 1 grants five actions precisely because their upstream default
|
|
45 |
+ |
# is `auth_admin_keep`, and a Fedora override or an upstream change would make
|
|
46 |
+ |
# a shipped rules file either redundant or, worse, the only thing standing
|
|
47 |
+ |
# between a user and a prompt nobody can explain. `--policy` is that re-read,
|
|
48 |
+ |
# reduced to one command someone can run on fw12 and paste back.
|
|
49 |
+ |
#
|
| 35 |
50 |
|
# Usage:
|
| 36 |
51 |
|
# sudo build/check-installed.sh # check this machine
|
|
52 |
+ |
# build/check-installed.sh --policy # read the polkit defaults back
|
| 37 |
53 |
|
# build/check-installed.sh --self-test # check the filter; touches nothing
|
| 38 |
54 |
|
#
|
| 39 |
55 |
|
# Or against a VM from the harness in build/vmtest:
|
| 45 |
61 |
|
#
|
| 46 |
62 |
|
# Exit codes follow check-rust-stage.sh:
|
| 47 |
63 |
|
#
|
| 48 |
|
- |
# 0 the machine is labelled correctly and DynamicUser works.
|
| 49 |
|
- |
# 1 it is not. Every offending line is printed, with the repair.
|
|
64 |
+ |
# 0 the machine is labelled correctly and DynamicUser works. Under
|
|
65 |
+ |
# `--policy`, every action reads the way wiki `alloy-privilege` says.
|
|
66 |
+ |
# 1 it is not. Every offending line is printed, with the repair. Under
|
|
67 |
+ |
# `--policy`, at least one action has drifted or is not defined here.
|
| 50 |
68 |
|
# 3 something about the run, not about the machine: not root, no
|
| 51 |
69 |
|
# restorecon, or SELinux is not enforcing here. Prints `error:`.
|
| 52 |
70 |
|
#
|
| 127 |
145 |
|
printf 'self-test: the filter is right about all three shapes\n'
|
| 128 |
146 |
|
}
|
| 129 |
147 |
|
|
| 130 |
|
- |
if [ "${1:-}" = "--self-test" ]; then
|
| 131 |
|
- |
self_test
|
| 132 |
|
- |
exit 0
|
| 133 |
|
- |
fi
|
| 134 |
|
- |
[ $# -eq 0 ] || die "unknown argument: $1"
|
|
148 |
+ |
# The policy table from wiki `alloy-privilege`, as `<action> <implicit active>`.
|
|
149 |
+ |
#
|
|
150 |
+ |
# Only the implicit defaults are read, not the effective answer. The effective
|
|
151 |
+ |
# answer on an Alloy machine includes
|
|
152 |
+ |
# `usr/share/polkit-1/rules.d/50-alloy-settings.rules`, which is asserted
|
|
153 |
+ |
# separately by `crates/alloy/tests/polkit_rules.rs` and by a Containerfile
|
|
154 |
+ |
# block. What is unasserted anywhere, and what this reads, is the vendor
|
|
155 |
+ |
# default underneath: the five granted actions are granted *because* their
|
|
156 |
+ |
# default is `auth_admin_keep`, and a default that quietly became `yes` would
|
|
157 |
+ |
# make the rules file a security artifact shipped for no reason, while one that
|
|
158 |
+ |
# became `auth_admin` would mean the burst-caching the settings tab counts on
|
|
159 |
+ |
# is gone.
|
|
160 |
+ |
#
|
|
161 |
+ |
# rpm-ostree and systemd1.manage-units are in the list without being granted
|
|
162 |
+ |
# anything: the first is what `alloy update` and `alloy pkg` go through and the
|
|
163 |
+ |
# prompt there is deliberate, and the second is what `run0` asks for, which is
|
|
164 |
+ |
# the command Alloy teaches instead of sudo.
|
|
165 |
+ |
POLICY_TABLE='
|
|
166 |
+ |
org.freedesktop.NetworkManager.network-control yes
|
|
167 |
+ |
org.freedesktop.NetworkManager.enable-disable-wifi yes
|
|
168 |
+ |
org.freedesktop.NetworkManager.enable-disable-network yes
|
|
169 |
+ |
org.freedesktop.NetworkManager.settings.modify.system auth_admin_keep
|
|
170 |
+ |
org.freedesktop.timedate1.set-timezone auth_admin_keep
|
|
171 |
+ |
org.freedesktop.timedate1.set-ntp auth_admin_keep
|
|
172 |
+ |
org.freedesktop.timedate1.set-time auth_admin_keep
|
|
173 |
+ |
org.freedesktop.hostname1.set-static-hostname auth_admin_keep
|
|
174 |
+ |
org.freedesktop.hostname1.set-machine-info auth_admin_keep
|
|
175 |
+ |
org.freedesktop.locale1.set-locale auth_admin_keep
|
|
176 |
+ |
org.freedesktop.locale1.set-keyboard auth_admin_keep
|
|
177 |
+ |
org.projectatomic.rpmostree1.upgrade auth_admin_keep
|
|
178 |
+ |
org.projectatomic.rpmostree1.rollback auth_admin_keep
|
|
179 |
+ |
org.projectatomic.rpmostree1.install-uninstall-packages auth_admin_keep
|
|
180 |
+ |
org.projectatomic.rpmostree1.client-management yes
|
|
181 |
+ |
org.freedesktop.systemd1.manage-units auth_admin_keep
|
|
182 |
+ |
'
|
|
183 |
+ |
|
|
184 |
+ |
# What polkit says the default is for one action, or `undefined` when this
|
|
185 |
+ |
# machine does not define it at all.
|
|
186 |
+ |
#
|
|
187 |
+ |
# An action nobody defines is the quiet failure worth catching: a grant naming
|
|
188 |
+ |
# a renamed action is inert and says nothing, and the symptom is a password
|
|
189 |
+ |
# prompt on a machine that was supposed to have none.
|
|
190 |
+ |
implicit_active() {
|
|
191 |
+ |
local out
|
|
192 |
+ |
out="$(pkaction --action-id "$1" --verbose 2>/dev/null)" || true
|
|
193 |
+ |
[ -n "$out" ] || { printf 'undefined\n'; return; }
|
|
194 |
+ |
printf '%s\n' "$out" | awk -F': *' '/implicit active:/ { print $2; found = 1 }
|
|
195 |
+ |
END { if (!found) print "unreadable" }'
|
|
196 |
+ |
}
|
|
197 |
+ |
|
|
198 |
+ |
read_policy() {
|
|
199 |
+ |
command -v pkaction >/dev/null 2>&1 || die "no pkaction: install polkit"
|
|
200 |
+ |
|
|
201 |
+ |
local drift=0 absent=0 action expected actual mark
|
|
202 |
+ |
while read -r action expected; do
|
|
203 |
+ |
[ -n "$action" ] || continue
|
|
204 |
+ |
actual="$(implicit_active "$action")"
|
|
205 |
+ |
if [ "$actual" = "$expected" ]; then
|
|
206 |
+ |
mark='ok '
|
|
207 |
+ |
elif [ "$actual" = undefined ]; then
|
|
208 |
+ |
mark='ABSENT '
|
|
209 |
+ |
absent=$((absent + 1))
|
|
210 |
+ |
else
|
|
211 |
+ |
mark='DRIFT '
|
|
212 |
+ |
drift=$((drift + 1))
|
|
213 |
+ |
fi
|
|
214 |
+ |
printf '%s %-56s %s\n' "$mark" "$action" "$actual"
|
|
215 |
+ |
done <<< "$POLICY_TABLE"
|
|
216 |
+ |
|
|
217 |
+ |
# Reported apart because they mean different things. DRIFT is the reading
|
|
218 |
+ |
# this exists to catch: the default moved and the ladder is built on the old
|
|
219 |
+ |
# one. ABSENT is usually the host, not the policy — run this on a machine
|
|
220 |
+ |
# without rpm-ostree, as fw13 is, and the four rpm-ostree rows cannot be
|
|
221 |
+ |
# answered by anything. On a booted Alloy image both are findings.
|
|
222 |
+ |
if [ "$((drift + absent))" -ne 0 ]; then
|
|
223 |
+ |
[ "$drift" -eq 0 ] || printf '\n%s action(s) read differently than wiki `alloy-privilege` records.\n' "$drift"
|
|
224 |
+ |
[ "$absent" -eq 0 ] || printf '\n%s action(s) are not defined on this machine.\n' "$absent"
|
|
225 |
+ |
printf 'That table decides which actions tier 1 grants, so correct the note before the rules file.\n'
|
|
226 |
+ |
return 1
|
|
227 |
+ |
fi
|
|
228 |
+ |
printf '\nEvery action reads the way wiki `alloy-privilege` records it.\n'
|
|
229 |
+ |
}
|
|
230 |
+ |
|
|
231 |
+ |
case "${1:-}" in
|
|
232 |
+ |
--self-test) self_test; exit 0 ;;
|
|
233 |
+ |
# Spelled as a conditional rather than `read_policy; exit $?`, so a drift
|
|
234 |
+ |
# verdict returns through the `if` instead of tripping the ERR trap.
|
|
235 |
+ |
--policy) if read_policy; then exit 0; else exit 1; fi ;;
|
|
236 |
+ |
'') ;;
|
|
237 |
+ |
*) die "unknown argument: $1" ;;
|
|
238 |
+ |
esac
|
| 135 |
239 |
|
|
| 136 |
240 |
|
[ "$(id -u)" -eq 0 ] || die "run as root: restorecon cannot stat everything under /etc otherwise, and a partial read would pass"
|
| 137 |
241 |
|
command -v restorecon >/dev/null 2>&1 || die "no restorecon: install policycoreutils"
|