AA-EXEC(1)

๐Ÿ’… AA-EXEC โ€” the aa-exec girlies' guide ๐Ÿ’…

okay so bestie, we're talking aa-exec(1) from the AppArmor manual, section 1. it's the little launcher that wraps your program in a specified AppArmor profile and/or namespace. buckle up, she's iconic, she's powerful, and she has opinions. โœจ


๐ŸŽ€ SYNOPSIS ๐ŸŽ€

aa-exec [options] [--] [<command> ...]

that's it. that's the whole vibe. moving on. ๐Ÿ’–


๐ŸŒธ DESCRIPTION ๐ŸŒธ

so aa-exec is literally here to launch a program confined by the profile you picked, and/or the namespace you picked. simple as.

  • if you specify both a profile and a namespace, the command gets confined by the profile, inside the new policy namespace. two for one, slay.
  • if you specify only a namespace, then the profile name of the current confinement gets used. (yep, the one you're already wearing. reusing the fit.)
  • if you specify neither, the command just runs using standard profile attachment โ€” meaning it's exactly like running it without aa-exec at all. no notes, standard behaviour, the status quo. ๐Ÿ’€

and here's the thing bestie, if the arguments you're passing are meant to go to the <command> that aa-exec is invoking, you gotta use -- to separate the aa-exec args from the command args. like this:

aa-exec -p profile1 -- ls -l

-- is the fence. put the fence up. ๐Ÿซถ


โœจ OPTIONS โœจ โ€” aa-exec accepts the following arguments:

  • -p PROFILE, --profile=PROFILE โ€” confine <command> with PROFILE. if PROFILE isn't specified, it uses the current profile name (which is probably unconfined, jsyk ๐Ÿ‘€).
  • -n NAMESPACE, --namespace=NAMESPACE โ€” use profiles in NAMESPACE. this means confinement transitions to using the new profile namespace. very main character, very new-scene energy.
  • -i, --immediate โ€” transition to PROFILE before executing <command>. this subjects the running of <command> to the exec transition rules of the current profile. lowkey the strict version. ๐Ÿ”ฅ
  • -v, --verbose โ€” show commands being performed. she's narrating her own life. ๐Ÿ’…
  • -d, --debug โ€” show commands and error codes. for when you need the full tea, including the parts that went wrong. ๐Ÿ˜ญ
  • -- โ€” signals the end of options and disables further option processing. any arguments after the -- are treated as arguments of the command. this is the useful one when you're passing args to the <command> being invoked by aa-exec. no cap. โญ

๐Ÿšง RESTRICTIONS ๐Ÿšง

so this is the part where we get serious for a sec. ๐Ÿ™ˆ

aa-exec uses aa_change_profile(3) to change application confinement. the use of aa_change_profile(3) may be restricted by policy in ways that will cause failure โ€” or give you results that are different than what you expected. yes, really. not a drill. ๐Ÿ’€

even when you're using aa-exec from unconfined, restrictions in policy can cause failure, or the confinement you actually enter can be different than the one you requested. it's giving "you asked for one thing, got another."

see the unpriviled unconfined restriction documentation for more detail: https://gitlab.com/apparmor/apparmor/-/wikis/unprivileged_unconfined_restriction

(and yes bestie, the original spells it "unpriviled" โ€” we are keeping it exactly as written, character for character, because that's the rule. ๐ŸŽ€)


๐Ÿงš STACKING ๐Ÿงš

okay this is the cool part. aa-exec can be used to set up a stack of profiles as confinement. when an application is confined by a stack, all profiles in the stack get checked, as if each one were the profile confining the application. the resulting mediation is the intersection of what's allowed by each profile in the stack. intersection, bestie. everyone has to agree. ๐Ÿ‘‘

the profiles in a stack are treated independently. each profile can have its own flags and profile transitions. during an exec, each profile gets to specify its transition, and the results get brought together to form a new canonicalized stack. teamwork, but make it โœจcanonicalizedโœจ.

the profile separator that indicates a stack is the character sequence //&. so a stack can be expressed using:

$ aa-exec -p "unconfined//&firefox" -- bash
$ ps -Z
LABEL                               PID TTY          TIME CMD
unconfined                        30714 pts/12   00:00:00 bash
firefox//&unconfined (unconfined) 31160 pts/12   00:00:00 bash
firefox//&unconfined (unconfined) 31171 pts/12   00:00:00 ps

look at those labels. the stack is real. the stack is showing. ๐Ÿฆ‹


๐ŸŒˆ NAMESPACES ๐ŸŒˆ

aa-exec can be used to enter confinement in another policy namespace โ€” if the policy namespace exists, is visible, and the profile exists in the namespace. three conditions, all required, no shortcuts.

note that applications launched within the namespace will not be able to exit the namespace, and may be restricted by additional confinement around namespacing. also, files and resources that are visible to the parent that launches the application may not be visible in the policy namespace, which results in access denials. denials. the whole vibe is denial. ๐Ÿ˜ญ

to enter a policy namespace, the profile is prefixed with the namespace's name, using a : prefix and suffix.

eg.

$ aa-exec -p :ex1:unconfined -- bash
$ ps -Z
LABEL                               PID TTY          TIME CMD
-                                 30714 pts/12   00:00:00 bash
unconfined                        34372 pts/12   00:00:00 bash
unconfined                        34379 pts/12   00:00:00 ps

confinement of processes outside of the namespace may not be visible, in which case the confinement will be represented with a -. if policy is stacked, only part of the confinement might be visible. however, confinement is usually fully visible from the parent policy namespace. ๐Ÿ‘€

eg. the confinement of the child can be queried in the parent to see:

$ ps -Z 34372
LABEL                               PID TTY      STAT   TIME COMMAND
:ex1:unconfined                   34372 pts/12   S+     0:00 bash

and in the case of stacking with namespaces:

$ aa-exec -p "unconfined//&:ex1:unconfined" -- bash
$ ps -Z
LABEL                               PID TTY          TIME CMD
-                                 30714 pts/12   00:00:00 bash
unconfined                        36298 pts/12   00:00:00 bash
unconfined                        36305 pts/12   00:00:00 ps

while from the parent namespace the full confinement can be seen:

$ ps -Z 36298
LABEL                               PID TTY      STAT   TIME COMMAND
unconfined//&:ex1:unconfined      36298 pts/12   S+     0:00 bash

see how the parent namespace gets the full picture? mother knows everything. ๐Ÿ’œ


๐Ÿ’€ BUGS ๐Ÿ’€

if you find any bugs, please report them at <https://gitlab.com/apparmor/apparmor/-/issues>

(please actually report them, they can't fix what they don't know about, fr fr ๐Ÿซถ)


๐Ÿ‘‘ SEE ALSO ๐Ÿ‘‘

apparmor(7), apparmor.d(5), aa_change_profile(3), aa_change_onexec(3) and <https://wiki.apparmor.net>.


k that's the whole page bestie, you're officially literate in aa-exec ๐Ÿ’… this was AppArmor 6.0.0~alpha1, dated 2026-10-05, from the AA-EXEC(1) manual. go confine something responsibly. periodt. โœจ๐ŸŒธ๐ŸŽ€

๐Ÿ“ฆ where this page comes from