Skip to content

Memory budget desync after subshell/command-substitution state restoration #993

@chaliy

Description

@chaliy

Summary

When executing subshells (...), command substitutions $(...), or scripts via path, the interpreter saves and restores variables, arrays, assoc_arrays, functions, etc. However, memory_budget is never saved or restored. After a subshell runs, the variables/arrays/functions are restored to the parent's snapshot, but memory_budget retains the child's accounting. This creates two exploitable desync scenarios.

Severity: Medium
Category: TM-ISO (Isolation) / TM-DOS (Resource Exhaustion) — new sub-category: memory budget isolation

Affected Files

  • crates/bashkit/src/interpreter/mod.rs lines 1366-1422 (subshell)
  • crates/bashkit/src/interpreter/mod.rs lines 5956-5998 (command substitution)
  • crates/bashkit/src/interpreter/mod.rs lines 3976-4027 (script execution)

Steps to Reproduce

Budget inflation (DoS):

# After enough iterations, variable creation silently fails
for i in $(seq 1 1000); do
  $(echo x$i=val 2>/dev/null)
done
# memory_budget.variable_count inflated by ~1000
# even though command substitution state was restored
newvar="test"  # may silently fail due to inflated budget
echo $newvar   # prints empty

Budget undercount (limit bypass):

# Create 9999 variables (near limit of 10000)
for i in $(seq 1 9999); do eval "v$i=$i"; done
# Execute a script by path (clears and restores state)
echo 'echo ok' > /tmp/test.sh && chmod +x /tmp/test.sh
/tmp/test.sh
# memory_budget counters decremented during script execution
# but variables were restored — budget now undercounts
for i in $(seq 10000 20000); do eval "v$i=$i"; done  # bypasses limit

Impact

  • Limit bypass: Memory limits can be circumvented, allowing unbounded variable/array/function creation → OOM
  • False denial: Budget inflation prevents legitimate variable creation

Acceptance Criteria

  • Save and restore memory_budget alongside other state in subshell, command substitution, and script execution paths
  • Or: recompute budget from actual state after restoration
  • Test: Budget is accurate after 1000 command substitutions
  • Test: Memory limit still enforced after script-by-path execution

Metadata

Metadata

Assignees

No one assigned

    Labels

    securitySecurity vulnerability or hardening

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions