Add an interface for trusted applications to use when they need to query AppArmor kernel policy to determine if an action should be allowed.
This is a simplified interface that tries to make it as easy as possible for applications to use. They provide a permissions mask and query string and they get a pair of booleans back that let them know if the action should be allowed and/or audited. Signed-off-by: Tyler Hicks <[email protected]> --- libraries/libapparmor/src/Makefile.am | 2 +- libraries/libapparmor/src/apparmor.h | 41 +++++++++++ libraries/libapparmor/src/kernel_interface.c | 98 +++++++++++++++++++++++++++ libraries/libapparmor/src/libapparmor.map | 7 ++ libraries/libapparmor/swig/SWIG/libapparmor.i | 2 + 5 files changed, 149 insertions(+), 1 deletion(-) diff --git a/libraries/libapparmor/src/Makefile.am b/libraries/libapparmor/src/Makefile.am index 6507673..48bf2f4 100644 --- a/libraries/libapparmor/src/Makefile.am +++ b/libraries/libapparmor/src/Makefile.am @@ -47,7 +47,7 @@ lib_LTLIBRARIES = libapparmor.la noinst_HEADERS = grammar.h parser.h scanner.h af_protos.h libapparmor_la_SOURCES = grammar.y libaalogparse.c kernel_interface.c scanner.c -libapparmor_la_LDFLAGS = -version-info $(AA_LIB_CURRENT):$(AA_LIB_REVISION):$(AA_LIB_AGE) -XCClinker -dynamic \ +libapparmor_la_LDFLAGS = -version-info $(AA_LIB_CURRENT):$(AA_LIB_REVISION):$(AA_LIB_AGE) -XCClinker -dynamic -pthread \ -Wl,--version-script=$(top_srcdir)/src/libapparmor.map -Wl,-soname=libapparmor.so.1 pkgconfigdir = $(libdir)/pkgconfig diff --git a/libraries/libapparmor/src/apparmor.h b/libraries/libapparmor/src/apparmor.h index 79bc69c..387e197 100644 --- a/libraries/libapparmor/src/apparmor.h +++ b/libraries/libapparmor/src/apparmor.h @@ -18,10 +18,41 @@ #ifndef _SYS_APPARMOR_H_ #define _SYS_APPARMOR_H 1 +#include <stdint.h> #include <sys/types.h> __BEGIN_DECLS +/* + * Class of mediation types in the AppArmor policy db + */ +#define AA_CLASS_COND 0 +#define AA_CLASS_UNKNOWN 1 +#define AA_CLASS_FILE 2 +#define AA_CLASS_CAP 3 +#define AA_CLASS_NET 4 +#define AA_CLASS_RLIMITS 5 +#define AA_CLASS_DOMAIN 6 +#define AA_CLASS_MOUNT 7 +#define AA_CLASS_NS_DOMAIN 8 +#define AA_CLASS_PTRACE 9 + +#define AA_CLASS_ENV 16 + +#define AA_CLASS_DBUS 32 +#define AA_CLASS_X 33 + + +/* Permission Flags for Mediation classes */ +#define AA_MAY_WRITE (1 << 1) +#define AA_MAY_READ (1 << 2) +#define AA_MAY_BIND (1 << 6) + +#define AA_DBUS_SEND AA_MAY_WRITE +#define AA_DBUS_RECEIVE AA_MAY_READ +#define AA_DBUS_BIND AA_MAY_BIND + + /* Prototypes for apparmor state queries */ extern int aa_is_enabled(void); extern int aa_find_mountpoint(char **mnt); @@ -51,6 +82,16 @@ extern int aa_getcon(char **con, char **mode); extern int aa_getpeercon_raw(int fd, char *buf, int *len, char **mode); extern int aa_getpeercon(int fd, char **con, char **mode); +/* A NUL character is used to separate the query command prefix string from the + * rest of the query string. The query command sizes intentionally include the + * NUL-terminator in their values. + */ +#define AA_QUERY_CMD_LABEL "label" +#define AA_QUERY_CMD_LABEL_SIZE sizeof(AA_QUERY_CMD_LABEL) + +extern int aa_query_label(uint32_t mask, char *query, size_t size, int *allow, + int *audit); + #define __macroarg_counter(Y...) __macroarg_count1 ( , ##Y) #define __macroarg_count1(Y...) __macroarg_count2 (Y, 16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0) #define __macroarg_count2(_,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,n,Y...) n diff --git a/libraries/libapparmor/src/kernel_interface.c b/libraries/libapparmor/src/kernel_interface.c index ea1659d..356307e 100644 --- a/libraries/libapparmor/src/kernel_interface.c +++ b/libraries/libapparmor/src/kernel_interface.c @@ -28,6 +28,9 @@ #include <limits.h> #include <stdarg.h> #include <mntent.h> +#include <inttypes.h> +#include <stdint.h> +#include <pthread.h> #include "apparmor.h" @@ -650,3 +653,98 @@ int aa_getpeercon(int fd, char **con, char **mode) return size; } + +static pthread_once_t aafs_access_control = PTHREAD_ONCE_INIT; +static char *aafs_access = NULL; + +static void aafs_access_init_once(void) +{ + char *aafs; + int ret; + + ret = aa_find_mountpoint(&aafs); + if (ret < 0) + return; + + ret = asprintf(&aafs_access, "%s/.access", aafs); + if (ret < 0) + aafs_access = NULL; + + free(aafs); +} + +/* "allow 0x00000000\ndeny 0x00000000\naudit 0x00000000\nquiet 0x00000000\n" */ +#define QUERY_LABEL_REPLY_LEN 67 + +/** + * aa_query_label - query the access(es) of a label + * @mask: permission bits to query + * @query: binary query string, must be offset by AA_QUERY_CMD_LABEL_SIZE + * @size: size of the query string must include AA_QUERY_CMD_LABEL_SIZE + * @allowed: upon successful return, will be 1 if query is allowed and 0 if not + * @audited: upon successful return, will be 1 if query should be audited and 0 + * if not + * + * Returns: 0 on success else -1 and sets errno + */ +int aa_query_label(uint32_t mask, char *query, size_t size, int *allowed, + int *audited) +{ + char buf[QUERY_LABEL_REPLY_LEN]; + uint32_t allow, deny, audit, quiet; + int fd, ret, saved; + + if (!mask || size <= AA_QUERY_CMD_LABEL_SIZE) { + errno = EINVAL; + return -1; + } + + ret = pthread_once(&aafs_access_control, aafs_access_init_once); + if (ret) { + errno = EINVAL; + return -1; + } else if (!aafs_access) { + errno = ENOMEM; + return -1; + } + + fd = open(aafs_access, O_RDWR); + if (fd == -1) + return -1; + + memcpy(query, AA_QUERY_CMD_LABEL, AA_QUERY_CMD_LABEL_SIZE); + errno = 0; + ret = write(fd, query, size); + if (ret != size) { + if (ret >= 0) + errno = EPROTO; + return -1; + } + + ret = read(fd, buf, QUERY_LABEL_REPLY_LEN); + saved = errno; + (void)close(fd); + errno = saved; + if (ret != QUERY_LABEL_REPLY_LEN) { + if (ret >= 0) + errno = EPROTO; + return -1; + } + + ret = sscanf(buf, "allow 0x%8" SCNx32 "\n" + "deny 0x%8" SCNx32 "\n" + "audit 0x%8" SCNx32 "\n" + "quiet 0x%8" SCNx32 "\n", + &allow, &deny, &audit, &quiet); + if (ret != 4) { + errno = EPROTONOSUPPORT; + return -1; + } + + *allowed = mask & ~(allow & ~deny) ? 0 : 1; + if (!(*allowed)) + audit = 0xFFFFFFFF; + *audited = mask & ~(audit & ~quiet) ? 0 : 1; + + return 0; +} diff --git a/libraries/libapparmor/src/libapparmor.map b/libraries/libapparmor/src/libapparmor.map index c4fcf8f..df696a7 100644 --- a/libraries/libapparmor/src/libapparmor.map +++ b/libraries/libapparmor/src/libapparmor.map @@ -37,3 +37,10 @@ APPARMOR_1.1 { local: *; } APPARMOR_1.0; + +APPARMOR_3.0 { + global: + aa_query_label; + local: + *; +} APPARMOR_1.1; diff --git a/libraries/libapparmor/swig/SWIG/libapparmor.i b/libraries/libapparmor/swig/SWIG/libapparmor.i index 1d3ca07..a94cb23 100644 --- a/libraries/libapparmor/swig/SWIG/libapparmor.i +++ b/libraries/libapparmor/swig/SWIG/libapparmor.i @@ -27,3 +27,5 @@ extern int aa_gettaskcon(pid_t target, char **con, char **mode); extern int aa_getcon(char **con, char **mode); extern int aa_getpeercon_raw(int fd, char *buf, int *len, char **mode); extern int aa_getpeercon(int fd, char **con, char **mode); +extern int aa_query_label(uint32_t mask, char *query, size_t size, int *allow, + int *audit); -- 1.8.3.2 -- AppArmor mailing list [email protected] Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor
