[apparmor] [RFC v2] "features" directory for version/capability information

Kees Cook kees at ubuntu.com
Fri Dec 30 00:46:18 UTC 2011


AppArmor: implement static feature reporting interface

This adds the ability to query the internal versions of the various
policy features of AppArmor.

Signed-off-by: Kees Cook <kees at ubuntu.com>
---
v2:
 - start using enum/union for display values.
v1:
 - initial patch.
---

diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 0848292..9f54625 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -18,6 +18,7 @@
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
 #include <linux/namei.h>
+#include <linux/capability.h>
 
 #include "include/apparmor.h"
 #include "include/apparmorfs.h"
@@ -146,11 +147,104 @@ static const struct file_operations aa_fs_profile_remove = {
 
 static struct dentry *aa_fs_dentry __initdata;
 
-static void __init aafs_remove(const char *name)
+enum aa_fs_value {
+	AA_FS_STRING,
+	AA_FS_BOOLEAN,
+	AA_FS_U64,
+};
+
+struct aa_fs_file {
+	char *name;
+	enum aa_fs_value v_type;
+	union {
+		char *string;
+		unsigned long u64;
+		bool boolean;
+	} v;
+	const struct file_operations *file_ops;
+};
+
+struct aa_fs_dir {
+	const char *name;
+	struct dentry *dentry;
+	struct aa_fs_file *files;
+};
+
+static int aa_fs_seq_show(struct seq_file *seq, void *v)
+{
+	struct aa_fs_file *fs_file = seq->private;
+
+	if (!fs_file)
+		return 0;
+
+	switch (fs_file->v_type) {
+		case AA_FS_STRING:
+			seq_printf(seq, "%s\n", fs_file->v.string);
+			break;
+		case AA_FS_U64:
+			seq_printf(seq, "%#08lx\n", fs_file->v.u64);
+			break;
+		case AA_FS_BOOLEAN:
+			seq_printf(seq, "%s\n", fs_file->v.boolean ?
+						"yes" : "no");
+			break;
+	}
+
+	return 0;
+}
+
+static int aa_fs_seq_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, aa_fs_seq_show, inode->i_private);
+}
+
+static const struct file_operations aa_fs_seq_file_ops = {
+	.owner		= THIS_MODULE,
+	.open		= aa_fs_seq_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+#define AA_FS_STRING_FILE(name, value) \
+	{ name, \
+	  .v_type = AA_FS_STRING, .v.string = value, \
+	  &aa_fs_seq_file_ops }
+#define AA_FS_BOOLEAN_FILE(name, value) \
+	{ name, \
+	  .v_type = AA_FS_BOOLEAN, .v.boolean = value, \
+	  &aa_fs_seq_file_ops }
+#define AA_FS_U64_FILE(name, value) \
+	{ name, \
+	  .v_type = AA_FS_U64, .v.u64 = value, \
+	  &aa_fs_seq_file_ops }
+static struct aa_fs_file aa_fs_features_files[] = {
+	AA_FS_BOOLEAN_FILE("change_hat",	1),
+	AA_FS_BOOLEAN_FILE("change_hatv",	1),
+	AA_FS_BOOLEAN_FILE("change_onexec",	1),
+	AA_FS_BOOLEAN_FILE("change_profile",	1),
+	AA_FS_BOOLEAN_FILE("namespaces",	1),
+	AA_FS_BOOLEAN_FILE("network",		0),
+	AA_FS_STRING_FILE("file",		"3.1"),
+	AA_FS_STRING_FILE("rlimit",		"1.1"),
+	AA_FS_U64_FILE("capability",		VFS_CAP_FLAGS_MASK),
+	{ }
+};
+#undef AA_FS_STRING_FILE
+
+static struct aa_fs_dir aa_fs_dirs[] = {
+	{ "features", NULL, aa_fs_features_files },
+	{ }
+};
+
+static void __init aafs_remove(const char *name, struct dentry *dir_dentry)
 {
 	struct dentry *dentry;
 
-	dentry = lookup_one_len(name, aa_fs_dentry, strlen(name));
+	if (!dir_dentry)
+		return;
+
+	dentry = lookup_one_len(name, dir_dentry, strlen(name));
 	if (!IS_ERR(dentry)) {
 		securityfs_remove(dentry);
 		dput(dentry);
@@ -166,12 +260,14 @@ static void __init aafs_remove(const char *name)
  * Used aafs_remove to remove entries created with this fn.
  */
 static int __init aafs_create(const char *name, int mask,
+			      struct dentry *dir_dentry,
+			      void *data,
 			      const struct file_operations *fops)
 {
 	struct dentry *dentry;
 
-	dentry = securityfs_create_file(name, S_IFREG | mask, aa_fs_dentry,
-					NULL, fops);
+	dentry = securityfs_create_file(name, S_IFREG | mask, dir_dentry,
+					data, fops);
 
 	return IS_ERR(dentry) ? PTR_ERR(dentry) : 0;
 }
@@ -184,9 +280,21 @@ static int __init aafs_create(const char *name, int mask,
 void __init aa_destroy_aafs(void)
 {
 	if (aa_fs_dentry) {
-		aafs_remove(".remove");
-		aafs_remove(".replace");
-		aafs_remove(".load");
+		struct aa_fs_dir *fs_dir;
+
+		aafs_remove(".remove", aa_fs_dentry);
+		aafs_remove(".replace", aa_fs_dentry);
+		aafs_remove(".load", aa_fs_dentry);
+
+		for (fs_dir = aa_fs_dirs; fs_dir->name; ++fs_dir) {
+			struct aa_fs_file *fs_file;
+
+			for (fs_file = fs_dir->files; fs_file->name; ++fs_file)
+				aafs_remove(fs_file->name, fs_dir->dentry);
+
+			aafs_remove(fs_dir->name, aa_fs_dentry);
+			fs_dir->dentry = NULL;
+		}
 
 		securityfs_remove(aa_fs_dentry);
 		aa_fs_dentry = NULL;
@@ -203,6 +311,7 @@ void __init aa_destroy_aafs(void)
 int __init aa_create_aafs(void)
 {
 	int error;
+	struct aa_fs_dir *fs_dir;
 
 	if (!apparmor_initialized)
 		return 0;
@@ -219,16 +328,39 @@ int __init aa_create_aafs(void)
 		goto error;
 	}
 
-	error = aafs_create(".load", 0640, &aa_fs_profile_load);
+	error = aafs_create(".load", 0640, aa_fs_dentry, NULL,
+			    &aa_fs_profile_load);
 	if (error)
 		goto error;
-	error = aafs_create(".replace", 0640, &aa_fs_profile_replace);
+	error = aafs_create(".replace", 0640, aa_fs_dentry, NULL,
+			    &aa_fs_profile_replace);
 	if (error)
 		goto error;
-	error = aafs_create(".remove", 0640, &aa_fs_profile_remove);
+	error = aafs_create(".remove", 0640, aa_fs_dentry, NULL,
+			    &aa_fs_profile_remove);
 	if (error)
 		goto error;
 
+	for (fs_dir = aa_fs_dirs; fs_dir->name; ++fs_dir) {
+		struct aa_fs_file *fs_file;
+
+		fs_dir->dentry = securityfs_create_dir(fs_dir->name,
+						       aa_fs_dentry);
+		if (IS_ERR(fs_dir->dentry)) {
+			error = PTR_ERR(fs_dir->dentry);
+			fs_dir->dentry = NULL;
+			goto error;
+		}
+
+		for (fs_file = fs_dir->files; fs_file->name; ++fs_file) {
+			error = aafs_create(fs_file->name, 0444,
+					    fs_dir->dentry, fs_file,
+					    fs_file->file_ops);
+			if (error)
+				goto error;
+		}
+	}
+
 	/* TODO: add support for apparmorfs_null and apparmorfs_mnt */
 
 	/* Report that AppArmor fs is enabled */

-- 
Kees Cook



More information about the AppArmor mailing list