From eeb794b54d89a85af8df5077a0ad2f66531f151a Mon Sep 17 00:00:00 2001
From: Claude
Reading qubes-db failed for some reason. This could be due to a broken upgrade, race condition or other bug. Try restarting the VM to see if this error persists.
qubesdb-read /qubes-ip output:
-$qubes_ip
+$(html_escape "$qubes_ip")
Check the systemd unit status of qubes-db.
1. Open a terminal. ($start_menu_instructions_system_first_part Terminal)
@@ -161,6 +161,11 @@ check_qubes_persistent_mounts() {
-- "${should_be_ephemeral_path}" \
| sed 's/.*\[\([^]]*\)\].*/\1/' || true)
for bind_mount_item in "${bind_mount_list[@]}"; do
+ ## Validate: only allow safe path characters (alphanumeric, /, -, _, .).
+ if ! [[ "${bind_mount_item}" =~ ^[a-zA-Z0-9/_.-]+$ ]]; then
+ printf '%s\n' "WARNING: Skipping unexpected findmnt output: '${bind_mount_item}'" >&2
+ continue
+ fi
printf '%s\n' "${bind_mount_item}" >&2
if [ -d "/rw/${bind_mount_item}" ]; then
MSG="\
@@ -333,9 +338,9 @@ This is expected because not running in Template.
Qubes UpdatesProxy Reachability Result: Ok, non-torified update proxy reachable. -curl_status_message:
$curl_status_message-PROXY_META:
${PROXY_META}-curl_output:
$curl_output" +curl_status_message:
$(html_escape "$curl_status_message")+PROXY_META:
$(html_escape "${PROXY_META}")+curl_output:
$(html_escape "$curl_output")" $output_x ${output_opts[@]} --messagex --typex "warning" --message "$MSG" $output_cli ${output_opts[@]} --messagecli --typecli "warning" --message "$MSG" } diff --git a/usr/libexec/systemcheck/check_tor_socks_or_trans_port.bsh b/usr/libexec/systemcheck/check_tor_socks_or_trans_port.bsh index f554f7fa..87cce674 100755 --- a/usr/libexec/systemcheck/check_tor_socks_or_trans_port.bsh +++ b/usr/libexec/systemcheck/check_tor_socks_or_trans_port.bsh @@ -182,12 +182,21 @@ check_tor_socks_or_trans_port() { if [ "$verbose" -ge "2" ]; then local MSG="\
$FUNCNAME $1: check_tor_out_file_content_sanitized:
-
$check_tor_out_file_content_sanitized" +
$(html_escape "$check_tor_out_file_content_sanitized")" $output_x ${output_opts[@]} --messagex --typex "info" --message "$MSG" $output_cli ${output_opts[@]} --messagecli --typecli "info" --message "$MSG" fi - tor_detected_raw="$(printf "%s" "$check_tor_out_file_content_sanitized" | python3 -c "import sys, json; print(json.load(sys.stdin)['IsTor'])")" || { tor_detected_raw="$?" ; true; }; + tor_detected_raw="$(printf "%s" "$check_tor_out_file_content_sanitized" | python3 -c " +import sys, json +try: + data = json.load(sys.stdin) +except (json.JSONDecodeError, ValueError): + print('JSONError', end='') + sys.exit(1) +value = data.get('IsTor', '') +print(value, end='') +")" || { tor_detected_raw="$?" ; true; }; ## example tor_detected_raw: # True ## example tor_detected_raw: @@ -214,7 +223,15 @@ check_tor_socks_or_trans_port() { local json_ip_exit_code ip_raw json_ip_exit_code="0" - ip_raw="$(printf "%s" "$check_tor_out_file_content_sanitized" | python3 -c "import sys, json; print(json.load(sys.stdin)['IP'])")" || { json_ip_exit_code="$?" ; true; }; + ip_raw="$(printf "%s" "$check_tor_out_file_content_sanitized" | python3 -c " +import sys, json +try: + data = json.load(sys.stdin) +except (json.JSONDecodeError, ValueError): + sys.exit(1) +value = data.get('IP', '') +print(value, end='') +")" || { json_ip_exit_code="$?" ; true; }; ## example ip_raw: ## 94.242.204.74 diff --git a/usr/libexec/systemcheck/function_manual_run.bsh b/usr/libexec/systemcheck/function_manual_run.bsh index bd47a0e1..22ef314f 100755 --- a/usr/libexec/systemcheck/function_manual_run.bsh +++ b/usr/libexec/systemcheck/function_manual_run.bsh @@ -14,6 +14,12 @@ function_manual_run() { if [ "$FUNCTION" = "" ]; then return 0 fi + if ! declare -F "$FUNCTION" >/dev/null 2>&1; then + echo "$SCRIPTNAME ERROR: function '$FUNCTION' is not a known bash function. Refusing to execute." >&2 + EXIT_CODE="1" + cleanup + return 0 + fi $FUNCTION cleanup return 0 diff --git a/usr/libexec/systemcheck/log-checker b/usr/libexec/systemcheck/log-checker index 753f836d..3e58a48f 100755 --- a/usr/libexec/systemcheck/log-checker +++ b/usr/libexec/systemcheck/log-checker @@ -24,11 +24,16 @@ source /usr/libexec/helper-scripts/strings.bsh ## Copied from /usr/libexec/systemcheck/preparation.bsh. source_config() { shopt -s nullglob - local i + local i file_perms for i in \ /etc/systemcheck.d/*.conf \ /usr/local/etc/systemcheck.d/*.conf \ ; do + ## Refuse to source world-writable config files. + file_perms="$(stat -c '%a' "$i" 2>/dev/null)" || continue + case "$file_perms" in + *[2367]) echo "WARNING: Skipping world-writable config file: $i" >&2 ; continue ;; + esac bash -n "$i" source "$i" done @@ -66,7 +71,8 @@ check_service_logs() { journal_ignore_patterns_list+=( "virtualbox" ) fi - grep --extended-regexp --ignore-case "$journal_search_pattern_list" -- "$TMPDIR/journalctl_output.txt" \ + timeout --kill-after="5" "60" \ + grep --extended-regexp --ignore-case "$journal_search_pattern_list" -- "$TMPDIR/journalctl_output.txt" \ | tee -- "$TMPDIR/journalctl_matched.txt" >/dev/null safe-rm --force -- "$TMPDIR/journalctl_output.txt" @@ -101,14 +107,16 @@ check_service_logs() { # #printf '%s\n' "$counter: '$journal_ignore_pattern_item'" >/dev/null # done - "${grep_ignore_fixed_items_command[@]}" -- "$TMPDIR/journalctl_matched.txt" \ + timeout --kill-after="5" "60" \ + "${grep_ignore_fixed_items_command[@]}" -- "$TMPDIR/journalctl_matched.txt" \ | tee -- "$TMPDIR/journalctl_fixed_filtered.txt" >/dev/null safe-rm --force -- "$TMPDIR/journalctl_matched.txt" patterns="$(printf '%s|' "${journal_ignore_patterns_list[@]}" | head -c-1)" - grep --invert-match --extended-regexp --ignore-case "$patterns" -- "$TMPDIR/journalctl_fixed_filtered.txt" \ + timeout --kill-after="5" "60" \ + grep --invert-match --extended-regexp --ignore-case "$patterns" -- "$TMPDIR/journalctl_fixed_filtered.txt" \ | tee -- "$TMPDIR/journalctl_match_filtered.txt" >/dev/null ## Creates file: '$TMPDIR/journalctl_match_filtered.txt_br' @@ -130,7 +138,8 @@ check_critical_logs() { ## The space before ' BUG:' is important to avoid matching 'debug:'. critical_pattern='Bad RAM detected|self-detected stall on CPU| BUG:|nouveau .* channel .* killed!' - grep --ignore-case --extended-regexp "$critical_pattern" -- "$TMPDIR/journalctl_match_filtered.txt_br" | \ + timeout --kill-after="5" "60" \ + grep --ignore-case --extended-regexp "$critical_pattern" -- "$TMPDIR/journalctl_match_filtered.txt_br" | \ stcatn safe-rm --force -- "$TMPDIR/journalctl_match_filtered.txt_br" diff --git a/usr/libexec/systemcheck/preparation.bsh b/usr/libexec/systemcheck/preparation.bsh index 95da16e2..e589c9ae 100755 --- a/usr/libexec/systemcheck/preparation.bsh +++ b/usr/libexec/systemcheck/preparation.bsh @@ -12,6 +12,17 @@ systemcheck_autostart_functions+=" msgdispatcher_init " systemcheck_autostart_functions+=" sysmaint_state_detection " systemcheck_autostart_functions+=" cleanup " +## Escape HTML special characters to prevent output injection. +html_escape() { + local str="${1:-}" + str="${str//&/&}" + str="${str//<}" + str="${str//>/>}" + str="${str//\"/"}" + str="${str//\'/'}" + printf '%s' "$str" +} + output_if_verbose() { if [ "$verbose" -ge "1" ]; then "$@" @@ -20,11 +31,16 @@ output_if_verbose() { source_config() { shopt -s nullglob - local i + local i file_perms for i in \ /etc/systemcheck.d/*.conf \ /usr/local/etc/systemcheck.d/*.conf \ ; do + ## Refuse to source world-writable config files. + file_perms="$(stat -c '%a' "$i" 2>/dev/null)" || continue + case "$file_perms" in + *[2367]) echo "WARNING: Skipping world-writable config file: $i" >&2 ; continue ;; + esac bash -n "$i" source "$i" done @@ -334,8 +350,9 @@ preparation() { ## returns: derivative_deb_package_version get_local_derivative_version - ## Prepare temporary directory. - chmod 700 "$TEMP_DIR" + ## mktemp --directory already creates the directory with mode 0700 (via + ## umask), so an explicit chmod is unnecessary. + #chmod 700 "$TEMP_DIR" if [ -f "/usr/share/anon-gw-base-files/gateway" ]; then VM="Whonix-Gateway"