summaryrefslogtreecommitdiff
path: root/security/apparmor/path.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-05 11:26:35 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-05 11:26:35 -0700
commite24dd9ee5399747b71c1d982a484fc7601795f31 (patch)
tree14fcec8728916092a9f6dbeb0f2b8d5c5a4e5c9a /security/apparmor/path.c
parent7391786a64dcfe9c609a1f8e2204c1abf42ded23 (diff)
parentc4758fa59285fe4dbfeab4364a6957936d040fbf (diff)
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security layer updates from James Morris: - a major update for AppArmor. From JJ: * several bug fixes and cleanups * the patch to add symlink support to securityfs that was floated on the list earlier and the apparmorfs changes that make use of securityfs symlinks * it introduces the domain labeling base code that Ubuntu has been carrying for several years, with several cleanups applied. And it converts the current mediation over to using the domain labeling base, which brings domain stacking support with it. This finally will bring the base upstream code in line with Ubuntu and provide a base to upstream the new feature work that Ubuntu carries. * This does _not_ contain any of the newer apparmor mediation features/controls (mount, signals, network, keys, ...) that Ubuntu is currently carrying, all of which will be RFC'd on top of this. - Notable also is the Infiniband work in SELinux, and the new file:map permission. From Paul: "While we're down to 21 patches for v4.13 (it was 31 for v4.12), the diffstat jumps up tremendously with over 2k of line changes. Almost all of these changes are the SELinux/IB work done by Daniel Jurgens; some other noteworthy changes include a NFS v4.2 labeling fix, a new file:map permission, and reporting of policy capabilities on policy load" There's also now genfscon labeling support for tracefs, which was lost in v4.1 with the separation from debugfs. - Smack incorporates a safer socket check in file_receive, and adds a cap_capable call in privilege check. - TPM as usual has a bunch of fixes and enhancements. - Multiple calls to security_add_hooks() can now be made for the same LSM, to allow LSMs to have hook declarations across multiple files. - IMA now supports different "ima_appraise=" modes (eg. log, fix) from the boot command line. * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (126 commits) apparmor: put back designators in struct initialisers seccomp: Switch from atomic_t to recount_t seccomp: Adjust selftests to avoid double-join seccomp: Clean up core dump logic IMA: update IMA policy documentation to include pcr= option ima: Log the same audit cause whenever a file has no signature ima: Simplify policy_func_show. integrity: Small code improvements ima: fix get_binary_runtime_size() ima: use ima_parse_buf() to parse template data ima: use ima_parse_buf() to parse measurements headers ima: introduce ima_parse_buf() ima: Add cgroups2 to the defaults list ima: use memdup_user_nul ima: fix up #endif comments IMA: Correct Kconfig dependencies for hash selection ima: define is_ima_appraise_enabled() ima: define Kconfig IMA_APPRAISE_BOOTPARAM option ima: define a set of appraisal rules requiring file signatures ima: extend the "ima_policy" boot command line to support multiple policies ...
Diffstat (limited to 'security/apparmor/path.c')
-rw-r--r--security/apparmor/path.c130
1 files changed, 52 insertions, 78 deletions
diff --git a/security/apparmor/path.c b/security/apparmor/path.c
index a8fc7d08c144..9d5de1d05be4 100644
--- a/security/apparmor/path.c
+++ b/security/apparmor/path.c
@@ -50,7 +50,7 @@ static int prepend(char **buffer, int buflen, const char *str, int namelen)
* namespace root.
*/
static int disconnect(const struct path *path, char *buf, char **name,
- int flags)
+ int flags, const char *disconnected)
{
int error = 0;
@@ -63,9 +63,14 @@ static int disconnect(const struct path *path, char *buf, char **name,
error = -EACCES;
if (**name == '/')
*name = *name + 1;
- } else if (**name != '/')
- /* CONNECT_PATH with missing root */
- error = prepend(name, *name - buf, "/", 1);
+ } else {
+ if (**name != '/')
+ /* CONNECT_PATH with missing root */
+ error = prepend(name, *name - buf, "/", 1);
+ if (!error && disconnected)
+ error = prepend(name, *name - buf, disconnected,
+ strlen(disconnected));
+ }
return error;
}
@@ -74,9 +79,9 @@ static int disconnect(const struct path *path, char *buf, char **name,
* d_namespace_path - lookup a name associated with a given path
* @path: path to lookup (NOT NULL)
* @buf: buffer to store path to (NOT NULL)
- * @buflen: length of @buf
* @name: Returns - pointer for start of path name with in @buf (NOT NULL)
* @flags: flags controlling path lookup
+ * @disconnected: string to prefix to disconnected paths
*
* Handle path name lookup.
*
@@ -84,12 +89,14 @@ static int disconnect(const struct path *path, char *buf, char **name,
* When no error the path name is returned in @name which points to
* to a position in @buf
*/
-static int d_namespace_path(const struct path *path, char *buf, int buflen,
- char **name, int flags)
+static int d_namespace_path(const struct path *path, char *buf, char **name,
+ int flags, const char *disconnected)
{
char *res;
int error = 0;
int connected = 1;
+ int isdir = (flags & PATH_IS_DIR) ? 1 : 0;
+ int buflen = aa_g_path_max - isdir;
if (path->mnt->mnt_flags & MNT_INTERNAL) {
/* it's not mounted anywhere */
@@ -104,10 +111,12 @@ static int d_namespace_path(const struct path *path, char *buf, int buflen,
/* TODO: convert over to using a per namespace
* control instead of hard coded /proc
*/
- return prepend(name, *name - buf, "/proc", 5);
+ error = prepend(name, *name - buf, "/proc", 5);
+ goto out;
} else
- return disconnect(path, buf, name, flags);
- return 0;
+ error = disconnect(path, buf, name, flags,
+ disconnected);
+ goto out;
}
/* resolve paths relative to chroot?*/
@@ -126,8 +135,11 @@ static int d_namespace_path(const struct path *path, char *buf, int buflen,
* be returned.
*/
if (!res || IS_ERR(res)) {
- if (PTR_ERR(res) == -ENAMETOOLONG)
- return -ENAMETOOLONG;
+ if (PTR_ERR(res) == -ENAMETOOLONG) {
+ error = -ENAMETOOLONG;
+ *name = buf;
+ goto out;
+ }
connected = 0;
res = dentry_path_raw(path->dentry, buf, buflen);
if (IS_ERR(res)) {
@@ -140,6 +152,9 @@ static int d_namespace_path(const struct path *path, char *buf, int buflen,
*name = res;
+ if (!connected)
+ error = disconnect(path, buf, name, flags, disconnected);
+
/* Handle two cases:
* 1. A deleted dentry && profile is not allowing mediation of deleted
* 2. On some filesystems, newly allocated dentries appear to the
@@ -147,62 +162,30 @@ static int d_namespace_path(const struct path *path, char *buf, int buflen,
* allocated.
*/
if (d_unlinked(path->dentry) && d_is_positive(path->dentry) &&
- !(flags & PATH_MEDIATE_DELETED)) {
+ !(flags & (PATH_MEDIATE_DELETED | PATH_DELEGATE_DELETED))) {
error = -ENOENT;
goto out;
}
- if (!connected)
- error = disconnect(path, buf, name, flags);
-
out:
- return error;
-}
-
-/**
- * get_name_to_buffer - get the pathname to a buffer ensure dir / is appended
- * @path: path to get name for (NOT NULL)
- * @flags: flags controlling path lookup
- * @buffer: buffer to put name in (NOT NULL)
- * @size: size of buffer
- * @name: Returns - contains position of path name in @buffer (NOT NULL)
- *
- * Returns: %0 else error on failure
- */
-static int get_name_to_buffer(const struct path *path, int flags, char *buffer,
- int size, char **name, const char **info)
-{
- int adjust = (flags & PATH_IS_DIR) ? 1 : 0;
- int error = d_namespace_path(path, buffer, size - adjust, name, flags);
-
- if (!error && (flags & PATH_IS_DIR) && (*name)[1] != '\0')
- /*
- * Append "/" to the pathname. The root directory is a special
- * case; it already ends in slash.
- */
- strcpy(&buffer[size - 2], "/");
-
- if (info && error) {
- if (error == -ENOENT)
- *info = "Failed name lookup - deleted entry";
- else if (error == -EACCES)
- *info = "Failed name lookup - disconnected path";
- else if (error == -ENAMETOOLONG)
- *info = "Failed name lookup - name too long";
- else
- *info = "Failed name lookup";
- }
+ /*
+ * Append "/" to the pathname. The root directory is a special
+ * case; it already ends in slash.
+ */
+ if (!error && isdir && ((*name)[1] != '\0' || (*name)[0] != '/'))
+ strcpy(&buf[aa_g_path_max - 2], "/");
return error;
}
/**
- * aa_path_name - compute the pathname of a file
+ * aa_path_name - get the pathname to a buffer ensure dir / is appended
* @path: path the file (NOT NULL)
* @flags: flags controlling path name generation
- * @buffer: buffer that aa_get_name() allocated (NOT NULL)
+ * @buffer: buffer to put name in (NOT NULL)
* @name: Returns - the generated path name if !error (NOT NULL)
* @info: Returns - information on why the path lookup failed (MAYBE NULL)
+ * @disconnected: string to prepend to disconnected paths
*
* @name is a pointer to the beginning of the pathname (which usually differs
* from the beginning of the buffer), or NULL. If there is an error @name
@@ -215,32 +198,23 @@ static int get_name_to_buffer(const struct path *path, int flags, char *buffer,
*
* Returns: %0 else error code if could retrieve name
*/
-int aa_path_name(const struct path *path, int flags, char **buffer,
- const char **name, const char **info)
+int aa_path_name(const struct path *path, int flags, char *buffer,
+ const char **name, const char **info, const char *disconnected)
{
- char *buf, *str = NULL;
- int size = 256;
- int error;
-
- *name = NULL;
- *buffer = NULL;
- for (;;) {
- /* freed by caller */
- buf = kmalloc(size, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- error = get_name_to_buffer(path, flags, buf, size, &str, info);
- if (error != -ENAMETOOLONG)
- break;
-
- kfree(buf);
- size <<= 1;
- if (size > aa_g_path_max)
- return -ENAMETOOLONG;
- *info = NULL;
+ char *str = NULL;
+ int error = d_namespace_path(path, buffer, &str, flags, disconnected);
+
+ if (info && error) {
+ if (error == -ENOENT)
+ *info = "Failed name lookup - deleted entry";
+ else if (error == -EACCES)
+ *info = "Failed name lookup - disconnected path";
+ else if (error == -ENAMETOOLONG)
+ *info = "Failed name lookup - name too long";
+ else
+ *info = "Failed name lookup";
}
- *buffer = buf;
+
*name = str;
return error;