aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2010-07-29 17:48:03 -0400
committerJames Morris <jmorris@namei.org>2010-08-02 01:35:13 -0400
commit63e2b423771ab0bc7ad4d407f3f6517c6d05cdc0 (patch)
treee50efc9593c7558d3700ec55869f9ddbac283a1d /security
parente06f75a6a2b43bd3a7a197bd21466f9da130e4af (diff)
AppArmor: userspace interfaces
The /proc/<pid>/attr/* interface is used for process introspection and commands. While the apparmorfs interface is used for global introspection and loading and removing policy. The interface currently only contains the files necessary for loading policy, and will be extended in the future to include sysfs style single per file introspection inteface. The old AppArmor 2.4 interface files have been removed into a compatibility patch, that distros can use to maintain backwards compatibility. Signed-off-by: John Johansen <john.johansen@canonical.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/apparmorfs.c239
-rw-r--r--security/apparmor/include/apparmorfs.h20
-rw-r--r--security/apparmor/include/procattr.h26
-rw-r--r--security/apparmor/procattr.c170
4 files changed, 455 insertions, 0 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
new file mode 100644
index 000000000000..7320331b44ab
--- /dev/null
+++ b/security/apparmor/apparmorfs.c
@@ -0,0 +1,239 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor /sys/kernel/security/apparmor interface functions
5 *
6 * Copyright (C) 1998-2008 Novell/SUSE
7 * Copyright 2009-2010 Canonical Ltd.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation, version 2 of the
12 * License.
13 */
14
15#include <linux/security.h>
16#include <linux/vmalloc.h>
17#include <linux/module.h>
18#include <linux/seq_file.h>
19#include <linux/uaccess.h>
20#include <linux/namei.h>
21
22#include "include/apparmor.h"
23#include "include/apparmorfs.h"
24#include "include/audit.h"
25#include "include/context.h"
26#include "include/policy.h"
27
28/**
29 * aa_simple_write_to_buffer - common routine for getting policy from user
30 * @op: operation doing the user buffer copy
31 * @userbuf: user buffer to copy data from (NOT NULL)
32 * @alloc_size: size of user buffer
33 * @copy_size: size of data to copy from user buffer
34 * @pos: position write is at in the file (NOT NULL)
35 *
36 * Returns: kernel buffer containing copy of user buffer data or an
37 * ERR_PTR on failure.
38 */
39static char *aa_simple_write_to_buffer(int op, const char __user *userbuf,
40 size_t alloc_size, size_t copy_size,
41 loff_t *pos)
42{
43 char *data;
44
45 if (*pos != 0)
46 /* only writes from pos 0, that is complete writes */
47 return ERR_PTR(-ESPIPE);
48
49 /*
50 * Don't allow profile load/replace/remove from profiles that don't
51 * have CAP_MAC_ADMIN
52 */
53 if (!aa_may_manage_policy(op))
54 return ERR_PTR(-EACCES);
55
56 /* freed by caller to simple_write_to_buffer */
57 data = kvmalloc(alloc_size);
58 if (data == NULL)
59 return ERR_PTR(-ENOMEM);
60
61 if (copy_from_user(data, userbuf, copy_size)) {
62 kvfree(data);
63 return ERR_PTR(-EFAULT);
64 }
65
66 return data;
67}
68
69
70/* .load file hook fn to load policy */
71static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
72 loff_t *pos)
73{
74 char *data;
75 ssize_t error;
76
77 data = aa_simple_write_to_buffer(OP_PROF_LOAD, buf, size, size, pos);
78
79 error = PTR_ERR(data);
80 if (!IS_ERR(data)) {
81 error = aa_replace_profiles(data, size, PROF_ADD);
82 kvfree(data);
83 }
84
85 return error;
86}
87
88static const struct file_operations aa_fs_profile_load = {
89 .write = profile_load
90};
91
92/* .replace file hook fn to load and/or replace policy */
93static ssize_t profile_replace(struct file *f, const char __user *buf,
94 size_t size, loff_t *pos)
95{
96 char *data;
97 ssize_t error;
98
99 data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos);
100 error = PTR_ERR(data);
101 if (!IS_ERR(data)) {
102 error = aa_replace_profiles(data, size, PROF_REPLACE);
103 kvfree(data);
104 }
105
106 return error;
107}
108
109static const struct file_operations aa_fs_profile_replace = {
110 .write = profile_replace
111};
112
113/* .remove file hook fn to remove loaded policy */
114static ssize_t profile_remove(struct file *f, const char __user *buf,
115 size_t size, loff_t *pos)
116{
117 char *data;
118 ssize_t error;
119
120 /*
121 * aa_remove_profile needs a null terminated string so 1 extra
122 * byte is allocated and the copied data is null terminated.
123 */
124 data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size, pos);
125
126 error = PTR_ERR(data);
127 if (!IS_ERR(data)) {
128 data[size] = 0;
129 error = aa_remove_profiles(data, size);
130 kvfree(data);
131 }
132
133 return error;
134}
135
136static const struct file_operations aa_fs_profile_remove = {
137 .write = profile_remove
138};
139
140/** Base file system setup **/
141
142static struct dentry *aa_fs_dentry __initdata;
143
144static void __init aafs_remove(const char *name)
145{
146 struct dentry *dentry;
147
148 dentry = lookup_one_len(name, aa_fs_dentry, strlen(name));
149 if (!IS_ERR(dentry)) {
150 securityfs_remove(dentry);
151 dput(dentry);
152 }
153}
154
155/**
156 * aafs_create - create an entry in the apparmor filesystem
157 * @name: name of the entry (NOT NULL)
158 * @mask: file permission mask of the file
159 * @fops: file operations for the file (NOT NULL)
160 *
161 * Used aafs_remove to remove entries created with this fn.
162 */
163static int __init aafs_create(const char *name, int mask,
164 const struct file_operations *fops)
165{
166 struct dentry *dentry;
167
168 dentry = securityfs_create_file(name, S_IFREG | mask, aa_fs_dentry,
169 NULL, fops);
170
171 return IS_ERR(dentry) ? PTR_ERR(dentry) : 0;
172}
173
174/**
175 * aa_destroy_aafs - cleanup and free aafs
176 *
177 * releases dentries allocated by aa_create_aafs
178 */
179void __init aa_destroy_aafs(void)
180{
181 if (aa_fs_dentry) {
182 aafs_remove(".remove");
183 aafs_remove(".replace");
184 aafs_remove(".load");
185
186 securityfs_remove(aa_fs_dentry);
187 aa_fs_dentry = NULL;
188 }
189}
190
191/**
192 * aa_create_aafs - create the apparmor security filesystem
193 *
194 * dentries created here are released by aa_destroy_aafs
195 *
196 * Returns: error on failure
197 */
198int __init aa_create_aafs(void)
199{
200 int error;
201
202 if (!apparmor_initialized)
203 return 0;
204
205 if (aa_fs_dentry) {
206 AA_ERROR("%s: AppArmor securityfs already exists\n", __func__);
207 return -EEXIST;
208 }
209
210 aa_fs_dentry = securityfs_create_dir("apparmor", NULL);
211 if (IS_ERR(aa_fs_dentry)) {
212 error = PTR_ERR(aa_fs_dentry);
213 aa_fs_dentry = NULL;
214 goto error;
215 }
216
217 error = aafs_create(".load", 0640, &aa_fs_profile_load);
218 if (error)
219 goto error;
220 error = aafs_create(".replace", 0640, &aa_fs_profile_replace);
221 if (error)
222 goto error;
223 error = aafs_create(".remove", 0640, &aa_fs_profile_remove);
224 if (error)
225 goto error;
226
227 /* TODO: add support for apparmorfs_null and apparmorfs_mnt */
228
229 /* Report that AppArmor fs is enabled */
230 aa_info_message("AppArmor Filesystem Enabled");
231 return 0;
232
233error:
234 aa_destroy_aafs();
235 AA_ERROR("Error creating AppArmor securityfs\n");
236 return error;
237}
238
239fs_initcall(aa_create_aafs);
diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h
new file mode 100644
index 000000000000..cb1e93a114d7
--- /dev/null
+++ b/security/apparmor/include/apparmorfs.h
@@ -0,0 +1,20 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor filesystem definitions.
5 *
6 * Copyright (C) 1998-2008 Novell/SUSE
7 * Copyright 2009-2010 Canonical Ltd.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation, version 2 of the
12 * License.
13 */
14
15#ifndef __AA_APPARMORFS_H
16#define __AA_APPARMORFS_H
17
18extern void __init aa_destroy_aafs(void);
19
20#endif /* __AA_APPARMORFS_H */
diff --git a/security/apparmor/include/procattr.h b/security/apparmor/include/procattr.h
new file mode 100644
index 000000000000..544aa6b766a4
--- /dev/null
+++ b/security/apparmor/include/procattr.h
@@ -0,0 +1,26 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor /proc/<pid>/attr/ interface function definitions.
5 *
6 * Copyright (C) 1998-2008 Novell/SUSE
7 * Copyright 2009-2010 Canonical Ltd.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation, version 2 of the
12 * License.
13 */
14
15#ifndef __AA_PROCATTR_H
16#define __AA_PROCATTR_H
17
18#define AA_DO_TEST 1
19#define AA_ONEXEC 1
20
21int aa_getprocattr(struct aa_profile *profile, char **string);
22int aa_setprocattr_changehat(char *args, size_t size, int test);
23int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test);
24int aa_setprocattr_permipc(char *fqname);
25
26#endif /* __AA_PROCATTR_H */
diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c
new file mode 100644
index 000000000000..04a2cf8d1b65
--- /dev/null
+++ b/security/apparmor/procattr.c
@@ -0,0 +1,170 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor /proc/<pid>/attr/ interface functions
5 *
6 * Copyright (C) 1998-2008 Novell/SUSE
7 * Copyright 2009-2010 Canonical Ltd.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation, version 2 of the
12 * License.
13 */
14
15#include "include/apparmor.h"
16#include "include/context.h"
17#include "include/policy.h"
18#include "include/domain.h"
19
20
21/**
22 * aa_getprocattr - Return the profile information for @profile
23 * @profile: the profile to print profile info about (NOT NULL)
24 * @string: Returns - string containing the profile info (NOT NULL)
25 *
26 * Returns: length of @string on success else error on failure
27 *
28 * Requires: profile != NULL
29 *
30 * Creates a string containing the namespace_name://profile_name for
31 * @profile.
32 *
33 * Returns: size of string placed in @string else error code on failure
34 */
35int aa_getprocattr(struct aa_profile *profile, char **string)
36{
37 char *str;
38 int len = 0, mode_len = 0, ns_len = 0, name_len;
39 const char *mode_str = profile_mode_names[profile->mode];
40 const char *ns_name = NULL;
41 struct aa_namespace *ns = profile->ns;
42 struct aa_namespace *current_ns = __aa_current_profile()->ns;
43 char *s;
44
45 if (!aa_ns_visible(current_ns, ns))
46 return -EACCES;
47
48 ns_name = aa_ns_name(current_ns, ns);
49 ns_len = strlen(ns_name);
50
51 /* if the visible ns_name is > 0 increase size for : :// seperator */
52 if (ns_len)
53 ns_len += 4;
54
55 /* unconfined profiles don't have a mode string appended */
56 if (!unconfined(profile))
57 mode_len = strlen(mode_str) + 3; /* + 3 for _() */
58
59 name_len = strlen(profile->base.hname);
60 len = mode_len + ns_len + name_len + 1; /* + 1 for \n */
61 s = str = kmalloc(len + 1, GFP_KERNEL); /* + 1 \0 */
62 if (!str)
63 return -ENOMEM;
64
65 if (ns_len) {
66 /* skip over prefix current_ns->base.hname and separating // */
67 sprintf(s, ":%s://", ns_name);
68 s += ns_len;
69 }
70 if (unconfined(profile))
71 /* mode string not being appended */
72 sprintf(s, "%s\n", profile->base.hname);
73 else
74 sprintf(s, "%s (%s)\n", profile->base.hname, mode_str);
75 *string = str;
76
77 /* NOTE: len does not include \0 of string, not saved as part of file */
78 return len;
79}
80
81/**
82 * split_token_from_name - separate a string of form <token>^<name>
83 * @op: operation being checked
84 * @args: string to parse (NOT NULL)
85 * @token: stores returned parsed token value (NOT NULL)
86 *
87 * Returns: start position of name after token else NULL on failure
88 */
89static char *split_token_from_name(int op, char *args, u64 * token)
90{
91 char *name;
92
93 *token = simple_strtoull(args, &name, 16);
94 if ((name == args) || *name != '^') {
95 AA_ERROR("%s: Invalid input '%s'", op_table[op], args);
96 return ERR_PTR(-EINVAL);
97 }
98
99 name++; /* skip ^ */
100 if (!*name)
101 name = NULL;
102 return name;
103}
104
105/**
106 * aa_setprocattr_chagnehat - handle procattr interface to change_hat
107 * @args: args received from writing to /proc/<pid>/attr/current (NOT NULL)
108 * @size: size of the args
109 * @test: true if this is a test of change_hat permissions
110 *
111 * Returns: %0 or error code if change_hat fails
112 */
113int aa_setprocattr_changehat(char *args, size_t size, int test)
114{
115 char *hat;
116 u64 token;
117 const char *hats[16]; /* current hard limit on # of names */
118 int count = 0;
119
120 hat = split_token_from_name(OP_CHANGE_HAT, args, &token);
121 if (IS_ERR(hat))
122 return PTR_ERR(hat);
123
124 if (!hat && !token) {
125 AA_ERROR("change_hat: Invalid input, NULL hat and NULL magic");
126 return -EINVAL;
127 }
128
129 if (hat) {
130 /* set up hat name vector, args guaranteed null terminated
131 * at args[size] by setprocattr.
132 *
133 * If there are multiple hat names in the buffer each is
134 * separated by a \0. Ie. userspace writes them pre tokenized
135 */
136 char *end = args + size;
137 for (count = 0; (hat < end) && count < 16; ++count) {
138 char *next = hat + strlen(hat) + 1;
139 hats[count] = hat;
140 hat = next;
141 }
142 }
143
144 AA_DEBUG("%s: Magic 0x%llx Hat '%s'\n",
145 __func__, token, hat ? hat : NULL);
146
147 return aa_change_hat(hats, count, token, test);
148}
149
150/**
151 * aa_setprocattr_changeprofile - handle procattr interface to changeprofile
152 * @fqname: args received from writting to /proc/<pid>/attr/current (NOT NULL)
153 * @onexec: true if change_profile should be delayed until exec
154 * @test: true if this is a test of change_profile permissions
155 *
156 * Returns: %0 or error code if change_profile fails
157 */
158int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test)
159{
160 char *name, *ns_name;
161
162 name = aa_split_fqname(fqname, &ns_name);
163 return aa_change_profile(ns_name, name, onexec, test);
164}
165
166int aa_setprocattr_permipc(char *fqname)
167{
168 /* TODO: add ipc permission querying */
169 return -ENOTSUPP;
170}