diff --git a/aa-audit.8.md b/manpage_aa-audit.8.md similarity index 100% rename from aa-audit.8.md rename to manpage_aa-audit.8.md diff --git a/aa-autodep.8.md b/manpage_aa-autodep.8.md similarity index 100% rename from aa-autodep.8.md rename to manpage_aa-autodep.8.md diff --git a/aa-cleanprof.8.md b/manpage_aa-cleanprof.8.md similarity index 100% rename from aa-cleanprof.8.md rename to manpage_aa-cleanprof.8.md diff --git a/aa-complain.8.md b/manpage_aa-complain.8.md similarity index 100% rename from aa-complain.8.md rename to manpage_aa-complain.8.md diff --git a/aa-decode.8.md b/manpage_aa-decode.8.md similarity index 100% rename from aa-decode.8.md rename to manpage_aa-decode.8.md diff --git a/aa-disable.8.md b/manpage_aa-disable.8.md similarity index 100% rename from aa-disable.8.md rename to manpage_aa-disable.8.md diff --git a/aa-easyprof.8.md b/manpage_aa-easyprof.8.md similarity index 100% rename from aa-easyprof.8.md rename to manpage_aa-easyprof.8.md diff --git a/aa-enforce.8.md b/manpage_aa-enforce.8.md similarity index 100% rename from aa-enforce.8.md rename to manpage_aa-enforce.8.md diff --git a/aa-genprof.8.md b/manpage_aa-genprof.8.md similarity index 100% rename from aa-genprof.8.md rename to manpage_aa-genprof.8.md diff --git a/aa-logprof.8.md b/manpage_aa-logprof.8.md similarity index 100% rename from aa-logprof.8.md rename to manpage_aa-logprof.8.md diff --git a/aa-mergeprof.8.md b/manpage_aa-mergeprof.8.md similarity index 100% rename from aa-mergeprof.8.md rename to manpage_aa-mergeprof.8.md diff --git a/aa-notify.8.md b/manpage_aa-notify.8.md similarity index 100% rename from aa-notify.8.md rename to manpage_aa-notify.8.md diff --git a/aa-remove-unknown.8.md b/manpage_aa-remove-unknown.8.md similarity index 100% rename from aa-remove-unknown.8.md rename to manpage_aa-remove-unknown.8.md diff --git a/aa-teardown.8.md b/manpage_aa-teardown.8.md similarity index 100% rename from aa-teardown.8.md rename to manpage_aa-teardown.8.md diff --git a/aa-unconfined.8.md b/manpage_aa-unconfined.8.md similarity index 100% rename from aa-unconfined.8.md rename to manpage_aa-unconfined.8.md diff --git a/manpage_aa_change_hat.2.md b/manpage_aa_change_hat.2.md new file mode 100644 index 0000000..7b411be --- /dev/null +++ b/manpage_aa_change_hat.2.md @@ -0,0 +1,230 @@ +# NAME + +aa\_change\_hat - change to or from a "hat" within a AppArmor profile + +# SYNOPSIS + +**#include <sys/apparmor.h>** + +**int aa\_change\_hat (char \*subprofile, unsigned long magic\_token);** + +**int aa\_change\_hatv (char \*subprofiles\[\], unsigned long magic\_token);** + +**int aa\_change\_hat\_vargs (unsigned long magic\_token, ...);** + +Link with **-lapparmor** when compiling. + +# DESCRIPTION + +An AppArmor profile applies to an executable program; if a portion of +the program needs different access permissions than other portions, +the program can "change hats" to a different role, also known as a +subprofile. + +To change into a new hat, it calls one of the family of change\_hat +functions to do so. It passes in a pointer to the _subprofile_ which it +wants to change into, and a 64bit _magic\_token_. The _magic\_token_ +is used to return out of the subprofile at a later time. + +The aa\_change\_hat() function allows specifying the name of a single +_subprofile_ that the application wants to change into. A pointer to the +name of the _subprofile_ is passed along with the _magic\_token_. If the +profile is not present the call will fail with the appropriate error. + +The aa\_change\_hatv() function allows passing a _NULL_ terminated vector +of pointers to _subprofile_ names which will be tried in order. The +first _subprofile_ in the vector that exists will be transitioned to +and if none of the _subprofiles_ exist the call will fail with the +appropriate error. + +The aa\_change\_hat\_vargs() function is a convenience wrapper for the +aa\_change\_hatv() function. After the _magic\_token_ it takes an arbitrary +number of pointers to _subprofile_ names. Similar to execl(3), +aa\_change\_hat\_vargs() assembles the list of _subprofile_ names into a +vector and calls aa\_change\_hatv(). + +If a program wants to return out of the current subprofile to the +original profile, it calls aa\_change\_hat() with a pointer to NULL as +the _subprofile_, and the original _magic\_token_ value. If the +_magic\_token_ does not match the original _magic\_token_ passed into the +kernel when the program entered the subprofile, the change back to the +original profile will not happen, and the current task will be killed. +If the _magic\_token_ matches the original token, then the process will +change back to the original profile. + +As both read(2) and write(2) are mediated, a file must be listed in a +subprofile definition if the file is to be accessed while the process +is in a "hat". + +# RETURN VALUE + +On success zero is returned. On error, -1 is returned, and +errno(3) is set appropriately. + +# ERRORS + +- **EINVAL** + + The apparmor kernel module is not loaded or the communication via the + `/proc/*/attr/current` file did not conform to protocol. + +- **ENOMEM** + + Insufficient kernel memory was available. + +- **EPERM** + + The calling application is not confined by apparmor, the specified + _subprofile_ is not a _hat profile_, the task is being ptraced and the + tracing task does not have permission to trace the specified _subprofile_ or the no\_new\_privs execution bit is + enabled. + +- **ECHILD** + + The application's profile has no hats defined for it. + +- **ENOENT** + + The specified _subprofile_ does not exist in this profile but other hats + are defined. + +- **EACCES** + + The specified magic token did not match, and permissions to change to + the specified _subprofile_ has been denied. This will in most situations + also result in the task being killed, to prevent brute force attacks. + +# EXAMPLE + +The following code examples shows simple, if contrived, uses of +aa\_change\_hat(); a typical use of aa\_change\_hat() will separate +privileged portions of a process from unprivileged portions of a process, +such as keeping unauthenticated network traffic handling separate +from authenticated network traffic handling in OpenSSH or executing +user-supplied CGI scripts in apache. + +The use of random(3) is simply illustrative. Use of `/dev/urandom` is +recommended. + +First, a simple high-level overview of aa\_change\_hat() use: + + void foo (void) { + unsigned long magic_token; + + /* get a random magic token value + from our huge entropy pool */ + magic_token = random_function(); + + /* change into the subprofile while + * we do stuff we don't trust */ + aa_change_hat("stuff_we_dont_trust", magic_token); + + /* Go do stuff we don't trust -- this is all + * done in *this* process space, no separate + * fork()/exec()'s are done. */ + interpret_perl_stuff(stuff_from_user); + + /* now change back to our original profile */ + aa_change_hat(NULL, magic_token); + } + +Second, an example to show that files not listed in a subprofile ("hat") +aren't accessible after an aa\_change\_hat() call: + + #include + #include + #include + #include + #include + #include + #include + #include + + + int main(int argc, char *argv[]) { + int fd; + unsigned long tok; + char buf[10]; + + /* random() is a poor choice */ + tok = random(); + + /* open /etc/passwd outside of any hat */ + if ((fd=open("/etc/passwd", O_RDONLY)) < 0) + perror("Failure opening /etc/passwd"); + + /* confirm for ourselves that we can really read /etc/passwd */ + memset(&buf, 0, 10); + if (read(fd, &buf, 10) == -1) { + perror("Failure reading /etc/passwd pre-hat"); + _exit(1); + } + buf[9] = '\0'; + printf("/etc/passwd: %s\n", buf); + + /* change hat to the "hat" subprofile, which should not have + * read access to /etc/passwd -- even though we have a valid + * file descriptor at the time of the aa_change_hat() call. */ + if (aa_change_hat("hat", tok)) { + perror("Failure changing hat -- aborting"); + _exit(1); + } + + /* confirm that we cannot read /etc/passwd */ + lseek(fd,0,SEEK_SET); + memset(&buf, 0, 10); + if (read(fd, &buf, 10) == -1) + perror("Failure reading /etc/passwd post-hat"); + buf[9] = '\0'; + printf("/etc/passwd: %s\n", buf); + + return 0; + } + +This code example requires the following profile to be loaded with +apparmor\_parser(8): + + /tmp/ch { + /etc/ld.so.cache mr, + /etc/locale/** r, + /etc/localtime r, + /usr/share/locale/** r, + /usr/share/zoneinfo/** r, + /usr/lib/locale/** mr, + /usr/lib/gconv/*.so mr, + /usr/lib/gconv/gconv-modules* mr, + + /lib/ld-*.so* mrix, + /lib/libc*.so* mr, + /lib/libapparmor*.so* mr, + /dev/pts/* rw, + /tmp/ch mr, + + /etc/passwd r, + + ^hat { + /dev/pts/* rw, + } + } + +The output when run: + + $ /tmp/ch + /etc/passwd: root:x:0: + Failure reading /etc/passwd post-hat: Permission denied + /etc/passwd: + $ + +# BUGS + +None known. If you find any, please report them at +[https://gitlab.com/apparmor/apparmor/-/issues](https://gitlab.com/apparmor/apparmor/-/issues). Note that +aa\_change\_hat(2) provides no memory barriers between different areas of a +program; if address space separation is required, then separate processes +should be used. + +# SEE ALSO + +apparmor(7), apparmor.d(5), apparmor\_parser(8), aa\_change\_profile(2), +aa\_getcon(2) and +[https://wiki.apparmor.net](https://wiki.apparmor.net). diff --git a/manpage_aa_change_profile.2.md b/manpage_aa_change_profile.2.md new file mode 100644 index 0000000..9b50ad8 --- /dev/null +++ b/manpage_aa_change_profile.2.md @@ -0,0 +1,180 @@ +# NAME + +aa\_change\_profile, aa\_change\_onexec - change a tasks profile + +# SYNOPSIS + +**#include <sys/apparmor.h>** + +**int aa\_change\_profile(const char \*profile);** + +**int aa\_change\_onexec(const char \*profile);** + +Link with **-lapparmor** when compiling. + +# DESCRIPTION + +An AppArmor profile applies to an executable program; if a portion of +the program needs different access permissions than other portions, +the program can "change profile" to a different profile. To change into a +new profile, it can use the aa\_change\_profile() function to do so. It passes +in a pointer to the _profile_ to transition to. Confined programs wanting to +use aa\_change\_profile() need to have rules permitting changing to the named +profile. See apparmor.d(8) for details. + +If a program wants to return out of the current profile to the +original profile, it may use aa\_change\_hat(2). Otherwise, the two profiles must +have rules permitting changing between the two profiles. + +Open file descriptors may not be remediated after a call to aa\_change\_profile() +so the calling program must close(2) open file descriptors to ensure they +are not available after calling aa\_change\_profile(). As aa\_change\_profile() +is typically used just before execve(2), you may want to use open(2) or +fcntl(2) with close-on-exec. + +The aa\_change\_onexec() function is like the aa\_change\_profile() function +except it specifies that the profile transition should take place on the +next exec instead of immediately. The delayed profile change takes +precedence over any exec transition rules within the confining profile. +Delaying the profile boundary has a couple of advantages, it removes the +need for stub transition profiles and the exec boundary is a natural security +layer where potentially sensitive memory is unmapped. + +# RETURN VALUE + +On success zero is returned. On error, -1 is returned, and +errno(3) is set appropriately. + +# ERRORS + +- **EINVAL** + + The apparmor kernel module is not loaded, neither a profile nor a namespace + was specified, or the communication via the `/proc/*/attr/current` file did + not conform to protocol. + +- **ENOMEM** + + Insufficient kernel memory was available. + +- **EPERM** + + The calling application is confined by apparmor and the no\_new\_privs bit is + set. + +- **EACCES** + + The task does not have sufficient permissions to change its domain. + +- **ENOENT** + + The specified profile does not exist, or is not visible from the current + Namespace. + +# EXAMPLE + +The following example shows a simple, if contrived, use of +aa\_change\_profile(); a typical use of aa\_change\_profile() will +aa\_change\_profile() just before an execve(2) so that the new +child process is permanently confined. + + #include + #include + #include + #include + #include + #include + #include + #include + + int main(int argc, char * argv[]) + { + int fd; + char buf[10]; + char *execve_args[4]; + + printf("Before aa_change_profile():\n"); + if ((fd=open("/etc/passwd", O_RDONLY)) < 0) { + perror("Failure opening /etc/passwd"); + return 1; + } + + /* Confirm for ourselves that we can really read /etc/passwd */ + memset(&buf, 0, 10); + if (read(fd, &buf, 10) == -1) { + perror("Failure reading /etc/passwd"); + return 1; + } + buf[9] = '\0'; + printf("/etc/passwd: %s\n", buf); + close(fd); + + printf("After aa_change_profile():\n"); + + /* change profile to the "i_cant_be_trusted_anymore" profile, which + * should not have read access to /etc/passwd. */ + if (aa_change_profile("i_cant_be_trusted_anymore") < 0) { + perror("Failure changing profile -- aborting"); + _exit(1); + } + + /* confirm that we cannot read /etc/passwd */ + execve_args[0] = "/usr/bin/head"; + execve_args[1] = "-1"; + execve_args[2] = "/etc/passwd"; + execve_args[3] = NULL; + execve("/usr/bin/head", execve_args, NULL); + perror("execve"); + _exit(1); + } + +This code example requires a profile similar to the following to be loaded +with apparmor\_parser(8): + + profile i_cant_be_trusted_anymore { + /etc/ld.so.cache mr, + /lib/ld-*.so* mrix, + /lib/libc*.so* mr, + + /usr/bin/head ix, + } + +The output when run: + + $ /tmp/change_p + Before aa_change_profile(): + /etc/passwd: root:x:0: + After aa_change_profile(): + /usr/bin/head: cannot open `/etc/passwd' for reading: Permission denied + $ + +If /tmp/change\_p is to be confined as well, then the following profile can be +used (in addition to the one for 'i\_cant\_be\_trusted\_anymore', above): + + # Confine change_p to be able to read /etc/passwd and aa_change_profile() + # to the 'i_cant_be_trusted_anymore' profile. + /tmp/change_p { + /etc/ld.so.cache mr, + /lib/ld-*.so* mrix, + /lib/libc*.so* mr, + + /etc/passwd r, + + # Needed for aa_change_profile() + /usr/lib/libapparmor*.so* mr, + /proc/[0-9]*/attr/current w, + change_profile -> i_cant_be_trusted_anymore, + } + +# BUGS + +None known. If you find any, please report them at +[https://gitlab.com/apparmor/apparmor/-/issues](https://gitlab.com/apparmor/apparmor/-/issues). Note that using +aa\_change\_profile(2) without execve(2) provides no memory barriers between +different areas of a program; if address space separation is required, then +separate processes should be used. + +# SEE ALSO + +apparmor(7), apparmor.d(5), apparmor\_parser(8), aa\_change\_hat(2) and +[https://wiki.apparmor.net](https://wiki.apparmor.net). diff --git a/manpage_aa_features.3.md b/manpage_aa_features.3.md new file mode 100644 index 0000000..28ee58c --- /dev/null +++ b/manpage_aa_features.3.md @@ -0,0 +1,157 @@ +# NAME + +aa\_features - an opaque object representing a set of AppArmor kernel features + +aa\_features\_new - create a new aa\_features object based on a path + +aa\_features\_new\_from\_string - create a new aa\_features object based on a string + +aa\_features\_new\_from\_kernel - create a new aa\_features object based on the current kernel + +aa\_features\_ref - increments the ref count of an aa\_features object + +aa\_features\_unref - decrements the ref count and frees the aa\_features object when 0 + +aa\_features\_write\_to\_file - write a string representation of an aa\_features object to a file + +aa\_features\_is\_equal - equality test for two aa\_features objects + +aa\_features\_supports - provides aa\_features object support status + +aa\_features\_id - provides unique identifier for an aa\_features object + +aa\_features\_value - the value associated with a given feature. + +# SYNOPSIS + +**#include <sys/apparmor.h>** + +**typedef struct aa\_features aa\_features;** + +**int aa\_features\_new(aa\_features \*\*features, int dirfd, const char \*path);** + +**int aa\_features\_new\_from\_file(aa\_features \*\*features, int fd);** + +**int aa\_features\_new\_from\_string(aa\_features \*\*features, const char \*string, size\_t size);** + +**int aa\_features\_new\_from\_kernel(aa\_features \*\*features);** + +**aa\_features \*aa\_features\_ref(aa\_features \*features);** + +**void aa\_features\_unref(aa\_features \*features);** + +**int aa\_features\_write\_to\_file(aa\_features \*features, int dirfd, const char \*path);** + +**bool aa\_features\_is\_equal(aa\_features \*features1, aa\_features \*features2);** + +**bool aa\_features\_supports(aa\_features \*features, const char \*str);** + +**char \*aa\_features\_id(aa\_features \*features);** + +**char \*aa\_features\_value(aa\_features \*features, const char \*str, size\_t \*len);** + +Link with **-lapparmor** when compiling. + +# DESCRIPTION + +The _aa\_features_ object contains information about the AppArmor features +supported by a kernel. The feature support information is based upon the files +AppArmor represents in securityfs, which is typically found at +/sys/kernel/security/apparmor/features/. That information may be parsed and +turned into a string or flat file in order to represent a set of features of a +kernel that is not currently running. + +The aa\_features\_new() function creates an _aa\_features_ object based upon a +directory file descriptor and path. The _path_ can point to a file or +directory. See the openat(2) man page for examples of _dirfd_ and _path_. The +allocated _features_ object must be freed using aa\_features\_unref(). + +The aa\_features\_new\_from\_file() function is similar except that it +accepts an open file as the argument. The allocated _features_ object +must be freed using aa\_features\_unref(). + +The aa\_features\_new\_from\_string() function is similar except that it accepts a +NUL-terminated string representation of the AppArmor features as the _string_ +argument. The length of the features string, not counting the NUL-terminator, +must be specified as the _size_ argument. The allocated _features_ object +must be freed using aa\_features\_unref(). + +The aa\_features\_new\_from\_kernel() function creates an _aa\_features_ object +from the current running kernel. The allocated _features_ object must be freed +using aa\_features\_unref(). + +aa\_features\_ref() increments the reference count on the _features_ object. + +aa\_features\_unref() decrements the reference count on the _features_ object +and releases all corresponding resources when the reference count reaches zero. + +The aa\_features\_write\_to\_file() function writes a string representation of the +_features_ object to the file specified by the _dirfd_ and _path_ +combination. + +aa\_features\_is\_equal() can be used to detect if the _features1_ and +_features2_ objects are equal. The definition of equality is private to +libapparmor and may be changed in ways that do not break backward +compatibility. + +The aa\_features\_supports() function can be used to query the _features_ object +to determine if a feature is supported. The _str_ argument should be equal to +the path, relative to the "apparmor/features/" directory of securityfs, of the +feature to query. For example, to test if policy version 6 is supported, _str_ +would be "policy/versions/v6". + +The aa\_features\_id() function returns a string representation of an +identifier that can be used to uniquely identify an _aa\_features_ object. +The mechanism for generating the string representation is internal to +libapparmor and subject to change but an example implementation is +applying a hash function to the features string. + +# RETURN VALUE + +The aa\_features\_new() family of functions return 0 on success and _\*features_ +will point to an _aa\_features_ object that must be freed by +aa\_features\_unref(). -1 is returned on error, with errno set appropriately, and +_\*features_ will be set to NULL. + +aa\_features\_ref() returns the value of _features_. + +aa\_features\_write\_to\_file() returns 0 on success. -1 is returned on error, with +errno set appropriately. + +aa\_features\_is\_equal() returns true if _features1_ and _features2_ are equal +and false if they are not equal. + +aa\_features\_supports() returns true if the feature represented by _str_ is +supported and false if it is not supported. + +aa\_features\_id() returns a string identifying _features_ which must be +freed by the caller. NULL is returned on error, with errno set +appropriately. + +aa\_features\_value() returns a null terminated string with is +associated length which must be freed by the caller. NULL is returned +on error, with errno set to ENOENT if the feature was not found, +ENODIR if the specified feature does not resolve to a leaf feature. + +# ERRORS + +The errno value will be set according to the underlying error in the +_aa\_features_ family of functions that return -1 or NULL on error. + +# NOTES + +The aa\_features\_id() function can be found in libapparmor version +2.13. All the other aa\_feature functions described above are present +in libapparmor version 2.10. + +aa\_features\_unref() saves the value of errno when called and restores errno +before exiting in libapparmor version 2.12 and newer. + +# BUGS + +None known. If you find any, please report them at +[https://gitlab.com/apparmor/apparmor/-/issues](https://gitlab.com/apparmor/apparmor/-/issues). + +# SEE ALSO + +openat(2) and [https://wiki.apparmor.net](https://wiki.apparmor.net). diff --git a/manpage_aa_find_mountpoint.2.md b/manpage_aa_find_mountpoint.2.md new file mode 100644 index 0000000..6948d5f --- /dev/null +++ b/manpage_aa_find_mountpoint.2.md @@ -0,0 +1,93 @@ +# NAME + +aa\_is\_enabled - determine if apparmor is available + +aa\_find\_mountpoint - find where the apparmor interface filesystem is mounted + +# SYNOPSIS + +**#include <sys/apparmor.h>** + +**int aa\_is\_enabled(void);** + +**int aa\_find\_mountpoint(char \*\*mnt);** + +Link with **-lapparmor** when compiling. + +# DESCRIPTION + +The aa\_is\_enabled function returns true (1) if apparmor is enabled. +If it isn't it sets the errno(3) to reflect the reason it is not +enabled and returns 0. + +The aa\_find\_mountpoint function finds where the apparmor filesystem is mounted +on the system, and returns a string containing the mount path. It is the +caller's responsibility to free(3) the returned path. + +# RETURN VALUE + +**aa\_is\_enabled** +On success 1 is returned. On error, 0 is returned, and errno(3) is set +appropriately. + +**aa\_find\_mountpoint** +On success zero is returned. On error, -1 is returned, and errno(3) is set +appropriately. + +# ERRORS + +**aa\_is\_enabled** + +- **ENOSYS** + + AppArmor extensions to the system are not available. + +- **ECANCELED** + + AppArmor is available on the system but has been disabled at boot. + +- **ENOENT** + + AppArmor is available (and maybe even enforcing policy) but the interface is + not available. + +- **ENOMEM** + + Insufficient memory was available. + +- **EPERM** + + Did not have sufficient permissions to determine if AppArmor is enabled. + +- **EACCES** + + Did not have sufficient permissions to determine if AppArmor is enabled. + +- **EBUSY** + + AppArmor is enabled but does not have access to shared interfaces, and + only private interfaces are available. + +**aa\_find\_mountpoint** + +- **ENOMEM** + + Insufficient memory was available. + +- **EACCES** + + Access to the required paths was denied. + +- **ENOENT** + + The apparmor filesystem mount could not be found + +# BUGS + +None known. If you find any, please report them at +[https://gitlab.com/apparmor/apparmor/-/issues](https://gitlab.com/apparmor/apparmor/-/issues). + +# SEE ALSO + +apparmor(7), apparmor.d(5), apparmor\_parser(8), and +[https://wiki.apparmor.net](https://wiki.apparmor.net). diff --git a/manpage_aa_getcon.2.md b/manpage_aa_getcon.2.md new file mode 100644 index 0000000..e876c9e --- /dev/null +++ b/manpage_aa_getcon.2.md @@ -0,0 +1,109 @@ +# NAME + +aa\_getprocattr\_raw, aa\_getprocattr - read and parse procattr data + +aa\_getcon, aa\_gettaskcon - get task confinement information + +aa\_getpeercon - get the confinement of a socket's other end (peer) + +# SYNOPSIS + +**#include <sys/apparmor.h>** + +**int aa\_getprocattr\_raw(pid\_t tid, const char \*attr, char \*buf, int len, char \*\*mode);** + +**int aa\_getprocattr(pid\_t tid, const char \*attr, char \*\*label, char \*\*mode);** + +**int aa\_gettaskcon(pid\_t target, char \*\*label, char \*\*mode);** + +**int aa\_getcon(char \*\*label, char \*\*mode);** + +**int aa\_getpeercon\_raw(int fd, char \*buf, int \*len, char \*\*mode);** + +**int aa\_getpeercon(int fd, char \*\*label, char \*\*mode);** + +Link with **-lapparmor** when compiling. + +# DESCRIPTION + +The aa\_getcon function gets the current AppArmor confinement context for the +current task. The confinement context consists of a label and a mode. The label +is usually just the name of the AppArmor profile restricting the task, but it +may include the profile namespace or in some cases a set of profile names +(known as a stack of profiles). The mode is a string that describes how the +kernel is enforcing the policy defined in the profile. Profiles loaded in +"enforce" mode will result in enforcement of the policy defined in the profile +as well as reporting policy violation attempts. Profiles in "complain" mode +will not enforce policy but instead report policy violation attempts. + +Some examples of possible returned \*label strings are "unconfined", "/sbin/dhclient", +and "Firefox". The string can consist of any non-NUL characters but it will be +NUL-terminated. The \*label string must be freed using free(). + +The possible \*mode strings are "enforce" and "complain". Additionally, \*mode may +be NULL when \*label is "unconfined". **The \*mode string must not be freed**. The +\*label and \*mode strings come from a single buffer allocation and are separated +by a NUL character. + +The aa\_gettaskcon function is like the aa\_getcon function except it will work +for any arbitrary task in the system. + +The aa\_getpeercon function is similar to that of aa\_gettaskcon except that +it returns the confinement information for task on the other end of a socket +connection. + +The aa\_getpeercon\_raw function is the backend for the aa\_getpeercon function +and does not handle buffer allocation. + +The aa\_getprocattr function is the backend for the aa\_getcon and aa\_gettaskcon +functions and handles the reading and parsing of the confinement data from +different arbitrary attr files and returns the processed results in +an allocated buffer. + +The aa\_getprocattr\_raw() is the backend for the aa\_getprocattr function and +does not handle buffer allocation. + +# RETURN VALUE + +On success size of data placed in the buffer is returned, this includes the +mode if present and any terminating characters. On error, -1 is returned, and +errno(3) is set appropriately. + +# ERRORS + +- **EINVAL** + + The apparmor kernel module is not loaded or the communication via the + `/proc/*/attr/file` did not conform to protocol. + +- **ENOMEM** + + Insufficient kernel memory was available. + +- **EACCES** + + Access to the specified _file/task_ was denied. + +- **ENOENT** + + The specified _file/task_ does not exist or is not visible. + +- **ERANGE** + + The confinement data is too large to fit in the supplied buffer. + +# NOTES + +If aa\_getpeercon\_raw returns -1 and errno is ERANGE, the value of \*len can be +used to reallocate buf so that it is sufficiently large enough to store the +confinement data. + +# BUGS + +None known. If you find any, please report them at +[https://gitlab.com/apparmor/apparmor/-/issues](https://gitlab.com/apparmor/apparmor/-/issues). + +# SEE ALSO + +apparmor(7), apparmor.d(5), apparmor\_parser(8), aa\_change\_profile(2), +aa\_splitcon(3) and [https://wiki.apparmor.net](https://wiki.apparmor.net). diff --git a/manpage_aa_kernel_interface.3.md b/manpage_aa_kernel_interface.3.md new file mode 100644 index 0000000..e0cc7be --- /dev/null +++ b/manpage_aa_kernel_interface.3.md @@ -0,0 +1,141 @@ +# NAME + +aa\_kernel\_interface - an opaque object representing the AppArmor kernel interface for policy loading, replacing, and removing + +aa\_kernel\_interface\_new - create a new aa\_kernel\_interface object from an optional path + +aa\_kernel\_interface\_ref - increments the ref count of an aa\_kernel\_interface object + +aa\_kernel\_interface\_unref - decrements the ref count and frees the aa\_kernel\_interface object when 0 + +aa\_kernel\_interface\_load\_policy - load a policy from a buffer into the kernel + +aa\_kernel\_interface\_load\_policy\_from\_file - load a policy from a file into the kernel + +aa\_kernel\_interface\_load\_policy\_from\_fd - load a policy from a file descriptor into the kernel + +aa\_kernel\_interface\_replace\_policy - replace a policy in the kernel with a policy from a buffer + +aa\_kernel\_interface\_replace\_policy\_from\_file - replace a policy in the kernel with a policy from a file + +aa\_kernel\_interface\_replace\_policy\_from\_fd - replace a policy in the kernel with a policy from a file descriptor + +aa\_kernel\_interface\_remove\_policy - remove a policy from the kernel + +aa\_kernel\_interface\_write\_policy - write a policy to a file descriptor + +# SYNOPSIS + +**#include <sys/apparmor.h>** + +**typedef struct aa\_kernel\_interface aa\_kernel\_interface;** + +**int aa\_kernel\_interface\_new(aa\_kernel\_interface \*\*kernel\_interface, aa\_features \*kernel\_features, const char \*apparmorfs);** + +**aa\_kernel\_interface \*aa\_kernel\_interface\_ref(aa\_kernel\_interface \*kernel\_interface);** + +**void aa\_kernel\_interface\_unref(aa\_kernel\_interface \*kernel\_interface);** + +**int aa\_kernel\_interface\_load\_policy(aa\_kernel\_interface \*kernel\_interface, const char \*buffer, size\_t size);** + +**int aa\_kernel\_interface\_load\_policy\_from\_file(aa\_kernel\_interface \*kernel\_interface, int dirfd, const char \*path);** + +**int aa\_kernel\_interface\_load\_policy\_from\_fd(aa\_kernel\_interface \*kernel\_interface, int fd);** + +**int aa\_kernel\_interface\_replace\_policy(aa\_kernel\_interface \*kernel\_interface, const char \*buffer, size\_t size);** + +**int aa\_kernel\_interface\_replace\_policy\_from\_file(aa\_kernel\_interface \*kernel\_interface, int dirfd, const char \*path);** + +**int aa\_kernel\_interface\_replace\_policy\_from\_fd(aa\_kernel\_interface \*kernel\_interface, int fd);** + +**int aa\_kernel\_interface\_remove\_policy(aa\_kernel\_interface \*kernel\_interface, const char \*fqname);** + +**int aa\_kernel\_interface\_write\_policy(int fd, const char \*buffer, size\_t size);** + +Link with **-lapparmor** when compiling. + +# DESCRIPTION + +The _aa\_kernel\_interface_ object contains information about the AppArmor +kernel interface for policy loading, replacing, and removing. + +The aa\_kernel\_interface\_new() function creates an _aa\_kernel\_interface_ object +based on an optional _aa\_features_ object and an optional path to the apparmor +directory of securityfs, which is typically found at +"/sys/kernel/security/apparmor/". If _kernel\_features_ is NULL, then the +features of the current kernel are used. When specifying a valid +_kernel\_features_ object, it must be compatible with the features of the +currently running kernel. If _apparmorfs_ is NULL, then the default location +is used. The allocated _kernel\_interface_ object must be freed using +aa\_kernel\_interface\_unref(). + +aa\_kernel\_interface\_ref() increments the reference count on the +_kernel\_interface_ object. + +aa\_kernel\_interface\_unref() decrements the reference count on the +_kernel\_interface_ object and releases all corresponding resources when the +reference count reaches zero. + +The aa\_kernel\_interface\_load() family of functions load a policy into the +kernel. The operation will fail if a policy of the same name is already loaded. +Use the aa\_kernel\_interface\_replace() family of functions if you wish to +replace a previously loaded policy with a new policy of the same name. The +aa\_kernel\_interface\_replace() functions can also be used to load a policy that +does not correspond to a previously loaded policy. + +When loading or replacing from a buffer, the _buffer_ will contain binary +data. The _size_ argument must specify the size of the _buffer_ argument. + +When loading or replacing from a file, the _dirfd_ and _path_ combination are +used to specify the location of the file. See the openat(2) man page for +examples of _dirfd_ and _path_. + +It is also possible to load or replace from a file descriptor specified by the +_fd_ argument. The file must be open for reading and the file offset must be +set appropriately. + +The aa\_kernel\_interface\_remove\_policy() function can be used to unload a +previously loaded policy. The fully qualified policy name must be specified +with the _fqname_ argument. The operation will fail if a policy matching +_fqname_ is not found. + +The aa\_kernel\_interface\_write\_policy() function allows for a policy, which is +stored in _buffer_ and consists of _size_ bytes, to be written to a file +descriptor. The _fd_ must be open for writing and the file offset must be set +appropriately. + +# RETURN VALUE + +The aa\_kernel\_interface\_new() function returns 0 on success and +_\*kernel\_interface_ will point to an _aa\_kernel\_interface_ object that must +be freed by aa\_kernel\_interface\_unref(). -1 is returned on error, with errno +set appropriately, and _\*kernel\_interface_ will be set to NULL. + +aa\_kernel\_interface\_ref() returns the value of _kernel\_interface_. + +The aa\_kernel\_interface\_load() family of functions, the +aa\_kernel\_interface\_replace() family of functions, +aa\_kernel\_interface\_remove(), and aa\_kernel\_interface\_write\_policy() +return 0 on success. -1 is returned on error, with errno set appropriately. + +# ERRORS + +The errno value will be set according to the underlying error in the +_aa\_kernel\_interface_ family of functions that return -1 on error. + +# NOTES + +All aa\_kernel\_interface functions described above are present in libapparmor +version 2.10 and newer. + +aa\_kernel\_interface\_unref() saves the value of errno when called and restores +errno before exiting in libapparmor version 2.12 and newer. + +# BUGS + +None known. If you find any, please report them at +[https://gitlab.com/apparmor/apparmor/-/issues](https://gitlab.com/apparmor/apparmor/-/issues). + +# SEE ALSO + +aa\_features(3), openat(2) and [https://wiki.apparmor.net](https://wiki.apparmor.net). diff --git a/manpage_aa_policy_cache.3.md b/manpage_aa_policy_cache.3.md new file mode 100644 index 0000000..b54f953 --- /dev/null +++ b/manpage_aa_policy_cache.3.md @@ -0,0 +1,155 @@ +# NAME + +aa\_policy\_cache - an opaque object representing an AppArmor policy cache + +aa\_policy\_cache\_new - create a new aa\_policy\_cache object from a path + +aa\_policy\_cache\_ref - increments the ref count of an aa\_policy\_cache object + +aa\_policy\_cache\_unref - decrements the ref count and frees the aa\_policy\_cache object when 0 + +aa\_policy\_cache\_remove - removes all policy cache files under a path + +aa\_policy\_cache\_replace\_all - performs a kernel policy replacement of all cached policies + +aa\_policy\_cache\_dir\_path - returns the path to the aa\_policy\_cache directory + +aa\_policy\_cache\_dir\_path\_preview - returns a preview of the path to the aa\_policy\_cache directory without an existing aa\_policy\_cache object + +# SYNOPSIS + +**#include <sys/apparmor.h>** + +**typedef struct aa\_policy\_cache aa\_policy\_cache;** + +**int aa\_policy\_cache\_new(aa\_policy\_cache \*\*policy\_cache, aa\_features \*kernel\_features, int dirfd, const char \*path, uint16\_t max\_caches);** + +**int aa\_policy\_cache\_add\_ro\_dir(aa\_policy\_cache \*policy\_cache, int dirfd, const char \*path);** + +**aa\_policy\_cache \*aa\_policy\_cache\_ref(aa\_policy\_cache \*policy\_cache);** + +**void aa\_policy\_cache\_unref(aa\_policy\_cache \*policy\_cache);** + +**int aa\_policy\_cache\_remove(int dirfd, const char \*path);** + +**int aa\_policy\_cache\_replace\_all(aa\_policy\_cache \*policy\_cache, aa\_kernel\_interface \*kernel\_interface);** + +**char \*aa\_policy\_cache\_dir\_path(aa\_policy\_cache \*policy\_cache, int level);** + +**char \*aa\_policy\_cache\_dir\_path\_preview(aa\_features \*kernel\_features, int dirfd, const char \*path);** + +Link with **-lapparmor** when compiling. + +# DESCRIPTION + +The _aa\_policy\_cache_ object contains information about a set of AppArmor +policy cache files. The policy cache files are the binary representation of a +human-readable AppArmor profile. The binary representation is the form that is +loaded into the kernel. + +The aa\_policy\_cache\_new() function creates an _aa\_policy\_cache_ +object based upon a directory file descriptor and path. See the +openat(2) man page for examples of _dirfd_ and _path_. The _path_ +must point to a directory and it will be used as the basis for the +location of policy cache files. See _aa\_policy\_cache\_dir\_path_ to +find out which directory will be used to store the binary policy cache +files. If additional overlay cache directories are used (see +_aa\_policy\_cache\_add\_ro\_dir_) the directory specified in +_aa\_policy\_cache\_new_ is the first directory searched and is the +writable overlay. If _kernel\_features_ is NULL, then the features of +the current kernel are used. When specifying a valid +_kernel\_features_ object, it must be compatible with the features +of the kernel of interest. The value of _max\_caches_ should be equal +to the number of caches that should be allowed before old caches are +automatically reaped. The definition of what is considered to be an +old cache is private to libapparmor. Specifying 0 means that no new +caches should be created and only existing, valid caches may be used. +Specifying UINT16\_MAX means that a new cache may be created and that +the reaping of old caches is disabled. The allocated +_aa\_policy\_cache_ object must be freed using aa\_policy\_cache\_unref(). + +The aa\_policy\_cache\_add\_ro\_dir() function adds an existing cache directory +to the policy cache, as a readonly layer under the primary directory +the cache was created with. When the cache is searched for an existing +cache file the primary directory will be searched and then the readonly +directories in the order that they were added to the policy cache. +This allows the policy cache to be seeded with precompiled policy +that can be updated by overlaying the read only cache file with one +written to the primary cache dir. + +aa\_policy\_cache\_ref() increments the reference count on the _policy\_cache_ +object. + +aa\_policy\_cache\_unref() decrements the reference count on the _policy\_cache_ +object and releases all corresponding resources when the reference count +reaches zero. + +The aa\_policy\_cache\_remove() function deletes all of the policy cache files +based upon a directory file descriptor and path. The _path_ must point to a +directory. See the openat(2) man page for examples of _dirfd_ and _path_. + +The aa\_policy\_cache\_replace\_all() function can be used to perform a policy +replacement of all of the cache policies in the cache directory represented by +the _policy\_cache_ object. If _kernel\_interface_ is NULL, then the current +kernel interface is used. When specifying a valid _kernel\_interface_ object, +it must be the interface of the currently running kernel. + +The aa\_policy\_cache\_dir\_path() function provides the path to the cache +directory for a _policy\_cache_ object at _level_ in the policy cache +overlay of cache directories. A _level_ of 0 will always be present +and is the first directory to search in an overlay of cache +directories, and will also be the writable cache directory +layer. Binary policy cache files will be located in the directory +returned by this function. + +The aa\_policy\_cache\_dir\_levels() function provides access to the number +of directories that are being overlayed to create the policy cache. + +# RETURN VALUE + +The aa\_policy\_cache\_new() function returns 0 on success and _\*policy\_cache_ +will point to an _aa\_policy\_cache_ object that must be freed by +aa\_policy\_cache\_unref(). -1 is returned on error, with errno set appropriately, +and _\*policy\_cache_ will be set to NULL. + +aa\_policy\_cache\_ref() returns the value of _policy\_cache_. + +aa\_policy\_cache\_remove() and aa\_policy\_cache\_replace\_all() return 0 on success. +\-1 is returned on error, with errno set appropriately. + +aa\_policy\_cache\_dir\_path() returns a path string which must be freed by the +caller. NULL is returned on error, with errno set appropriately. + +aa\_policy\_cache\_dir\_levels() returns a number indicating the number of +directory levels there are associated with the _policy\_cache_. + +aa\_policy\_cache\_dir\_path\_preview() is the same as +aa\_policy\_cache\_dir\_path() except that it doesn't require an existing +_aa\_policy\_cache_ object. This is useful if the calling program cannot +create an _aa\_policy\_cache_ object due to lack of privileges needed to +create the cache directory. + +# ERRORS + +The errno value will be set according to the underlying error in the +_aa\_policy\_cache_ family of functions that return -1 or NULL on error. + +# NOTES + +All aa\_policy\_cache functions described above, except for the +aa\_policy\_cache\_dir\_path() function was added in libapparmor version +2.13. All the other aa\_policy\_cache functions described above are +present in libapparmor version 2.10. + +aa\_policy\_cache\_unref() saves the value of errno when called and restores errno +before exiting in libapparmor version 2.12 and newer. + +# BUGS + +None known. If you find any, please report them at +[https://gitlab.com/apparmor/apparmor/-/issues](https://gitlab.com/apparmor/apparmor/-/issues). + +# SEE ALSO + +aa\_features(3), aa\_kernel\_interface(3), openat(2) and +[https://wiki.apparmor.net](https://wiki.apparmor.net). diff --git a/manpage_aa_query_label.2.md b/manpage_aa_query_label.2.md new file mode 100644 index 0000000..d899ad6 --- /dev/null +++ b/manpage_aa_query_label.2.md @@ -0,0 +1,104 @@ +# NAME + +aa\_query\_label - query access permission associated with a label + +aa\_query\_file\_path, aa\_query\_file\_path\_len - query access permissions of a file path + +aa\_query\_link\_path, aa\_query\_link\_path\_len - query access permissions of a link path + +# SYNOPSIS + +**#include <sys/apparmor.h>** + +**int aa\_query\_label(uint32\_t mask, char \*query, size\_t size, int \*allowed, int \*audited);** + +**int aa\_query\_file\_path(uint32\_t mask, const char \*label, size\_t label\_len, const char \*path, int \*allowed, int \*audited);** + +**int aa\_query\_file\_path\_len(uint32\_t mask, const char \*label, size\_t label\_len, const char \*path, size\_t path\_len, int \*allowed, int \*audited);** + +**int aa\_query\_link\_path(const char \*label, const char \*target, const char \*link, int \*allowed, int \*audited);** + +**int aa\_query\_link\_path\_len(const char \*label, size\_t label\_len, const char \*target, size\_t target\_len, const char \*link, size\_t link\_len, int \*allowed, int \*audited);** + +Link with **-lapparmor** when compiling. + +# DESCRIPTION + +The **aa\_query\_label** function fetches the current permissions granted by the +specified _label_ in the _query_ string. + +The query is a raw binary formatted query, containing the label and +permission query to make. The returned _allowed_ and _audited_ values are +interpreted boolean values, simply stating whether the query is allowed and +if it is audited. + +The mask of the query string is a bit mask of permissions to query and is +class type dependent (see **AA\_CLASS\_xxx** entries in _sys/apparmor.h_). + +The format of the query string is also dependent on the **AA\_CLASS** and as +such the **aa\_query\_xxx** helper functions should usually be used instead +of directly using **aa\_query\_label**. If directly using the interface the +_query_ string is required to have a header of **AA\_QUERY\_CMD\_LABEL\_SIZE** +that will be used by **aa\_query\_label**. + +The **aa\_query\_file\_path** and **aa\_query\_file\_path\_len** functions are helper +function that assemble a properly formatted file path query for the +**aa\_query\_label** function. The _label_ is a valid apparmor label as +returned by _aa\_splitcon_ with _label\_len_ being the length of the _label_. +The _path_ is any valid filesystem path to query permissions for. For the +**aa\_query\_file\_path\_len** variant the _path\_len_ parameter specifies the +number of bytes in the _path_ to use as part of the query. + +The **aa\_query\_link\_path** and **aa\_query\_link\_path\_len** functions are helper +functions that assemble a properly formatted link path query for the +**aa\_query\_label** function. The _link\_len_ and _target\_len_ parameters +specify the number of bytes in the _link_ and _target_ to use as part of +the query. + +# RETURN VALUE + +On success 0 is returned, and the _allowed_ and _audited_ parameters +contain a boolean value of 0 not allowed/audited or 1 allowed/audited. On +error, -1 is returned, and errno(3) is set appropriately. + +# ERRORS + +- **EINVAL** + + The requested _mask_ is empty. + + The _size_ of the query is less than the query **AA\_QUERY\_CMD\_LABEL\_SIZE** + + The apparmor kernel module is not loaded or the kernel interface access + interface is not available + +- **ENOMEM** + + Insufficient memory was available. + +- **EACCES** + + Access to the specified _label_ or query interface was denied. + +- **ENOENT** + + The specified _label_ does not exist or is not visible. + +- **ERANGE** + + The confinement data is too large to fit in the supplied buffer. + +# NOTES + +The label permissions returned are only valid for the time of the +query and can change at any point in the future. + +# BUGS + +None known. If you find any, please report them at +[https://gitlab.com/apparmor/apparmor/-/issues](https://gitlab.com/apparmor/apparmor/-/issues). + +# SEE ALSO + +apparmor(7), apparmor.d(5), apparmor\_parser(8), aa\_getcon(2), aa\_splitcon(3) +and [https://wiki.apparmor.net](https://wiki.apparmor.net). diff --git a/manpage_aa_splitcon.3.md b/manpage_aa_splitcon.3.md new file mode 100644 index 0000000..878bcfc --- /dev/null +++ b/manpage_aa_splitcon.3.md @@ -0,0 +1,48 @@ +# NAME + +aa\_splitcon - split the confinement context into a label and mode + +# SYNOPSIS + +**#include <sys/apparmor.h>** + +**char \*aa\_splitcon(char \*con, char \*\*mode);** + +Link with **-lapparmor** when compiling. + +# DESCRIPTION + +The aa\_splitcon() function splits a confinement context into separate label +and mode strings. The @con string is modified so that the label portion is NUL +terminated. The enforcement mode is also NUL terminated and the parenthesis +surrounding the mode are removed. If @mode is non-NULL, it will point to the +first character in the enforcement mode string on success. + +The Linux kernel's /proc//attr/current interface appends a +trailing newline character to AppArmor contexts that are read from that file. +If @con contains a single trailing newline character, it will be stripped by +aa\_splitcon() prior to all other processing. + +# RETURN VALUE + +Returns a pointer to the first character in the label string. NULL is returned +on error. + +# EXAMPLE + + Context Label Mode + ----------------------------- ------------------ ------- + unconfined unconfined NULL + unconfined\n unconfined NULL + /bin/ping (enforce) /bin/ping enforce + /bin/ping (enforce)\n /bin/ping enforce + /usr/sbin/rsyslogd (complain) /usr/sbin/rsyslogd complain + +# BUGS + +None known. If you find any, please report them at +[https://gitlab.com/apparmor/apparmor/-/issues](https://gitlab.com/apparmor/apparmor/-/issues). + +# SEE ALSO + +aa\_getcon(2) and [https://wiki.apparmor.net](https://wiki.apparmor.net). diff --git a/manpage_aa_stack_profile.2.md b/manpage_aa_stack_profile.2.md new file mode 100644 index 0000000..73a1cad --- /dev/null +++ b/manpage_aa_stack_profile.2.md @@ -0,0 +1,193 @@ +# NAME + +aa\_stack\_profile, aa\_stack\_onexec - combine multiple profiles to confine a task + +# SYNOPSIS + +**#include <sys/apparmor.h>** + +**int aa\_stack\_profile(const char \*profile);** + +**int aa\_stack\_onexec(const char \*profile);** + +Link with **-lapparmor** when compiling. + +# DESCRIPTION + +AppArmor supports stacking two or more profiles when confining a task. The +result is an intersection of all profiles which are stacked. Stacking profiles +together is desirable when wanting to ensure that confinement will never become +more permissive. When changing between two profiles, as performed with +aa\_change\_profile(2), there is always the possibility that the new profile is +more permissive than the old profile but that possibility is eliminated when +using aa\_stack\_profile(). + +To stack a profile with the current confinement context, a task can use the +aa\_stack\_profile() function. The _profile_ parameter is a NUL-terminated +string indicating a profile name that should be stacked with the current +confinement. + +Calling aa\_stack\_profile("profile\_a") while unconfined is equivalent to calling +aa\_change\_profile("profile\_a") since the intersection of unconfined and +"profile\_a" is "profile\_a". Calling aa\_stack\_profile("profile\_b") while +confined by "profile\_a" results in the task's confinement to be the +intersection of "profile\_a" and "profile\_b". The resulting confinement context +will be represented as "profile\_a//&profile\_b" in audit log messages, the +return value of aa\_getcon(2), etc. + +Confined programs wanting to use aa\_stack\_profile() need to have rules +permitting stacking the named profile. See apparmor.d(8) for details. + +Open file descriptors may not be remediated after a call to aa\_stack\_profile() +so the calling program must close(2) open file descriptors to ensure they +are not available after calling aa\_stack\_profile(). + +The aa\_stack\_onexec() function is like the aa\_stack\_profile() function +except it specifies that the stacking should take place on the next exec +instead of immediately. The delayed profile change takes precedence over any +exec transition rules within the confining profile. Delaying the stacking +boundary has a couple of advantages, it removes the need for stub transition +profiles and the exec boundary is a natural security layer where potentially +sensitive memory is unmapped. + +# RETURN VALUE + +On success zero is returned. On error, -1 is returned, and +errno(3) is set appropriately. + +# ERRORS + +- **EINVAL** + + AppArmor is not loaded, neither a profile nor a namespace was specified, + or the communication via the `/proc/*/attr/current` file did not conform + to protocol. + +- **ENOMEM** + + Insufficient kernel memory was available. + +- **ENOENT** + + The specified profile does not exist, or is not visible from the current + namespace. + +# NOTES + +Using aa\_stack\_profile() and related libapparmor functions are the only way to +ensure compatibility between varying kernel versions. However, there may be +some situations where libapparmor is not available and directly interacting +with the AppArmor filesystem is required to stack a profile. + +To immediately stack a profile named "profile\_a", as performed with +aa\_stack\_profile("profile\_a"), the equivalent of this shell command can be +used: + + $ echo -n "stackprofile profile_a" > /proc/self/attr/current + +To stack a profile named "profile\_a" at the next exec, as performed with +aa\_stack\_onexec("profile\_a"), the equivalent of this shell command can be used: + + $ echo -n "stackexec profile_a" > /proc/self/attr/exec + +These raw AppArmor filesystem operations must only be used when using +libapparmor is not a viable option. + +# EXAMPLE + +The following example shows a simple, if contrived, use of +aa\_stack\_profile(). + + #include + #include + #include + #include + #include + #include + #include + #include + + static void read_passwd() + { + int fd; + char buf[10]; + + if ((fd=open("/etc/passwd", O_RDONLY)) < 0) { + perror("Failure opening /etc/passwd"); + _exit(1); + } + + /* Verify that we can read /etc/passwd */ + memset(&buf, 0, 10); + if (read(fd, &buf, 10) == -1) { + perror("Failure reading /etc/passwd"); + _exit(1); + } + buf[9] = '\0'; + printf("/etc/passwd: %s\n", buf); + close(fd); + } + + int main(int argc, char * argv[]) + { + printf("Before aa_stack_profile():\n"); + read_passwd(); + + /* stack the "i_cant_be_trusted_anymore" profile, which + * should not have read access to /etc/passwd. */ + if (aa_stack_profile("i_cant_be_trusted_anymore") < 0) { + perror("Failure changing profile -- aborting"); + _exit(1); + } + + printf("After aa_stack_profile():\n"); + read_passwd(); + _exit(0); + } + +This code example requires a profile similar to the following to be loaded +with apparmor\_parser(8): + + # Confine stack_p to be able to read /etc/passwd and aa_stack_profile() + # to the 'i_cant_be_trusted_anymore' profile. + /tmp/stack_p { + /etc/ld.so.cache mr, + /lib/ld-*.so* mrix, + /lib/libc*.so* mr, + + /etc/passwd r, + + # Needed for aa_stack_profile() + /usr/lib/libapparmor*.so* mr, + /proc/[0-9]*/attr/current w, + } + +As well as the profile to stack: + + profile i_cant_be_trusted_anymore { + /etc/ld.so.cache mr, + /lib/ld-*.so* mrix, + /lib/libc*.so* mr, + } + +The output when run: + + $ /tmp/stack_p + Before aa_stack_profile(): + /etc/passwd: root:x:0: + After aa_stack_profile(): + Failure opening /etc/passwd: Permission denied + $ + +# BUGS + +None known. If you find any, please report them at +[https://gitlab.com/apparmor/apparmor/-/issues](https://gitlab.com/apparmor/apparmor/-/issues). Note that using +aa\_stack\_profile(2) without execve(2) provides no memory barriers between +different areas of a program; if address space separation is required, then +separate processes should be used. + +# SEE ALSO + +apparmor(7), apparmor.d(5), apparmor\_parser(8), aa\_change\_profile(2), +aa\_getcon(2) and [https://wiki.apparmor.net](https://wiki.apparmor.net). diff --git a/apparmor.7.md b/manpage_apparmor.7.md similarity index 100% rename from apparmor.7.md rename to manpage_apparmor.7.md diff --git a/apparmor.d.5.md b/manpage_apparmor.d.5.md similarity index 100% rename from apparmor.d.5.md rename to manpage_apparmor.d.5.md diff --git a/apparmor_parser.8.md b/manpage_apparmor_parser.8.md similarity index 100% rename from apparmor_parser.8.md rename to manpage_apparmor_parser.8.md diff --git a/apparmor_parser.md b/manpage_apparmor_parser.md similarity index 100% rename from apparmor_parser.md rename to manpage_apparmor_parser.md diff --git a/apparmor_xattrs.7.md b/manpage_apparmor_xattrs.7.md similarity index 100% rename from apparmor_xattrs.7.md rename to manpage_apparmor_xattrs.7.md diff --git a/logprof.conf.5.md b/manpage_logprof.conf.5.md similarity index 100% rename from logprof.conf.5.md rename to manpage_logprof.conf.5.md