#!/bin/bash # Запуск только в одноразовом Docker-контейнере от root, без host state/socket. set -eu test "$(id -u)" = 0 test ! -e /srv/preland-admin test ! -e /usr/bin/docker base=/srv/preland-admin install -d -m 700 "$base" "$base/secrets" "$base/deploy" /tmp/catalog-victim install -d -m 700 -o 997 -g 987 "$base/state" printf 'unchanged\n' > /tmp/catalog-victim/original printf 'not executed\n' > "$base/deploy/export-catalog.php" cat > /usr/bin/docker <<'SH' #!/bin/sh printf '%s\n' '{"host":"zoomzilla.ru","generated_at":"2026-10-25T00:00:00Z","groups":{"degr":[],"tp":[],"cons":[]}}' SH chmod 755 /usr/bin/docker # Унаследованный cwd моделирует доступ к корню bind mount внутри приложения, # минуя закрытый host-parent /srv/preland-admin. (cd "$base/state" && setpriv --reuid=997 --regid=987 --clear-groups ln -s /tmp/catalog-victim catalog.json) sed 's/\r$//' /work/admin/deploy/refresh-catalog.sh > /tmp/catalog-refresh.sh bash /tmp/catalog-refresh.sh test ! -L "$base/state/catalog.json" test -f "$base/state/catalog.json" test "$(stat -c %u /tmp/catalog-victim/original)" = 0 test "$(cat /tmp/catalog-victim/original)" = unchanged test "$(find /tmp/catalog-victim -type f | wc -l)" = 1 test "$(stat -c '%u:%g:%a' "$base/state/catalog.json")" = 997:987:600 if setpriv --reuid=997 --regid=987 --clear-groups ls "$base/secrets" >/dev/null 2>&1; then echo 'FAIL: app UID can inspect root preparation directory' >&2 exit 1 fi echo 'PASS root catalog publisher replaces destination symlink without following it; victim and owner intact; preparation inaccessible to app UID'