R/7A6

Shell execution controls mediate operations one at a time, and none surveyed mediates their aggregate effect

Mechanisms for constraining what a shell may run have been built continuously since multi-user Unix, and they bind to a wide range of objects: a command name, a filesystem path, a user identity, a label carried on an inode, a syscall number, a capability, a measured quantity of a resource. Several bind to operations rather than to names, and the mandatory access control systems do so by design. What none of them binds to is the effect those operations produce together. The projects record this themselves: AppArmor documents that a rename restriction is defeated by copying, SELinux that deleting one file and deleting every file are the same permission checked more times, and sudo that it cannot restrict reading or writing sensitive files from within a shell it has authorised. A permitted sequence of permitted operations produces an unpermitted result, and nothing in these models represents the result.

part one

Scope

This artifact catalogues mechanisms that constrain shell command execution, from the restricted shells of the late 1970s to the permission systems shipping in agent harnesses, and records for each what object the control binds to. It compiles manual pages, project documentation, published papers, vulnerability records, and two public catalogues read directly. It contributes no new experiment.

Selection is deliberately diverse, and thematic rather than exhaustive. A mechanism is included where it is deployed at scale, where its own documentation states what it does or does not guarantee, or where it occupies a position no other mechanism does.

Each finding carries its sourcing: (from documentation) for a manual page or project documentation read directly, (published) for a dated paper, advisory, or archived message, and (measured) for a quantity counted from a source repository. Manual pages were read on Debian 12.10 with bash 5.2.15, sudo 1.9.13p3, and Linux man-pages 6.03. Web sources were retrieved 2026-08-15.

part two

What the mechanisms bind to

The bound object varies more than the lineage suggests, and it does not reduce to a division between names and operations. Seven distinct objects appear across the corpus.

Command name and shell grammar. The System III restricted shell of 1980 forbade cd, setting PATH, command names containing /, and the redirection operators, and was implemented as a link to sh2. rbash carries the same list. git-shell permits three server-side commands by name1. Agent command-prefix allowlists sit here as wellR/9B1. What these regulate is what the parser will accept, which is neither a path nor an operation.

Filesystem path. chroot binds one step of pathname resolution4. AppArmor file rules bind glob patterns over paths10. sudoers matches a fully qualified command path, with arguments matched as one concatenated string3.

Identity. sudo matches user, host, and target account3. OpenSSH command= and ForceCommand bind a key or a login to a single program, and pass the client’s original request through in SSH_ORIGINAL_COMMAND for that program to filter.

A label carried on the object. SELinux type enforcement matches a tuple of source type, target type, class, and permission12. The label lives in an extended attribute, so renaming a file does not change its access rules.

File content or provenance. The sudoers Digest_Spec matches a SHA-2 hash of the binary rather than its name3. AppLocker offers publisher and hash rules alongside path rules. Provenance binding is not sufficient on its own: of the Microsoft-signed binaries catalogued by LOLBAS, 35 carry a command documented as an application-allowlist bypass19 (measured), so publisher rules admit them by construction while the effect remains attacker-chosen.

A class of privileged operation. POSIX capabilities, FreeBSD jail allow.* toggles5, Solaris zone privileges6, seccomp filters7, OpenBSD pledge promises, Capsicum rights14, and Landlock access rights15 all name operations directly.

A measured resource. Control groups bind to consumption rather than to any request, which makes them the one mechanism in the corpus with no name to spoof and no path to move.

Two mechanisms fit none of these. PowerShell Constrained Language Mode binds to an allowlist of .NET type names and language constructs, an axis with no Unix analogue. Firecracker binds to a hardware-enforced address-space partition, the only boundary here not enforced by kernel software deciding about a request.

table 1
Bound object by mechanism, as documented by each project. Mechanisms binding several objects at once are listed against each.
Bound objectMechanisms
Command name, shell grammarrsh, rbash, git-shell, lshell, agent prefix allowlists
Filesystem pathchroot, unveil, AppArmor file rules, sudoers command paths
Identitysudo, SSH command= and ForceCommand, user namespaces
Label on the objectSELinux type enforcement
File content or provenancesudoers Digest_Spec, AppLocker hash and publisher rules
Class of privileged operationPOSIX capabilities, jail allow.*, zone privileges, seccomp, pledge, Capsicum, Landlock
Measured resourcecontrol groups
part three

The permission vocabulary is operations

The mandatory access control systems do not gate names in place of operations. The Linux Security Modules paper states the abstraction directly: the interface exists to answer whether a subject may perform a kernel operation on an internal kernel object9. The same paper rejects the system call layer as unsound for the purpose, recording that mediating it “is not race-free, may require code duplication, and may not adequately express the full context needed to make security policy decisions” (published).

SELinux permissions are the verbs of the kernel interface, read, write, execute, unlink, link, rename, getattr, setattr, checked against a labelled object12. Capsicum removes the global name as an access path altogether: a process in capability mode is denied access to global namespaces, authority is an unforgeable descriptor carrying a mask of roughly sixty rights, and openat on a relative name inside a permitted directory succeeds where an absolute path fails14 (published).

The claim that these mechanisms bind to names rather than to what an operation does is therefore false as stated. They bind to a pair, an operation and an object, and only the object half is named or labelled.

What the projects document about themselves

The gap the corpus does record is different, and it is recorded by the projects rather than inferred from them. AppArmor’s own account of why it has no separate rename permission is the clearest statement of it11 (from documentation):

As long as reading the source and writing to the destination are allowed, rename restrictions can be worked around simply by copying the files’ contents to the destination.

The SELinux Notebook states the same property for deletion: an application permitted to delete its data files can delete all of them, and a compromised process holding those privileges can do the same12. rm file and rm -rf / decompose into one permission checked a different number of times. The model holds no aggregate.

The same gap is named in a different lineage. JEP 411, deprecating the Java security manager, records that permissions “allow application or library code to perform a series of safe operations whose overall effect is sufficiently unsafe that it would require a more powerful permission if granted directly”17 (published).

sudoers states its own boundary between tools and data (from documentation):

Once sudo executes a program, that program is free to do whatever it pleases, including run other programs.

and, of its interception facility, that “it is not possible to intercept shell built-in commands or restrict the ability to read or write sensitive files from within a shell”3. The manual also records that argument wildcards match across word boundaries, so a rule permitting cat /var/log/messages* also permits cat /var/log/messages /etc/shadow, and that subtracting commands from ALL with ! should be “considered advisory at best.”

bash records that its restricted mode is turned off in the shell spawned to execute a shell script1. chroot(2) records that it “is not intended to be used for any kind of security purpose, neither to fully sandbox a process nor to restrict filesystem system calls”4. seccomp_unotify(2) records that the user-space notification mechanism “can not be used to implement a security policy”7.

part four

Findings

No mechanism surveyed binds to the aggregate effect of an operation. Every mechanism decides a single request against a single object. AppArmor, SELinux, and the Java security manager each document the consequence in their own words, which places the finding in the projects’ records rather than in this survey’s interpretation. The one lineage that bound to propagating labels rather than to individual checks, decentralized information flow control, reached publication and not deployment21.

The permission vocabulary of the strongest mechanisms is already operations. This refutes the narrower reading, that these systems fail because they gate names. They gate operations against named or labelled objects, and the residue is that a sequence of individually permitted operations is not itself an object any of them can see.

Every mechanism that escapes name-binding is self-imposed. seccomp, pledge, Capsicum, and Landlock are all a program voluntarily and irreversibly confining itself, with the restriction inherited by its children7,14,15. None can be pointed by an operator at a program the operator does not control. The capability lineage exists because authority carried by a caller-supplied name rather than by an unforgeable reference produces the confused deputy, a failure named in 198820. The mechanisms an administrator can aim at an untrusted binary, sudo, SELinux, AppArmor, and Just Enough Administration, are the ones that bind to names, paths, identities, and labels. That correlation holds across the whole corpus.

Argument-level control exists, and only outside the Unix lineage. Just Enough Administration constrains a command, then its named parameters, then the values those parameters may take, by set membership or regular expression16. sudoers by contrast matches arguments as one concatenated string. Microsoft documents the limits of its own mechanism in detail, including that custom function bodies run outside the session’s language constraints and that permitting the filesystem provider defeats it entirely.

Tool access and data access are separated inconsistently, and several mechanisms conflate them. chroot constrains what can be read and written and places no constraint on what runs4. Restricted shells constrain what runs and reach data only incidentally, by forbidding the redirection operators1. sudoers states that it governs the first and cannot govern the second3. Of 478 binaries catalogued by GTFOBins, 228 expose a documented shell function (measured), while file-read and file-write functions are catalogued separately and in comparable numbers18, so the data half of the gap is close in size to the tool half.

The disclaimer migrates away from the interface an operator uses. chroot(2) carries the security disclaimer; chroot(1), the command an operator types, documents only that it runs a command with the root directory set, and carries no caveat (from documentation). The seccomp warning against implementing a security policy sits in seccomp_unotify(2) rather than where filters are written. The GNU Bash Reference Manual’s recommendation to prefer jails, zones, or containers appears there and not in bash(1)1.

Where an operation vocabulary proved too coarse, the response was consistently more categories. CAP_BPF and CAP_CHECKPOINT_RESTORE were split out of CAP_SYS_ADMIN, of which the manual says “it can plausibly be called ‘the new root’”13. Landlock added rights across six ABI versions15. FreeBSD jail accreted allow.* toggles5. The vocabulary grows; the kind of object bound does not change.

Composition, not a better binding, is what shipped. The FreeBSD jail paper diagnosed chroot as binding only one namespace and answered with path, address, and privilege bindings at once5. Solaris zones layered a privilege reduction beneath namespace isolation explicitly as a backstop for the failure of the outer layer6. Firecracker’s jailer stacks chroot, namespaces, control groups, and seccomp around a hardware boundary. Eighteen years separate the first and last of these, and the response did not change.

The corpus is not internally consistent. The projects disagree about whether path-based policy is sound, a disagreement conducted on the public record between the SELinux and AppArmor developers and never technically conceded on either side8,10. This artifact records the disagreement and does not adjudicate it.


related
E/2D8
The shell needs a separation of concerns
One program reads the text, expands it, decides what it may do, and runs it, with no boundary between any of those jobs. On separating them, and on the interface that appears where the seam is cut.
R/9B1
Three agent harnesses drive the same shell through three separately built integration layers
Executable resolution, invocation contracts, emitted shell constructs, state carry, and approval units for three harnesses, with the code each spends on them.
R/B84
No major shell dialect beyond the POSIX subset has a definition other than its implementation
POSIX was specified because several implementations had to interoperate. The bash, zsh, and fish dialects were not, because each had exactly one.

sources

Manual pages read on Debian 12.10; papers, documentation, and catalogues retrieved 2026-08-15. Ordered by theme rather than by date, and cited by number in the text.

1
GNU Project. bash(1), and the GNU Bash Reference Manual: The Restricted Shell
bash 5.2.15 · manual updated 2025
2
AT&T. rsh(1), restricted shell
System III · 1980
3
Miller, T. C. sudoers(5), SECURITY NOTES
sudo 1.9.13p3
4
Linux man-pages. chroot(2)
6.03 · page dated 2023-02-05
5
Kamp, P.-H., Watson, R. N. M. Jails: Confining the omnipotent root
SANE 2000
6
Price, D., Tucker, A. Solaris Zones: Operating System Support for Consolidating Commercial Workloads
USENIX LISA 2004
7
Linux man-pages. seccomp(2), seccomp_unotify(2)
6.03
8
Spencer, R., Smalley, S., Loscocco, P., Hibler, M., Andersen, D., Lepreau, J. The Flask Security Architecture
USENIX Security 1999
9
Wright, C., Cowan, C., Smalley, S., Morris, J., Kroah-Hartman, G. Linux Security Modules: General Security Support for the Linux Kernel
USENIX Security 2002
10
Cowan, C., Beattie, S., Kroah-Hartman, G., Pu, C., Wagle, P., Gligor, V. SubDomain: Parsimonious Server Security
USENIX LISA 2000
11
AppArmor project. Frequently Asked Questions; apparmor.d(5)
apparmor.net
12
SELinux project. The SELinux Notebook
type enforcement, object classes, transitions
13
Linux man-pages. capabilities(7)
6.03
14
Watson, R. N. M., Anderson, J., Laurie, B., Kennaway, K. Capsicum: practical capabilities for UNIX
USENIX Security 2010
15
Linux man-pages. landlock(7)
6.03
16
Microsoft. Just Enough Administration: role capabilities, security considerations
learn.microsoft.com
17
Mullan, S. JEP 411: Deprecate the Security Manager for Removal
OpenJDK · 2021
18
GTFOBins. Catalogue of Unix binaries and the functions they expose
478 entries · read 2026-08-15
19
LOLBAS. Living Off The Land Binaries, Scripts and Libraries
243 entries · read 2026-08-15
20
Hardy, N. The Confused Deputy: or why capabilities might have been invented
ACM SIGOPS OSR 22(4) · 1988
21
Zeldovich, N., Boyd-Wickizer, S., Kohler, E., Mazières, D. Making Information Flow Explicit in HiStar
USENIX OSDI 2006