Skip to content

security: harden PAGER execution by switching from shell invocation to execvp#653

Open
Devansh-567 wants to merge 1 commit into
openSUSE:masterfrom
Devansh-567:fix/harden-pager-execution
Open

security: harden PAGER execution by switching from shell invocation to execvp#653
Devansh-567 wants to merge 1 commit into
openSUSE:masterfrom
Devansh-567:fix/harden-pager-execution

Conversation

@Devansh-567

Copy link
Copy Markdown

The Problem

The existing implementation in src/utils/pager.cc evaluates the user-defined PAGER environment variable by constructing a shell command string and invoking it via standard shell execution:

execlp("sh", "sh", "-c", cmdline.str().c_str(), (char *)0);

Invoking an arbitrary command through sh -c introduces serious security risks, specifically command injection vulnerabilities, if the PAGER variable contains malicious shell metacharacters.

Furthermore, the existing codebase lacked robust handling for completely valid, whitespace-containing PAGER environment configurations (e.g., passing flags like PAGER="less -R"). This configuration would break or evaluate incorrectly. Finally, edge cases in string matching resulted in a potential boundary crash on pager.substr() and false-positive hits for user UI hints if an absolute binary path contained the substring less accidentally (e.g., /usr/bin/headless-viewer).


The Solution

This patch systematically modernizes and hardens the application's process execution mechanism:

  • Swapped Shell Invocations for `execvp`: Bypassed the shell interpreter (`sh -c`) entirely. Arguments are now cleanly isolated and treated strictly as data arrays via an explicit vector of string pointers (`argv`).
  • Safe Input Tokenization: Integrated `std::istringstream` parsing to split user runtime variables into clean tokens. This gracefully supports arbitrary user-defined operational flags (like `less -X -R`) without opening arbitrary evaluation holes.
  • Isolated UI Hint Logic: Refactored `show_text_in_pager` and `show_file_in_pager` to parse and extract the primary executable binary name before matching layout hints. This mitigates substring collisions on flags and paths.
  • Resiliency Bug Fixes: Added defensive checks ensuring `pager.size() >= 4` before calling `substr()` to completely avoid out-of-bounds execution termination, and fixed a minor typo in the codebase (`navigaion -> navigation`).
---

How the Problem Was Found

The issue was identified during a static code analysis pass focusing on system safety boundaries and unsafe process invocations within the utility wrappers (src/utils/pager.cc). Reviewing the string construction line:

cmdline << "'" << pager << "' '" << file << "'";

revealed that reliance on string interpolation directly tied to user environment blocks bypassed programmatic sanitization boundaries, exposing downstream system environments to arbitrary variable expansion or argument manipulation.


Change Scope Summary

  1. Impacted Components: `src/utils/pager.cc` (`show_in_pager`, `show_text_in_pager`, `show_file_in_pager`)
  2. Dependencies Added: `vector`
  3. Backward Compatibility: Fully preserved. Standard user behaviors, custom pagers, and localized layout hints function exactly as expected, but under a strict argument array boundary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant