diff --git a/libraries/libapparmor/doc/aa_query_label.pod b/libraries/libapparmor/doc/aa_query_label.pod index 613e9d0c9..3e943a7ad 100644 --- a/libraries/libapparmor/doc/aa_query_label.pod +++ b/libraries/libapparmor/doc/aa_query_label.pod @@ -38,6 +38,14 @@ B +B + +B + Link with B<-lapparmor> when compiling. @@ -68,6 +76,12 @@ The I is any valid filesystem path to query permissions for. For the B variant the I parameter specifies the number of bytes in the I to use as part of the query. +The B and B functions are helper +functions that assemble a properly formatted link path query for the +B function. The I and I parameters +specify the number of bytes in the I and I to use as part of +the query. + =head1 RETURN VALUE On success 0 is returned, and the I and I parameters diff --git a/libraries/libapparmor/include/sys/apparmor.h b/libraries/libapparmor/include/sys/apparmor.h index 43f95497e..5a920ad8e 100644 --- a/libraries/libapparmor/include/sys/apparmor.h +++ b/libraries/libapparmor/include/sys/apparmor.h @@ -106,6 +106,12 @@ extern int aa_query_file_path_len(uint32_t mask, const char *label, size_t path_len, int *allowed, int *audited); extern int aa_query_file_path(uint32_t mask, const char *label, const char *path, int *allowed, int *audited); +extern 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); +extern int aa_query_link_path(const char *label, const char *target, + const char *link, int *allowed, int *audited); #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) diff --git a/libraries/libapparmor/src/kernel.c b/libraries/libapparmor/src/kernel.c index 50bc06244..a3f8efab9 100644 --- a/libraries/libapparmor/src/kernel.c +++ b/libraries/libapparmor/src/kernel.c @@ -905,3 +905,78 @@ int aa_query_file_path(uint32_t mask, const char *label, const char *path, return aa_query_file_path_len(mask, label, strlen(label), path, strlen(path), allowed, audited); } + +/** + * aa_query_link_path_len - query access permissions for a hard link @link + * @label: apparmor label + * @label_len: length of @label (does not include any terminating nul byte) + * @target: file path that hard link will point to + * @target_len: length of @target (does not include any terminating nul byte) + * @link: file path of hard link + * @link_len: length of @link (does not include any terminating nul byte) + * @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. If -1 is returned and errno is + * ENOENT, the subject label in the query string is unknown to the + * kernel. + */ +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) +{ + autofree char *query = NULL; + int rc; + + /* + 1 for null separators */ + size_t size = AA_QUERY_CMD_LABEL_SIZE + label_len + 1 + target_len + + 1 + link_len; + size_t pos = AA_QUERY_CMD_LABEL_SIZE; + + query = malloc(size); + if (!query) + return -1; + memcpy(query + pos, label, label_len); + /* null separator */ + pos += label_len; + query[pos] = 0; + query[++pos] = AA_CLASS_FILE; + memcpy(query + pos + 1, link, link_len); + /* The kernel does the query in two parts we could similate this + * doing the following, however as long as policy is compiled + * correctly this isn't requied, and it requires and extra round + * trip to the kernel and adds a race on policy replacement between + * the two queries. + * + rc = aa_query_label(AA_MAY_LINK, query, size, allowed, audited); + if (rc || !*allowed) + return rc; + */ + pos += 1 + link_len; + query[pos] = 0; + memcpy(query + pos + 1, target, target_len); + return aa_query_label(AA_MAY_LINK, query, size, allowed, audited); +} + +/** + * aa_query_link_path - query access permissions for a hard link @link + * @label: apparmor label + * @target: file path that hard link will point to + * @link: file path of hard link + * @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. If -1 is returned and errno is + * ENOENT, the subject label in the query string is unknown to the + * kernel. + */ +int aa_query_link_path(const char *label, const char *target, const char *link, + int *allowed, int *audited) +{ + return aa_query_link_path_len(label, strlen(label), target, + strlen(target), link, strlen(link), + allowed, audited); +} diff --git a/libraries/libapparmor/src/libapparmor.map b/libraries/libapparmor/src/libapparmor.map index 8a3c60bcf..d93acf637 100644 --- a/libraries/libapparmor/src/libapparmor.map +++ b/libraries/libapparmor/src/libapparmor.map @@ -56,6 +56,8 @@ APPARMOR_2.10 { global: aa_query_file_path; aa_query_file_path_len; + aa_query_link_path; + aa_query_link_path_len; aa_features_new; aa_features_new_from_string; aa_features_new_from_kernel; diff --git a/libraries/libapparmor/swig/SWIG/libapparmor.i b/libraries/libapparmor/swig/SWIG/libapparmor.i index c98cca892..98f984f31 100644 --- a/libraries/libapparmor/swig/SWIG/libapparmor.i +++ b/libraries/libapparmor/swig/SWIG/libapparmor.i @@ -44,5 +44,11 @@ extern int aa_query_file_path_len(uint32_t mask, const char *label, size_t path_len, int *allowed, int *audited); extern int aa_query_file_path(uint32_t mask, const char *label, const char *path, int *allowed, int *audited); +extern 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); +extern int aa_query_link_path(const char *label, const char *target, + const char *link, int *allowed, int *audited); %exception;