Commit 80a17a5f authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'apparmor-pr-2018-04-10' of...

Merge tag 'apparmor-pr-2018-04-10' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor

Pull apparmor updates from John Johansen:
 "Features:
  - add base infrastructure for socket mediation. ABI bump and
    additional checks to ensure only v8 compliant policy uses socket af
    mediation.
  - improve and cleanup dfa verification
  - improve profile attachment logic
     - improve overlapping expression handling
     - add the xattr matching to the attachment logic
  - improve signal mediation handling with stacked labels
  - improve handling of no_new_privs in a label stack

  Cleanups and changes:
  - use dfa to parse string split
  - bounded version of label_parse
  - proper line wrap nulldfa.in
  - split context out into task and cred naming to better match usage
  - simplify code in aafs

  Bug fixes:
  - fix display of .ns_name for containers
  - fix resource audit messages when auditing peer
  - fix logging of the existence test for signals
  - fix resource audit messages when auditing peer
  - fix display of .ns_name for containers
  - fix an error code in verify_table_headers()
  - fix memory leak on buffer on error exit path
  - fix error returns checks by making size a ssize_t"

* tag 'apparmor-pr-2018-04-10' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor: (36 commits)
  apparmor: fix memory leak on buffer on error exit path
  apparmor: fix dangling symlinks to policy rawdata after replacement
  apparmor: Fix an error code in verify_table_headers()
  apparmor: fix error returns checks by making size a ssize_t
  apparmor: update MAINTAINERS file git and wiki locations
  apparmor: remove POLICY_MEDIATES_SAFE
  apparmor: add base infastructure for socket mediation
  apparmor: improve overlapping domain attachment resolution
  apparmor: convert attaching profiles via xattrs to use dfa matching
  apparmor: Add support for attaching profiles via xattr, presence and value
  apparmor: cleanup: simplify code to get ns symlink name
  apparmor: cleanup create_aafs() error path
  apparmor: dfa split verification of table headers
  apparmor: dfa add support for state differential encoding
  apparmor: dfa move character match into a macro
  apparmor: update domain transitions that are subsets of confinement at nnp
  apparmor: move context.h to cred.h
  apparmor: move task related defines and fns to task.X files
  apparmor: cleanup, drop unused fn __aa_task_is_confined()
  apparmor: cleanup fixup description of aa_replace_profiles
  ...
parents edda4153 588558eb
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -934,8 +934,8 @@ F: drivers/char/apm-emulation.c
APPARMOR SECURITY MODULE
M:	John Johansen <john.johansen@canonical.com>
L:	apparmor@lists.ubuntu.com (subscribers-only, general discussion)
W:	apparmor.wiki.kernel.org
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git
W:	wiki.apparmor.net
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor
S:	Supported
F:	security/apparmor/
F:	Documentation/admin-guide/LSM/apparmor.rst
+1 −0
Original line number Diff line number Diff line
#
# Generated include files
#
net_names.h
capability_names.h
rlim_names.h
+42 −3
Original line number Diff line number Diff line
@@ -3,13 +3,46 @@
#
obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o

apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
apparmor-y := apparmorfs.o audit.o capability.o task.o ipc.o lib.o match.o \
              path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
              resource.o secid.o file.o policy_ns.o label.o mount.o
              resource.o secid.o file.o policy_ns.o label.o mount.o net.o
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o

clean-files := capability_names.h rlim_names.h
clean-files := capability_names.h rlim_names.h net_names.h

# Build a lower case string table of address family names
# Transform lines from
#    #define AF_LOCAL		1	/* POSIX name for AF_UNIX	*/
#    #define AF_INET		2	/* Internet IP Protocol 	*/
# to
#    [1] = "local",
#    [2] = "inet",
#
# and build the securityfs entries for the mapping.
# Transforms lines from
#    #define AF_INET		2	/* Internet IP Protocol 	*/
# to
#    #define AA_SFS_AF_MASK "local inet"
quiet_cmd_make-af = GEN     $@
cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
	sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \
	 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
	echo "};" >> $@ ;\
	printf '%s' '\#define AA_SFS_AF_MASK "' >> $@ ;\
	sed -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \
	 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
	 $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@

# Build a lower case string table of sock type names
# Transform lines from
#    SOCK_STREAM	= 1,
# to
#    [1] = "stream",
quiet_cmd_make-sock = GEN     $@
cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
	sed $^ >>$@ -r -n \
	-e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
	echo "};" >> $@

# Build a lower case string table of capability names
# Transforms lines from
@@ -62,6 +95,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
	    tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@

$(obj)/capability.o : $(obj)/capability_names.h
$(obj)/net.o : $(obj)/net_names.h
$(obj)/resource.o : $(obj)/rlim_names.h
$(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
			    $(src)/Makefile
@@ -69,3 +103,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
$(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
		      $(src)/Makefile
	$(call cmd,make-rlim)
$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
		     $(srctree)/include/linux/net.h \
		     $(src)/Makefile
	$(call cmd,make-af)
	$(call cmd,make-sock)
+127 −76
Original line number Diff line number Diff line
@@ -30,10 +30,9 @@
#include "include/apparmor.h"
#include "include/apparmorfs.h"
#include "include/audit.h"
#include "include/context.h"
#include "include/cred.h"
#include "include/crypto.h"
#include "include/ipc.h"
#include "include/policy_ns.h"
#include "include/label.h"
#include "include/policy.h"
#include "include/policy_ns.h"
@@ -120,9 +119,7 @@ static int aafs_count;

static int aafs_show_path(struct seq_file *seq, struct dentry *dentry)
{
	struct inode *inode = d_inode(dentry);

	seq_printf(seq, "%s:[%lu]", AAFS_NAME, inode->i_ino);
	seq_printf(seq, "%s:[%lu]", AAFS_NAME, d_inode(dentry)->i_ino);
	return 0;
}

@@ -313,6 +310,7 @@ static struct dentry *aafs_create_dir(const char *name, struct dentry *parent)
 * @name: name of dentry to create
 * @parent: parent directory for this dentry
 * @target: if symlink, symlink target string
 * @private: private data
 * @iops: struct of inode_operations that should be used
 *
 * If @target parameter is %NULL, then the @iops parameter needs to be
@@ -321,17 +319,17 @@ static struct dentry *aafs_create_dir(const char *name, struct dentry *parent)
static struct dentry *aafs_create_symlink(const char *name,
					  struct dentry *parent,
					  const char *target,
					  void *private,
					  const struct inode_operations *iops)
{
	struct dentry *dent;
	char *link = NULL;

	if (target) {
		link = kstrdup(target, GFP_KERNEL);
		if (!link)
			return ERR_PTR(-ENOMEM);
	}
	dent = aafs_create(name, S_IFLNK | 0444, parent, NULL, link, NULL,
	dent = aafs_create(name, S_IFLNK | 0444, parent, private, link, NULL,
			   iops);
	if (IS_ERR(dent))
		kfree(link);
@@ -622,7 +620,7 @@ static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms,
			tmp = aa_compute_fperms(dfa, state, &cond);
		}
	} else if (profile->policy.dfa) {
		if (!PROFILE_MEDIATES_SAFE(profile, *match_str))
		if (!PROFILE_MEDIATES(profile, *match_str))
			return;	/* no change to current perms */
		dfa = profile->policy.dfa;
		state = aa_dfa_match_len(dfa, profile->policy.start[0],
@@ -1189,9 +1187,7 @@ static int seq_ns_level_show(struct seq_file *seq, void *v)
static int seq_ns_name_show(struct seq_file *seq, void *v)
{
	struct aa_label *label = begin_current_label_crit_section();

	seq_printf(seq, "%s\n", aa_ns_name(labels_ns(label),
					   labels_ns(label), true));
	seq_printf(seq, "%s\n", labels_ns(label)->base.name);
	end_current_label_crit_section(label);

	return 0;
@@ -1484,26 +1480,97 @@ static int profile_depth(struct aa_profile *profile)
	return depth;
}

static int gen_symlink_name(char *buffer, size_t bsize, int depth,
			    const char *dirname, const char *fname)
static char *gen_symlink_name(int depth, const char *dirname, const char *fname)
{
	char *buffer, *s;
	int error;
	int size = depth * 6 + strlen(dirname) + strlen(fname) + 11;

	s = buffer = kmalloc(size, GFP_KERNEL);
	if (!buffer)
		return ERR_PTR(-ENOMEM);

	for (; depth > 0; depth--) {
		if (bsize < 7)
			return -ENAMETOOLONG;
		strcpy(buffer, "../../");
		buffer += 6;
		bsize -= 6;
		strcpy(s, "../../");
		s += 6;
		size -= 6;
	}

	error = snprintf(buffer, bsize, "raw_data/%s/%s", dirname, fname);
	if (error >= bsize || error < 0)
		return -ENAMETOOLONG;
	error = snprintf(s, size, "raw_data/%s/%s", dirname, fname);
	if (error >= size || error < 0) {
		kfree(buffer);
		return ERR_PTR(-ENAMETOOLONG);
	}

	return 0;
	return buffer;
}

static void rawdata_link_cb(void *arg)
{
	kfree(arg);
}

static const char *rawdata_get_link_base(struct dentry *dentry,
					 struct inode *inode,
					 struct delayed_call *done,
					 const char *name)
{
	struct aa_proxy *proxy = inode->i_private;
	struct aa_label *label;
	struct aa_profile *profile;
	char *target;
	int depth;

	if (!dentry)
		return ERR_PTR(-ECHILD);

	label = aa_get_label_rcu(&proxy->label);
	profile = labels_profile(label);
	depth = profile_depth(profile);
	target = gen_symlink_name(depth, profile->rawdata->name, name);
	aa_put_label(label);

	if (IS_ERR(target))
		return target;

	set_delayed_call(done, rawdata_link_cb, target);

	return target;
}

static const char *rawdata_get_link_sha1(struct dentry *dentry,
					 struct inode *inode,
					 struct delayed_call *done)
{
	return rawdata_get_link_base(dentry, inode, done, "sha1");
}

static const char *rawdata_get_link_abi(struct dentry *dentry,
					struct inode *inode,
					struct delayed_call *done)
{
	return rawdata_get_link_base(dentry, inode, done, "abi");
}

static const char *rawdata_get_link_data(struct dentry *dentry,
					 struct inode *inode,
					 struct delayed_call *done)
{
	return rawdata_get_link_base(dentry, inode, done, "raw_data");
}

static const struct inode_operations rawdata_link_sha1_iops = {
	.get_link	= rawdata_get_link_sha1,
};

static const struct inode_operations rawdata_link_abi_iops = {
	.get_link	= rawdata_get_link_abi,
};
static const struct inode_operations rawdata_link_data_iops = {
	.get_link	= rawdata_get_link_data,
};


/*
 * Requires: @profile->ns->lock held
 */
@@ -1574,34 +1641,28 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
	}

	if (profile->rawdata) {
		char target[64];
		int depth = profile_depth(profile);

		error = gen_symlink_name(target, sizeof(target), depth,
					 profile->rawdata->name, "sha1");
		if (error < 0)
			goto fail2;
		dent = aafs_create_symlink("raw_sha1", dir, target, NULL);
		dent = aafs_create_symlink("raw_sha1", dir, NULL,
					   profile->label.proxy,
					   &rawdata_link_sha1_iops);
		if (IS_ERR(dent))
			goto fail;
		aa_get_proxy(profile->label.proxy);
		profile->dents[AAFS_PROF_RAW_HASH] = dent;

		error = gen_symlink_name(target, sizeof(target), depth,
					 profile->rawdata->name, "abi");
		if (error < 0)
			goto fail2;
		dent = aafs_create_symlink("raw_abi", dir, target, NULL);
		dent = aafs_create_symlink("raw_abi", dir, NULL,
					   profile->label.proxy,
					   &rawdata_link_abi_iops);
		if (IS_ERR(dent))
			goto fail;
		aa_get_proxy(profile->label.proxy);
		profile->dents[AAFS_PROF_RAW_ABI] = dent;

		error = gen_symlink_name(target, sizeof(target), depth,
					 profile->rawdata->name, "raw_data");
		if (error < 0)
			goto fail2;
		dent = aafs_create_symlink("raw_data", dir, target, NULL);
		dent = aafs_create_symlink("raw_data", dir, NULL,
					   profile->label.proxy,
					   &rawdata_link_data_iops);
		if (IS_ERR(dent))
			goto fail;
		aa_get_proxy(profile->label.proxy);
		profile->dents[AAFS_PROF_RAW_DATA] = dent;
	}

@@ -2152,6 +2213,10 @@ static struct aa_sfs_entry aa_sfs_entry_signal[] = {
	{ }
};

static struct aa_sfs_entry aa_sfs_entry_attach[] = {
	AA_SFS_FILE_BOOLEAN("xattr", 1),
	{ }
};
static struct aa_sfs_entry aa_sfs_entry_domain[] = {
	AA_SFS_FILE_BOOLEAN("change_hat",	1),
	AA_SFS_FILE_BOOLEAN("change_hatv",	1),
@@ -2159,6 +2224,9 @@ static struct aa_sfs_entry aa_sfs_entry_domain[] = {
	AA_SFS_FILE_BOOLEAN("change_profile",	1),
	AA_SFS_FILE_BOOLEAN("stack",		1),
	AA_SFS_FILE_BOOLEAN("fix_binfmt_elf_mmap",	1),
	AA_SFS_FILE_BOOLEAN("post_nnp_subset",	1),
	AA_SFS_FILE_BOOLEAN("computed_longest_left",	1),
	AA_SFS_DIR("attach_conditions",		aa_sfs_entry_attach),
	AA_SFS_FILE_STRING("version", "1.2"),
	{ }
};
@@ -2167,6 +2235,7 @@ static struct aa_sfs_entry aa_sfs_entry_versions[] = {
	AA_SFS_FILE_BOOLEAN("v5",	1),
	AA_SFS_FILE_BOOLEAN("v6",	1),
	AA_SFS_FILE_BOOLEAN("v7",	1),
	AA_SFS_FILE_BOOLEAN("v8",	1),
	{ }
};

@@ -2202,6 +2271,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
	AA_SFS_DIR("policy",			aa_sfs_entry_policy),
	AA_SFS_DIR("domain",			aa_sfs_entry_domain),
	AA_SFS_DIR("file",			aa_sfs_entry_file),
	AA_SFS_DIR("network_v8",		aa_sfs_entry_network),
	AA_SFS_DIR("mount",			aa_sfs_entry_mount),
	AA_SFS_DIR("namespaces",		aa_sfs_entry_ns),
	AA_SFS_FILE_U64("capability",		VFS_CAP_FLAGS_MASK),
@@ -2394,29 +2464,18 @@ static const char *policy_get_link(struct dentry *dentry,
	return NULL;
}

static int ns_get_name(char *buf, size_t size, struct aa_ns *ns,
		       struct inode *inode)
{
	int res = snprintf(buf, size, "%s:[%lu]", AAFS_NAME, inode->i_ino);

	if (res < 0 || res >= size)
		res = -ENOENT;

	return res;
}

static int policy_readlink(struct dentry *dentry, char __user *buffer,
			   int buflen)
{
	struct aa_ns *ns;
	char name[32];
	int res;

	ns = aa_get_current_ns();
	res = ns_get_name(name, sizeof(name), ns, d_inode(dentry));
	if (res >= 0)
	res = snprintf(name, sizeof(name), "%s:[%lu]", AAFS_NAME,
		       d_inode(dentry)->i_ino);
	if (res > 0 && res < sizeof(name))
		res = readlink_copy(buffer, buflen, name);
	aa_put_ns(ns);
	else
		res = -ENOENT;

	return res;
}
@@ -2460,34 +2519,26 @@ static int __init aa_create_aafs(void)

	dent = securityfs_create_file(".load", 0666, aa_sfs_entry.dentry,
				      NULL, &aa_fs_profile_load);
	if (IS_ERR(dent)) {
		error = PTR_ERR(dent);
		goto error;
	}
	if (IS_ERR(dent))
		goto dent_error;
	ns_subload(root_ns) = dent;

	dent = securityfs_create_file(".replace", 0666, aa_sfs_entry.dentry,
				      NULL, &aa_fs_profile_replace);
	if (IS_ERR(dent)) {
		error = PTR_ERR(dent);
		goto error;
	}
	if (IS_ERR(dent))
		goto dent_error;
	ns_subreplace(root_ns) = dent;

	dent = securityfs_create_file(".remove", 0666, aa_sfs_entry.dentry,
				      NULL, &aa_fs_profile_remove);
	if (IS_ERR(dent)) {
		error = PTR_ERR(dent);
		goto error;
	}
	if (IS_ERR(dent))
		goto dent_error;
	ns_subremove(root_ns) = dent;

	dent = securityfs_create_file("revision", 0444, aa_sfs_entry.dentry,
				      NULL, &aa_fs_ns_revision_fops);
	if (IS_ERR(dent)) {
		error = PTR_ERR(dent);
		goto error;
	}
	if (IS_ERR(dent))
		goto dent_error;
	ns_subrevision(root_ns) = dent;

	/* policy tree referenced by magic policy symlink */
@@ -2501,10 +2552,8 @@ static int __init aa_create_aafs(void)
	/* magic symlink similar to nsfs redirects based on task policy */
	dent = securityfs_create_symlink("policy", aa_sfs_entry.dentry,
					 NULL, &policy_link_iops);
	if (IS_ERR(dent)) {
		error = PTR_ERR(dent);
		goto error;
	}
	if (IS_ERR(dent))
		goto dent_error;

	error = aa_mk_null_file(aa_sfs_entry.dentry);
	if (error)
@@ -2516,6 +2565,8 @@ static int __init aa_create_aafs(void)
	aa_info_message("AppArmor Filesystem Enabled");
	return 0;

dent_error:
	error = PTR_ERR(dent);
error:
	aa_destroy_aafs();
	AA_ERROR("Error creating AppArmor securityfs\n");
+1 −1
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@

#include "include/apparmor.h"
#include "include/capability.h"
#include "include/context.h"
#include "include/cred.h"
#include "include/policy.h"
#include "include/audit.h"

Loading