[apparmor] [PATCH 3/5] Library interface for tasks introspectingconfinement.
John Johansen
john.johansen at canonical.com
Thu Jul 21 20:40:58 UTC 2011
On 07/21/2011 11:43 AM, Seth Arnold wrote:
> Looks cool :)
>
> +aa_getpeercon - get the confinement of a sockets other end (peer)
>
> "socket's"
>
thanks
> The BUGS section was copied from another manpage and refers to memory barriers -- not needed here.
>
Now I wouldn't do that would I? :)
> The exit(errno) calls in the test program feel brittle -- fprintf() might reset errno internally to zero, thus not exiting with the proper error status.
yep, fixed
revised patch below
---
Library interface for tasks introspecting confinement.
Signed-off-by: John Johansen <john.johansen at canonical.com>
diff --git a/libraries/libapparmor/doc/Makefile.am b/libraries/libapparmor/doc/Makefile.am
index 2881709..c3f8f9b 100644
--- a/libraries/libapparmor/doc/Makefile.am
+++ b/libraries/libapparmor/doc/Makefile.am
@@ -2,7 +2,7 @@
POD2MAN = pod2man
-man_MANS = aa_change_hat.2 aa_change_profile.2
+man_MANS = aa_change_hat.2 aa_change_profile.2 aa_getcon.2
PODS = $(subst .2,.pod,$(man_MANS))
diff --git a/libraries/libapparmor/doc/aa_change_hat.pod b/libraries/libapparmor/doc/aa_change_hat.pod
index cf61e87..0931f40 100644
--- a/libraries/libapparmor/doc/aa_change_hat.pod
+++ b/libraries/libapparmor/doc/aa_change_hat.pod
@@ -246,7 +246,8 @@ should be used.
=head1 SEE ALSO
-apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_profile(2) and
+apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_profile(2),
+aa_getcon(2) and
L<http://wiki.apparmor.net>.
=cut
diff --git a/libraries/libapparmor/doc/aa_getcon.pod b/libraries/libapparmor/doc/aa_getcon.pod
new file mode 100644
index 0000000..c16ade3
--- /dev/null
+++ b/libraries/libapparmor/doc/aa_getcon.pod
@@ -0,0 +1,108 @@
+# This publication is intellectual property of Canonical Ltd. Its contents
+# can be duplicated, either in part or in whole, provided that a copyright
+# label is visibly located on each copy.
+#
+# All information found in this book has been compiled with utmost
+# attention to detail. However, this does not guarantee complete accuracy.
+# Neither Canonical Ltd, the authors, nor the translators shall be held
+# liable for possible errors or the consequences thereof.
+#
+# Many of the software and hardware descriptions cited in this book
+# are registered trademarks. All trade names are subject to copyright
+# restrictions and may be registered trade marks. Canonical Ltd.
+# essentially adhere to the manufacturer's spelling.
+#
+# Names of products and trademarks appearing in this book (with or without
+# specific notation) are likewise subject to trademark and trade protection
+# laws and may thus fall under copyright restrictions.
+#
+
+
+=pod
+
+=head1 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)
+
+=head1 SYNOPSIS
+
+B<#include E<lt>sys/apparmor.hE<gt>>
+
+B<int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
+ char **mode);>
+
+B<int aa_getprocattr(pid_t tid, const char *attr, char **buf, char **mode);>
+
+B<int aa_gettaskcon(pid_t target, char **con, char **mode);>
+
+B<int aa_getcon(char **con, char **mode);>
+
+B<int aa_getpeercon(int fd, char **con);>
+
+Link with B<-lapparmor> when compiling.
+
+=head1 DESCRIPTION
+
+The aa_getcon function gets the current AppArmor confinement context for the
+current task. The confinement context 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 returned string *con should be freed using <free()>.
+
+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_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.
+
+=head1 RETURN VALUE
+
+On success zero is returned. On error, -1 is returned, and
+errno(3) is set appropriately.
+
+=head1 ERRORS
+
+=over 4
+
+=item B<EINVAL>
+
+The apparmor kernel module is not loaded or the communication via the
+F</proc/*/attr/file> did not conform to protocol.
+
+=item B<ENOMEM>
+
+Insufficient kernel memory was available.
+
+=item B<EACCES>
+
+Access to the specified I<file/task> was denied.
+
+=item B<ENOENT>
+
+The specified I<file/task> does not exist or is not visible.
+
+=back
+
+=head1 BUGS
+
+None known. If you find any, please report them at
+L<http://https://bugs.launchpad.net/apparmor/+filebug>.
+
+=head1 SEE ALSO
+
+apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_profile(2) and
+L<http://wiki.apparmor.net>.
+
+=cut
diff --git a/libraries/libapparmor/src/apparmor.h b/libraries/libapparmor/src/apparmor.h
index b0e6a65..58e95c6 100644
--- a/libraries/libapparmor/src/apparmor.h
+++ b/libraries/libapparmor/src/apparmor.h
@@ -34,10 +34,16 @@ extern int aa_change_onexec(const char *profile);
extern int aa_change_hatv(const char *subprofiles[], unsigned long token);
extern int (aa_change_hat_vargs)(unsigned long token, int count, ...);
-/* Protypes for introspecting task confinement */
+/* Protypes for introspecting task confinement
+ * Please see the aa_getcon(2) manpage for information
+ */
extern int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
char **mode);
extern int aa_getprocattr(pid_t tid, const char *attr, char **buf, char **mode);
+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 *buffer, int *size);
+extern int aa_getpeercon(int fd, char **con);
#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_interface.c b/libraries/libapparmor/src/kernel_interface.c
index 67356dc..955944b 100644
--- a/libraries/libapparmor/src/kernel_interface.c
+++ b/libraries/libapparmor/src/kernel_interface.c
@@ -22,6 +22,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
+#include <sys/socket.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
@@ -402,3 +403,113 @@ int (aa_change_hat_vargs)(unsigned long token, int nhats, ...)
va_end(ap);
return aa_change_hatv(argv, token);
}
+
+/**
+ * aa_gettaskcon - get the confinement for task @target in an allocated buffer
+ * @target: task to query
+ * @con: pointer to returned buffer with the confinement string
+ * @mode: if provided will point to the mode string in @con if present
+ *
+ * Returns: length of confinement data or -1 on error and sets errno
+ *
+ * Guarentees that @con and @mode are null terminated. The length returned
+ * is for all data including both @con and @mode, and maybe > than strlen(@con)
+ * even if @mode is NULL
+ *
+ * Caller is responsible for freeing the buffer returned in @con. @mode is
+ * always contained within @con's buffer and so NEVER do free(@mode)
+ */
+int aa_gettaskcon(pid_t target, char **con, char **mode)
+{
+ return aa_getprocattr(target, "current", con, mode);
+}
+
+/**
+ * aa_getcon - get the confinement for current task in an allocated buffer
+ * @con: pointer to return buffer with the confinement if successful
+ * @mode: if provided will point to the mode string in @con if present
+ *
+ * Returns: length of confinement data or -1 on error and sets errno
+ *
+ * Guarentees that @con and @mode are null terminated. The length returned
+ * is for all data including both @con and @mode, and may > than strlen(@con)
+ * even if @mode is NULL
+ *
+ * Caller is responsible for freeing the buffer returned in @con. @mode is
+ * always contained within @con's buffer and so NEVER do free(@mode)
+ */
+int aa_getcon(char **con, char **mode)
+{
+ return aa_gettaskcon(aa_gettid(), con, mode);
+}
+
+
+#ifndef SO_PEERSEC
+#define SO_PEERSEC 31
+#endif
+
+/**
+ * aa_getpeercon_raw - get the confinement of the socket's peer (other end)
+ * @fd: socket to get peer confinement for
+ * @con: pointer to buffer to store confinement string
+ * @size: initially contains size of the buffer, returns size of data read
+ *
+ * Returns: length of confinement data including null termination or -1 on error
+ * if errno == ERANGE then @size will hold the size needed
+ */
+int aa_getpeercon_raw(int fd, char *buffer, int *size)
+{
+ socklen_t optlen = *size;
+ int rc = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buffer, &optlen);
+ if (rc == -1)
+ goto out;
+
+ /* check for null termination */
+ if (buffer[optlen - 1] != 0) {
+ if (optlen < *size) {
+ buffer[optlen] = 0;
+ optlen++;
+ } else {
+ /* buffer needs to be bigger by 1 */
+ rc = -1;
+ errno = ERANGE;
+ optlen++;
+ }
+ }
+out:
+ *size = optlen;
+ return rc;
+}
+
+/**
+ * aa_getpeercon - get the confinement of the socket's peer (other end)
+ * @fd: socket to get peer confinement for
+ * @con: pointer to allocated buffer with the confinement string
+ *
+ * Returns: length of confinement data including null termination or -1 on error
+ *
+ * Caller is responsible for freeing the buffer returned.
+ */
+int aa_getpeercon(int fd, char **con)
+{
+ int rc, size = INITIAL_GUESS_SIZE;
+
+ char *buffer = NULL;
+
+ do {
+ buffer = realloc(buffer, size);
+ if (!buffer)
+ return -1;
+ memset(buffer, 0, size);
+
+ rc = aa_getpeercon_raw(fd, buffer, &size);
+ } while (rc == -1 && errno == ERANGE);
+
+ if (rc == -1) {
+ free(buffer);
+ size = -1;
+ } else
+ *con = buffer;
+
+ return size;
+}
diff --git a/libraries/libapparmor/src/libapparmor.map b/libraries/libapparmor/src/libapparmor.map
index a0c1a25..6b209af 100644
--- a/libraries/libapparmor/src/libapparmor.map
+++ b/libraries/libapparmor/src/libapparmor.map
@@ -21,6 +21,10 @@ APPARMOR_1.1 {
aa_change_hat_vargs;
aa_change_profile;
aa_change_onexec;
+ aa_gettaskcon;
+ aa_getcon;
+ aa_getpeercon_raw;
+ aa_getpeercon;
parse_record;
free_record;
aa_getprocattr_raw;
diff --git a/libraries/libapparmor/swig/SWIG/libapparmor.i b/libraries/libapparmor/swig/SWIG/libapparmor.i
index 9c39359..d0f6bd5 100644
--- a/libraries/libapparmor/swig/SWIG/libapparmor.i
+++ b/libraries/libapparmor/swig/SWIG/libapparmor.i
@@ -21,3 +21,7 @@ extern int aa_change_hat_vargs(unsigned long token, int count, ...);
extern int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
char **mode);
extern int aa_getprocattr(pid_t tid, const char *attr, char **buf, char **mode);
+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 *buffer, int *size);
+extern int aa_getpeercon(int fd, char **con);
diff --git a/tests/regression/apparmor/Makefile b/tests/regression/apparmor/Makefile
index 9403618..b288626 100644
--- a/tests/regression/apparmor/Makefile
+++ b/tests/regression/apparmor/Makefile
@@ -6,6 +6,7 @@
# License.
SRC=access.c \
+ introspect.c \
changeprofile.c \
changehat.c \
changehat_fork.c \
@@ -106,6 +107,7 @@ LDLIBS+=$(LIBIMMUNIX)
EXEC=$(SRC:%.c=%)
TESTS=access \
+ introspect \
capabilities \
changeprofile \
changehat \
diff --git a/tests/regression/apparmor/introspect.c b/tests/regression/apparmor/introspect.c
new file mode 100644
index 0000000..bbdf908
--- /dev/null
+++ b/tests/regression/apparmor/introspect.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2002-2005 Novell/SUSE
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <linux/unistd.h>
+
+#include <sys/apparmor.h>
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ char *profile, *mode;
+
+ if (argc < 3 || argc > 4) {
+ fprintf(stderr, "usage: %s <task> <expected profile> [<expect mode>]\n",
+ argv[0]);
+ return 1;
+ }
+
+ if (strcmp(argv[1], "self") == 0){
+ if (aa_getcon(&profile, &mode) == -1) {
+ int serrno = errno;
+ fprintf(stderr,
+ "FAIL: introspect_confinement %s failed - %s\n",
+ argv[1], strerror(errno));
+ exit(serrno);
+ }
+ } else {
+ char *end;
+ pid_t pid = strtol(argv[1], &end, 10);
+ if (end == argv[1] || *end != 0) {
+ int serrno = errno;
+ fprintf(stderr,
+ "FAIL: query_confinement - invalid pid: %s\n",
+ argv[1]);
+ exit(serrno);
+ } else if (aa_gettaskcon(pid, &profile, &mode) == -1) {
+ int serrno = errno;
+ fprintf(stderr,
+ "FAIL: query_confinement %s failed - %s\n",
+ argv[1], strerror(errno));
+ exit(serrno);
+ }
+ }
+ if (strcmp(profile, argv[2]) != 0) {
+ fprintf(stderr,
+ "FAIL: expected confinement \"%s\" != \"%s\"\n", argv[2],
+ profile);
+ exit(1);
+ }
+ if (argv[3] && (!mode || strcmp(mode, argv[3]) != 0)) {
+ fprintf(stderr,
+ "FAIL: expected mode \"%s\" != \"%s\"\n", argv[3],
+ mode ? mode : "(null)");
+ exit(1);
+ }
+ free(profile);
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/tests/regression/apparmor/introspect.sh b/tests/regression/apparmor/introspect.sh
new file mode 100755
index 0000000..e397da4
--- /dev/null
+++ b/tests/regression/apparmor/introspect.sh
@@ -0,0 +1,67 @@
+#! /bin/bash
+# Copyright (C) 20011 Canonical
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation, version 2 of the
+# License.
+
+#=NAME introspect
+#=DESCRIPTION Test process confinement introspection
+
+pwd=`dirname $0`
+pwd=`cd $pwd ; /bin/pwd`
+
+bin=$pwd
+
+. $bin/prologue.inc
+
+ok_ix_perm=rix
+badperm=r
+ok_ux_perm=ux
+ok_px_perm=px
+bad_mx_perm=rm
+
+#self unconfined
+runchecktest "introspect self unconfined" pass self unconfined
+
+#self unconfined (mode)
+runchecktest "introspect self unconfined (mode)" fail self unconfined enforce
+
+#self confined - no access to introspection
+genprofile
+runchecktest "introspect self confined" fail self "$testexec"
+
+#self confined
+genprofile "/proc/*/attr/current":r
+runchecktest "introspect self confined" pass self "$testexec"
+
+#self confined (enforce)
+runchecktest "introspect self confined" pass self "$testexec" enforce
+
+#### TODO
+
+# query unconfined of unconfined
+
+# query unconfined of confined
+
+# query unconfined of confined (enfore)
+
+# query confined of unconfined - no access permission
+
+# query confined of unconfined - access permission
+
+# query confined of unconfined (mode) - access permission
+
+# query confined of confined same profile - no access permission
+
+# query confined of confined same profile
+
+# query confined of confined same profile (enforce)
+
+# query confined of confined diff profile - no access permission
+
+# query confined of confined diff profile
+
+# query confined of confined diff profile (enforce)
+
More information about the AppArmor
mailing list