[apparmor] [PATCH v2 37/42] libapparmor: Rename kernel_interface.c to kernel.c

Tyler Hicks tyhicks at canonical.com
Fri Mar 6 21:48:53 UTC 2015


The existing kernel_interface.c file collides with the expected file
name of the implementation of the aa_kernel_interface API.

Signed-off-by: Tyler Hicks <tyhicks at canonical.com>
Acked-by: Seth Arnold <seth.arnold at canonical.com>
---
 libraries/libapparmor/src/Makefile.am        |   2 +-
 libraries/libapparmor/src/kernel.c           | 778 +++++++++++++++++++++++++++
 libraries/libapparmor/src/kernel_interface.c | 778 ---------------------------
 3 files changed, 779 insertions(+), 779 deletions(-)
 create mode 100644 libraries/libapparmor/src/kernel.c
 delete mode 100644 libraries/libapparmor/src/kernel_interface.c

diff --git a/libraries/libapparmor/src/Makefile.am b/libraries/libapparmor/src/Makefile.am
index ac93bf5..a43109d 100644
--- a/libraries/libapparmor/src/Makefile.am
+++ b/libraries/libapparmor/src/Makefile.am
@@ -48,7 +48,7 @@ af_protos.h: /usr/include/netinet/in.h
 lib_LTLIBRARIES = libapparmor.la
 noinst_HEADERS = grammar.h parser.h scanner.h af_protos.h private.h
 
-libapparmor_la_SOURCES = grammar.y libaalogparse.c kernel_interface.c scanner.c private.c features.c
+libapparmor_la_SOURCES = grammar.y libaalogparse.c kernel.c scanner.c private.c features.c
 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
 
diff --git a/libraries/libapparmor/src/kernel.c b/libraries/libapparmor/src/kernel.c
new file mode 100644
index 0000000..de856f7
--- /dev/null
+++ b/libraries/libapparmor/src/kernel.c
@@ -0,0 +1,778 @@
+/*
+ * Copyright (c) 2003-2008 Novell, Inc. (All rights reserved)
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * The libapparmor library is licensed under the terms of the GNU
+ * Lesser General Public License, version 2.1. Please see the file
+ * COPYING.LGPL.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#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>
+#include <stdarg.h>
+#include <mntent.h>
+#include <inttypes.h>
+#include <pthread.h>
+
+#include <sys/apparmor.h>
+
+/* some non-Linux systems do not define a static value */
+#ifndef PATH_MAX
+# define PATH_MAX 4096
+#endif
+
+#define symbol_version(real, name, version) \
+		__asm__ (".symver " #real "," #name "@" #version)
+#define default_symbol_version(real, name, version) \
+		__asm__ (".symver " #real "," #name "@@" #version)
+
+/**
+ * aa_find_mountpoint - find where the apparmor interface filesystem is mounted
+ * @mnt: returns buffer with the mountpoint string
+ *
+ * Returns: 0 on success else -1 on error
+ *
+ * NOTE: this function only supports versions of apparmor using securityfs
+ */
+int aa_find_mountpoint(char **mnt)
+{
+	struct stat statbuf;
+	struct mntent *mntpt;
+	FILE *mntfile;
+	int rc = -1;
+
+	if (!mnt) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	mntfile = setmntent("/proc/mounts", "r");
+	if (!mntfile)
+		return -1;
+
+	while ((mntpt = getmntent(mntfile))) {
+		char *proposed = NULL;
+		if (strcmp(mntpt->mnt_type, "securityfs") != 0)
+			continue;
+
+		if (asprintf(&proposed, "%s/apparmor", mntpt->mnt_dir) < 0)
+			/* ENOMEM */
+			break;
+
+		if (stat(proposed, &statbuf) == 0) {
+			*mnt = proposed;
+			rc = 0;
+			break;
+		}
+		free(proposed);
+	}
+	endmntent(mntfile);
+	if (rc == -1)
+		errno = ENOENT;
+	return rc;
+}
+
+/**
+ * aa_is_enabled - determine if apparmor is enabled
+ *
+ * Returns: 1 if enabled else reason it is not, or 0 on error
+ *
+ * ENOSYS - no indication apparmor is present in the system
+ * ENOENT - enabled but interface could not be found
+ * ECANCELED - disabled at boot
+ * ENOMEM - out of memory
+ */
+int aa_is_enabled(void)
+{
+	int serrno, fd, rc, size;
+	char buffer[2];
+	char *mnt;
+
+	/* if the interface mountpoint is available apparmor is enabled */
+	rc = aa_find_mountpoint(&mnt);
+	if (rc == 0) {
+		free(mnt);
+		return 1;
+	}
+
+	/* determine why the interface mountpoint isn't available */
+	fd = open("/sys/module/apparmor/parameters/enabled", O_RDONLY);
+	if (fd == -1) {
+		if (errno == ENOENT)
+			errno = ENOSYS;
+		return 0;
+	}
+
+	size = read(fd, &buffer, 2);
+	serrno = errno;
+	close(fd);
+	errno = serrno;
+
+	if (size > 0) {
+		if (buffer[0] == 'Y')
+			errno = ENOENT;
+		else
+			errno = ECANCELED;
+	}
+	return 0;
+}
+
+static inline pid_t aa_gettid(void)
+{
+#ifdef SYS_gettid
+	return syscall(SYS_gettid);
+#else
+	return getpid();
+#endif
+}
+
+static char *procattr_path(pid_t pid, const char *attr)
+{
+	char *path = NULL;
+	if (asprintf(&path, "/proc/%d/attr/%s", pid, attr) > 0)
+		return path;
+	return NULL;
+}
+
+/**
+ * parse_confinement_mode - get the mode from the confinement context
+ * @con: the confinement context
+ * @size: size of the confinement context
+ *
+ * Modifies con to NUL-terminate the label string and the mode string.
+ *
+ * Returns: a pointer to the NUL-terminated mode inside the confinement context
+ * or NULL if the mode was not found
+ */
+static char *parse_confinement_mode(char *con, int size)
+{
+	if (strcmp(con, "unconfined") != 0 &&
+	    size > 4 && con[size - 2] == ')') {
+		int pos = size - 3;
+
+		while (pos > 0 && !(con[pos] == ' ' && con[pos + 1] == '('))
+			pos--;
+		if (pos > 0) {
+			con[pos] = 0; /* overwrite ' ' */
+			con[size - 2] = 0; /* overwrite trailing ) */
+			return &con[pos + 2]; /* skip '(' */
+		}
+	}
+	return NULL;
+}
+
+/**
+ * aa_getprocattr_raw - get the contents of @attr for @tid into @buf
+ * @tid: tid of task to query
+ * @attr: which /proc/<tid>/attr/<attr> to query
+ * @buf: buffer to store the result in
+ * @len: size of the buffer
+ * @mode: if non-NULL and a mode is present, will point to mode string in @buf
+ *
+ * Returns: size of data read or -1 on error, and sets errno
+ */
+int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
+		       char **mode)
+{
+	int rc = -1;
+	int fd, ret;
+	char *tmp = NULL;
+	char *mode_str;
+	int size = 0;
+
+	if (!buf || len <= 0) {
+		errno = EINVAL;
+		goto out;
+	}
+
+	tmp = procattr_path(tid, attr);
+	if (!tmp)
+		goto out;
+
+	fd = open(tmp, O_RDONLY);
+	free(tmp);
+	if (fd == -1) {
+		goto out;
+	}
+
+	tmp = buf;
+	do {
+		ret = read(fd, tmp, len);
+		if (ret <= 0)
+			break;
+		tmp += ret;
+		size += ret;
+		len -= ret;
+		if (len < 0) {
+			errno = ERANGE;
+			goto out2;
+		}
+	} while (ret > 0);
+
+	if (ret < 0) {
+		int saved;
+		if (ret != -1) {
+			errno = EPROTO;
+		}
+		saved = errno;
+		(void)close(fd);
+		errno = saved;
+		goto out;
+	} else if (size > 0 && buf[size - 1] != 0) {
+		/* check for null termination */
+		if (buf[size - 1] == '\n') {
+			buf[size - 1] = 0;
+		} else if (len == 0) {
+			errno = ERANGE;
+			goto out2;
+		} else {
+			buf[size] = 0;
+			size++;
+		}
+
+		mode_str = parse_confinement_mode(buf, size);
+		if (mode)
+			*mode = mode_str;
+	}
+	rc = size;
+
+out2:
+	(void)close(fd);
+out:
+	return rc;
+}
+
+#define INITIAL_GUESS_SIZE 128
+
+/**
+ * aa_getprocattr - get the contents of @attr for @tid into @label and @mode
+ * @tid: tid of task to query
+ * @attr: which /proc/<tid>/attr/<attr> to query
+ * @label: allocated buffer the label is stored in
+ * @mode: if non-NULL and a mode is present, will point to mode string in @label
+ *
+ * Returns: size of data read or -1 on error, and sets errno
+ *
+ * Guarantees that @label and @mode are null terminated.  The length returned
+ * is for all data including both @label and @mode, and maybe > than
+ * strlen(@label) even if @mode is NULL
+ *
+ * Caller is responsible for freeing the buffer returned in @label.  @mode is
+ * always contained within @label's buffer and so NEVER do free(@mode)
+ */
+int aa_getprocattr(pid_t tid, const char *attr, char **label, char **mode)
+{
+	int rc, size = INITIAL_GUESS_SIZE/2;
+	char *buffer = NULL;
+
+	if (!label) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	do {
+		size <<= 1;
+		buffer = realloc(buffer, size);
+		if (!buffer)
+			return -1;
+		memset(buffer, 0, size);
+
+		rc = aa_getprocattr_raw(tid, attr, buffer, size, mode);
+	} while (rc == -1 && errno == ERANGE);
+
+	if (rc == -1) {
+		free(buffer);
+		*label = NULL;
+		if (mode)
+			*mode = NULL;
+	} else
+		*label = buffer;
+
+	return rc;
+}
+
+static int setprocattr(pid_t tid, const char *attr, const char *buf, int len)
+{
+	int rc = -1;
+	int fd, ret;
+	char *ctl = NULL;
+
+	if (!buf) {
+		errno = EINVAL;
+		goto out;
+	}
+
+	ctl = procattr_path(tid, attr);
+	if (!ctl)
+		goto out;
+
+	fd = open(ctl, O_WRONLY);
+	if (fd == -1) {
+		goto out;
+	}
+
+	ret = write(fd, buf, len);
+	if (ret != len) {
+		int saved;
+		if (ret != -1) {
+			errno = EPROTO;
+		}
+		saved = errno;
+		(void)close(fd);
+		errno = saved;
+		goto out;
+	}
+
+	rc = 0;
+	(void)close(fd);
+
+out:
+	if (ctl) {
+		free(ctl);
+	}
+	return rc;
+}
+
+int aa_change_hat(const char *subprofile, unsigned long token)
+{
+	int rc = -1;
+	int len = 0;
+	char *buf = NULL;
+	const char *fmt = "changehat %016lx^%s";
+
+	/* both may not be null */
+	if (!(token || subprofile)) {
+		errno = EINVAL;
+		goto out;
+	}
+
+	if (subprofile && strnlen(subprofile, PATH_MAX + 1) > PATH_MAX) {
+		errno = EPROTO;
+		goto out;
+	}
+
+	len = asprintf(&buf, fmt, token, subprofile ? subprofile : "");
+	if (len < 0) {
+		goto out;
+	}
+
+	rc = setprocattr(aa_gettid(), "current", buf, len);
+out:
+	if (buf) {
+		/* clear local copy of magic token before freeing */
+		memset(buf, '\0', len);
+		free(buf);
+	}
+	return rc;
+}
+
+/* original change_hat interface */
+int __change_hat(char *subprofile, unsigned int token)
+{
+	return aa_change_hat(subprofile, (unsigned long) token);
+}
+
+int aa_change_profile(const char *profile)
+{
+	char *buf = NULL;
+	int len;
+	int rc;
+
+	if (!profile) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	len = asprintf(&buf, "changeprofile %s", profile);
+	if (len < 0)
+		return -1;
+
+	rc = setprocattr(aa_gettid(), "current", buf, len);
+
+	free(buf);
+	return rc;
+}
+
+int aa_change_onexec(const char *profile)
+{
+	char *buf = NULL;
+	int len;
+	int rc;
+
+	if (!profile) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	len = asprintf(&buf, "exec %s", profile);
+	if (len < 0)
+		return -1;
+
+	rc = setprocattr(aa_gettid(), "exec", buf, len);
+
+	free(buf);
+	return rc;
+}
+
+/* create an alias for the old change_hat at IMMUNIX_1.0 symbol */
+extern typeof((__change_hat)) __old_change_hat __attribute__((alias ("__change_hat")));
+symbol_version(__old_change_hat, change_hat, IMMUNIX_1.0);
+default_symbol_version(__change_hat, change_hat, APPARMOR_1.0);
+
+
+int aa_change_hatv(const char *subprofiles[], unsigned long token)
+{
+	int size, totallen = 0, hatcount = 0;
+	int rc = -1;
+	const char **hats;
+	char *pos, *buf = NULL;
+	const char *cmd = "changehat";
+
+	/* both may not be null */
+	if (!token && !(subprofiles && *subprofiles)) {
+		errno = EINVAL;
+                goto out;
+        }
+
+	/* validate hat lengths and while we are at it count how many and
+	 * mem required */
+	if (subprofiles) {
+		for (hats = subprofiles; *hats; hats++) {
+			int len = strnlen(*hats, PATH_MAX + 1);
+			if (len > PATH_MAX) {
+				errno = EPROTO;
+				goto out;
+			}
+			totallen += len + 1;
+			hatcount++;
+                }
+	}
+
+	/* allocate size of cmd + space + token + ^ + vector of hats */
+	size = strlen(cmd) + 18 + totallen + 1;
+	buf = malloc(size);
+	if (!buf) {
+                goto out;
+        }
+
+	/* setup command string which is of the form
+	 * changehat <token>^hat1\0hat2\0hat3\0..\0
+	 */
+	sprintf(buf, "%s %016lx^", cmd, token);
+	pos = buf + strlen(buf);
+	if (subprofiles) {
+		for (hats = subprofiles; *hats; hats++) {
+			strcpy(pos, *hats);
+			pos += strlen(*hats) + 1;
+		}
+	} else
+		/* step pos past trailing \0 */
+		pos++;
+
+	rc = setprocattr(aa_gettid(), "current", buf, pos - buf);
+
+out:
+	if (buf) {
+		/* clear local copy of magic token before freeing */
+		memset(buf, '\0', size);
+		free(buf);
+	}
+
+	return rc;
+}
+
+/**
+ * change_hat_vargs - change_hatv but passing the hats as fn arguments
+ * @token: the magic token
+ * @nhat: the number of hats being passed in the arguments
+ * ...: a argument list of const char * being passed
+ *
+ * change_hat_vargs can be called directly but it is meant to be called
+ * through its macro wrapper of the same name.  Which automatically
+ * fills in the nhats arguments based on the number of parameters
+ * passed.
+ * to call change_hat_vargs direction do
+ * (change_hat_vargs)(token, nhats, hat1, hat2...)
+ */
+int (aa_change_hat_vargs)(unsigned long token, int nhats, ...)
+{
+	va_list ap;
+	const char *argv[nhats+1];
+	int i;
+
+	va_start(ap, nhats);
+	for (i = 0; i < nhats ; i++) {
+		argv[i] = va_arg(ap, char *);
+	}
+	argv[nhats] = NULL;
+	va_end(ap);
+	return aa_change_hatv(argv, token);
+}
+
+/**
+ * aa_gettaskcon - get the confinement context for task @target in an allocated buffer
+ * @target: task to query
+ * @label: pointer to returned buffer with the label
+ * @mode: if non-NULL and a mode is present, will point to mode string in @label
+ *
+ * Returns: length of confinement context or -1 on error and sets errno
+ *
+ * Guarantees that @label and @mode are null terminated.  The length returned
+ * is for all data including both @label and @mode, and maybe > than
+ * strlen(@label) even if @mode is NULL
+ *
+ * Caller is responsible for freeing the buffer returned in @label.  @mode is
+ * always contained within @label's buffer and so NEVER do free(@mode)
+ */
+int aa_gettaskcon(pid_t target, char **label, char **mode)
+{
+	return aa_getprocattr(target, "current", label, mode);
+}
+
+/**
+ * aa_getcon - get the confinement context for current task in an allocated buffer
+ * @label: pointer to return buffer with the label if successful
+ * @mode: if non-NULL and a mode is present, will point to mode string in @label
+ *
+ * Returns: length of confinement context or -1 on error and sets errno
+ *
+ * Guarantees that @label and @mode are null terminated.  The length returned
+ * is for all data including both @label and @mode, and may > than
+ * strlen(@label) even if @mode is NULL
+ *
+ * Caller is responsible for freeing the buffer returned in @label.  @mode is
+ * always contained within @label's buffer and so NEVER do free(@mode)
+ */
+int aa_getcon(char **label, char **mode)
+{
+	return aa_gettaskcon(aa_gettid(), label, mode);
+}
+
+
+#ifndef SO_PEERSEC
+#define SO_PEERSEC 31
+#endif
+
+/**
+ * aa_getpeercon_raw - get the confinement context of the socket's peer (other end)
+ * @fd: socket to get peer confinement context for
+ * @buf: buffer to store the result in
+ * @len: initially contains size of the buffer, returns size of data read
+ * @mode: if non-NULL and a mode is present, will point to mode string in @buf
+ *
+ * Returns: length of confinement context including null termination or -1 on
+ *          error if errno == ERANGE then @len will hold the size needed
+ */
+int aa_getpeercon_raw(int fd, char *buf, int *len, char **mode)
+{
+	socklen_t optlen = *len;
+	char *mode_str;
+	int rc;
+
+	if (optlen <= 0 || buf == NULL) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	rc = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buf, &optlen);
+	if (rc == -1 || optlen <= 0)
+		goto out;
+
+	/* check for null termination */
+	if (buf[optlen - 1] != 0) {
+		if (optlen < *len) {
+			buf[optlen] = 0;
+			optlen++;
+		} else {
+			/* buf needs to be bigger by 1 */
+			rc = -1;
+			errno = ERANGE;
+			optlen++;
+			goto out;
+		}
+	}
+
+	mode_str = parse_confinement_mode(buf, optlen);
+	if (mode)
+		*mode = mode_str;
+
+	rc = optlen;
+out:
+	*len = optlen;
+	return rc;
+}
+
+/**
+ * aa_getpeercon - get the confinement context of the socket's peer (other end)
+ * @fd: socket to get peer confinement context for
+ * @label: pointer to allocated buffer with the label
+ * @mode: if non-NULL and a mode is present, will point to mode string in @label
+ *
+ * Returns: length of confinement context including null termination or -1 on error
+ *
+ * Guarantees that @label and @mode are null terminated.  The length returned
+ * is for all data including both @label and @mode, and maybe > than
+ * strlen(@label) even if @mode is NULL
+ *
+ * Caller is responsible for freeing the buffer returned in @label.  @mode is
+ * always contained within @label's buffer and so NEVER do free(@mode)
+ */
+int aa_getpeercon(int fd, char **label, char **mode)
+{
+	int rc, last_size, size = INITIAL_GUESS_SIZE;
+	char *buffer = NULL;
+
+	if (!label) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	do {
+		last_size = size;
+		buffer = realloc(buffer, size);
+		if (!buffer)
+			return -1;
+		memset(buffer, 0, size);
+
+		rc = aa_getpeercon_raw(fd, buffer, &size, mode);
+		/* size should contain actual size needed if errno == ERANGE */
+	} while (rc == -1 && errno == ERANGE && size > last_size);
+
+	if (rc == -1) {
+		free(buffer);
+		*label = NULL;
+		if (mode)
+			*mode = NULL;
+		size = -1;
+	} else
+		*label = buffer;
+
+	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. If -1 is returned and errno is
+ *          ENOENT, the subject label in the query string is unknown to the
+ *          kernel.
+ */
+int 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) {
+		if (errno == ENOENT)
+			errno = EPROTONOSUPPORT;
+		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;
+		/* IMPORTANT: This is the only valid error path that can have
+		 * errno set to ENOENT. It indicates that the subject label
+		 * could not be found by the kernel.
+		 */
+		(void)close(fd);
+		return -1;
+	}
+
+	ret = read(fd, buf, QUERY_LABEL_REPLY_LEN);
+	saved = errno;
+	(void)close(fd);
+	errno = saved;
+	if (ret != QUERY_LABEL_REPLY_LEN) {
+		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;
+}
+
+/* export multiple aa_query_label symbols to compensate for downstream
+ * releases with differing symbol versions. */
+extern typeof((query_label)) __aa_query_label __attribute__((alias ("query_label")));
+symbol_version(__aa_query_label, aa_query_label, APPARMOR_1.1);
+default_symbol_version(query_label, aa_query_label, APPARMOR_2.9);
diff --git a/libraries/libapparmor/src/kernel_interface.c b/libraries/libapparmor/src/kernel_interface.c
deleted file mode 100644
index de856f7..0000000
--- a/libraries/libapparmor/src/kernel_interface.c
+++ /dev/null
@@ -1,778 +0,0 @@
-/*
- * Copyright (c) 2003-2008 Novell, Inc. (All rights reserved)
- * Copyright 2009-2010 Canonical Ltd.
- *
- * The libapparmor library is licensed under the terms of the GNU
- * Lesser General Public License, version 2.1. Please see the file
- * COPYING.LGPL.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#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>
-#include <stdarg.h>
-#include <mntent.h>
-#include <inttypes.h>
-#include <pthread.h>
-
-#include <sys/apparmor.h>
-
-/* some non-Linux systems do not define a static value */
-#ifndef PATH_MAX
-# define PATH_MAX 4096
-#endif
-
-#define symbol_version(real, name, version) \
-		__asm__ (".symver " #real "," #name "@" #version)
-#define default_symbol_version(real, name, version) \
-		__asm__ (".symver " #real "," #name "@@" #version)
-
-/**
- * aa_find_mountpoint - find where the apparmor interface filesystem is mounted
- * @mnt: returns buffer with the mountpoint string
- *
- * Returns: 0 on success else -1 on error
- *
- * NOTE: this function only supports versions of apparmor using securityfs
- */
-int aa_find_mountpoint(char **mnt)
-{
-	struct stat statbuf;
-	struct mntent *mntpt;
-	FILE *mntfile;
-	int rc = -1;
-
-	if (!mnt) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	mntfile = setmntent("/proc/mounts", "r");
-	if (!mntfile)
-		return -1;
-
-	while ((mntpt = getmntent(mntfile))) {
-		char *proposed = NULL;
-		if (strcmp(mntpt->mnt_type, "securityfs") != 0)
-			continue;
-
-		if (asprintf(&proposed, "%s/apparmor", mntpt->mnt_dir) < 0)
-			/* ENOMEM */
-			break;
-
-		if (stat(proposed, &statbuf) == 0) {
-			*mnt = proposed;
-			rc = 0;
-			break;
-		}
-		free(proposed);
-	}
-	endmntent(mntfile);
-	if (rc == -1)
-		errno = ENOENT;
-	return rc;
-}
-
-/**
- * aa_is_enabled - determine if apparmor is enabled
- *
- * Returns: 1 if enabled else reason it is not, or 0 on error
- *
- * ENOSYS - no indication apparmor is present in the system
- * ENOENT - enabled but interface could not be found
- * ECANCELED - disabled at boot
- * ENOMEM - out of memory
- */
-int aa_is_enabled(void)
-{
-	int serrno, fd, rc, size;
-	char buffer[2];
-	char *mnt;
-
-	/* if the interface mountpoint is available apparmor is enabled */
-	rc = aa_find_mountpoint(&mnt);
-	if (rc == 0) {
-		free(mnt);
-		return 1;
-	}
-
-	/* determine why the interface mountpoint isn't available */
-	fd = open("/sys/module/apparmor/parameters/enabled", O_RDONLY);
-	if (fd == -1) {
-		if (errno == ENOENT)
-			errno = ENOSYS;
-		return 0;
-	}
-
-	size = read(fd, &buffer, 2);
-	serrno = errno;
-	close(fd);
-	errno = serrno;
-
-	if (size > 0) {
-		if (buffer[0] == 'Y')
-			errno = ENOENT;
-		else
-			errno = ECANCELED;
-	}
-	return 0;
-}
-
-static inline pid_t aa_gettid(void)
-{
-#ifdef SYS_gettid
-	return syscall(SYS_gettid);
-#else
-	return getpid();
-#endif
-}
-
-static char *procattr_path(pid_t pid, const char *attr)
-{
-	char *path = NULL;
-	if (asprintf(&path, "/proc/%d/attr/%s", pid, attr) > 0)
-		return path;
-	return NULL;
-}
-
-/**
- * parse_confinement_mode - get the mode from the confinement context
- * @con: the confinement context
- * @size: size of the confinement context
- *
- * Modifies con to NUL-terminate the label string and the mode string.
- *
- * Returns: a pointer to the NUL-terminated mode inside the confinement context
- * or NULL if the mode was not found
- */
-static char *parse_confinement_mode(char *con, int size)
-{
-	if (strcmp(con, "unconfined") != 0 &&
-	    size > 4 && con[size - 2] == ')') {
-		int pos = size - 3;
-
-		while (pos > 0 && !(con[pos] == ' ' && con[pos + 1] == '('))
-			pos--;
-		if (pos > 0) {
-			con[pos] = 0; /* overwrite ' ' */
-			con[size - 2] = 0; /* overwrite trailing ) */
-			return &con[pos + 2]; /* skip '(' */
-		}
-	}
-	return NULL;
-}
-
-/**
- * aa_getprocattr_raw - get the contents of @attr for @tid into @buf
- * @tid: tid of task to query
- * @attr: which /proc/<tid>/attr/<attr> to query
- * @buf: buffer to store the result in
- * @len: size of the buffer
- * @mode: if non-NULL and a mode is present, will point to mode string in @buf
- *
- * Returns: size of data read or -1 on error, and sets errno
- */
-int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
-		       char **mode)
-{
-	int rc = -1;
-	int fd, ret;
-	char *tmp = NULL;
-	char *mode_str;
-	int size = 0;
-
-	if (!buf || len <= 0) {
-		errno = EINVAL;
-		goto out;
-	}
-
-	tmp = procattr_path(tid, attr);
-	if (!tmp)
-		goto out;
-
-	fd = open(tmp, O_RDONLY);
-	free(tmp);
-	if (fd == -1) {
-		goto out;
-	}
-
-	tmp = buf;
-	do {
-		ret = read(fd, tmp, len);
-		if (ret <= 0)
-			break;
-		tmp += ret;
-		size += ret;
-		len -= ret;
-		if (len < 0) {
-			errno = ERANGE;
-			goto out2;
-		}
-	} while (ret > 0);
-
-	if (ret < 0) {
-		int saved;
-		if (ret != -1) {
-			errno = EPROTO;
-		}
-		saved = errno;
-		(void)close(fd);
-		errno = saved;
-		goto out;
-	} else if (size > 0 && buf[size - 1] != 0) {
-		/* check for null termination */
-		if (buf[size - 1] == '\n') {
-			buf[size - 1] = 0;
-		} else if (len == 0) {
-			errno = ERANGE;
-			goto out2;
-		} else {
-			buf[size] = 0;
-			size++;
-		}
-
-		mode_str = parse_confinement_mode(buf, size);
-		if (mode)
-			*mode = mode_str;
-	}
-	rc = size;
-
-out2:
-	(void)close(fd);
-out:
-	return rc;
-}
-
-#define INITIAL_GUESS_SIZE 128
-
-/**
- * aa_getprocattr - get the contents of @attr for @tid into @label and @mode
- * @tid: tid of task to query
- * @attr: which /proc/<tid>/attr/<attr> to query
- * @label: allocated buffer the label is stored in
- * @mode: if non-NULL and a mode is present, will point to mode string in @label
- *
- * Returns: size of data read or -1 on error, and sets errno
- *
- * Guarantees that @label and @mode are null terminated.  The length returned
- * is for all data including both @label and @mode, and maybe > than
- * strlen(@label) even if @mode is NULL
- *
- * Caller is responsible for freeing the buffer returned in @label.  @mode is
- * always contained within @label's buffer and so NEVER do free(@mode)
- */
-int aa_getprocattr(pid_t tid, const char *attr, char **label, char **mode)
-{
-	int rc, size = INITIAL_GUESS_SIZE/2;
-	char *buffer = NULL;
-
-	if (!label) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	do {
-		size <<= 1;
-		buffer = realloc(buffer, size);
-		if (!buffer)
-			return -1;
-		memset(buffer, 0, size);
-
-		rc = aa_getprocattr_raw(tid, attr, buffer, size, mode);
-	} while (rc == -1 && errno == ERANGE);
-
-	if (rc == -1) {
-		free(buffer);
-		*label = NULL;
-		if (mode)
-			*mode = NULL;
-	} else
-		*label = buffer;
-
-	return rc;
-}
-
-static int setprocattr(pid_t tid, const char *attr, const char *buf, int len)
-{
-	int rc = -1;
-	int fd, ret;
-	char *ctl = NULL;
-
-	if (!buf) {
-		errno = EINVAL;
-		goto out;
-	}
-
-	ctl = procattr_path(tid, attr);
-	if (!ctl)
-		goto out;
-
-	fd = open(ctl, O_WRONLY);
-	if (fd == -1) {
-		goto out;
-	}
-
-	ret = write(fd, buf, len);
-	if (ret != len) {
-		int saved;
-		if (ret != -1) {
-			errno = EPROTO;
-		}
-		saved = errno;
-		(void)close(fd);
-		errno = saved;
-		goto out;
-	}
-
-	rc = 0;
-	(void)close(fd);
-
-out:
-	if (ctl) {
-		free(ctl);
-	}
-	return rc;
-}
-
-int aa_change_hat(const char *subprofile, unsigned long token)
-{
-	int rc = -1;
-	int len = 0;
-	char *buf = NULL;
-	const char *fmt = "changehat %016lx^%s";
-
-	/* both may not be null */
-	if (!(token || subprofile)) {
-		errno = EINVAL;
-		goto out;
-	}
-
-	if (subprofile && strnlen(subprofile, PATH_MAX + 1) > PATH_MAX) {
-		errno = EPROTO;
-		goto out;
-	}
-
-	len = asprintf(&buf, fmt, token, subprofile ? subprofile : "");
-	if (len < 0) {
-		goto out;
-	}
-
-	rc = setprocattr(aa_gettid(), "current", buf, len);
-out:
-	if (buf) {
-		/* clear local copy of magic token before freeing */
-		memset(buf, '\0', len);
-		free(buf);
-	}
-	return rc;
-}
-
-/* original change_hat interface */
-int __change_hat(char *subprofile, unsigned int token)
-{
-	return aa_change_hat(subprofile, (unsigned long) token);
-}
-
-int aa_change_profile(const char *profile)
-{
-	char *buf = NULL;
-	int len;
-	int rc;
-
-	if (!profile) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	len = asprintf(&buf, "changeprofile %s", profile);
-	if (len < 0)
-		return -1;
-
-	rc = setprocattr(aa_gettid(), "current", buf, len);
-
-	free(buf);
-	return rc;
-}
-
-int aa_change_onexec(const char *profile)
-{
-	char *buf = NULL;
-	int len;
-	int rc;
-
-	if (!profile) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	len = asprintf(&buf, "exec %s", profile);
-	if (len < 0)
-		return -1;
-
-	rc = setprocattr(aa_gettid(), "exec", buf, len);
-
-	free(buf);
-	return rc;
-}
-
-/* create an alias for the old change_hat at IMMUNIX_1.0 symbol */
-extern typeof((__change_hat)) __old_change_hat __attribute__((alias ("__change_hat")));
-symbol_version(__old_change_hat, change_hat, IMMUNIX_1.0);
-default_symbol_version(__change_hat, change_hat, APPARMOR_1.0);
-
-
-int aa_change_hatv(const char *subprofiles[], unsigned long token)
-{
-	int size, totallen = 0, hatcount = 0;
-	int rc = -1;
-	const char **hats;
-	char *pos, *buf = NULL;
-	const char *cmd = "changehat";
-
-	/* both may not be null */
-	if (!token && !(subprofiles && *subprofiles)) {
-		errno = EINVAL;
-                goto out;
-        }
-
-	/* validate hat lengths and while we are at it count how many and
-	 * mem required */
-	if (subprofiles) {
-		for (hats = subprofiles; *hats; hats++) {
-			int len = strnlen(*hats, PATH_MAX + 1);
-			if (len > PATH_MAX) {
-				errno = EPROTO;
-				goto out;
-			}
-			totallen += len + 1;
-			hatcount++;
-                }
-	}
-
-	/* allocate size of cmd + space + token + ^ + vector of hats */
-	size = strlen(cmd) + 18 + totallen + 1;
-	buf = malloc(size);
-	if (!buf) {
-                goto out;
-        }
-
-	/* setup command string which is of the form
-	 * changehat <token>^hat1\0hat2\0hat3\0..\0
-	 */
-	sprintf(buf, "%s %016lx^", cmd, token);
-	pos = buf + strlen(buf);
-	if (subprofiles) {
-		for (hats = subprofiles; *hats; hats++) {
-			strcpy(pos, *hats);
-			pos += strlen(*hats) + 1;
-		}
-	} else
-		/* step pos past trailing \0 */
-		pos++;
-
-	rc = setprocattr(aa_gettid(), "current", buf, pos - buf);
-
-out:
-	if (buf) {
-		/* clear local copy of magic token before freeing */
-		memset(buf, '\0', size);
-		free(buf);
-	}
-
-	return rc;
-}
-
-/**
- * change_hat_vargs - change_hatv but passing the hats as fn arguments
- * @token: the magic token
- * @nhat: the number of hats being passed in the arguments
- * ...: a argument list of const char * being passed
- *
- * change_hat_vargs can be called directly but it is meant to be called
- * through its macro wrapper of the same name.  Which automatically
- * fills in the nhats arguments based on the number of parameters
- * passed.
- * to call change_hat_vargs direction do
- * (change_hat_vargs)(token, nhats, hat1, hat2...)
- */
-int (aa_change_hat_vargs)(unsigned long token, int nhats, ...)
-{
-	va_list ap;
-	const char *argv[nhats+1];
-	int i;
-
-	va_start(ap, nhats);
-	for (i = 0; i < nhats ; i++) {
-		argv[i] = va_arg(ap, char *);
-	}
-	argv[nhats] = NULL;
-	va_end(ap);
-	return aa_change_hatv(argv, token);
-}
-
-/**
- * aa_gettaskcon - get the confinement context for task @target in an allocated buffer
- * @target: task to query
- * @label: pointer to returned buffer with the label
- * @mode: if non-NULL and a mode is present, will point to mode string in @label
- *
- * Returns: length of confinement context or -1 on error and sets errno
- *
- * Guarantees that @label and @mode are null terminated.  The length returned
- * is for all data including both @label and @mode, and maybe > than
- * strlen(@label) even if @mode is NULL
- *
- * Caller is responsible for freeing the buffer returned in @label.  @mode is
- * always contained within @label's buffer and so NEVER do free(@mode)
- */
-int aa_gettaskcon(pid_t target, char **label, char **mode)
-{
-	return aa_getprocattr(target, "current", label, mode);
-}
-
-/**
- * aa_getcon - get the confinement context for current task in an allocated buffer
- * @label: pointer to return buffer with the label if successful
- * @mode: if non-NULL and a mode is present, will point to mode string in @label
- *
- * Returns: length of confinement context or -1 on error and sets errno
- *
- * Guarantees that @label and @mode are null terminated.  The length returned
- * is for all data including both @label and @mode, and may > than
- * strlen(@label) even if @mode is NULL
- *
- * Caller is responsible for freeing the buffer returned in @label.  @mode is
- * always contained within @label's buffer and so NEVER do free(@mode)
- */
-int aa_getcon(char **label, char **mode)
-{
-	return aa_gettaskcon(aa_gettid(), label, mode);
-}
-
-
-#ifndef SO_PEERSEC
-#define SO_PEERSEC 31
-#endif
-
-/**
- * aa_getpeercon_raw - get the confinement context of the socket's peer (other end)
- * @fd: socket to get peer confinement context for
- * @buf: buffer to store the result in
- * @len: initially contains size of the buffer, returns size of data read
- * @mode: if non-NULL and a mode is present, will point to mode string in @buf
- *
- * Returns: length of confinement context including null termination or -1 on
- *          error if errno == ERANGE then @len will hold the size needed
- */
-int aa_getpeercon_raw(int fd, char *buf, int *len, char **mode)
-{
-	socklen_t optlen = *len;
-	char *mode_str;
-	int rc;
-
-	if (optlen <= 0 || buf == NULL) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	rc = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buf, &optlen);
-	if (rc == -1 || optlen <= 0)
-		goto out;
-
-	/* check for null termination */
-	if (buf[optlen - 1] != 0) {
-		if (optlen < *len) {
-			buf[optlen] = 0;
-			optlen++;
-		} else {
-			/* buf needs to be bigger by 1 */
-			rc = -1;
-			errno = ERANGE;
-			optlen++;
-			goto out;
-		}
-	}
-
-	mode_str = parse_confinement_mode(buf, optlen);
-	if (mode)
-		*mode = mode_str;
-
-	rc = optlen;
-out:
-	*len = optlen;
-	return rc;
-}
-
-/**
- * aa_getpeercon - get the confinement context of the socket's peer (other end)
- * @fd: socket to get peer confinement context for
- * @label: pointer to allocated buffer with the label
- * @mode: if non-NULL and a mode is present, will point to mode string in @label
- *
- * Returns: length of confinement context including null termination or -1 on error
- *
- * Guarantees that @label and @mode are null terminated.  The length returned
- * is for all data including both @label and @mode, and maybe > than
- * strlen(@label) even if @mode is NULL
- *
- * Caller is responsible for freeing the buffer returned in @label.  @mode is
- * always contained within @label's buffer and so NEVER do free(@mode)
- */
-int aa_getpeercon(int fd, char **label, char **mode)
-{
-	int rc, last_size, size = INITIAL_GUESS_SIZE;
-	char *buffer = NULL;
-
-	if (!label) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	do {
-		last_size = size;
-		buffer = realloc(buffer, size);
-		if (!buffer)
-			return -1;
-		memset(buffer, 0, size);
-
-		rc = aa_getpeercon_raw(fd, buffer, &size, mode);
-		/* size should contain actual size needed if errno == ERANGE */
-	} while (rc == -1 && errno == ERANGE && size > last_size);
-
-	if (rc == -1) {
-		free(buffer);
-		*label = NULL;
-		if (mode)
-			*mode = NULL;
-		size = -1;
-	} else
-		*label = buffer;
-
-	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. If -1 is returned and errno is
- *          ENOENT, the subject label in the query string is unknown to the
- *          kernel.
- */
-int 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) {
-		if (errno == ENOENT)
-			errno = EPROTONOSUPPORT;
-		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;
-		/* IMPORTANT: This is the only valid error path that can have
-		 * errno set to ENOENT. It indicates that the subject label
-		 * could not be found by the kernel.
-		 */
-		(void)close(fd);
-		return -1;
-	}
-
-	ret = read(fd, buf, QUERY_LABEL_REPLY_LEN);
-	saved = errno;
-	(void)close(fd);
-	errno = saved;
-	if (ret != QUERY_LABEL_REPLY_LEN) {
-		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;
-}
-
-/* export multiple aa_query_label symbols to compensate for downstream
- * releases with differing symbol versions. */
-extern typeof((query_label)) __aa_query_label __attribute__((alias ("query_label")));
-symbol_version(__aa_query_label, aa_query_label, APPARMOR_1.1);
-default_symbol_version(query_label, aa_query_label, APPARMOR_2.9);
-- 
2.1.4




More information about the AppArmor mailing list