From 5bc41b2585d664e5a37708055d9a2621f44c5ac4 Mon Sep 17 00:00:00 2001 From: Afonso Oliveira Date: Mon, 7 Sep 2026 17:31:54 +0100 Subject: [PATCH] Resolve security libraries beside canonical entrypoints --- bin/omarchy-refresh-pacman | 3 +- bin/omarchy-security-functions | 2 +- bin/omarchy-update | 3 +- bin/omarchy-update-stay-awake | 3 +- default/omarchy/sudo-no-update/sudo | 3 +- .../security-entrypoint-symlink-test.sh | 34 +++++++++++++++++++ 6 files changed, 43 insertions(+), 5 deletions(-) create mode 100755 test/shell.d/security-entrypoint-symlink-test.sh diff --git a/bin/omarchy-refresh-pacman b/bin/omarchy-refresh-pacman index de6ca405..d70ffd9c 100755 --- a/bin/omarchy-refresh-pacman +++ b/bin/omarchy-refresh-pacman @@ -8,7 +8,8 @@ if [[ $- != *p* ]]; then exit 126 fi -source "${BASH_SOURCE[0]%/*}/omarchy-security-functions" || exit 126 +security_entrypoint=$(/usr/bin/readlink -e -- "${BASH_SOURCE[0]}") || exit 126 +source "${security_entrypoint%/*}/omarchy-security-functions" || exit 126 omarchy_security_require_privileged_bash_startup || exit 126 set -e omarchy_security_sanitize_bash_environment "$0" "$@" diff --git a/bin/omarchy-security-functions b/bin/omarchy-security-functions index 703fd630..5826c825 100644 --- a/bin/omarchy-security-functions +++ b/bin/omarchy-security-functions @@ -50,7 +50,7 @@ omarchy_security_require_source_root() { # A runtime root selects the code used by this invocation. Accept the # canonical checkout containing the entrypoint or the package's bin links. - if [[ $OMARCHY_PATH != /* || $(/usr/bin/realpath -e -- "$OMARCHY_PATH") != "$OMARCHY_PATH" ]] || + if [[ ${OMARCHY_PATH:-} != /* || $(/usr/bin/realpath -e -- "$OMARCHY_PATH") != "$OMARCHY_PATH" ]] || ! { [[ $command_source == "$OMARCHY_PATH/bin/$command_name" ]] || [[ $OMARCHY_PATH == "/usr/share/omarchy" && $command_source == "/usr/bin/$command_name" ]]; }; then echo "OMARCHY_PATH does not match this Omarchy command." >&2 diff --git a/bin/omarchy-update b/bin/omarchy-update index 2026e5e9..3873a6bc 100755 --- a/bin/omarchy-update +++ b/bin/omarchy-update @@ -10,7 +10,8 @@ if [[ $- != *p* ]]; then exit 126 fi -source "${BASH_SOURCE[0]%/*}/omarchy-security-functions" || exit 126 +security_entrypoint=$(/usr/bin/readlink -e -- "${BASH_SOURCE[0]}") || exit 126 +source "${security_entrypoint%/*}/omarchy-security-functions" || exit 126 omarchy_security_require_privileged_bash_startup || exit 126 set -e omarchy_security_sanitize_bash_environment "$0" "$@" diff --git a/bin/omarchy-update-stay-awake b/bin/omarchy-update-stay-awake index 4cb0af52..af941c4a 100755 --- a/bin/omarchy-update-stay-awake +++ b/bin/omarchy-update-stay-awake @@ -9,7 +9,8 @@ if [[ $- != *p* ]]; then exit 126 fi -source "${BASH_SOURCE[0]%/*}/omarchy-security-functions" || exit 126 +security_entrypoint=$(/usr/bin/readlink -e -- "${BASH_SOURCE[0]}") || exit 126 +source "${security_entrypoint%/*}/omarchy-security-functions" || exit 126 omarchy_security_require_privileged_bash_startup || exit 126 set -e omarchy_security_sanitize_bash_environment "$0" "$@" diff --git a/default/omarchy/sudo-no-update/sudo b/default/omarchy/sudo-no-update/sudo index de69347b..7019a4dc 100755 --- a/default/omarchy/sudo-no-update/sudo +++ b/default/omarchy/sudo-no-update/sudo @@ -6,7 +6,8 @@ if [[ $- != *p* ]]; then echo "Refusing an unsafe Bash startup for the sudo boundary." >&2 exit 126 fi -source "${BASH_SOURCE[0]%/*}/../../../bin/omarchy-security-functions" || exit 126 +security_entrypoint=$(/usr/bin/readlink -e -- "${BASH_SOURCE[0]}") || exit 126 +source "${security_entrypoint%/*}/../../../bin/omarchy-security-functions" || exit 126 omarchy_security_require_privileged_bash_startup || exit 126 if (( $# == 1 )); then diff --git a/test/shell.d/security-entrypoint-symlink-test.sh b/test/shell.d/security-entrypoint-symlink-test.sh new file mode 100755 index 00000000..678a6742 --- /dev/null +++ b/test/shell.d/security-entrypoint-symlink-test.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +set -euo pipefail + +source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh" +source "$SHELL_TEST_DIR/fixtures/sudo-boundary-test.sh" +export OMARCHY_UPDATE_LOGGED=1 + +# The real fixed entrypoints run only fixture operations. The sibling library +# is a harmless sentinel: invoking a command through another directory must +# source the library beside the resolved command instead of this file. +mkdir "$boundary_tmp/links" +printf '%s\n' 'touch "$SUDO_TEST_HOME/wrong-library"' >"$boundary_tmp/links/omarchy-security-functions" +for command in omarchy-update omarchy-refresh-pacman omarchy-update-stay-awake; do + rm -f "$SUDO_TEST_ROOT/bin/$command" + copy_boundary_file "bin/$command" + ln -s "$SUDO_TEST_ROOT/bin/$command" "$boundary_tmp/links/$command" + reset_boundary + args=(unexpected) + [[ $command != "omarchy-update" ]] || args=(-y) + status=0 + "$boundary_tmp/links/$command" "${args[@]}" >"$boundary_tmp/output" 2>&1 || status=$? + [[ ! -e $SUDO_TEST_HOME/wrong-library ]] || fail "$command sourced a library beside its symlink" + (( status != 126 )) || fail "$command failed to locate its actual library" "$(<"$boundary_tmp/output")" + [[ -s $SUDO_TEST_LOG ]] || fail "$command did not reach the protected fixture boundary" + assert_boundary_cold "$command symlink" + pass "$command resolves its own library when invoked through a symlink" +done + +ln -s "$SUDO_TEST_ROOT/default/omarchy/sudo-no-update/sudo" "$boundary_tmp/links/sudo" +reset_boundary +"$boundary_tmp/links/sudo" -k || fail "symlinked sudo wrapper lost its source library" +[[ $(<"$SUDO_TEST_LOG") == "sudo -k" ]] || fail "symlinked wrapper did not reach the fixed sudo stand-in" +pass "the sudo wrapper resolves its source library independently of its invocation link"