aboutsummaryrefslogtreecommitdiffstats
path: root/security/apparmor
diff options
context:
space:
mode:
Diffstat (limited to 'security/apparmor')
-rw-r--r--security/apparmor/.gitignore5
-rw-r--r--security/apparmor/Kconfig31
-rw-r--r--security/apparmor/Makefile24
-rw-r--r--security/apparmor/apparmorfs.c239
-rw-r--r--security/apparmor/audit.c215
-rw-r--r--security/apparmor/capability.c141
-rw-r--r--security/apparmor/context.c216
-rw-r--r--security/apparmor/domain.c823
-rw-r--r--security/apparmor/file.c457
-rw-r--r--security/apparmor/include/apparmor.h92
-rw-r--r--security/apparmor/include/apparmorfs.h20
-rw-r--r--security/apparmor/include/audit.h123
-rw-r--r--security/apparmor/include/capability.h45
-rw-r--r--security/apparmor/include/context.h154
-rw-r--r--security/apparmor/include/domain.h36
-rw-r--r--security/apparmor/include/file.h217
-rw-r--r--security/apparmor/include/ipc.h28
-rw-r--r--security/apparmor/include/match.h132
-rw-r--r--security/apparmor/include/path.h31
-rw-r--r--security/apparmor/include/policy.h305
-rw-r--r--security/apparmor/include/policy_unpack.h20
-rw-r--r--security/apparmor/include/procattr.h26
-rw-r--r--security/apparmor/include/resource.h46
-rw-r--r--security/apparmor/include/sid.h24
-rw-r--r--security/apparmor/ipc.c114
-rw-r--r--security/apparmor/lib.c133
-rw-r--r--security/apparmor/lsm.c938
-rw-r--r--security/apparmor/match.c353
-rw-r--r--security/apparmor/path.c235
-rw-r--r--security/apparmor/policy.c1184
-rw-r--r--security/apparmor/policy_unpack.c703
-rw-r--r--security/apparmor/procattr.c170
-rw-r--r--security/apparmor/resource.c134
-rw-r--r--security/apparmor/sid.c55
34 files changed, 7469 insertions, 0 deletions
diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
new file mode 100644
index 00000000000..0a0a99f3b08
--- /dev/null
+++ b/security/apparmor/.gitignore
@@ -0,0 +1,5 @@
1#
2# Generated include files
3#
4af_names.h
5capability_names.h
diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig
new file mode 100644
index 00000000000..9b9013b2e32
--- /dev/null
+++ b/security/apparmor/Kconfig
@@ -0,0 +1,31 @@
1config SECURITY_APPARMOR
2 bool "AppArmor support"
3 depends on SECURITY && NET
4 select AUDIT
5 select SECURITY_PATH
6 select SECURITYFS
7 select SECURITY_NETWORK
8 default n
9 help
10 This enables the AppArmor security module.
11 Required userspace tools (if they are not included in your
12 distribution) and further information may be found at
13 http://apparmor.wiki.kernel.org
14
15 If you are unsure how to answer this question, answer N.
16
17config SECURITY_APPARMOR_BOOTPARAM_VALUE
18 int "AppArmor boot parameter default value"
19 depends on SECURITY_APPARMOR
20 range 0 1
21 default 1
22 help
23 This option sets the default value for the kernel parameter
24 'apparmor', which allows AppArmor to be enabled or disabled
25 at boot. If this option is set to 0 (zero), the AppArmor
26 kernel parameter will default to 0, disabling AppArmor at
27 boot. If this option is set to 1 (one), the AppArmor
28 kernel parameter will default to 1, enabling AppArmor at
29 boot.
30
31 If you are unsure how to answer this question, answer 1.
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
new file mode 100644
index 00000000000..f204869399e
--- /dev/null
+++ b/security/apparmor/Makefile
@@ -0,0 +1,24 @@
1# Makefile for AppArmor Linux Security Module
2#
3obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
4
5apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
6 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
7 resource.o sid.o file.o
8
9clean-files: capability_names.h af_names.h
10
11quiet_cmd_make-caps = GEN $@
12cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ; sed -n -e "/CAP_FS_MASK/d" -e "s/^\#define[ \\t]\\+CAP_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\$$/[\\2] = \"\\1\",/p" $< | tr A-Z a-z >> $@ ; echo "};" >> $@
13
14quiet_cmd_make-rlim = GEN $@
15cmd_make-rlim = echo "static const char *rlim_names[] = {" > $@ ; sed -n --e "/AF_MAX/d" -e "s/^\# \\?define[ \\t]\\+RLIMIT_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/[\\2] = \"\\1\",/p" $< | tr A-Z a-z >> $@ ; echo "};" >> $@ ; echo "static const int rlim_map[] = {" >> $@ ; sed -n -e "/AF_MAX/d" -e "s/^\# \\?define[ \\t]\\+\\(RLIMIT_[A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/\\1,/p" $< >> $@ ; echo "};" >> $@
16
17$(obj)/capability.o : $(obj)/capability_names.h
18$(obj)/resource.o : $(obj)/rlim_names.h
19$(obj)/capability_names.h : $(srctree)/include/linux/capability.h
20 $(call cmd,make-caps)
21$(obj)/af_names.h : $(srctree)/include/linux/socket.h
22 $(call cmd,make-af)
23$(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h
24 $(call cmd,make-rlim)
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
new file mode 100644
index 00000000000..7320331b44a
--- /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/audit.c b/security/apparmor/audit.c
new file mode 100644
index 00000000000..96502b22b26
--- /dev/null
+++ b/security/apparmor/audit.c
@@ -0,0 +1,215 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor auditing 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/audit.h>
16#include <linux/socket.h>
17
18#include "include/apparmor.h"
19#include "include/audit.h"
20#include "include/policy.h"
21
22const char *op_table[] = {
23 "null",
24
25 "sysctl",
26 "capable",
27
28 "unlink",
29 "mkdir",
30 "rmdir",
31 "mknod",
32 "truncate",
33 "link",
34 "symlink",
35 "rename_src",
36 "rename_dest",
37 "chmod",
38 "chown",
39 "getattr",
40 "open",
41
42 "file_perm",
43 "file_lock",
44 "file_mmap",
45 "file_mprotect",
46
47 "create",
48 "post_create",
49 "bind",
50 "connect",
51 "listen",
52 "accept",
53 "sendmsg",
54 "recvmsg",
55 "getsockname",
56 "getpeername",
57 "getsockopt",
58 "setsockopt",
59 "socket_shutdown",
60
61 "ptrace",
62
63 "exec",
64 "change_hat",
65 "change_profile",
66 "change_onexec",
67
68 "setprocattr",
69 "setrlimit",
70
71 "profile_replace",
72 "profile_load",
73 "profile_remove"
74};
75
76const char *audit_mode_names[] = {
77 "normal",
78 "quiet_denied",
79 "quiet",
80 "noquiet",
81 "all"
82};
83
84static char *aa_audit_type[] = {
85 "AUDIT",
86 "ALLOWED",
87 "DENIED",
88 "HINT",
89 "STATUS",
90 "ERROR",
91 "KILLED"
92};
93
94/*
95 * Currently AppArmor auditing is fed straight into the audit framework.
96 *
97 * TODO:
98 * netlink interface for complain mode
99 * user auditing, - send user auditing to netlink interface
100 * system control of whether user audit messages go to system log
101 */
102
103/**
104 * audit_base - core AppArmor function.
105 * @ab: audit buffer to fill (NOT NULL)
106 * @ca: audit structure containing data to audit (NOT NULL)
107 *
108 * Record common AppArmor audit data from @sa
109 */
110static void audit_pre(struct audit_buffer *ab, void *ca)
111{
112 struct common_audit_data *sa = ca;
113 struct task_struct *tsk = sa->tsk ? sa->tsk : current;
114
115 if (aa_g_audit_header) {
116 audit_log_format(ab, "apparmor=");
117 audit_log_string(ab, aa_audit_type[sa->aad.type]);
118 }
119
120 if (sa->aad.op) {
121 audit_log_format(ab, " operation=");
122 audit_log_string(ab, op_table[sa->aad.op]);
123 }
124
125 if (sa->aad.info) {
126 audit_log_format(ab, " info=");
127 audit_log_string(ab, sa->aad.info);
128 if (sa->aad.error)
129 audit_log_format(ab, " error=%d", sa->aad.error);
130 }
131
132 if (sa->aad.profile) {
133 struct aa_profile *profile = sa->aad.profile;
134 pid_t pid;
135 rcu_read_lock();
136 pid = tsk->real_parent->pid;
137 rcu_read_unlock();
138 audit_log_format(ab, " parent=%d", pid);
139 if (profile->ns != root_ns) {
140 audit_log_format(ab, " namespace=");
141 audit_log_untrustedstring(ab, profile->ns->base.hname);
142 }
143 audit_log_format(ab, " profile=");
144 audit_log_untrustedstring(ab, profile->base.hname);
145 }
146
147 if (sa->aad.name) {
148 audit_log_format(ab, " name=");
149 audit_log_untrustedstring(ab, sa->aad.name);
150 }
151}
152
153/**
154 * aa_audit_msg - Log a message to the audit subsystem
155 * @sa: audit event structure (NOT NULL)
156 * @cb: optional callback fn for type specific fields (MAYBE NULL)
157 */
158void aa_audit_msg(int type, struct common_audit_data *sa,
159 void (*cb) (struct audit_buffer *, void *))
160{
161 sa->aad.type = type;
162 sa->lsm_pre_audit = audit_pre;
163 sa->lsm_post_audit = cb;
164 common_lsm_audit(sa);
165}
166
167/**
168 * aa_audit - Log a profile based audit event to the audit subsystem
169 * @type: audit type for the message
170 * @profile: profile to check against (NOT NULL)
171 * @gfp: allocation flags to use
172 * @sa: audit event (NOT NULL)
173 * @cb: optional callback fn for type specific fields (MAYBE NULL)
174 *
175 * Handle default message switching based off of audit mode flags
176 *
177 * Returns: error on failure
178 */
179int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
180 struct common_audit_data *sa,
181 void (*cb) (struct audit_buffer *, void *))
182{
183 BUG_ON(!profile);
184
185 if (type == AUDIT_APPARMOR_AUTO) {
186 if (likely(!sa->aad.error)) {
187 if (AUDIT_MODE(profile) != AUDIT_ALL)
188 return 0;
189 type = AUDIT_APPARMOR_AUDIT;
190 } else if (COMPLAIN_MODE(profile))
191 type = AUDIT_APPARMOR_ALLOWED;
192 else
193 type = AUDIT_APPARMOR_DENIED;
194 }
195 if (AUDIT_MODE(profile) == AUDIT_QUIET ||
196 (type == AUDIT_APPARMOR_DENIED &&
197 AUDIT_MODE(profile) == AUDIT_QUIET))
198 return sa->aad.error;
199
200 if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
201 type = AUDIT_APPARMOR_KILL;
202
203 if (!unconfined(profile))
204 sa->aad.profile = profile;
205
206 aa_audit_msg(type, sa, cb);
207
208 if (sa->aad.type == AUDIT_APPARMOR_KILL)
209 (void)send_sig_info(SIGKILL, NULL, sa->tsk ? sa->tsk : current);
210
211 if (sa->aad.type == AUDIT_APPARMOR_ALLOWED)
212 return complain_error(sa->aad.error);
213
214 return sa->aad.error;
215}
diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c
new file mode 100644
index 00000000000..9982c48def4
--- /dev/null
+++ b/security/apparmor/capability.c
@@ -0,0 +1,141 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor capability mediation 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/capability.h>
16#include <linux/errno.h>
17#include <linux/gfp.h>
18
19#include "include/apparmor.h"
20#include "include/capability.h"
21#include "include/context.h"
22#include "include/policy.h"
23#include "include/audit.h"
24
25/*
26 * Table of capability names: we generate it from capabilities.h.
27 */
28#include "capability_names.h"
29
30struct audit_cache {
31 struct aa_profile *profile;
32 kernel_cap_t caps;
33};
34
35static DEFINE_PER_CPU(struct audit_cache, audit_cache);
36
37/**
38 * audit_cb - call back for capability components of audit struct
39 * @ab - audit buffer (NOT NULL)
40 * @va - audit struct to audit data from (NOT NULL)
41 */
42static void audit_cb(struct audit_buffer *ab, void *va)
43{
44 struct common_audit_data *sa = va;
45 audit_log_format(ab, " capname=");
46 audit_log_untrustedstring(ab, capability_names[sa->u.cap]);
47}
48
49/**
50 * audit_caps - audit a capability
51 * @profile: profile confining task (NOT NULL)
52 * @task: task capability test was performed against (NOT NULL)
53 * @cap: capability tested
54 * @error: error code returned by test
55 *
56 * Do auditing of capability and handle, audit/complain/kill modes switching
57 * and duplicate message elimination.
58 *
59 * Returns: 0 or sa->error on success, error code on failure
60 */
61static int audit_caps(struct aa_profile *profile, struct task_struct *task,
62 int cap, int error)
63{
64 struct audit_cache *ent;
65 int type = AUDIT_APPARMOR_AUTO;
66 struct common_audit_data sa;
67 COMMON_AUDIT_DATA_INIT(&sa, CAP);
68 sa.tsk = task;
69 sa.u.cap = cap;
70 sa.aad.op = OP_CAPABLE;
71 sa.aad.error = error;
72
73 if (likely(!error)) {
74 /* test if auditing is being forced */
75 if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
76 !cap_raised(profile->caps.audit, cap)))
77 return 0;
78 type = AUDIT_APPARMOR_AUDIT;
79 } else if (KILL_MODE(profile) ||
80 cap_raised(profile->caps.kill, cap)) {
81 type = AUDIT_APPARMOR_KILL;
82 } else if (cap_raised(profile->caps.quiet, cap) &&
83 AUDIT_MODE(profile) != AUDIT_NOQUIET &&
84 AUDIT_MODE(profile) != AUDIT_ALL) {
85 /* quiet auditing */
86 return error;
87 }
88
89 /* Do simple duplicate message elimination */
90 ent = &get_cpu_var(audit_cache);
91 if (profile == ent->profile && cap_raised(ent->caps, cap)) {
92 put_cpu_var(audit_cache);
93 if (COMPLAIN_MODE(profile))
94 return complain_error(error);
95 return error;
96 } else {
97 aa_put_profile(ent->profile);
98 ent->profile = aa_get_profile(profile);
99 cap_raise(ent->caps, cap);
100 }
101 put_cpu_var(audit_cache);
102
103 return aa_audit(type, profile, GFP_ATOMIC, &sa, audit_cb);
104}
105
106/**
107 * profile_capable - test if profile allows use of capability @cap
108 * @profile: profile being enforced (NOT NULL, NOT unconfined)
109 * @cap: capability to test if allowed
110 *
111 * Returns: 0 if allowed else -EPERM
112 */
113static int profile_capable(struct aa_profile *profile, int cap)
114{
115 return cap_raised(profile->caps.allow, cap) ? 0 : -EPERM;
116}
117
118/**
119 * aa_capable - test permission to use capability
120 * @task: task doing capability test against (NOT NULL)
121 * @profile: profile confining @task (NOT NULL)
122 * @cap: capability to be tested
123 * @audit: whether an audit record should be generated
124 *
125 * Look up capability in profile capability set.
126 *
127 * Returns: 0 on success, or else an error code.
128 */
129int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap,
130 int audit)
131{
132 int error = profile_capable(profile, cap);
133
134 if (!audit) {
135 if (COMPLAIN_MODE(profile))
136 return complain_error(error);
137 return error;
138 }
139
140 return audit_caps(profile, task, cap, error);
141}
diff --git a/security/apparmor/context.c b/security/apparmor/context.c
new file mode 100644
index 00000000000..8a9b5027c81
--- /dev/null
+++ b/security/apparmor/context.c
@@ -0,0 +1,216 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor functions used to manipulate object security
5 * contexts.
6 *
7 * Copyright (C) 1998-2008 Novell/SUSE
8 * Copyright 2009-2010 Canonical Ltd.
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation, version 2 of the
13 * License.
14 *
15 *
16 * AppArmor sets confinement on every task, via the the aa_task_cxt and
17 * the aa_task_cxt.profile, both of which are required and are not allowed
18 * to be NULL. The aa_task_cxt is not reference counted and is unique
19 * to each cred (which is reference count). The profile pointed to by
20 * the task_cxt is reference counted.
21 *
22 * TODO
23 * If a task uses change_hat it currently does not return to the old
24 * cred or task context but instead creates a new one. Ideally the task
25 * should return to the previous cred if it has not been modified.
26 *
27 */
28
29#include "include/context.h"
30#include "include/policy.h"
31
32/**
33 * aa_alloc_task_context - allocate a new task_cxt
34 * @flags: gfp flags for allocation
35 *
36 * Returns: allocated buffer or NULL on failure
37 */
38struct aa_task_cxt *aa_alloc_task_context(gfp_t flags)
39{
40 return kzalloc(sizeof(struct aa_task_cxt), flags);
41}
42
43/**
44 * aa_free_task_context - free a task_cxt
45 * @cxt: task_cxt to free (MAYBE NULL)
46 */
47void aa_free_task_context(struct aa_task_cxt *cxt)
48{
49 if (cxt) {
50 aa_put_profile(cxt->profile);
51 aa_put_profile(cxt->previous);
52 aa_put_profile(cxt->onexec);
53
54 kzfree(cxt);
55 }
56}
57
58/**
59 * aa_dup_task_context - duplicate a task context, incrementing reference counts
60 * @new: a blank task context (NOT NULL)
61 * @old: the task context to copy (NOT NULL)
62 */
63void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old)
64{
65 *new = *old;
66 aa_get_profile(new->profile);
67 aa_get_profile(new->previous);
68 aa_get_profile(new->onexec);
69}
70
71/**
72 * aa_replace_current_profile - replace the current tasks profiles
73 * @profile: new profile (NOT NULL)
74 *
75 * Returns: 0 or error on failure
76 */
77int aa_replace_current_profile(struct aa_profile *profile)
78{
79 struct aa_task_cxt *cxt = current_cred()->security;
80 struct cred *new;
81 BUG_ON(!profile);
82
83 if (cxt->profile == profile)
84 return 0;
85
86 new = prepare_creds();
87 if (!new)
88 return -ENOMEM;
89
90 cxt = new->security;
91 if (unconfined(profile) || (cxt->profile->ns != profile->ns)) {
92 /* if switching to unconfined or a different profile namespace
93 * clear out context state
94 */
95 aa_put_profile(cxt->previous);
96 aa_put_profile(cxt->onexec);
97 cxt->previous = NULL;
98 cxt->onexec = NULL;
99 cxt->token = 0;
100 }
101 /* be careful switching cxt->profile, when racing replacement it
102 * is possible that cxt->profile->replacedby is the reference keeping
103 * @profile valid, so make sure to get its reference before dropping
104 * the reference on cxt->profile */
105 aa_get_profile(profile);
106 aa_put_profile(cxt->profile);
107 cxt->profile = profile;
108
109 commit_creds(new);
110 return 0;
111}
112
113/**
114 * aa_set_current_onexec - set the tasks change_profile to happen onexec
115 * @profile: system profile to set at exec (MAYBE NULL to clear value)
116 *
117 * Returns: 0 or error on failure
118 */
119int aa_set_current_onexec(struct aa_profile *profile)
120{
121 struct aa_task_cxt *cxt;
122 struct cred *new = prepare_creds();
123 if (!new)
124 return -ENOMEM;
125
126 cxt = new->security;
127 aa_get_profile(profile);
128 aa_put_profile(cxt->onexec);
129 cxt->onexec = profile;
130
131 commit_creds(new);
132 return 0;
133}
134
135/**
136 * aa_set_current_hat - set the current tasks hat
137 * @profile: profile to set as the current hat (NOT NULL)
138 * @token: token value that must be specified to change from the hat
139 *
140 * Do switch of tasks hat. If the task is currently in a hat
141 * validate the token to match.
142 *
143 * Returns: 0 or error on failure
144 */
145int aa_set_current_hat(struct aa_profile *profile, u64 token)
146{
147 struct aa_task_cxt *cxt;
148 struct cred *new = prepare_creds();
149 if (!new)
150 return -ENOMEM;
151 BUG_ON(!profile);
152
153 cxt = new->security;
154 if (!cxt->previous) {
155 /* transfer refcount */
156 cxt->previous = cxt->profile;
157 cxt->token = token;
158 } else if (cxt->token == token) {
159 aa_put_profile(cxt->profile);
160 } else {
161 /* previous_profile && cxt->token != token */
162 abort_creds(new);
163 return -EACCES;
164 }
165 cxt->profile = aa_get_profile(aa_newest_version(profile));
166 /* clear exec on switching context */
167 aa_put_profile(cxt->onexec);
168 cxt->onexec = NULL;
169
170 commit_creds(new);
171 return 0;
172}
173
174/**
175 * aa_restore_previous_profile - exit from hat context restoring the profile
176 * @token: the token that must be matched to exit hat context
177 *
178 * Attempt to return out of a hat to the previous profile. The token
179 * must match the stored token value.
180 *
181 * Returns: 0 or error of failure
182 */
183int aa_restore_previous_profile(u64 token)
184{
185 struct aa_task_cxt *cxt;
186 struct cred *new = prepare_creds();
187 if (!new)
188 return -ENOMEM;
189
190 cxt = new->security;
191 if (cxt->token != token) {
192 abort_creds(new);
193 return -EACCES;
194 }
195 /* ignore restores when there is no saved profile */
196 if (!cxt->previous) {
197 abort_creds(new);
198 return 0;
199 }
200
201 aa_put_profile(cxt->profile);
202 cxt->profile = aa_newest_version(cxt->previous);
203 BUG_ON(!cxt->profile);
204 if (unlikely(cxt->profile != cxt->previous)) {
205 aa_get_profile(cxt->profile);
206 aa_put_profile(cxt->previous);
207 }
208 /* clear exec && prev information when restoring to previous context */
209 cxt->previous = NULL;
210 cxt->token = 0;
211 aa_put_profile(cxt->onexec);
212 cxt->onexec = NULL;
213
214 commit_creds(new);
215 return 0;
216}
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
new file mode 100644
index 00000000000..c825c6e0b63
--- /dev/null
+++ b/security/apparmor/domain.c
@@ -0,0 +1,823 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor policy attachment and domain transitions
5 *
6 * Copyright (C) 2002-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/errno.h>
16#include <linux/fdtable.h>
17#include <linux/file.h>
18#include <linux/mount.h>
19#include <linux/syscalls.h>
20#include <linux/tracehook.h>
21#include <linux/personality.h>
22
23#include "include/audit.h"
24#include "include/apparmorfs.h"
25#include "include/context.h"
26#include "include/domain.h"
27#include "include/file.h"
28#include "include/ipc.h"
29#include "include/match.h"
30#include "include/path.h"
31#include "include/policy.h"
32
33/**
34 * aa_free_domain_entries - free entries in a domain table
35 * @domain: the domain table to free (MAYBE NULL)
36 */
37void aa_free_domain_entries(struct aa_domain *domain)
38{
39 int i;
40 if (domain) {
41 if (!domain->table)
42 return;
43
44 for (i = 0; i < domain->size; i++)
45 kzfree(domain->table[i]);
46 kzfree(domain->table);
47 domain->table = NULL;
48 }
49}
50
51/**
52 * may_change_ptraced_domain - check if can change profile on ptraced task
53 * @task: task we want to change profile of (NOT NULL)
54 * @to_profile: profile to change to (NOT NULL)
55 *
56 * Check if the task is ptraced and if so if the tracing task is allowed
57 * to trace the new domain
58 *
59 * Returns: %0 or error if change not allowed
60 */
61static int may_change_ptraced_domain(struct task_struct *task,
62 struct aa_profile *to_profile)
63{
64 struct task_struct *tracer;
65 const struct cred *cred = NULL;
66 struct aa_profile *tracerp = NULL;
67 int error = 0;
68
69 rcu_read_lock();
70 tracer = tracehook_tracer_task(task);
71 if (tracer) {
72 /* released below */
73 cred = get_task_cred(tracer);
74 tracerp = aa_cred_profile(cred);
75 }
76 rcu_read_unlock();
77
78 /* not ptraced */
79 if (!tracer || unconfined(tracerp))
80 goto out;
81
82 error = aa_may_ptrace(tracer, tracerp, to_profile, PTRACE_MODE_ATTACH);
83
84out:
85 if (cred)
86 put_cred(cred);
87
88 return error;
89}
90
91/**
92 * change_profile_perms - find permissions for change_profile
93 * @profile: the current profile (NOT NULL)
94 * @ns: the namespace being switched to (NOT NULL)
95 * @name: the name of the profile to change to (NOT NULL)
96 * @request: requested perms
97 * @start: state to start matching in
98 *
99 * Returns: permission set
100 */
101static struct file_perms change_profile_perms(struct aa_profile *profile,
102 struct aa_namespace *ns,
103 const char *name, u32 request,
104 unsigned int start)
105{
106 struct file_perms perms;
107 struct path_cond cond = { };
108 unsigned int state;
109
110 if (unconfined(profile)) {
111 perms.allow = AA_MAY_CHANGE_PROFILE | AA_MAY_ONEXEC;
112 perms.audit = perms.quiet = perms.kill = 0;
113 return perms;
114 } else if (!profile->file.dfa) {
115 return nullperms;
116 } else if ((ns == profile->ns)) {
117 /* try matching against rules with out namespace prepended */
118 aa_str_perms(profile->file.dfa, start, name, &cond, &perms);
119 if (COMBINED_PERM_MASK(perms) & request)
120 return perms;
121 }
122
123 /* try matching with namespace name and then profile */
124 state = aa_dfa_match(profile->file.dfa, start, ns->base.name);
125 state = aa_dfa_match_len(profile->file.dfa, state, ":", 1);
126 aa_str_perms(profile->file.dfa, state, name, &cond, &perms);
127
128 return perms;
129}
130
131/**
132 * __attach_match_ - find an attachment match
133 * @name - to match against (NOT NULL)
134 * @head - profile list to walk (NOT NULL)
135 *
136 * Do a linear search on the profiles in the list. There is a matching
137 * preference where an exact match is preferred over a name which uses
138 * expressions to match, and matching expressions with the greatest
139 * xmatch_len are preferred.
140 *
141 * Requires: @head not be shared or have appropriate locks held
142 *
143 * Returns: profile or NULL if no match found
144 */
145static struct aa_profile *__attach_match(const char *name,
146 struct list_head *head)
147{
148 int len = 0;
149 struct aa_profile *profile, *candidate = NULL;
150
151 list_for_each_entry(profile, head, base.list) {
152 if (profile->flags & PFLAG_NULL)
153 continue;
154 if (profile->xmatch && profile->xmatch_len > len) {
155 unsigned int state = aa_dfa_match(profile->xmatch,
156 DFA_START, name);
157 u32 perm = dfa_user_allow(profile->xmatch, state);
158 /* any accepting state means a valid match. */
159 if (perm & MAY_EXEC) {
160 candidate = profile;
161 len = profile->xmatch_len;
162 }
163 } else if (!strcmp(profile->base.name, name))
164 /* exact non-re match, no more searching required */
165 return profile;
166 }
167
168 return candidate;
169}
170
171/**
172 * find_attach - do attachment search for unconfined processes
173 * @ns: the current namespace (NOT NULL)
174 * @list: list to search (NOT NULL)
175 * @name: the executable name to match against (NOT NULL)
176 *
177 * Returns: profile or NULL if no match found
178 */
179static struct aa_profile *find_attach(struct aa_namespace *ns,
180 struct list_head *list, const char *name)
181{
182 struct aa_profile *profile;
183
184 read_lock(&ns->lock);
185 profile = aa_get_profile(__attach_match(name, list));
186 read_unlock(&ns->lock);
187
188 return profile;
189}
190
191/**
192 * separate_fqname - separate the namespace and profile names
193 * @fqname: the fqname name to split (NOT NULL)
194 * @ns_name: the namespace name if it exists (NOT NULL)
195 *
196 * This is the xtable equivalent routine of aa_split_fqname. It finds the
197 * split in an xtable fqname which contains an embedded \0 instead of a :
198 * if a namespace is specified. This is done so the xtable is constant and
199 * isn't re-split on every lookup.
200 *
201 * Either the profile or namespace name may be optional but if the namespace
202 * is specified the profile name termination must be present. This results
203 * in the following possible encodings:
204 * profile_name\0
205 * :ns_name\0profile_name\0
206 * :ns_name\0\0
207 *
208 * NOTE: the xtable fqname is pre-validated at load time in unpack_trans_table
209 *
210 * Returns: profile name if it is specified else NULL
211 */
212static const char *separate_fqname(const char *fqname, const char **ns_name)
213{
214 const char *name;
215
216 if (fqname[0] == ':') {
217 /* In this case there is guaranteed to be two \0 terminators
218 * in the string. They are verified at load time by
219 * by unpack_trans_table
220 */
221 *ns_name = fqname + 1; /* skip : */
222 name = *ns_name + strlen(*ns_name) + 1;
223 if (!*name)
224 name = NULL;
225 } else {
226 *ns_name = NULL;
227 name = fqname;
228 }
229
230 return name;
231}
232
233static const char *next_name(int xtype, const char *name)
234{
235 return NULL;
236}
237
238/**
239 * x_table_lookup - lookup an x transition name via transition table
240 * @profile: current profile (NOT NULL)
241 * @xindex: index into x transition table
242 *
243 * Returns: refcounted profile, or NULL on failure (MAYBE NULL)
244 */
245static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
246{
247 struct aa_profile *new_profile = NULL;
248 struct aa_namespace *ns = profile->ns;
249 u32 xtype = xindex & AA_X_TYPE_MASK;
250 int index = xindex & AA_X_INDEX_MASK;
251 const char *name;
252
253 /* index is guaranteed to be in range, validated at load time */
254 for (name = profile->file.trans.table[index]; !new_profile && name;
255 name = next_name(xtype, name)) {
256 struct aa_namespace *new_ns;
257 const char *xname = NULL;
258
259 new_ns = NULL;
260 if (xindex & AA_X_CHILD) {
261 /* release by caller */
262 new_profile = aa_find_child(profile, name);
263 continue;
264 } else if (*name == ':') {
265 /* switching namespace */
266 const char *ns_name;
267 xname = name = separate_fqname(name, &ns_name);
268 if (!xname)
269 /* no name so use profile name */
270 xname = profile->base.hname;
271 if (*ns_name == '@') {
272 /* TODO: variable support */
273 ;
274 }
275 /* released below */
276 new_ns = aa_find_namespace(ns, ns_name);
277 if (!new_ns)
278 continue;
279 } else if (*name == '@') {
280 /* TODO: variable support */
281 continue;
282 } else {
283 /* basic namespace lookup */
284 xname = name;
285 }
286
287 /* released by caller */
288 new_profile = aa_lookup_profile(new_ns ? new_ns : ns, xname);
289 aa_put_namespace(new_ns);
290 }
291
292 /* released by caller */
293 return new_profile;
294}
295
296/**
297 * x_to_profile - get target profile for a given xindex
298 * @profile: current profile (NOT NULL)
299 * @name: name to lookup (NOT NULL)
300 * @xindex: index into x transition table
301 *
302 * find profile for a transition index
303 *
304 * Returns: refcounted profile or NULL if not found available
305 */
306static struct aa_profile *x_to_profile(struct aa_profile *profile,
307 const char *name, u32 xindex)
308{
309 struct aa_profile *new_profile = NULL;
310 struct aa_namespace *ns = profile->ns;
311 u32 xtype = xindex & AA_X_TYPE_MASK;
312
313 switch (xtype) {
314 case AA_X_NONE:
315 /* fail exec unless ix || ux fallback - handled by caller */
316 return NULL;
317 case AA_X_NAME:
318 if (xindex & AA_X_CHILD)
319 /* released by caller */
320 new_profile = find_attach(ns, &profile->base.profiles,
321 name);
322 else
323 /* released by caller */
324 new_profile = find_attach(ns, &ns->base.profiles,
325 name);
326 break;
327 case AA_X_TABLE:
328 /* released by caller */
329 new_profile = x_table_lookup(profile, xindex);
330 break;
331 }
332
333 /* released by caller */
334 return new_profile;
335}
336
337/**
338 * apparmor_bprm_set_creds - set the new creds on the bprm struct
339 * @bprm: binprm for the exec (NOT NULL)
340 *
341 * Returns: %0 or error on failure
342 */
343int apparmor_bprm_set_creds(struct linux_binprm *bprm)
344{
345 struct aa_task_cxt *cxt;
346 struct aa_profile *profile, *new_profile = NULL;
347 struct aa_namespace *ns;
348 char *buffer = NULL;
349 unsigned int state;
350 struct file_perms perms = {};
351 struct path_cond cond = {
352 bprm->file->f_path.dentry->d_inode->i_uid,
353 bprm->file->f_path.dentry->d_inode->i_mode
354 };
355 const char *name = NULL, *target = NULL, *info = NULL;
356 int error = cap_bprm_set_creds(bprm);
357 if (error)
358 return error;
359
360 if (bprm->cred_prepared)
361 return 0;
362
363 cxt = bprm->cred->security;
364 BUG_ON(!cxt);
365
366 profile = aa_get_profile(aa_newest_version(cxt->profile));
367 /*
368 * get the namespace from the replacement profile as replacement
369 * can change the namespace
370 */
371 ns = profile->ns;
372 state = profile->file.start;
373
374 /* buffer freed below, name is pointer into buffer */
375 error = aa_get_name(&bprm->file->f_path, profile->path_flags, &buffer,
376 &name);
377 if (error) {
378 if (profile->flags &
379 (PFLAG_IX_ON_NAME_ERROR | PFLAG_UNCONFINED))
380 error = 0;
381 info = "Exec failed name resolution";
382 name = bprm->filename;
383 goto audit;
384 }
385
386 /* Test for onexec first as onexec directives override other
387 * x transitions.
388 */
389 if (unconfined(profile)) {
390 /* unconfined task */
391 if (cxt->onexec)
392 /* change_profile on exec already been granted */
393 new_profile = aa_get_profile(cxt->onexec);
394 else
395 new_profile = find_attach(ns, &ns->base.profiles, name);
396 if (!new_profile)
397 goto cleanup;
398 goto apply;
399 }
400
401 /* find exec permissions for name */
402 state = aa_str_perms(profile->file.dfa, state, name, &cond, &perms);
403 if (cxt->onexec) {
404 struct file_perms cp;
405 info = "change_profile onexec";
406 if (!(perms.allow & AA_MAY_ONEXEC))
407 goto audit;
408
409 /* test if this exec can be paired with change_profile onexec.
410 * onexec permission is linked to exec with a standard pairing
411 * exec\0change_profile
412 */
413 state = aa_dfa_null_transition(profile->file.dfa, state);
414 cp = change_profile_perms(profile, cxt->onexec->ns, name,
415 AA_MAY_ONEXEC, state);
416
417 if (!(cp.allow & AA_MAY_ONEXEC))
418 goto audit;
419 new_profile = aa_get_profile(aa_newest_version(cxt->onexec));
420 goto apply;
421 }
422
423 if (perms.allow & MAY_EXEC) {
424 /* exec permission determine how to transition */
425 new_profile = x_to_profile(profile, name, perms.xindex);
426 if (!new_profile) {
427 if (perms.xindex & AA_X_INHERIT) {
428 /* (p|c|n)ix - don't change profile but do
429 * use the newest version, which was picked
430 * up above when getting profile
431 */
432 info = "ix fallback";
433 new_profile = aa_get_profile(profile);
434 goto x_clear;
435 } else if (perms.xindex & AA_X_UNCONFINED) {
436 new_profile = aa_get_profile(ns->unconfined);
437 info = "ux fallback";
438 } else {
439 error = -ENOENT;
440 info = "profile not found";
441 }
442 }
443 } else if (COMPLAIN_MODE(profile)) {
444 /* no exec permission - are we in learning mode */
445 new_profile = aa_new_null_profile(profile, 0);
446 if (!new_profile) {
447 error = -ENOMEM;
448 info = "could not create null profile";
449 } else {
450 error = -EACCES;
451 target = new_profile->base.hname;
452 }
453 perms.xindex |= AA_X_UNSAFE;
454 } else
455 /* fail exec */
456 error = -EACCES;
457
458 if (!new_profile)
459 goto audit;
460
461 if (bprm->unsafe & LSM_UNSAFE_SHARE) {
462 /* FIXME: currently don't mediate shared state */
463 ;
464 }
465
466 if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
467 error = may_change_ptraced_domain(current, new_profile);
468 if (error) {
469 aa_put_profile(new_profile);
470 goto audit;
471 }
472 }
473
474 /* Determine if secure exec is needed.
475 * Can be at this point for the following reasons:
476 * 1. unconfined switching to confined
477 * 2. confined switching to different confinement
478 * 3. confined switching to unconfined
479 *
480 * Cases 2 and 3 are marked as requiring secure exec
481 * (unless policy specified "unsafe exec")
482 *
483 * bprm->unsafe is used to cache the AA_X_UNSAFE permission
484 * to avoid having to recompute in secureexec
485 */
486 if (!(perms.xindex & AA_X_UNSAFE)) {
487 AA_DEBUG("scrubbing environment variables for %s profile=%s\n",
488 name, new_profile->base.hname);
489 bprm->unsafe |= AA_SECURE_X_NEEDED;
490 }
491apply:
492 target = new_profile->base.hname;
493 /* when transitioning profiles clear unsafe personality bits */
494 bprm->per_clear |= PER_CLEAR_ON_SETID;
495
496x_clear:
497 aa_put_profile(cxt->profile);
498 /* transfer new profile reference will be released when cxt is freed */
499 cxt->profile = new_profile;
500
501 /* clear out all temporary/transitional state from the context */
502 aa_put_profile(cxt->previous);
503 aa_put_profile(cxt->onexec);
504 cxt->previous = NULL;
505 cxt->onexec = NULL;
506 cxt->token = 0;
507
508audit:
509 error = aa_audit_file(profile, &perms, GFP_KERNEL, OP_EXEC, MAY_EXEC,
510 name, target, cond.uid, info, error);
511
512cleanup:
513 aa_put_profile(profile);
514 kfree(buffer);
515
516 return error;
517}
518
519/**
520 * apparmor_bprm_secureexec - determine if secureexec is needed
521 * @bprm: binprm for exec (NOT NULL)
522 *
523 * Returns: %1 if secureexec is needed else %0
524 */
525int apparmor_bprm_secureexec(struct linux_binprm *bprm)
526{
527 int ret = cap_bprm_secureexec(bprm);
528
529 /* the decision to use secure exec is computed in set_creds
530 * and stored in bprm->unsafe.
531 */
532 if (!ret && (bprm->unsafe & AA_SECURE_X_NEEDED))
533 ret = 1;
534
535 return ret;
536}
537
538/**
539 * apparmor_bprm_committing_creds - do task cleanup on committing new creds
540 * @bprm: binprm for the exec (NOT NULL)
541 */
542void apparmor_bprm_committing_creds(struct linux_binprm *bprm)
543{
544 struct aa_profile *profile = __aa_current_profile();
545 struct aa_task_cxt *new_cxt = bprm->cred->security;
546
547 /* bail out if unconfined or not changing profile */
548 if ((new_cxt->profile == profile) ||
549 (unconfined(new_cxt->profile)))
550 return;
551
552 current->pdeath_signal = 0;
553
554 /* reset soft limits and set hard limits for the new profile */
555 __aa_transition_rlimits(profile, new_cxt->profile);
556}
557
558/**
559 * apparmor_bprm_commited_cred - do cleanup after new creds committed
560 * @bprm: binprm for the exec (NOT NULL)
561 */
562void apparmor_bprm_committed_creds(struct linux_binprm *bprm)
563{
564 /* TODO: cleanup signals - ipc mediation */
565 return;
566}
567
568/*
569 * Functions for self directed profile change
570 */
571
572/**
573 * new_compound_name - create an hname with @n2 appended to @n1
574 * @n1: base of hname (NOT NULL)
575 * @n2: name to append (NOT NULL)
576 *
577 * Returns: new name or NULL on error
578 */
579static char *new_compound_name(const char *n1, const char *n2)
580{
581 char *name = kmalloc(strlen(n1) + strlen(n2) + 3, GFP_KERNEL);
582 if (name)
583 sprintf(name, "%s//%s", n1, n2);
584 return name;
585}
586
587/**
588 * aa_change_hat - change hat to/from subprofile
589 * @hats: vector of hat names to try changing into (MAYBE NULL if @count == 0)
590 * @count: number of hat names in @hats
591 * @token: magic value to validate the hat change
592 * @permtest: true if this is just a permission test
593 *
594 * Change to the first profile specified in @hats that exists, and store
595 * the @hat_magic in the current task context. If the count == 0 and the
596 * @token matches that stored in the current task context, return to the
597 * top level profile.
598 *
599 * Returns %0 on success, error otherwise.
600 */
601int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
602{
603 const struct cred *cred;
604 struct aa_task_cxt *cxt;
605 struct aa_profile *profile, *previous_profile, *hat = NULL;
606 char *name = NULL;
607 int i;
608 struct file_perms perms = {};
609 const char *target = NULL, *info = NULL;
610 int error = 0;
611
612 /* released below */
613 cred = get_current_cred();
614 cxt = cred->security;
615 profile = aa_cred_profile(cred);
616 previous_profile = cxt->previous;
617
618 if (unconfined(profile)) {
619 info = "unconfined";
620 error = -EPERM;
621 goto audit;
622 }
623
624 if (count) {
625 /* attempting to change into a new hat or switch to a sibling */
626 struct aa_profile *root;
627 root = PROFILE_IS_HAT(profile) ? profile->parent : profile;
628
629 /* find first matching hat */
630 for (i = 0; i < count && !hat; i++)
631 /* released below */
632 hat = aa_find_child(root, hats[i]);
633 if (!hat) {
634 if (!COMPLAIN_MODE(root) || permtest) {
635 if (list_empty(&root->base.profiles))
636 error = -ECHILD;
637 else
638 error = -ENOENT;
639 goto out;
640 }
641
642 /*
643 * In complain mode and failed to match any hats.
644 * Audit the failure is based off of the first hat
645 * supplied. This is done due how userspace
646 * interacts with change_hat.
647 *
648 * TODO: Add logging of all failed hats
649 */
650
651 /* freed below */
652 name = new_compound_name(root->base.hname, hats[0]);
653 target = name;
654 /* released below */
655 hat = aa_new_null_profile(profile, 1);
656 if (!hat) {
657 info = "failed null profile create";
658 error = -ENOMEM;
659 goto audit;
660 }
661 } else {
662 target = hat->base.hname;
663 if (!PROFILE_IS_HAT(hat)) {
664 info = "target not hat";
665 error = -EPERM;
666 goto audit;
667 }
668 }
669
670 error = may_change_ptraced_domain(current, hat);
671 if (error) {
672 info = "ptraced";
673 error = -EPERM;
674 goto audit;
675 }
676
677 if (!permtest) {
678 error = aa_set_current_hat(hat, token);
679 if (error == -EACCES)
680 /* kill task in case of brute force attacks */
681 perms.kill = AA_MAY_CHANGEHAT;
682 else if (name && !error)
683 /* reset error for learning of new hats */
684 error = -ENOENT;
685 }
686 } else if (previous_profile) {
687 /* Return to saved profile. Kill task if restore fails
688 * to avoid brute force attacks
689 */
690 target = previous_profile->base.hname;
691 error = aa_restore_previous_profile(token);
692 perms.kill = AA_MAY_CHANGEHAT;
693 } else
694 /* ignore restores when there is no saved profile */
695 goto out;
696
697audit:
698 if (!permtest)
699 error = aa_audit_file(profile, &perms, GFP_KERNEL,
700 OP_CHANGE_HAT, AA_MAY_CHANGEHAT, NULL,
701 target, 0, info, error);
702
703out:
704 aa_put_profile(hat);
705 kfree(name);
706 put_cred(cred);
707
708 return error;
709}
710
711/**
712 * aa_change_profile - perform a one-way profile transition
713 * @ns_name: name of the profile namespace to change to (MAYBE NULL)
714 * @hname: name of profile to change to (MAYBE NULL)
715 * @onexec: whether this transition is to take place immediately or at exec
716 * @permtest: true if this is just a permission test
717 *
718 * Change to new profile @name. Unlike with hats, there is no way
719 * to change back. If @name isn't specified the current profile name is
720 * used.
721 * If @onexec then the transition is delayed until
722 * the next exec.
723 *
724 * Returns %0 on success, error otherwise.
725 */
726int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
727 bool permtest)
728{
729 const struct cred *cred;
730 struct aa_task_cxt *cxt;
731 struct aa_profile *profile, *target = NULL;
732 struct aa_namespace *ns = NULL;
733 struct file_perms perms = {};
734 const char *name = NULL, *info = NULL;
735 int op, error = 0;
736 u32 request;
737
738 if (!hname && !ns_name)
739 return -EINVAL;
740
741 if (onexec) {
742 request = AA_MAY_ONEXEC;
743 op = OP_CHANGE_ONEXEC;
744 } else {
745 request = AA_MAY_CHANGE_PROFILE;
746 op = OP_CHANGE_PROFILE;
747 }
748
749 cred = get_current_cred();
750 cxt = cred->security;
751 profile = aa_cred_profile(cred);
752
753 if (ns_name) {
754 /* released below */
755 ns = aa_find_namespace(profile->ns, ns_name);
756 if (!ns) {
757 /* we don't create new namespace in complain mode */
758 name = ns_name;
759 info = "namespace not found";
760 error = -ENOENT;
761 goto audit;
762 }
763 } else
764 /* released below */
765 ns = aa_get_namespace(profile->ns);
766
767 /* if the name was not specified, use the name of the current profile */
768 if (!hname) {
769 if (unconfined(profile))
770 hname = ns->unconfined->base.hname;
771 else
772 hname = profile->base.hname;
773 }
774
775 perms = change_profile_perms(profile, ns, hname, request,
776 profile->file.start);
777 if (!(perms.allow & request)) {
778 error = -EACCES;
779 goto audit;
780 }
781
782 /* released below */
783 target = aa_lookup_profile(ns, hname);
784 if (!target) {
785 info = "profile not found";
786 error = -ENOENT;
787 if (permtest || !COMPLAIN_MODE(profile))
788 goto audit;
789 /* released below */
790 target = aa_new_null_profile(profile, 0);
791 if (!target) {
792 info = "failed null profile create";
793 error = -ENOMEM;
794 goto audit;
795 }
796 }
797
798 /* check if tracing task is allowed to trace target domain */
799 error = may_change_ptraced_domain(current, target);
800 if (error) {
801 info = "ptrace prevents transition";
802 goto audit;
803 }
804
805 if (permtest)
806 goto audit;
807
808 if (onexec)
809 error = aa_set_current_onexec(target);
810 else
811 error = aa_replace_current_profile(target);
812
813audit:
814 if (!permtest)
815 error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request,
816 name, hname, 0, info, error);
817
818 aa_put_namespace(ns);
819 aa_put_profile(target);
820 put_cred(cred);
821
822 return error;
823}
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
new file mode 100644
index 00000000000..7312db74121
--- /dev/null
+++ b/security/apparmor/file.c
@@ -0,0 +1,457 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor mediation of files
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/audit.h"
17#include "include/file.h"
18#include "include/match.h"
19#include "include/path.h"
20#include "include/policy.h"
21
22struct file_perms nullperms;
23
24
25/**
26 * audit_file_mask - convert mask to permission string
27 * @buffer: buffer to write string to (NOT NULL)
28 * @mask: permission mask to convert
29 */
30static void audit_file_mask(struct audit_buffer *ab, u32 mask)
31{
32 char str[10];
33
34 char *m = str;
35
36 if (mask & AA_EXEC_MMAP)
37 *m++ = 'm';
38 if (mask & (MAY_READ | AA_MAY_META_READ))
39 *m++ = 'r';
40 if (mask & (MAY_WRITE | AA_MAY_META_WRITE | AA_MAY_CHMOD |
41 AA_MAY_CHOWN))
42 *m++ = 'w';
43 else if (mask & MAY_APPEND)
44 *m++ = 'a';
45 if (mask & AA_MAY_CREATE)
46 *m++ = 'c';
47 if (mask & AA_MAY_DELETE)
48 *m++ = 'd';
49 if (mask & AA_MAY_LINK)
50 *m++ = 'l';
51 if (mask & AA_MAY_LOCK)
52 *m++ = 'k';
53 if (mask & MAY_EXEC)
54 *m++ = 'x';
55 *m = '\0';
56
57 audit_log_string(ab, str);
58}
59
60/**
61 * file_audit_cb - call back for file specific audit fields
62 * @ab: audit_buffer (NOT NULL)
63 * @va: audit struct to audit values of (NOT NULL)
64 */
65static void file_audit_cb(struct audit_buffer *ab, void *va)
66{
67 struct common_audit_data *sa = va;
68 uid_t fsuid = current_fsuid();
69
70 if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) {
71 audit_log_format(ab, " requested_mask=");
72 audit_file_mask(ab, sa->aad.fs.request);
73 }
74 if (sa->aad.fs.denied & AA_AUDIT_FILE_MASK) {
75 audit_log_format(ab, " denied_mask=");
76 audit_file_mask(ab, sa->aad.fs.denied);
77 }
78 if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) {
79 audit_log_format(ab, " fsuid=%d", fsuid);
80 audit_log_format(ab, " ouid=%d", sa->aad.fs.ouid);
81 }
82
83 if (sa->aad.fs.target) {
84 audit_log_format(ab, " target=");
85 audit_log_untrustedstring(ab, sa->aad.fs.target);
86 }
87}
88
89/**
90 * aa_audit_file - handle the auditing of file operations
91 * @profile: the profile being enforced (NOT NULL)
92 * @perms: the permissions computed for the request (NOT NULL)
93 * @gfp: allocation flags
94 * @op: operation being mediated
95 * @request: permissions requested
96 * @name: name of object being mediated (MAYBE NULL)
97 * @target: name of target (MAYBE NULL)
98 * @ouid: object uid
99 * @info: extra information message (MAYBE NULL)
100 * @error: 0 if operation allowed else failure error code
101 *
102 * Returns: %0 or error on failure
103 */
104int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
105 gfp_t gfp, int op, u32 request, const char *name,
106 const char *target, uid_t ouid, const char *info, int error)
107{
108 int type = AUDIT_APPARMOR_AUTO;
109 struct common_audit_data sa;
110 COMMON_AUDIT_DATA_INIT(&sa, NONE);
111 sa.aad.op = op,
112 sa.aad.fs.request = request;
113 sa.aad.name = name;
114 sa.aad.fs.target = target;
115 sa.aad.fs.ouid = ouid;
116 sa.aad.info = info;
117 sa.aad.error = error;
118
119 if (likely(!sa.aad.error)) {
120 u32 mask = perms->audit;
121
122 if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
123 mask = 0xffff;
124
125 /* mask off perms that are not being force audited */
126 sa.aad.fs.request &= mask;
127
128 if (likely(!sa.aad.fs.request))
129 return 0;
130 type = AUDIT_APPARMOR_AUDIT;
131 } else {
132 /* only report permissions that were denied */
133 sa.aad.fs.request = sa.aad.fs.request & ~perms->allow;
134
135 if (sa.aad.fs.request & perms->kill)
136 type = AUDIT_APPARMOR_KILL;
137
138 /* quiet known rejects, assumes quiet and kill do not overlap */
139 if ((sa.aad.fs.request & perms->quiet) &&
140 AUDIT_MODE(profile) != AUDIT_NOQUIET &&
141 AUDIT_MODE(profile) != AUDIT_ALL)
142 sa.aad.fs.request &= ~perms->quiet;
143
144 if (!sa.aad.fs.request)
145 return COMPLAIN_MODE(profile) ? 0 : sa.aad.error;
146 }
147
148 sa.aad.fs.denied = sa.aad.fs.request & ~perms->allow;
149 return aa_audit(type, profile, gfp, &sa, file_audit_cb);
150}
151
152/**
153 * map_old_perms - map old file perms layout to the new layout
154 * @old: permission set in old mapping
155 *
156 * Returns: new permission mapping
157 */
158static u32 map_old_perms(u32 old)
159{
160 u32 new = old & 0xf;
161 if (old & MAY_READ)
162 new |= AA_MAY_META_READ;
163 if (old & MAY_WRITE)
164 new |= AA_MAY_META_WRITE | AA_MAY_CREATE | AA_MAY_DELETE |
165 AA_MAY_CHMOD | AA_MAY_CHOWN;
166 if (old & 0x10)
167 new |= AA_MAY_LINK;
168 /* the old mapping lock and link_subset flags where overlaid
169 * and use was determined by part of a pair that they were in
170 */
171 if (old & 0x20)
172 new |= AA_MAY_LOCK | AA_LINK_SUBSET;
173 if (old & 0x40) /* AA_EXEC_MMAP */
174 new |= AA_EXEC_MMAP;
175
176 new |= AA_MAY_META_READ;
177
178 return new;
179}
180
181/**
182 * compute_perms - convert dfa compressed perms to internal perms
183 * @dfa: dfa to compute perms for (NOT NULL)
184 * @state: state in dfa
185 * @cond: conditions to consider (NOT NULL)
186 *
187 * TODO: convert from dfa + state to permission entry, do computation conversion
188 * at load time.
189 *
190 * Returns: computed permission set
191 */
192static struct file_perms compute_perms(struct aa_dfa *dfa, unsigned int state,
193 struct path_cond *cond)
194{
195 struct file_perms perms;
196
197 /* FIXME: change over to new dfa format
198 * currently file perms are encoded in the dfa, new format
199 * splits the permissions from the dfa. This mapping can be
200 * done at profile load
201 */
202 perms.kill = 0;
203
204 if (current_fsuid() == cond->uid) {
205 perms.allow = map_old_perms(dfa_user_allow(dfa, state));
206 perms.audit = map_old_perms(dfa_user_audit(dfa, state));
207 perms.quiet = map_old_perms(dfa_user_quiet(dfa, state));
208 perms.xindex = dfa_user_xindex(dfa, state);
209 } else {
210 perms.allow = map_old_perms(dfa_other_allow(dfa, state));
211 perms.audit = map_old_perms(dfa_other_audit(dfa, state));
212 perms.quiet = map_old_perms(dfa_other_quiet(dfa, state));
213 perms.xindex = dfa_other_xindex(dfa, state);
214 }
215
216 /* change_profile wasn't determined by ownership in old mapping */
217 if (ACCEPT_TABLE(dfa)[state] & 0x80000000)
218 perms.allow |= AA_MAY_CHANGE_PROFILE;
219
220 return perms;
221}
222
223/**
224 * aa_str_perms - find permission that match @name
225 * @dfa: to match against (MAYBE NULL)
226 * @state: state to start matching in
227 * @name: string to match against dfa (NOT NULL)
228 * @cond: conditions to consider for permission set computation (NOT NULL)
229 * @perms: Returns - the permissions found when matching @name
230 *
231 * Returns: the final state in @dfa when beginning @start and walking @name
232 */
233unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
234 const char *name, struct path_cond *cond,
235 struct file_perms *perms)
236{
237 unsigned int state;
238 if (!dfa) {
239 *perms = nullperms;
240 return DFA_NOMATCH;
241 }
242
243 state = aa_dfa_match(dfa, start, name);
244 *perms = compute_perms(dfa, state, cond);
245
246 return state;
247}
248
249/**
250 * is_deleted - test if a file has been completely unlinked
251 * @dentry: dentry of file to test for deletion (NOT NULL)
252 *
253 * Returns: %1 if deleted else %0
254 */
255static inline bool is_deleted(struct dentry *dentry)
256{
257 if (d_unlinked(dentry) && dentry->d_inode->i_nlink == 0)
258 return 1;
259 return 0;
260}
261
262/**
263 * aa_path_perm - do permissions check & audit for @path
264 * @op: operation being checked
265 * @profile: profile being enforced (NOT NULL)
266 * @path: path to check permissions of (NOT NULL)
267 * @flags: any additional path flags beyond what the profile specifies
268 * @request: requested permissions
269 * @cond: conditional info for this request (NOT NULL)
270 *
271 * Returns: %0 else error if access denied or other error
272 */
273int aa_path_perm(int op, struct aa_profile *profile, struct path *path,
274 int flags, u32 request, struct path_cond *cond)
275{
276 char *buffer = NULL;
277 struct file_perms perms = {};
278 const char *name, *info = NULL;
279 int error;
280
281 flags |= profile->path_flags | (S_ISDIR(cond->mode) ? PATH_IS_DIR : 0);
282 error = aa_get_name(path, flags, &buffer, &name);
283 if (error) {
284 if (error == -ENOENT && is_deleted(path->dentry)) {
285 /* Access to open files that are deleted are
286 * give a pass (implicit delegation)
287 */
288 error = 0;
289 perms.allow = request;
290 } else if (error == -ENOENT)
291 info = "Failed name lookup - deleted entry";
292 else if (error == -ESTALE)
293 info = "Failed name lookup - disconnected path";
294 else if (error == -ENAMETOOLONG)
295 info = "Failed name lookup - name too long";
296 else
297 info = "Failed name lookup";
298 } else {
299 aa_str_perms(profile->file.dfa, profile->file.start, name, cond,
300 &perms);
301 if (request & ~perms.allow)
302 error = -EACCES;
303 }
304 error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request, name,
305 NULL, cond->uid, info, error);
306 kfree(buffer);
307
308 return error;
309}
310
311/**
312 * xindex_is_subset - helper for aa_path_link
313 * @link: link permission set
314 * @target: target permission set
315 *
316 * test target x permissions are equal OR a subset of link x permissions
317 * this is done as part of the subset test, where a hardlink must have
318 * a subset of permissions that the target has.
319 *
320 * Returns: %1 if subset else %0
321 */
322static inline bool xindex_is_subset(u32 link, u32 target)
323{
324 if (((link & ~AA_X_UNSAFE) != (target & ~AA_X_UNSAFE)) ||
325 ((link & AA_X_UNSAFE) && !(target & AA_X_UNSAFE)))
326 return 0;
327
328 return 1;
329}
330
331/**
332 * aa_path_link - Handle hard link permission check
333 * @profile: the profile being enforced (NOT NULL)
334 * @old_dentry: the target dentry (NOT NULL)
335 * @new_dir: directory the new link will be created in (NOT NULL)
336 * @new_dentry: the link being created (NOT NULL)
337 *
338 * Handle the permission test for a link & target pair. Permission
339 * is encoded as a pair where the link permission is determined
340 * first, and if allowed, the target is tested. The target test
341 * is done from the point of the link match (not start of DFA)
342 * making the target permission dependent on the link permission match.
343 *
344 * The subset test if required forces that permissions granted
345 * on link are a subset of the permission granted to target.
346 *
347 * Returns: %0 if allowed else error
348 */
349int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
350 struct path *new_dir, struct dentry *new_dentry)
351{
352 struct path link = { new_dir->mnt, new_dentry };
353 struct path target = { new_dir->mnt, old_dentry };
354 struct path_cond cond = {
355 old_dentry->d_inode->i_uid,
356 old_dentry->d_inode->i_mode
357 };
358 char *buffer = NULL, *buffer2 = NULL;
359 const char *lname, *tname = NULL, *info = NULL;
360 struct file_perms lperms, perms;
361 u32 request = AA_MAY_LINK;
362 unsigned int state;
363 int error;
364
365 lperms = nullperms;
366
367 /* buffer freed below, lname is pointer in buffer */
368 error = aa_get_name(&link, profile->path_flags, &buffer, &lname);
369 if (error)
370 goto audit;
371
372 /* buffer2 freed below, tname is pointer in buffer2 */
373 error = aa_get_name(&target, profile->path_flags, &buffer2, &tname);
374 if (error)
375 goto audit;
376
377 error = -EACCES;
378 /* aa_str_perms - handles the case of the dfa being NULL */
379 state = aa_str_perms(profile->file.dfa, profile->file.start, lname,
380 &cond, &lperms);
381
382 if (!(lperms.allow & AA_MAY_LINK))
383 goto audit;
384
385 /* test to see if target can be paired with link */
386 state = aa_dfa_null_transition(profile->file.dfa, state);
387 aa_str_perms(profile->file.dfa, state, tname, &cond, &perms);
388
389 /* force audit/quiet masks for link are stored in the second entry
390 * in the link pair.
391 */
392 lperms.audit = perms.audit;
393 lperms.quiet = perms.quiet;
394 lperms.kill = perms.kill;
395
396 if (!(perms.allow & AA_MAY_LINK)) {
397 info = "target restricted";
398 goto audit;
399 }
400
401 /* done if link subset test is not required */
402 if (!(perms.allow & AA_LINK_SUBSET))
403 goto done_tests;
404
405 /* Do link perm subset test requiring allowed permission on link are a
406 * subset of the allowed permissions on target.
407 */
408 aa_str_perms(profile->file.dfa, profile->file.start, tname, &cond,
409 &perms);
410
411 /* AA_MAY_LINK is not considered in the subset test */
412 request = lperms.allow & ~AA_MAY_LINK;
413 lperms.allow &= perms.allow | AA_MAY_LINK;
414
415 request |= AA_AUDIT_FILE_MASK & (lperms.allow & ~perms.allow);
416 if (request & ~lperms.allow) {
417 goto audit;
418 } else if ((lperms.allow & MAY_EXEC) &&
419 !xindex_is_subset(lperms.xindex, perms.xindex)) {
420 lperms.allow &= ~MAY_EXEC;
421 request |= MAY_EXEC;
422 info = "link not subset of target";
423 goto audit;
424 }
425
426done_tests:
427 error = 0;
428
429audit:
430 error = aa_audit_file(profile, &lperms, GFP_KERNEL, OP_LINK, request,
431 lname, tname, cond.uid, info, error);
432 kfree(buffer);
433 kfree(buffer2);
434
435 return error;
436}
437
438/**
439 * aa_file_perm - do permission revalidation check & audit for @file
440 * @op: operation being checked
441 * @profile: profile being enforced (NOT NULL)
442 * @file: file to revalidate access permissions on (NOT NULL)
443 * @request: requested permissions
444 *
445 * Returns: %0 if access allowed else error
446 */
447int aa_file_perm(int op, struct aa_profile *profile, struct file *file,
448 u32 request)
449{
450 struct path_cond cond = {
451 .uid = file->f_path.dentry->d_inode->i_uid,
452 .mode = file->f_path.dentry->d_inode->i_mode
453 };
454
455 return aa_path_perm(op, profile, &file->f_path, PATH_DELEGATE_DELETED,
456 request, &cond);
457}
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
new file mode 100644
index 00000000000..38ccaea0820
--- /dev/null
+++ b/security/apparmor/include/apparmor.h
@@ -0,0 +1,92 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor basic global and lib 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 __APPARMOR_H
16#define __APPARMOR_H
17
18#include <linux/fs.h>
19
20#include "match.h"
21
22/* Control parameters settable through module/boot flags */
23extern enum audit_mode aa_g_audit;
24extern int aa_g_audit_header;
25extern int aa_g_debug;
26extern int aa_g_lock_policy;
27extern int aa_g_logsyscall;
28extern int aa_g_paranoid_load;
29extern unsigned int aa_g_path_max;
30
31/*
32 * DEBUG remains global (no per profile flag) since it is mostly used in sysctl
33 * which is not related to profile accesses.
34 */
35
36#define AA_DEBUG(fmt, args...) \
37 do { \
38 if (aa_g_debug && printk_ratelimit()) \
39 printk(KERN_DEBUG "AppArmor: " fmt, ##args); \
40 } while (0)
41
42#define AA_ERROR(fmt, args...) \
43 do { \
44 if (printk_ratelimit()) \
45 printk(KERN_ERR "AppArmor: " fmt, ##args); \
46 } while (0)
47
48/* Flag indicating whether initialization completed */
49extern int apparmor_initialized __initdata;
50
51/* fn's in lib */
52char *aa_split_fqname(char *args, char **ns_name);
53void aa_info_message(const char *str);
54void *kvmalloc(size_t size);
55void kvfree(void *buffer);
56
57
58/**
59 * aa_strneq - compare null terminated @str to a non null terminated substring
60 * @str: a null terminated string
61 * @sub: a substring, not necessarily null terminated
62 * @len: length of @sub to compare
63 *
64 * The @str string must be full consumed for this to be considered a match
65 */
66static inline bool aa_strneq(const char *str, const char *sub, int len)
67{
68 return !strncmp(str, sub, len) && !str[len];
69}
70
71/**
72 * aa_dfa_null_transition - step to next state after null character
73 * @dfa: the dfa to match against
74 * @start: the state of the dfa to start matching in
75 *
76 * aa_dfa_null_transition transitions to the next state after a null
77 * character which is not used in standard matching and is only
78 * used to separate pairs.
79 */
80static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa,
81 unsigned int start)
82{
83 /* the null transition only needs the string's null terminator byte */
84 return aa_dfa_match_len(dfa, start, "", 1);
85}
86
87static inline bool mediated_filesystem(struct inode *inode)
88{
89 return !(inode->i_sb->s_flags & MS_NOUSER);
90}
91
92#endif /* __APPARMOR_H */
diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h
new file mode 100644
index 00000000000..cb1e93a114d
--- /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/audit.h b/security/apparmor/include/audit.h
new file mode 100644
index 00000000000..1951786d32e
--- /dev/null
+++ b/security/apparmor/include/audit.h
@@ -0,0 +1,123 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor auditing 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_AUDIT_H
16#define __AA_AUDIT_H
17
18#include <linux/audit.h>
19#include <linux/fs.h>
20#include <linux/lsm_audit.h>
21#include <linux/sched.h>
22#include <linux/slab.h>
23
24#include "file.h"
25
26struct aa_profile;
27
28extern const char *audit_mode_names[];
29#define AUDIT_MAX_INDEX 5
30
31#define AUDIT_APPARMOR_AUTO 0 /* auto choose audit message type */
32
33enum audit_mode {
34 AUDIT_NORMAL, /* follow normal auditing of accesses */
35 AUDIT_QUIET_DENIED, /* quiet all denied access messages */
36 AUDIT_QUIET, /* quiet all messages */
37 AUDIT_NOQUIET, /* do not quiet audit messages */
38 AUDIT_ALL /* audit all accesses */
39};
40
41enum audit_type {
42 AUDIT_APPARMOR_AUDIT,
43 AUDIT_APPARMOR_ALLOWED,
44 AUDIT_APPARMOR_DENIED,
45 AUDIT_APPARMOR_HINT,
46 AUDIT_APPARMOR_STATUS,
47 AUDIT_APPARMOR_ERROR,
48 AUDIT_APPARMOR_KILL
49};
50
51extern const char *op_table[];
52enum aa_ops {
53 OP_NULL,
54
55 OP_SYSCTL,
56 OP_CAPABLE,
57
58 OP_UNLINK,
59 OP_MKDIR,
60 OP_RMDIR,
61 OP_MKNOD,
62 OP_TRUNC,
63 OP_LINK,
64 OP_SYMLINK,
65 OP_RENAME_SRC,
66 OP_RENAME_DEST,
67 OP_CHMOD,
68 OP_CHOWN,
69 OP_GETATTR,
70 OP_OPEN,
71
72 OP_FPERM,
73 OP_FLOCK,
74 OP_FMMAP,
75 OP_FMPROT,
76
77 OP_CREATE,
78 OP_POST_CREATE,
79 OP_BIND,
80 OP_CONNECT,
81 OP_LISTEN,
82 OP_ACCEPT,
83 OP_SENDMSG,
84 OP_RECVMSG,
85 OP_GETSOCKNAME,
86 OP_GETPEERNAME,
87 OP_GETSOCKOPT,
88 OP_SETSOCKOPT,
89 OP_SOCK_SHUTDOWN,
90
91 OP_PTRACE,
92
93 OP_EXEC,
94 OP_CHANGE_HAT,
95 OP_CHANGE_PROFILE,
96 OP_CHANGE_ONEXEC,
97
98 OP_SETPROCATTR,
99 OP_SETRLIMIT,
100
101 OP_PROF_REPL,
102 OP_PROF_LOAD,
103 OP_PROF_RM,
104};
105
106
107/* define a short hand for apparmor_audit_data portion of common_audit_data */
108#define aad apparmor_audit_data
109
110void aa_audit_msg(int type, struct common_audit_data *sa,
111 void (*cb) (struct audit_buffer *, void *));
112int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
113 struct common_audit_data *sa,
114 void (*cb) (struct audit_buffer *, void *));
115
116static inline int complain_error(int error)
117{
118 if (error == -EPERM || error == -EACCES)
119 return 0;
120 return error;
121}
122
123#endif /* __AA_AUDIT_H */
diff --git a/security/apparmor/include/capability.h b/security/apparmor/include/capability.h
new file mode 100644
index 00000000000..c24d2959ea0
--- /dev/null
+++ b/security/apparmor/include/capability.h
@@ -0,0 +1,45 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor capability mediation 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_CAPABILITY_H
16#define __AA_CAPABILITY_H
17
18#include <linux/sched.h>
19
20struct aa_profile;
21
22/* aa_caps - confinement data for capabilities
23 * @allowed: capabilities mask
24 * @audit: caps that are to be audited
25 * @quiet: caps that should not be audited
26 * @kill: caps that when requested will result in the task being killed
27 * @extended: caps that are subject finer grained mediation
28 */
29struct aa_caps {
30 kernel_cap_t allow;
31 kernel_cap_t audit;
32 kernel_cap_t quiet;
33 kernel_cap_t kill;
34 kernel_cap_t extended;
35};
36
37int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap,
38 int audit);
39
40static inline void aa_free_cap_rules(struct aa_caps *caps)
41{
42 /* NOP */
43}
44
45#endif /* __AA_CAPBILITY_H */
diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h
new file mode 100644
index 00000000000..a9cbee4d9e4
--- /dev/null
+++ b/security/apparmor/include/context.h
@@ -0,0 +1,154 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor contexts used to associate "labels" to objects.
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_CONTEXT_H
16#define __AA_CONTEXT_H
17
18#include <linux/cred.h>
19#include <linux/slab.h>
20#include <linux/sched.h>
21
22#include "policy.h"
23
24/* struct aa_file_cxt - the AppArmor context the file was opened in
25 * @perms: the permission the file was opened with
26 *
27 * The file_cxt could currently be directly stored in file->f_security
28 * as the profile reference is now stored in the f_cred. However the
29 * cxt struct will expand in the future so we keep the struct.
30 */
31struct aa_file_cxt {
32 u16 allow;
33};
34
35/**
36 * aa_alloc_file_context - allocate file_cxt
37 * @gfp: gfp flags for allocation
38 *
39 * Returns: file_cxt or NULL on failure
40 */
41static inline struct aa_file_cxt *aa_alloc_file_context(gfp_t gfp)
42{
43 return kzalloc(sizeof(struct aa_file_cxt), gfp);
44}
45
46/**
47 * aa_free_file_context - free a file_cxt
48 * @cxt: file_cxt to free (MAYBE_NULL)
49 */
50static inline void aa_free_file_context(struct aa_file_cxt *cxt)
51{
52 if (cxt)
53 kzfree(cxt);
54}
55
56/**
57 * struct aa_task_cxt - primary label for confined tasks
58 * @profile: the current profile (NOT NULL)
59 * @exec: profile to transition to on next exec (MAYBE NULL)
60 * @previous: profile the task may return to (MAYBE NULL)
61 * @token: magic value the task must know for returning to @previous_profile
62 *
63 * Contains the task's current profile (which could change due to
64 * change_hat). Plus the hat_magic needed during change_hat.
65 *
66 * TODO: make so a task can be confined by a stack of contexts
67 */
68struct aa_task_cxt {
69 struct aa_profile *profile;
70 struct aa_profile *onexec;
71 struct aa_profile *previous;
72 u64 token;
73};
74
75struct aa_task_cxt *aa_alloc_task_context(gfp_t flags);
76void aa_free_task_context(struct aa_task_cxt *cxt);
77void aa_dup_task_context(struct aa_task_cxt *new,
78 const struct aa_task_cxt *old);
79int aa_replace_current_profile(struct aa_profile *profile);
80int aa_set_current_onexec(struct aa_profile *profile);
81int aa_set_current_hat(struct aa_profile *profile, u64 token);
82int aa_restore_previous_profile(u64 cookie);
83
84/**
85 * __aa_task_is_confined - determine if @task has any confinement
86 * @task: task to check confinement of (NOT NULL)
87 *
88 * If @task != current needs to be called in RCU safe critical section
89 */
90static inline bool __aa_task_is_confined(struct task_struct *task)
91{
92 struct aa_task_cxt *cxt = __task_cred(task)->security;
93
94 BUG_ON(!cxt || !cxt->profile);
95 if (unconfined(aa_newest_version(cxt->profile)))
96 return 0;
97
98 return 1;
99}
100
101/**
102 * aa_cred_profile - obtain cred's profiles
103 * @cred: cred to obtain profiles from (NOT NULL)
104 *
105 * Returns: confining profile
106 *
107 * does NOT increment reference count
108 */
109static inline struct aa_profile *aa_cred_profile(const struct cred *cred)
110{
111 struct aa_task_cxt *cxt = cred->security;
112 BUG_ON(!cxt || !cxt->profile);
113 return aa_newest_version(cxt->profile);
114}
115
116/**
117 * __aa_current_profile - find the current tasks confining profile
118 *
119 * Returns: up to date confining profile or the ns unconfined profile (NOT NULL)
120 *
121 * This fn will not update the tasks cred to the most up to date version
122 * of the profile so it is safe to call when inside of locks.
123 */
124static inline struct aa_profile *__aa_current_profile(void)
125{
126 return aa_cred_profile(current_cred());
127}
128
129/**
130 * aa_current_profile - find the current tasks confining profile and do updates
131 *
132 * Returns: up to date confining profile or the ns unconfined profile (NOT NULL)
133 *
134 * This fn will update the tasks cred structure if the profile has been
135 * replaced. Not safe to call inside locks
136 */
137static inline struct aa_profile *aa_current_profile(void)
138{
139 const struct aa_task_cxt *cxt = current_cred()->security;
140 struct aa_profile *profile;
141 BUG_ON(!cxt || !cxt->profile);
142
143 profile = aa_newest_version(cxt->profile);
144 /*
145 * Whether or not replacement succeeds, use newest profile so
146 * there is no need to update it after replacement.
147 */
148 if (unlikely((cxt->profile != profile)))
149 aa_replace_current_profile(profile);
150
151 return profile;
152}
153
154#endif /* __AA_CONTEXT_H */
diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
new file mode 100644
index 00000000000..de04464f0a3
--- /dev/null
+++ b/security/apparmor/include/domain.h
@@ -0,0 +1,36 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor security domain transition 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#include <linux/binfmts.h>
16#include <linux/types.h>
17
18#ifndef __AA_DOMAIN_H
19#define __AA_DOMAIN_H
20
21struct aa_domain {
22 int size;
23 char **table;
24};
25
26int apparmor_bprm_set_creds(struct linux_binprm *bprm);
27int apparmor_bprm_secureexec(struct linux_binprm *bprm);
28void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
29void apparmor_bprm_committed_creds(struct linux_binprm *bprm);
30
31void aa_free_domain_entries(struct aa_domain *domain);
32int aa_change_hat(const char *hats[], int count, u64 token, bool permtest);
33int aa_change_profile(const char *ns_name, const char *name, bool onexec,
34 bool permtest);
35
36#endif /* __AA_DOMAIN_H */
diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h
new file mode 100644
index 00000000000..be36feabb16
--- /dev/null
+++ b/security/apparmor/include/file.h
@@ -0,0 +1,217 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor file mediation 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_FILE_H
16#define __AA_FILE_H
17
18#include <linux/path.h>
19
20#include "domain.h"
21#include "match.h"
22
23struct aa_profile;
24
25/*
26 * We use MAY_EXEC, MAY_WRITE, MAY_READ, MAY_APPEND and the following flags
27 * for profile permissions
28 */
29#define AA_MAY_CREATE 0x0010
30#define AA_MAY_DELETE 0x0020
31#define AA_MAY_META_WRITE 0x0040
32#define AA_MAY_META_READ 0x0080
33
34#define AA_MAY_CHMOD 0x0100
35#define AA_MAY_CHOWN 0x0200
36#define AA_MAY_LOCK 0x0400
37#define AA_EXEC_MMAP 0x0800
38
39#define AA_MAY_LINK 0x1000
40#define AA_LINK_SUBSET AA_MAY_LOCK /* overlaid */
41#define AA_MAY_ONEXEC 0x40000000 /* exec allows onexec */
42#define AA_MAY_CHANGE_PROFILE 0x80000000
43#define AA_MAY_CHANGEHAT 0x80000000 /* ctrl auditing only */
44
45#define AA_AUDIT_FILE_MASK (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND |\
46 AA_MAY_CREATE | AA_MAY_DELETE | \
47 AA_MAY_META_READ | AA_MAY_META_WRITE | \
48 AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \
49 AA_EXEC_MMAP | AA_MAY_LINK)
50
51/*
52 * The xindex is broken into 3 parts
53 * - index - an index into either the exec name table or the variable table
54 * - exec type - which determines how the executable name and index are used
55 * - flags - which modify how the destination name is applied
56 */
57#define AA_X_INDEX_MASK 0x03ff
58
59#define AA_X_TYPE_MASK 0x0c00
60#define AA_X_TYPE_SHIFT 10
61#define AA_X_NONE 0x0000
62#define AA_X_NAME 0x0400 /* use executable name px */
63#define AA_X_TABLE 0x0800 /* use a specified name ->n# */
64
65#define AA_X_UNSAFE 0x1000
66#define AA_X_CHILD 0x2000 /* make >AA_X_NONE apply to children */
67#define AA_X_INHERIT 0x4000
68#define AA_X_UNCONFINED 0x8000
69
70/* AA_SECURE_X_NEEDED - is passed in the bprm->unsafe field */
71#define AA_SECURE_X_NEEDED 0x8000
72
73/* need to make conditional which ones are being set */
74struct path_cond {
75 uid_t uid;
76 umode_t mode;
77};
78
79/* struct file_perms - file permission
80 * @allow: mask of permissions that are allowed
81 * @audit: mask of permissions to force an audit message for
82 * @quiet: mask of permissions to quiet audit messages for
83 * @kill: mask of permissions that when matched will kill the task
84 * @xindex: exec transition index if @allow contains MAY_EXEC
85 *
86 * The @audit and @queit mask should be mutually exclusive.
87 */
88struct file_perms {
89 u32 allow;
90 u32 audit;
91 u32 quiet;
92 u32 kill;
93 u16 xindex;
94};
95
96extern struct file_perms nullperms;
97
98#define COMBINED_PERM_MASK(X) ((X).allow | (X).audit | (X).quiet | (X).kill)
99
100/* FIXME: split perms from dfa and match this to description
101 * also add delegation info.
102 */
103static inline u16 dfa_map_xindex(u16 mask)
104{
105 u16 old_index = (mask >> 10) & 0xf;
106 u16 index = 0;
107
108 if (mask & 0x100)
109 index |= AA_X_UNSAFE;
110 if (mask & 0x200)
111 index |= AA_X_INHERIT;
112 if (mask & 0x80)
113 index |= AA_X_UNCONFINED;
114
115 if (old_index == 1) {
116 index |= AA_X_UNCONFINED;
117 } else if (old_index == 2) {
118 index |= AA_X_NAME;
119 } else if (old_index == 3) {
120 index |= AA_X_NAME | AA_X_CHILD;
121 } else {
122 index |= AA_X_TABLE;
123 index |= old_index - 4;
124 }
125
126 return index;
127}
128
129/*
130 * map old dfa inline permissions to new format
131 */
132#define dfa_user_allow(dfa, state) (((ACCEPT_TABLE(dfa)[state]) & 0x7f) | \
133 ((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
134#define dfa_user_audit(dfa, state) ((ACCEPT_TABLE2(dfa)[state]) & 0x7f)
135#define dfa_user_quiet(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 7) & 0x7f)
136#define dfa_user_xindex(dfa, state) \
137 (dfa_map_xindex(ACCEPT_TABLE(dfa)[state] & 0x3fff))
138
139#define dfa_other_allow(dfa, state) ((((ACCEPT_TABLE(dfa)[state]) >> 14) & \
140 0x7f) | \
141 ((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
142#define dfa_other_audit(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 14) & 0x7f)
143#define dfa_other_quiet(dfa, state) \
144 ((((ACCEPT_TABLE2(dfa)[state]) >> 7) >> 14) & 0x7f)
145#define dfa_other_xindex(dfa, state) \
146 dfa_map_xindex((ACCEPT_TABLE(dfa)[state] >> 14) & 0x3fff)
147
148int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
149 gfp_t gfp, int op, u32 request, const char *name,
150 const char *target, uid_t ouid, const char *info, int error);
151
152/**
153 * struct aa_file_rules - components used for file rule permissions
154 * @dfa: dfa to match path names and conditionals against
155 * @perms: permission table indexed by the matched state accept entry of @dfa
156 * @trans: transition table for indexed by named x transitions
157 *
158 * File permission are determined by matching a path against @dfa and then
159 * then using the value of the accept entry for the matching state as
160 * an index into @perms. If a named exec transition is required it is
161 * looked up in the transition table.
162 */
163struct aa_file_rules {
164 unsigned int start;
165 struct aa_dfa *dfa;
166 /* struct perms perms; */
167 struct aa_domain trans;
168 /* TODO: add delegate table */
169};
170
171unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
172 const char *name, struct path_cond *cond,
173 struct file_perms *perms);
174
175int aa_path_perm(int op, struct aa_profile *profile, struct path *path,
176 int flags, u32 request, struct path_cond *cond);
177
178int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
179 struct path *new_dir, struct dentry *new_dentry);
180
181int aa_file_perm(int op, struct aa_profile *profile, struct file *file,
182 u32 request);
183
184static inline void aa_free_file_rules(struct aa_file_rules *rules)
185{
186 aa_put_dfa(rules->dfa);
187 aa_free_domain_entries(&rules->trans);
188}
189
190#define ACC_FMODE(x) (("\000\004\002\006"[(x)&O_ACCMODE]) | (((x) << 1) & 0x40))
191
192/* from namei.c */
193#define MAP_OPEN_FLAGS(x) ((((x) + 1) & O_ACCMODE) ? (x) + 1 : (x))
194
195/**
196 * aa_map_file_perms - map file flags to AppArmor permissions
197 * @file: open file to map flags to AppArmor permissions
198 *
199 * Returns: apparmor permission set for the file
200 */
201static inline u32 aa_map_file_to_perms(struct file *file)
202{
203 int flags = MAP_OPEN_FLAGS(file->f_flags);
204 u32 perms = ACC_FMODE(file->f_mode);
205
206 if ((flags & O_APPEND) && (perms & MAY_WRITE))
207 perms = (perms & ~MAY_WRITE) | MAY_APPEND;
208 /* trunc implies write permission */
209 if (flags & O_TRUNC)
210 perms |= MAY_WRITE;
211 if (flags & O_CREAT)
212 perms |= AA_MAY_CREATE;
213
214 return perms;
215}
216
217#endif /* __AA_FILE_H */
diff --git a/security/apparmor/include/ipc.h b/security/apparmor/include/ipc.h
new file mode 100644
index 00000000000..aeda0fbc8b2
--- /dev/null
+++ b/security/apparmor/include/ipc.h
@@ -0,0 +1,28 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor ipc mediation 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_IPC_H
16#define __AA_IPC_H
17
18#include <linux/sched.h>
19
20struct aa_profile;
21
22int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer,
23 struct aa_profile *tracee, unsigned int mode);
24
25int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
26 unsigned int mode);
27
28#endif /* __AA_IPC_H */
diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h
new file mode 100644
index 00000000000..734a6d35112
--- /dev/null
+++ b/security/apparmor/include/match.h
@@ -0,0 +1,132 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor policy dfa matching engine 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_MATCH_H
16#define __AA_MATCH_H
17
18#include <linux/workqueue.h>
19
20#define DFA_NOMATCH 0
21#define DFA_START 1
22
23#define DFA_VALID_PERM_MASK 0xffffffff
24#define DFA_VALID_PERM2_MASK 0xffffffff
25
26/**
27 * The format used for transition tables is based on the GNU flex table
28 * file format (--tables-file option; see Table File Format in the flex
29 * info pages and the flex sources for documentation). The magic number
30 * used in the header is 0x1B5E783D insted of 0xF13C57B1 though, because
31 * the YY_ID_CHK (check) and YY_ID_DEF (default) tables are used
32 * slightly differently (see the apparmor-parser package).
33 */
34
35#define YYTH_MAGIC 0x1B5E783D
36#define YYTH_DEF_RECURSE 0x1 /* DEF Table is recursive */
37
38struct table_set_header {
39 u32 th_magic; /* YYTH_MAGIC */
40 u32 th_hsize;
41 u32 th_ssize;
42 u16 th_flags;
43 char th_version[];
44};
45
46/* The YYTD_ID are one less than flex table mappings. The flex id
47 * has 1 subtracted at table load time, this allows us to directly use the
48 * ID's as indexes.
49 */
50#define YYTD_ID_ACCEPT 0
51#define YYTD_ID_BASE 1
52#define YYTD_ID_CHK 2
53#define YYTD_ID_DEF 3
54#define YYTD_ID_EC 4
55#define YYTD_ID_META 5
56#define YYTD_ID_ACCEPT2 6
57#define YYTD_ID_NXT 7
58#define YYTD_ID_TSIZE 8
59
60#define YYTD_DATA8 1
61#define YYTD_DATA16 2
62#define YYTD_DATA32 4
63#define YYTD_DATA64 8
64
65/* Each ACCEPT2 table gets 6 dedicated flags, YYTD_DATAX define the
66 * first flags
67 */
68#define ACCEPT1_FLAGS(X) ((X) & 0x3f)
69#define ACCEPT2_FLAGS(X) ACCEPT1_FLAGS((X) >> YYTD_ID_ACCEPT2)
70#define TO_ACCEPT1_FLAG(X) ACCEPT1_FLAGS(X)
71#define TO_ACCEPT2_FLAG(X) (ACCEPT1_FLAGS(X) << YYTD_ID_ACCEPT2)
72#define DFA_FLAG_VERIFY_STATES 0x1000
73
74struct table_header {
75 u16 td_id;
76 u16 td_flags;
77 u32 td_hilen;
78 u32 td_lolen;
79 char td_data[];
80};
81
82#define DEFAULT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_DEF]->td_data))
83#define BASE_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_BASE]->td_data))
84#define NEXT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_NXT]->td_data))
85#define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK]->td_data))
86#define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC]->td_data))
87#define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT]->td_data))
88#define ACCEPT_TABLE2(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT2]->td_data))
89
90struct aa_dfa {
91 struct kref count;
92 u16 flags;
93 struct table_header *tables[YYTD_ID_TSIZE];
94};
95
96#define byte_to_byte(X) (X)
97
98#define UNPACK_ARRAY(TABLE, BLOB, LEN, TYPE, NTOHX) \
99 do { \
100 typeof(LEN) __i; \
101 TYPE *__t = (TYPE *) TABLE; \
102 TYPE *__b = (TYPE *) BLOB; \
103 for (__i = 0; __i < LEN; __i++) { \
104 __t[__i] = NTOHX(__b[__i]); \
105 } \
106 } while (0)
107
108static inline size_t table_size(size_t len, size_t el_size)
109{
110 return ALIGN(sizeof(struct table_header) + len * el_size, 8);
111}
112
113struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags);
114unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
115 const char *str, int len);
116unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
117 const char *str);
118void aa_dfa_free_kref(struct kref *kref);
119
120/**
121 * aa_put_dfa - put a dfa refcount
122 * @dfa: dfa to put refcount (MAYBE NULL)
123 *
124 * Requires: if @dfa != NULL that a valid refcount be held
125 */
126static inline void aa_put_dfa(struct aa_dfa *dfa)
127{
128 if (dfa)
129 kref_put(&dfa->count, aa_dfa_free_kref);
130}
131
132#endif /* __AA_MATCH_H */
diff --git a/security/apparmor/include/path.h b/security/apparmor/include/path.h
new file mode 100644
index 00000000000..27b327a7fae
--- /dev/null
+++ b/security/apparmor/include/path.h
@@ -0,0 +1,31 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor basic path manipulation 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_PATH_H
16#define __AA_PATH_H
17
18
19enum path_flags {
20 PATH_IS_DIR = 0x1, /* path is a directory */
21 PATH_CONNECT_PATH = 0x4, /* connect disconnected paths to / */
22 PATH_CHROOT_REL = 0x8, /* do path lookup relative to chroot */
23 PATH_CHROOT_NSCONNECT = 0x10, /* connect paths that are at ns root */
24
25 PATH_DELEGATE_DELETED = 0x08000, /* delegate deleted files */
26 PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */
27};
28
29int aa_get_name(struct path *path, int flags, char **buffer, const char **name);
30
31#endif /* __AA_PATH_H */
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
new file mode 100644
index 00000000000..aeda5cf5690
--- /dev/null
+++ b/security/apparmor/include/policy.h
@@ -0,0 +1,305 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor policy 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_POLICY_H
16#define __AA_POLICY_H
17
18#include <linux/capability.h>
19#include <linux/cred.h>
20#include <linux/kref.h>
21#include <linux/sched.h>
22#include <linux/slab.h>
23#include <linux/socket.h>
24
25#include "apparmor.h"
26#include "audit.h"
27#include "capability.h"
28#include "domain.h"
29#include "file.h"
30#include "resource.h"
31
32extern const char *profile_mode_names[];
33#define APPARMOR_NAMES_MAX_INDEX 3
34
35#define COMPLAIN_MODE(_profile) \
36 ((aa_g_profile_mode == APPARMOR_COMPLAIN) || \
37 ((_profile)->mode == APPARMOR_COMPLAIN))
38
39#define KILL_MODE(_profile) \
40 ((aa_g_profile_mode == APPARMOR_KILL) || \
41 ((_profile)->mode == APPARMOR_KILL))
42
43#define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT)
44
45/*
46 * FIXME: currently need a clean way to replace and remove profiles as a
47 * set. It should be done at the namespace level.
48 * Either, with a set of profiles loaded at the namespace level or via
49 * a mark and remove marked interface.
50 */
51enum profile_mode {
52 APPARMOR_ENFORCE, /* enforce access rules */
53 APPARMOR_COMPLAIN, /* allow and log access violations */
54 APPARMOR_KILL, /* kill task on access violation */
55};
56
57enum profile_flags {
58 PFLAG_HAT = 1, /* profile is a hat */
59 PFLAG_UNCONFINED = 2, /* profile is an unconfined profile */
60 PFLAG_NULL = 4, /* profile is null learning profile */
61 PFLAG_IX_ON_NAME_ERROR = 8, /* fallback to ix on name lookup fail */
62 PFLAG_IMMUTABLE = 0x10, /* don't allow changes/replacement */
63 PFLAG_USER_DEFINED = 0x20, /* user based profile - lower privs */
64 PFLAG_NO_LIST_REF = 0x40, /* list doesn't keep profile ref */
65 PFLAG_OLD_NULL_TRANS = 0x100, /* use // as the null transition */
66
67 /* These flags must correspond with PATH_flags */
68 PFLAG_MEDIATE_DELETED = 0x10000, /* mediate instead delegate deleted */
69};
70
71struct aa_profile;
72
73/* struct aa_policy - common part of both namespaces and profiles
74 * @name: name of the object
75 * @hname - The hierarchical name
76 * @count: reference count of the obj
77 * @list: list policy object is on
78 * @profiles: head of the profiles list contained in the object
79 */
80struct aa_policy {
81 char *name;
82 char *hname;
83 struct kref count;
84 struct list_head list;
85 struct list_head profiles;
86};
87
88/* struct aa_ns_acct - accounting of profiles in namespace
89 * @max_size: maximum space allowed for all profiles in namespace
90 * @max_count: maximum number of profiles that can be in this namespace
91 * @size: current size of profiles
92 * @count: current count of profiles (includes null profiles)
93 */
94struct aa_ns_acct {
95 int max_size;
96 int max_count;
97 int size;
98 int count;
99};
100
101/* struct aa_namespace - namespace for a set of profiles
102 * @base: common policy
103 * @parent: parent of namespace
104 * @lock: lock for modifying the object
105 * @acct: accounting for the namespace
106 * @unconfined: special unconfined profile for the namespace
107 * @sub_ns: list of namespaces under the current namespace.
108 *
109 * An aa_namespace defines the set profiles that are searched to determine
110 * which profile to attach to a task. Profiles can not be shared between
111 * aa_namespaces and profile names within a namespace are guaranteed to be
112 * unique. When profiles in separate namespaces have the same name they
113 * are NOT considered to be equivalent.
114 *
115 * Namespaces are hierarchical and only namespaces and profiles below the
116 * current namespace are visible.
117 *
118 * Namespace names must be unique and can not contain the characters :/\0
119 *
120 * FIXME TODO: add vserver support of namespaces (can it all be done in
121 * userspace?)
122 */
123struct aa_namespace {
124 struct aa_policy base;
125 struct aa_namespace *parent;
126 rwlock_t lock;
127 struct aa_ns_acct acct;
128 struct aa_profile *unconfined;
129 struct list_head sub_ns;
130};
131
132/* struct aa_profile - basic confinement data
133 * @base - base components of the profile (name, refcount, lists, lock ...)
134 * @parent: parent of profile
135 * @ns: namespace the profile is in
136 * @replacedby: is set to the profile that replaced this profile
137 * @rename: optional profile name that this profile renamed
138 * @xmatch: optional extended matching for unconfined executables names
139 * @xmatch_len: xmatch prefix len, used to determine xmatch priority
140 * @sid: the unique security id number of this profile
141 * @audit: the auditing mode of the profile
142 * @mode: the enforcement mode of the profile
143 * @flags: flags controlling profile behavior
144 * @path_flags: flags controlling path generation behavior
145 * @size: the memory consumed by this profiles rules
146 * @file: The set of rules governing basic file access and domain transitions
147 * @caps: capabilities for the profile
148 * @rlimits: rlimits for the profile
149 *
150 * The AppArmor profile contains the basic confinement data. Each profile
151 * has a name, and exists in a namespace. The @name and @exec_match are
152 * used to determine profile attachment against unconfined tasks. All other
153 * attachments are determined by profile X transition rules.
154 *
155 * The @replacedby field is write protected by the profile lock. Reads
156 * are assumed to be atomic, and are done without locking.
157 *
158 * Profiles have a hierarchy where hats and children profiles keep
159 * a reference to their parent.
160 *
161 * Profile names can not begin with a : and can not contain the \0
162 * character. If a profile name begins with / it will be considered when
163 * determining profile attachment on "unconfined" tasks.
164 */
165struct aa_profile {
166 struct aa_policy base;
167 struct aa_profile *parent;
168
169 struct aa_namespace *ns;
170 struct aa_profile *replacedby;
171 const char *rename;
172
173 struct aa_dfa *xmatch;
174 int xmatch_len;
175 u32 sid;
176 enum audit_mode audit;
177 enum profile_mode mode;
178 u32 flags;
179 u32 path_flags;
180 int size;
181
182 struct aa_file_rules file;
183 struct aa_caps caps;
184 struct aa_rlimit rlimits;
185};
186
187extern struct aa_namespace *root_ns;
188extern enum profile_mode aa_g_profile_mode;
189
190void aa_add_profile(struct aa_policy *common, struct aa_profile *profile);
191
192bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view);
193const char *aa_ns_name(struct aa_namespace *parent, struct aa_namespace *child);
194int aa_alloc_root_ns(void);
195void aa_free_root_ns(void);
196void aa_free_namespace_kref(struct kref *kref);
197
198struct aa_namespace *aa_find_namespace(struct aa_namespace *root,
199 const char *name);
200
201static inline struct aa_policy *aa_get_common(struct aa_policy *c)
202{
203 if (c)
204 kref_get(&c->count);
205
206 return c;
207}
208
209/**
210 * aa_get_namespace - increment references count on @ns
211 * @ns: namespace to increment reference count of (MAYBE NULL)
212 *
213 * Returns: pointer to @ns, if @ns is NULL returns NULL
214 * Requires: @ns must be held with valid refcount when called
215 */
216static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns)
217{
218 if (ns)
219 kref_get(&(ns->base.count));
220
221 return ns;
222}
223
224/**
225 * aa_put_namespace - decrement refcount on @ns
226 * @ns: namespace to put reference of
227 *
228 * Decrement reference count of @ns and if no longer in use free it
229 */
230static inline void aa_put_namespace(struct aa_namespace *ns)
231{
232 if (ns)
233 kref_put(&ns->base.count, aa_free_namespace_kref);
234}
235
236struct aa_profile *aa_alloc_profile(const char *name);
237struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat);
238void aa_free_profile_kref(struct kref *kref);
239struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name);
240struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *name);
241struct aa_profile *aa_match_profile(struct aa_namespace *ns, const char *name);
242
243ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace);
244ssize_t aa_remove_profiles(char *name, size_t size);
245
246#define PROF_ADD 1
247#define PROF_REPLACE 0
248
249#define unconfined(X) ((X)->flags & PFLAG_UNCONFINED)
250
251/**
252 * aa_newest_version - find the newest version of @profile
253 * @profile: the profile to check for newer versions of (NOT NULL)
254 *
255 * Returns: newest version of @profile, if @profile is the newest version
256 * return @profile.
257 *
258 * NOTE: the profile returned is not refcounted, The refcount on @profile
259 * must be held until the caller decides what to do with the returned newest
260 * version.
261 */
262static inline struct aa_profile *aa_newest_version(struct aa_profile *profile)
263{
264 while (profile->replacedby)
265 profile = profile->replacedby;
266
267 return profile;
268}
269
270/**
271 * aa_get_profile - increment refcount on profile @p
272 * @p: profile (MAYBE NULL)
273 *
274 * Returns: pointer to @p if @p is NULL will return NULL
275 * Requires: @p must be held with valid refcount when called
276 */
277static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
278{
279 if (p)
280 kref_get(&(p->base.count));
281
282 return p;
283}
284
285/**
286 * aa_put_profile - decrement refcount on profile @p
287 * @p: profile (MAYBE NULL)
288 */
289static inline void aa_put_profile(struct aa_profile *p)
290{
291 if (p)
292 kref_put(&p->base.count, aa_free_profile_kref);
293}
294
295static inline int AUDIT_MODE(struct aa_profile *profile)
296{
297 if (aa_g_audit != AUDIT_NORMAL)
298 return aa_g_audit;
299
300 return profile->audit;
301}
302
303bool aa_may_manage_policy(int op);
304
305#endif /* __AA_POLICY_H */
diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h
new file mode 100644
index 00000000000..a2dcccac45a
--- /dev/null
+++ b/security/apparmor/include/policy_unpack.h
@@ -0,0 +1,20 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor policy loading 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 __POLICY_INTERFACE_H
16#define __POLICY_INTERFACE_H
17
18struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns);
19
20#endif /* __POLICY_INTERFACE_H */
diff --git a/security/apparmor/include/procattr.h b/security/apparmor/include/procattr.h
new file mode 100644
index 00000000000..544aa6b766a
--- /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/include/resource.h b/security/apparmor/include/resource.h
new file mode 100644
index 00000000000..3c88be94649
--- /dev/null
+++ b/security/apparmor/include/resource.h
@@ -0,0 +1,46 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor resource limits 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_RESOURCE_H
16#define __AA_RESOURCE_H
17
18#include <linux/resource.h>
19#include <linux/sched.h>
20
21struct aa_profile;
22
23/* struct aa_rlimit - rlimit settings for the profile
24 * @mask: which hard limits to set
25 * @limits: rlimit values that override task limits
26 *
27 * AppArmor rlimits are used to set confined task rlimits. Only the
28 * limits specified in @mask will be controlled by apparmor.
29 */
30struct aa_rlimit {
31 unsigned int mask;
32 struct rlimit limits[RLIM_NLIMITS];
33};
34
35int aa_map_resource(int resource);
36int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
37 struct rlimit *new_rlim);
38
39void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new);
40
41static inline void aa_free_rlimit_rules(struct aa_rlimit *rlims)
42{
43 /* NOP */
44}
45
46#endif /* __AA_RESOURCE_H */
diff --git a/security/apparmor/include/sid.h b/security/apparmor/include/sid.h
new file mode 100644
index 00000000000..020db35c301
--- /dev/null
+++ b/security/apparmor/include/sid.h
@@ -0,0 +1,24 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor security identifier (sid) definitions
5 *
6 * Copyright 2009-2010 Canonical Ltd.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation, version 2 of the
11 * License.
12 */
13
14#ifndef __AA_SID_H
15#define __AA_SID_H
16
17#include <linux/types.h>
18
19struct aa_profile;
20
21u32 aa_alloc_sid(void);
22void aa_free_sid(u32 sid);
23
24#endif /* __AA_SID_H */
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c
new file mode 100644
index 00000000000..649fad88869
--- /dev/null
+++ b/security/apparmor/ipc.c
@@ -0,0 +1,114 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor ipc mediation
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/gfp.h>
16#include <linux/ptrace.h>
17
18#include "include/audit.h"
19#include "include/capability.h"
20#include "include/context.h"
21#include "include/policy.h"
22
23/* call back to audit ptrace fields */
24static void audit_cb(struct audit_buffer *ab, void *va)
25{
26 struct common_audit_data *sa = va;
27 audit_log_format(ab, " target=");
28 audit_log_untrustedstring(ab, sa->aad.target);
29}
30
31/**
32 * aa_audit_ptrace - do auditing for ptrace
33 * @profile: profile being enforced (NOT NULL)
34 * @target: profile being traced (NOT NULL)
35 * @error: error condition
36 *
37 * Returns: %0 or error code
38 */
39static int aa_audit_ptrace(struct aa_profile *profile,
40 struct aa_profile *target, int error)
41{
42 struct common_audit_data sa;
43 COMMON_AUDIT_DATA_INIT(&sa, NONE);
44 sa.aad.op = OP_PTRACE;
45 sa.aad.target = target;
46 sa.aad.error = error;
47
48 return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_ATOMIC, &sa,
49 audit_cb);
50}
51
52/**
53 * aa_may_ptrace - test if tracer task can trace the tracee
54 * @tracer_task: task who will do the tracing (NOT NULL)
55 * @tracer: profile of the task doing the tracing (NOT NULL)
56 * @tracee: task to be traced
57 * @mode: whether PTRACE_MODE_READ || PTRACE_MODE_ATTACH
58 *
59 * Returns: %0 else error code if permission denied or error
60 */
61int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer,
62 struct aa_profile *tracee, unsigned int mode)
63{
64 /* TODO: currently only based on capability, not extended ptrace
65 * rules,
66 * Test mode for PTRACE_MODE_READ || PTRACE_MODE_ATTACH
67 */
68
69 if (unconfined(tracer) || tracer == tracee)
70 return 0;
71 /* log this capability request */
72 return aa_capable(tracer_task, tracer, CAP_SYS_PTRACE, 1);
73}
74
75/**
76 * aa_ptrace - do ptrace permission check and auditing
77 * @tracer: task doing the tracing (NOT NULL)
78 * @tracee: task being traced (NOT NULL)
79 * @mode: ptrace mode either PTRACE_MODE_READ || PTRACE_MODE_ATTACH
80 *
81 * Returns: %0 else error code if permission denied or error
82 */
83int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
84 unsigned int mode)
85{
86 /*
87 * tracer can ptrace tracee when
88 * - tracer is unconfined ||
89 * - tracer is in complain mode
90 * - tracer has rules allowing it to trace tracee currently this is:
91 * - confined by the same profile ||
92 * - tracer profile has CAP_SYS_PTRACE
93 */
94
95 struct aa_profile *tracer_p;
96 /* cred released below */
97 const struct cred *cred = get_task_cred(tracer);
98 int error = 0;
99 tracer_p = aa_cred_profile(cred);
100
101 if (!unconfined(tracer_p)) {
102 /* lcred released below */
103 const struct cred *lcred = get_task_cred(tracee);
104 struct aa_profile *tracee_p = aa_cred_profile(lcred);
105
106 error = aa_may_ptrace(tracer, tracer_p, tracee_p, mode);
107 error = aa_audit_ptrace(tracer_p, tracee_p, error);
108
109 put_cred(lcred);
110 }
111 put_cred(cred);
112
113 return error;
114}
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
new file mode 100644
index 00000000000..6e85cdb4303
--- /dev/null
+++ b/security/apparmor/lib.c
@@ -0,0 +1,133 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains basic common functions used in AppArmor
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/slab.h>
16#include <linux/string.h>
17#include <linux/vmalloc.h>
18
19#include "include/audit.h"
20
21
22/**
23 * aa_split_fqname - split a fqname into a profile and namespace name
24 * @fqname: a full qualified name in namespace profile format (NOT NULL)
25 * @ns_name: pointer to portion of the string containing the ns name (NOT NULL)
26 *
27 * Returns: profile name or NULL if one is not specified
28 *
29 * Split a namespace name from a profile name (see policy.c for naming
30 * description). If a portion of the name is missing it returns NULL for
31 * that portion.
32 *
33 * NOTE: may modify the @fqname string. The pointers returned point
34 * into the @fqname string.
35 */
36char *aa_split_fqname(char *fqname, char **ns_name)
37{
38 char *name = strim(fqname);
39
40 *ns_name = NULL;
41 if (name[0] == ':') {
42 char *split = strchr(&name[1], ':');
43 if (split) {
44 /* overwrite ':' with \0 */
45 *split = 0;
46 name = skip_spaces(split + 1);
47 } else
48 /* a ns name without a following profile is allowed */
49 name = NULL;
50 *ns_name = &name[1];
51 }
52 if (name && *name == 0)
53 name = NULL;
54
55 return name;
56}
57
58/**
59 * aa_info_message - log a none profile related status message
60 * @str: message to log
61 */
62void aa_info_message(const char *str)
63{
64 if (audit_enabled) {
65 struct common_audit_data sa;
66 COMMON_AUDIT_DATA_INIT(&sa, NONE);
67 sa.aad.info = str;
68 aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
69 }
70 printk(KERN_INFO "AppArmor: %s\n", str);
71}
72
73/**
74 * kvmalloc - do allocation preferring kmalloc but falling back to vmalloc
75 * @size: size of allocation
76 *
77 * Return: allocated buffer or NULL if failed
78 *
79 * It is possible that policy being loaded from the user is larger than
80 * what can be allocated by kmalloc, in those cases fall back to vmalloc.
81 */
82void *kvmalloc(size_t size)
83{
84 void *buffer = NULL;
85
86 if (size == 0)
87 return NULL;
88
89 /* do not attempt kmalloc if we need more than 16 pages at once */
90 if (size <= (16*PAGE_SIZE))
91 buffer = kmalloc(size, GFP_NOIO | __GFP_NOWARN);
92 if (!buffer) {
93 /* see kvfree for why size must be at least work_struct size
94 * when allocated via vmalloc
95 */
96 if (size < sizeof(struct work_struct))
97 size = sizeof(struct work_struct);
98 buffer = vmalloc(size);
99 }
100 return buffer;
101}
102
103/**
104 * do_vfree - workqueue routine for freeing vmalloced memory
105 * @work: data to be freed
106 *
107 * The work_struct is overlaid to the data being freed, as at the point
108 * the work is scheduled the data is no longer valid, be its freeing
109 * needs to be delayed until safe.
110 */
111static void do_vfree(struct work_struct *work)
112{
113 vfree(work);
114}
115
116/**
117 * kvfree - free an allocation do by kvmalloc
118 * @buffer: buffer to free (MAYBE_NULL)
119 *
120 * Free a buffer allocated by kvmalloc
121 */
122void kvfree(void *buffer)
123{
124 if (is_vmalloc_addr(buffer)) {
125 /* Data is no longer valid so just use the allocated space
126 * as the work_struct
127 */
128 struct work_struct *work = (struct work_struct *) buffer;
129 INIT_WORK(work, do_vfree);
130 schedule_work(work);
131 } else
132 kfree(buffer);
133}
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
new file mode 100644
index 00000000000..8db33a8b50c
--- /dev/null
+++ b/security/apparmor/lsm.c
@@ -0,0 +1,938 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor LSM hooks.
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/moduleparam.h>
17#include <linux/mm.h>
18#include <linux/mman.h>
19#include <linux/mount.h>
20#include <linux/namei.h>
21#include <linux/ptrace.h>
22#include <linux/ctype.h>
23#include <linux/sysctl.h>
24#include <linux/audit.h>
25#include <net/sock.h>
26
27#include "include/apparmor.h"
28#include "include/apparmorfs.h"
29#include "include/audit.h"
30#include "include/capability.h"
31#include "include/context.h"
32#include "include/file.h"
33#include "include/ipc.h"
34#include "include/path.h"
35#include "include/policy.h"
36#include "include/procattr.h"
37
38/* Flag indicating whether initialization completed */
39int apparmor_initialized __initdata;
40
41/*
42 * LSM hook functions
43 */
44
45/*
46 * free the associated aa_task_cxt and put its profiles
47 */
48static void apparmor_cred_free(struct cred *cred)
49{
50 aa_free_task_context(cred->security);
51 cred->security = NULL;
52}
53
54/*
55 * allocate the apparmor part of blank credentials
56 */
57static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp)
58{
59 /* freed by apparmor_cred_free */
60 struct aa_task_cxt *cxt = aa_alloc_task_context(gfp);
61 if (!cxt)
62 return -ENOMEM;
63
64 cred->security = cxt;
65 return 0;
66}
67
68/*
69 * prepare new aa_task_cxt for modification by prepare_cred block
70 */
71static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
72 gfp_t gfp)
73{
74 /* freed by apparmor_cred_free */
75 struct aa_task_cxt *cxt = aa_alloc_task_context(gfp);
76 if (!cxt)
77 return -ENOMEM;
78
79 aa_dup_task_context(cxt, old->security);
80 new->security = cxt;
81 return 0;
82}
83
84/*
85 * transfer the apparmor data to a blank set of creds
86 */
87static void apparmor_cred_transfer(struct cred *new, const struct cred *old)
88{
89 const struct aa_task_cxt *old_cxt = old->security;
90 struct aa_task_cxt *new_cxt = new->security;
91
92 aa_dup_task_context(new_cxt, old_cxt);
93}
94
95static int apparmor_ptrace_access_check(struct task_struct *child,
96 unsigned int mode)
97{
98 int error = cap_ptrace_access_check(child, mode);
99 if (error)
100 return error;
101
102 return aa_ptrace(current, child, mode);
103}
104
105static int apparmor_ptrace_traceme(struct task_struct *parent)
106{
107 int error = cap_ptrace_traceme(parent);
108 if (error)
109 return error;
110
111 return aa_ptrace(parent, current, PTRACE_MODE_ATTACH);
112}
113
114/* Derived from security/commoncap.c:cap_capget */
115static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
116 kernel_cap_t *inheritable, kernel_cap_t *permitted)
117{
118 struct aa_profile *profile;
119 const struct cred *cred;
120
121 rcu_read_lock();
122 cred = __task_cred(target);
123 profile = aa_cred_profile(cred);
124
125 *effective = cred->cap_effective;
126 *inheritable = cred->cap_inheritable;
127 *permitted = cred->cap_permitted;
128
129 if (!unconfined(profile)) {
130 *effective = cap_intersect(*effective, profile->caps.allow);
131 *permitted = cap_intersect(*permitted, profile->caps.allow);
132 }
133 rcu_read_unlock();
134
135 return 0;
136}
137
138static int apparmor_capable(struct task_struct *task, const struct cred *cred,
139 int cap, int audit)
140{
141 struct aa_profile *profile;
142 /* cap_capable returns 0 on success, else -EPERM */
143 int error = cap_capable(task, cred, cap, audit);
144 if (!error) {
145 profile = aa_cred_profile(cred);
146 if (!unconfined(profile))
147 error = aa_capable(task, profile, cap, audit);
148 }
149 return error;
150}
151
152/**
153 * common_perm - basic common permission check wrapper fn for paths
154 * @op: operation being checked
155 * @path: path to check permission of (NOT NULL)
156 * @mask: requested permissions mask
157 * @cond: conditional info for the permission request (NOT NULL)
158 *
159 * Returns: %0 else error code if error or permission denied
160 */
161static int common_perm(int op, struct path *path, u32 mask,
162 struct path_cond *cond)
163{
164 struct aa_profile *profile;
165 int error = 0;
166
167 profile = __aa_current_profile();
168 if (!unconfined(profile))
169 error = aa_path_perm(op, profile, path, 0, mask, cond);
170
171 return error;
172}
173
174/**
175 * common_perm_dir_dentry - common permission wrapper when path is dir, dentry
176 * @op: operation being checked
177 * @dir: directory of the dentry (NOT NULL)
178 * @dentry: dentry to check (NOT NULL)
179 * @mask: requested permissions mask
180 * @cond: conditional info for the permission request (NOT NULL)
181 *
182 * Returns: %0 else error code if error or permission denied
183 */
184static int common_perm_dir_dentry(int op, struct path *dir,
185 struct dentry *dentry, u32 mask,
186 struct path_cond *cond)
187{
188 struct path path = { dir->mnt, dentry };
189
190 return common_perm(op, &path, mask, cond);
191}
192
193/**
194 * common_perm_mnt_dentry - common permission wrapper when mnt, dentry
195 * @op: operation being checked
196 * @mnt: mount point of dentry (NOT NULL)
197 * @dentry: dentry to check (NOT NULL)
198 * @mask: requested permissions mask
199 *
200 * Returns: %0 else error code if error or permission denied
201 */
202static int common_perm_mnt_dentry(int op, struct vfsmount *mnt,
203 struct dentry *dentry, u32 mask)
204{
205 struct path path = { mnt, dentry };
206 struct path_cond cond = { dentry->d_inode->i_uid,
207 dentry->d_inode->i_mode
208 };
209
210 return common_perm(op, &path, mask, &cond);
211}
212
213/**
214 * common_perm_rm - common permission wrapper for operations doing rm
215 * @op: operation being checked
216 * @dir: directory that the dentry is in (NOT NULL)
217 * @dentry: dentry being rm'd (NOT NULL)
218 * @mask: requested permission mask
219 *
220 * Returns: %0 else error code if error or permission denied
221 */
222static int common_perm_rm(int op, struct path *dir,
223 struct dentry *dentry, u32 mask)
224{
225 struct inode *inode = dentry->d_inode;
226 struct path_cond cond = { };
227
228 if (!inode || !dir->mnt || !mediated_filesystem(inode))
229 return 0;
230
231 cond.uid = inode->i_uid;
232 cond.mode = inode->i_mode;
233
234 return common_perm_dir_dentry(op, dir, dentry, mask, &cond);
235}
236
237/**
238 * common_perm_create - common permission wrapper for operations doing create
239 * @op: operation being checked
240 * @dir: directory that dentry will be created in (NOT NULL)
241 * @dentry: dentry to create (NOT NULL)
242 * @mask: request permission mask
243 * @mode: created file mode
244 *
245 * Returns: %0 else error code if error or permission denied
246 */
247static int common_perm_create(int op, struct path *dir, struct dentry *dentry,
248 u32 mask, umode_t mode)
249{
250 struct path_cond cond = { current_fsuid(), mode };
251
252 if (!dir->mnt || !mediated_filesystem(dir->dentry->d_inode))
253 return 0;
254
255 return common_perm_dir_dentry(op, dir, dentry, mask, &cond);
256}
257
258static int apparmor_path_unlink(struct path *dir, struct dentry *dentry)
259{
260 return common_perm_rm(OP_UNLINK, dir, dentry, AA_MAY_DELETE);
261}
262
263static int apparmor_path_mkdir(struct path *dir, struct dentry *dentry,
264 int mode)
265{
266 return common_perm_create(OP_MKDIR, dir, dentry, AA_MAY_CREATE,
267 S_IFDIR);
268}
269
270static int apparmor_path_rmdir(struct path *dir, struct dentry *dentry)
271{
272 return common_perm_rm(OP_RMDIR, dir, dentry, AA_MAY_DELETE);
273}
274
275static int apparmor_path_mknod(struct path *dir, struct dentry *dentry,
276 int mode, unsigned int dev)
277{
278 return common_perm_create(OP_MKNOD, dir, dentry, AA_MAY_CREATE, mode);
279}
280
281static int apparmor_path_truncate(struct path *path)
282{
283 struct path_cond cond = { path->dentry->d_inode->i_uid,
284 path->dentry->d_inode->i_mode
285 };
286
287 if (!path->mnt || !mediated_filesystem(path->dentry->d_inode))
288 return 0;
289
290 return common_perm(OP_TRUNC, path, MAY_WRITE | AA_MAY_META_WRITE,
291 &cond);
292}
293
294static int apparmor_path_symlink(struct path *dir, struct dentry *dentry,
295 const char *old_name)
296{
297 return common_perm_create(OP_SYMLINK, dir, dentry, AA_MAY_CREATE,
298 S_IFLNK);
299}
300
301static int apparmor_path_link(struct dentry *old_dentry, struct path *new_dir,
302 struct dentry *new_dentry)
303{
304 struct aa_profile *profile;
305 int error = 0;
306
307 if (!mediated_filesystem(old_dentry->d_inode))
308 return 0;
309
310 profile = aa_current_profile();
311 if (!unconfined(profile))
312 error = aa_path_link(profile, old_dentry, new_dir, new_dentry);
313 return error;
314}
315
316static int apparmor_path_rename(struct path *old_dir, struct dentry *old_dentry,
317 struct path *new_dir, struct dentry *new_dentry)
318{
319 struct aa_profile *profile;
320 int error = 0;
321
322 if (!mediated_filesystem(old_dentry->d_inode))
323 return 0;
324
325 profile = aa_current_profile();
326 if (!unconfined(profile)) {
327 struct path old_path = { old_dir->mnt, old_dentry };
328 struct path new_path = { new_dir->mnt, new_dentry };
329 struct path_cond cond = { old_dentry->d_inode->i_uid,
330 old_dentry->d_inode->i_mode
331 };
332
333 error = aa_path_perm(OP_RENAME_SRC, profile, &old_path, 0,
334 MAY_READ | AA_MAY_META_READ | MAY_WRITE |
335 AA_MAY_META_WRITE | AA_MAY_DELETE,
336 &cond);
337 if (!error)
338 error = aa_path_perm(OP_RENAME_DEST, profile, &new_path,
339 0, MAY_WRITE | AA_MAY_META_WRITE |
340 AA_MAY_CREATE, &cond);
341
342 }
343 return error;
344}
345
346static int apparmor_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
347 mode_t mode)
348{
349 if (!mediated_filesystem(dentry->d_inode))
350 return 0;
351
352 return common_perm_mnt_dentry(OP_CHMOD, mnt, dentry, AA_MAY_CHMOD);
353}
354
355static int apparmor_path_chown(struct path *path, uid_t uid, gid_t gid)
356{
357 struct path_cond cond = { path->dentry->d_inode->i_uid,
358 path->dentry->d_inode->i_mode
359 };
360
361 if (!mediated_filesystem(path->dentry->d_inode))
362 return 0;
363
364 return common_perm(OP_CHOWN, path, AA_MAY_CHOWN, &cond);
365}
366
367static int apparmor_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
368{
369 if (!mediated_filesystem(dentry->d_inode))
370 return 0;
371
372 return common_perm_mnt_dentry(OP_GETATTR, mnt, dentry,
373 AA_MAY_META_READ);
374}
375
376static int apparmor_dentry_open(struct file *file, const struct cred *cred)
377{
378 struct aa_file_cxt *fcxt = file->f_security;
379 struct aa_profile *profile;
380 int error = 0;
381
382 if (!mediated_filesystem(file->f_path.dentry->d_inode))
383 return 0;
384
385 /* If in exec, permission is handled by bprm hooks.
386 * Cache permissions granted by the previous exec check, with
387 * implicit read and executable mmap which are required to
388 * actually execute the image.
389 */
390 if (current->in_execve) {
391 fcxt->allow = MAY_EXEC | MAY_READ | AA_EXEC_MMAP;
392 return 0;
393 }
394
395 profile = aa_cred_profile(cred);
396 if (!unconfined(profile)) {
397 struct inode *inode = file->f_path.dentry->d_inode;
398 struct path_cond cond = { inode->i_uid, inode->i_mode };
399
400 error = aa_path_perm(OP_OPEN, profile, &file->f_path, 0,
401 aa_map_file_to_perms(file), &cond);
402 /* todo cache full allowed permissions set and state */
403 fcxt->allow = aa_map_file_to_perms(file);
404 }
405
406 return error;
407}
408
409static int apparmor_file_alloc_security(struct file *file)
410{
411 /* freed by apparmor_file_free_security */
412 file->f_security = aa_alloc_file_context(GFP_KERNEL);
413 if (!file->f_security)
414 return -ENOMEM;
415 return 0;
416
417}
418
419static void apparmor_file_free_security(struct file *file)
420{
421 struct aa_file_cxt *cxt = file->f_security;
422
423 aa_free_file_context(cxt);
424}
425
426static int common_file_perm(int op, struct file *file, u32 mask)
427{
428 struct aa_file_cxt *fcxt = file->f_security;
429 struct aa_profile *profile, *fprofile = aa_cred_profile(file->f_cred);
430 int error = 0;
431
432 BUG_ON(!fprofile);
433
434 if (!file->f_path.mnt ||
435 !mediated_filesystem(file->f_path.dentry->d_inode))
436 return 0;
437
438 profile = __aa_current_profile();
439
440 /* revalidate access, if task is unconfined, or the cached cred
441 * doesn't match or if the request is for more permissions than
442 * was granted.
443 *
444 * Note: the test for !unconfined(fprofile) is to handle file
445 * delegation from unconfined tasks
446 */
447 if (!unconfined(profile) && !unconfined(fprofile) &&
448 ((fprofile != profile) || (mask & ~fcxt->allow)))
449 error = aa_file_perm(op, profile, file, mask);
450
451 return error;
452}
453
454static int apparmor_file_permission(struct file *file, int mask)
455{
456 return common_file_perm(OP_FPERM, file, mask);
457}
458
459static int apparmor_file_lock(struct file *file, unsigned int cmd)
460{
461 u32 mask = AA_MAY_LOCK;
462
463 if (cmd == F_WRLCK)
464 mask |= MAY_WRITE;
465
466 return common_file_perm(OP_FLOCK, file, mask);
467}
468
469static int common_mmap(int op, struct file *file, unsigned long prot,
470 unsigned long flags)
471{
472 struct dentry *dentry;
473 int mask = 0;
474
475 if (!file || !file->f_security)
476 return 0;
477
478 if (prot & PROT_READ)
479 mask |= MAY_READ;
480 /*
481 * Private mappings don't require write perms since they don't
482 * write back to the files
483 */
484 if ((prot & PROT_WRITE) && !(flags & MAP_PRIVATE))
485 mask |= MAY_WRITE;
486 if (prot & PROT_EXEC)
487 mask |= AA_EXEC_MMAP;
488
489 dentry = file->f_path.dentry;
490 return common_file_perm(op, file, mask);
491}
492
493static int apparmor_file_mmap(struct file *file, unsigned long reqprot,
494 unsigned long prot, unsigned long flags,
495 unsigned long addr, unsigned long addr_only)
496{
497 int rc = 0;
498
499 /* do DAC check */
500 rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
501 if (rc || addr_only)
502 return rc;
503
504 return common_mmap(OP_FMMAP, file, prot, flags);
505}
506
507static int apparmor_file_mprotect(struct vm_area_struct *vma,
508 unsigned long reqprot, unsigned long prot)
509{
510 return common_mmap(OP_FMPROT, vma->vm_file, prot,
511 !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
512}
513
514static int apparmor_getprocattr(struct task_struct *task, char *name,
515 char **value)
516{
517 int error = -ENOENT;
518 struct aa_profile *profile;
519 /* released below */
520 const struct cred *cred = get_task_cred(task);
521 struct aa_task_cxt *cxt = cred->security;
522 profile = aa_cred_profile(cred);
523
524 if (strcmp(name, "current") == 0)
525 error = aa_getprocattr(aa_newest_version(cxt->profile),
526 value);
527 else if (strcmp(name, "prev") == 0 && cxt->previous)
528 error = aa_getprocattr(aa_newest_version(cxt->previous),
529 value);
530 else if (strcmp(name, "exec") == 0 && cxt->onexec)
531 error = aa_getprocattr(aa_newest_version(cxt->onexec),
532 value);
533 else
534 error = -EINVAL;
535
536 put_cred(cred);
537
538 return error;
539}
540
541static int apparmor_setprocattr(struct task_struct *task, char *name,
542 void *value, size_t size)
543{
544 char *command, *args = value;
545 size_t arg_size;
546 int error;
547
548 if (size == 0)
549 return -EINVAL;
550 /* args points to a PAGE_SIZE buffer, AppArmor requires that
551 * the buffer must be null terminated or have size <= PAGE_SIZE -1
552 * so that AppArmor can null terminate them
553 */
554 if (args[size - 1] != '\0') {
555 if (size == PAGE_SIZE)
556 return -EINVAL;
557 args[size] = '\0';
558 }
559
560 /* task can only write its own attributes */
561 if (current != task)
562 return -EACCES;
563
564 args = value;
565 args = strim(args);
566 command = strsep(&args, " ");
567 if (!args)
568 return -EINVAL;
569 args = skip_spaces(args);
570 if (!*args)
571 return -EINVAL;
572
573 arg_size = size - (args - (char *) value);
574 if (strcmp(name, "current") == 0) {
575 if (strcmp(command, "changehat") == 0) {
576 error = aa_setprocattr_changehat(args, arg_size,
577 !AA_DO_TEST);
578 } else if (strcmp(command, "permhat") == 0) {
579 error = aa_setprocattr_changehat(args, arg_size,
580 AA_DO_TEST);
581 } else if (strcmp(command, "changeprofile") == 0) {
582 error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
583 !AA_DO_TEST);
584 } else if (strcmp(command, "permprofile") == 0) {
585 error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
586 AA_DO_TEST);
587 } else if (strcmp(command, "permipc") == 0) {
588 error = aa_setprocattr_permipc(args);
589 } else {
590 struct common_audit_data sa;
591 COMMON_AUDIT_DATA_INIT(&sa, NONE);
592 sa.aad.op = OP_SETPROCATTR;
593 sa.aad.info = name;
594 sa.aad.error = -EINVAL;
595 return aa_audit(AUDIT_APPARMOR_DENIED, NULL, GFP_KERNEL,
596 &sa, NULL);
597 }
598 } else if (strcmp(name, "exec") == 0) {
599 error = aa_setprocattr_changeprofile(args, AA_ONEXEC,
600 !AA_DO_TEST);
601 } else {
602 /* only support the "current" and "exec" process attributes */
603 return -EINVAL;
604 }
605 if (!error)
606 error = size;
607 return error;
608}
609
610static int apparmor_task_setrlimit(unsigned int resource,
611 struct rlimit *new_rlim)
612{
613 struct aa_profile *profile = aa_current_profile();
614 int error = 0;
615
616 if (!unconfined(profile))
617 error = aa_task_setrlimit(profile, resource, new_rlim);
618
619 return error;
620}
621
622static struct security_operations apparmor_ops = {
623 .name = "apparmor",
624
625 .ptrace_access_check = apparmor_ptrace_access_check,
626 .ptrace_traceme = apparmor_ptrace_traceme,
627 .capget = apparmor_capget,
628 .capable = apparmor_capable,
629
630 .path_link = apparmor_path_link,
631 .path_unlink = apparmor_path_unlink,
632 .path_symlink = apparmor_path_symlink,
633 .path_mkdir = apparmor_path_mkdir,
634 .path_rmdir = apparmor_path_rmdir,
635 .path_mknod = apparmor_path_mknod,
636 .path_rename = apparmor_path_rename,
637 .path_chmod = apparmor_path_chmod,
638 .path_chown = apparmor_path_chown,
639 .path_truncate = apparmor_path_truncate,
640 .dentry_open = apparmor_dentry_open,
641 .inode_getattr = apparmor_inode_getattr,
642
643 .file_permission = apparmor_file_permission,
644 .file_alloc_security = apparmor_file_alloc_security,
645 .file_free_security = apparmor_file_free_security,
646 .file_mmap = apparmor_file_mmap,
647 .file_mprotect = apparmor_file_mprotect,
648 .file_lock = apparmor_file_lock,
649
650 .getprocattr = apparmor_getprocattr,
651 .setprocattr = apparmor_setprocattr,
652
653 .cred_alloc_blank = apparmor_cred_alloc_blank,
654 .cred_free = apparmor_cred_free,
655 .cred_prepare = apparmor_cred_prepare,
656 .cred_transfer = apparmor_cred_transfer,
657
658 .bprm_set_creds = apparmor_bprm_set_creds,
659 .bprm_committing_creds = apparmor_bprm_committing_creds,
660 .bprm_committed_creds = apparmor_bprm_committed_creds,
661 .bprm_secureexec = apparmor_bprm_secureexec,
662
663 .task_setrlimit = apparmor_task_setrlimit,
664};
665
666/*
667 * AppArmor sysfs module parameters
668 */
669
670static int param_set_aabool(const char *val, struct kernel_param *kp);
671static int param_get_aabool(char *buffer, struct kernel_param *kp);
672#define param_check_aabool(name, p) __param_check(name, p, int)
673
674static int param_set_aauint(const char *val, struct kernel_param *kp);
675static int param_get_aauint(char *buffer, struct kernel_param *kp);
676#define param_check_aauint(name, p) __param_check(name, p, int)
677
678static int param_set_aalockpolicy(const char *val, struct kernel_param *kp);
679static int param_get_aalockpolicy(char *buffer, struct kernel_param *kp);
680#define param_check_aalockpolicy(name, p) __param_check(name, p, int)
681
682static int param_set_audit(const char *val, struct kernel_param *kp);
683static int param_get_audit(char *buffer, struct kernel_param *kp);
684#define param_check_audit(name, p) __param_check(name, p, int)
685
686static int param_set_mode(const char *val, struct kernel_param *kp);
687static int param_get_mode(char *buffer, struct kernel_param *kp);
688#define param_check_mode(name, p) __param_check(name, p, int)
689
690/* Flag values, also controllable via /sys/module/apparmor/parameters
691 * We define special types as we want to do additional mediation.
692 */
693
694/* AppArmor global enforcement switch - complain, enforce, kill */
695enum profile_mode aa_g_profile_mode = APPARMOR_ENFORCE;
696module_param_call(mode, param_set_mode, param_get_mode,
697 &aa_g_profile_mode, S_IRUSR | S_IWUSR);
698
699/* Debug mode */
700int aa_g_debug;
701module_param_named(debug, aa_g_debug, aabool, S_IRUSR | S_IWUSR);
702
703/* Audit mode */
704enum audit_mode aa_g_audit;
705module_param_call(audit, param_set_audit, param_get_audit,
706 &aa_g_audit, S_IRUSR | S_IWUSR);
707
708/* Determines if audit header is included in audited messages. This
709 * provides more context if the audit daemon is not running
710 */
711int aa_g_audit_header = 1;
712module_param_named(audit_header, aa_g_audit_header, aabool,
713 S_IRUSR | S_IWUSR);
714
715/* lock out loading/removal of policy
716 * TODO: add in at boot loading of policy, which is the only way to
717 * load policy, if lock_policy is set
718 */
719int aa_g_lock_policy;
720module_param_named(lock_policy, aa_g_lock_policy, aalockpolicy,
721 S_IRUSR | S_IWUSR);
722
723/* Syscall logging mode */
724int aa_g_logsyscall;
725module_param_named(logsyscall, aa_g_logsyscall, aabool, S_IRUSR | S_IWUSR);
726
727/* Maximum pathname length before accesses will start getting rejected */
728unsigned int aa_g_path_max = 2 * PATH_MAX;
729module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR | S_IWUSR);
730
731/* Determines how paranoid loading of policy is and how much verification
732 * on the loaded policy is done.
733 */
734int aa_g_paranoid_load = 1;
735module_param_named(paranoid_load, aa_g_paranoid_load, aabool,
736 S_IRUSR | S_IWUSR);
737
738/* Boot time disable flag */
739static unsigned int apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE;
740module_param_named(enabled, apparmor_enabled, aabool, S_IRUSR);
741
742static int __init apparmor_enabled_setup(char *str)
743{
744 unsigned long enabled;
745 int error = strict_strtoul(str, 0, &enabled);
746 if (!error)
747 apparmor_enabled = enabled ? 1 : 0;
748 return 1;
749}
750
751__setup("apparmor=", apparmor_enabled_setup);
752
753/* set global flag turning off the ability to load policy */
754static int param_set_aalockpolicy(const char *val, struct kernel_param *kp)
755{
756 if (!capable(CAP_MAC_ADMIN))
757 return -EPERM;
758 if (aa_g_lock_policy)
759 return -EACCES;
760 return param_set_bool(val, kp);
761}
762
763static int param_get_aalockpolicy(char *buffer, struct kernel_param *kp)
764{
765 if (!capable(CAP_MAC_ADMIN))
766 return -EPERM;
767 return param_get_bool(buffer, kp);
768}
769
770static int param_set_aabool(const char *val, struct kernel_param *kp)
771{
772 if (!capable(CAP_MAC_ADMIN))
773 return -EPERM;
774 return param_set_bool(val, kp);
775}
776
777static int param_get_aabool(char *buffer, struct kernel_param *kp)
778{
779 if (!capable(CAP_MAC_ADMIN))
780 return -EPERM;
781 return param_get_bool(buffer, kp);
782}
783
784static int param_set_aauint(const char *val, struct kernel_param *kp)
785{
786 if (!capable(CAP_MAC_ADMIN))
787 return -EPERM;
788 return param_set_uint(val, kp);
789}
790
791static int param_get_aauint(char *buffer, struct kernel_param *kp)
792{
793 if (!capable(CAP_MAC_ADMIN))
794 return -EPERM;
795 return param_get_uint(buffer, kp);
796}
797
798static int param_get_audit(char *buffer, struct kernel_param *kp)
799{
800 if (!capable(CAP_MAC_ADMIN))
801 return -EPERM;
802
803 if (!apparmor_enabled)
804 return -EINVAL;
805
806 return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]);
807}
808
809static int param_set_audit(const char *val, struct kernel_param *kp)
810{
811 int i;
812 if (!capable(CAP_MAC_ADMIN))
813 return -EPERM;
814
815 if (!apparmor_enabled)
816 return -EINVAL;
817
818 if (!val)
819 return -EINVAL;
820
821 for (i = 0; i < AUDIT_MAX_INDEX; i++) {
822 if (strcmp(val, audit_mode_names[i]) == 0) {
823 aa_g_audit = i;
824 return 0;
825 }
826 }
827
828 return -EINVAL;
829}
830
831static int param_get_mode(char *buffer, struct kernel_param *kp)
832{
833 if (!capable(CAP_MAC_ADMIN))
834 return -EPERM;
835
836 if (!apparmor_enabled)
837 return -EINVAL;
838
839 return sprintf(buffer, "%s", profile_mode_names[aa_g_profile_mode]);
840}
841
842static int param_set_mode(const char *val, struct kernel_param *kp)
843{
844 int i;
845 if (!capable(CAP_MAC_ADMIN))
846 return -EPERM;
847
848 if (!apparmor_enabled)
849 return -EINVAL;
850
851 if (!val)
852 return -EINVAL;
853
854 for (i = 0; i < APPARMOR_NAMES_MAX_INDEX; i++) {
855 if (strcmp(val, profile_mode_names[i]) == 0) {
856 aa_g_profile_mode = i;
857 return 0;
858 }
859 }
860
861 return -EINVAL;
862}
863
864/*
865 * AppArmor init functions
866 */
867
868/**
869 * set_init_cxt - set a task context and profile on the first task.
870 *
871 * TODO: allow setting an alternate profile than unconfined
872 */
873static int __init set_init_cxt(void)
874{
875 struct cred *cred = (struct cred *)current->real_cred;
876 struct aa_task_cxt *cxt;
877
878 cxt = aa_alloc_task_context(GFP_KERNEL);
879 if (!cxt)
880 return -ENOMEM;
881
882 cxt->profile = aa_get_profile(root_ns->unconfined);
883 cred->security = cxt;
884
885 return 0;
886}
887
888static int __init apparmor_init(void)
889{
890 int error;
891
892 if (!apparmor_enabled || !security_module_enable(&apparmor_ops)) {
893 aa_info_message("AppArmor disabled by boot time parameter");
894 apparmor_enabled = 0;
895 return 0;
896 }
897
898 error = aa_alloc_root_ns();
899 if (error) {
900 AA_ERROR("Unable to allocate default profile namespace\n");
901 goto alloc_out;
902 }
903
904 error = set_init_cxt();
905 if (error) {
906 AA_ERROR("Failed to set context on init task\n");
907 goto register_security_out;
908 }
909
910 error = register_security(&apparmor_ops);
911 if (error) {
912 AA_ERROR("Unable to register AppArmor\n");
913 goto register_security_out;
914 }
915
916 /* Report that AppArmor successfully initialized */
917 apparmor_initialized = 1;
918 if (aa_g_profile_mode == APPARMOR_COMPLAIN)
919 aa_info_message("AppArmor initialized: complain mode enabled");
920 else if (aa_g_profile_mode == APPARMOR_KILL)
921 aa_info_message("AppArmor initialized: kill mode enabled");
922 else
923 aa_info_message("AppArmor initialized");
924
925 return error;
926
927register_security_out:
928 aa_free_root_ns();
929
930alloc_out:
931 aa_destroy_aafs();
932
933 apparmor_enabled = 0;
934 return error;
935
936}
937
938security_initcall(apparmor_init);
diff --git a/security/apparmor/match.c b/security/apparmor/match.c
new file mode 100644
index 00000000000..5cb4dc1f699
--- /dev/null
+++ b/security/apparmor/match.c
@@ -0,0 +1,353 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor dfa based regular expression matching engine
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/errno.h>
16#include <linux/kernel.h>
17#include <linux/mm.h>
18#include <linux/slab.h>
19#include <linux/vmalloc.h>
20#include <linux/err.h>
21#include <linux/kref.h>
22
23#include "include/apparmor.h"
24#include "include/match.h"
25
26/**
27 * unpack_table - unpack a dfa table (one of accept, default, base, next check)
28 * @blob: data to unpack (NOT NULL)
29 * @bsize: size of blob
30 *
31 * Returns: pointer to table else NULL on failure
32 *
33 * NOTE: must be freed by kvfree (not kmalloc)
34 */
35static struct table_header *unpack_table(char *blob, size_t bsize)
36{
37 struct table_header *table = NULL;
38 struct table_header th;
39 size_t tsize;
40
41 if (bsize < sizeof(struct table_header))
42 goto out;
43
44 /* loaded td_id's start at 1, subtract 1 now to avoid doing
45 * it every time we use td_id as an index
46 */
47 th.td_id = be16_to_cpu(*(u16 *) (blob)) - 1;
48 th.td_flags = be16_to_cpu(*(u16 *) (blob + 2));
49 th.td_lolen = be32_to_cpu(*(u32 *) (blob + 8));
50 blob += sizeof(struct table_header);
51
52 if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 ||
53 th.td_flags == YYTD_DATA8))
54 goto out;
55
56 tsize = table_size(th.td_lolen, th.td_flags);
57 if (bsize < tsize)
58 goto out;
59
60 table = kvmalloc(tsize);
61 if (table) {
62 *table = th;
63 if (th.td_flags == YYTD_DATA8)
64 UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
65 u8, byte_to_byte);
66 else if (th.td_flags == YYTD_DATA16)
67 UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
68 u16, be16_to_cpu);
69 else if (th.td_flags == YYTD_DATA32)
70 UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
71 u32, be32_to_cpu);
72 else
73 goto fail;
74 }
75
76out:
77 /* if table was vmalloced make sure the page tables are synced
78 * before it is used, as it goes live to all cpus.
79 */
80 if (is_vmalloc_addr(table))
81 vm_unmap_aliases();
82 return table;
83fail:
84 kvfree(table);
85 return NULL;
86}
87
88/**
89 * verify_dfa - verify that transitions and states in the tables are in bounds.
90 * @dfa: dfa to test (NOT NULL)
91 * @flags: flags controlling what type of accept table are acceptable
92 *
93 * Assumes dfa has gone through the first pass verification done by unpacking
94 * NOTE: this does not valid accept table values
95 *
96 * Returns: %0 else error code on failure to verify
97 */
98static int verify_dfa(struct aa_dfa *dfa, int flags)
99{
100 size_t i, state_count, trans_count;
101 int error = -EPROTO;
102
103 /* check that required tables exist */
104 if (!(dfa->tables[YYTD_ID_DEF] &&
105 dfa->tables[YYTD_ID_BASE] &&
106 dfa->tables[YYTD_ID_NXT] && dfa->tables[YYTD_ID_CHK]))
107 goto out;
108
109 /* accept.size == default.size == base.size */
110 state_count = dfa->tables[YYTD_ID_BASE]->td_lolen;
111 if (ACCEPT1_FLAGS(flags)) {
112 if (!dfa->tables[YYTD_ID_ACCEPT])
113 goto out;
114 if (state_count != dfa->tables[YYTD_ID_ACCEPT]->td_lolen)
115 goto out;
116 }
117 if (ACCEPT2_FLAGS(flags)) {
118 if (!dfa->tables[YYTD_ID_ACCEPT2])
119 goto out;
120 if (state_count != dfa->tables[YYTD_ID_ACCEPT2]->td_lolen)
121 goto out;
122 }
123 if (state_count != dfa->tables[YYTD_ID_DEF]->td_lolen)
124 goto out;
125
126 /* next.size == chk.size */
127 trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen;
128 if (trans_count != dfa->tables[YYTD_ID_CHK]->td_lolen)
129 goto out;
130
131 /* if equivalence classes then its table size must be 256 */
132 if (dfa->tables[YYTD_ID_EC] &&
133 dfa->tables[YYTD_ID_EC]->td_lolen != 256)
134 goto out;
135
136 if (flags & DFA_FLAG_VERIFY_STATES) {
137 for (i = 0; i < state_count; i++) {
138 if (DEFAULT_TABLE(dfa)[i] >= state_count)
139 goto out;
140 /* TODO: do check that DEF state recursion terminates */
141 if (BASE_TABLE(dfa)[i] + 255 >= trans_count) {
142 printk(KERN_ERR "AppArmor DFA next/check upper "
143 "bounds error\n");
144 goto out;
145 }
146 }
147
148 for (i = 0; i < trans_count; i++) {
149 if (NEXT_TABLE(dfa)[i] >= state_count)
150 goto out;
151 if (CHECK_TABLE(dfa)[i] >= state_count)
152 goto out;
153 }
154 }
155
156 error = 0;
157out:
158 return error;
159}
160
161/**
162 * dfa_free - free a dfa allocated by aa_dfa_unpack
163 * @dfa: the dfa to free (MAYBE NULL)
164 *
165 * Requires: reference count to dfa == 0
166 */
167static void dfa_free(struct aa_dfa *dfa)
168{
169 if (dfa) {
170 int i;
171
172 for (i = 0; i < ARRAY_SIZE(dfa->tables); i++) {
173 kvfree(dfa->tables[i]);
174 dfa->tables[i] = NULL;
175 }
176 kfree(dfa);
177 }
178}
179
180/**
181 * aa_dfa_free_kref - free aa_dfa by kref (called by aa_put_dfa)
182 * @kr: kref callback for freeing of a dfa (NOT NULL)
183 */
184void aa_dfa_free_kref(struct kref *kref)
185{
186 struct aa_dfa *dfa = container_of(kref, struct aa_dfa, count);
187 dfa_free(dfa);
188}
189
190/**
191 * aa_dfa_unpack - unpack the binary tables of a serialized dfa
192 * @blob: aligned serialized stream of data to unpack (NOT NULL)
193 * @size: size of data to unpack
194 * @flags: flags controlling what type of accept tables are acceptable
195 *
196 * Unpack a dfa that has been serialized. To find information on the dfa
197 * format look in Documentation/apparmor.txt
198 * Assumes the dfa @blob stream has been aligned on a 8 byte boundry
199 *
200 * Returns: an unpacked dfa ready for matching or ERR_PTR on failure
201 */
202struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
203{
204 int hsize;
205 int error = -ENOMEM;
206 char *data = blob;
207 struct table_header *table = NULL;
208 struct aa_dfa *dfa = kzalloc(sizeof(struct aa_dfa), GFP_KERNEL);
209 if (!dfa)
210 goto fail;
211
212 kref_init(&dfa->count);
213
214 error = -EPROTO;
215
216 /* get dfa table set header */
217 if (size < sizeof(struct table_set_header))
218 goto fail;
219
220 if (ntohl(*(u32 *) data) != YYTH_MAGIC)
221 goto fail;
222
223 hsize = ntohl(*(u32 *) (data + 4));
224 if (size < hsize)
225 goto fail;
226
227 dfa->flags = ntohs(*(u16 *) (data + 12));
228 data += hsize;
229 size -= hsize;
230
231 while (size > 0) {
232 table = unpack_table(data, size);
233 if (!table)
234 goto fail;
235
236 switch (table->td_id) {
237 case YYTD_ID_ACCEPT:
238 if (!(table->td_flags & ACCEPT1_FLAGS(flags)))
239 goto fail;
240 break;
241 case YYTD_ID_ACCEPT2:
242 if (!(table->td_flags & ACCEPT2_FLAGS(flags)))
243 goto fail;
244 break;
245 case YYTD_ID_BASE:
246 if (table->td_flags != YYTD_DATA32)
247 goto fail;
248 break;
249 case YYTD_ID_DEF:
250 case YYTD_ID_NXT:
251 case YYTD_ID_CHK:
252 if (table->td_flags != YYTD_DATA16)
253 goto fail;
254 break;
255 case YYTD_ID_EC:
256 if (table->td_flags != YYTD_DATA8)
257 goto fail;
258 break;
259 default:
260 goto fail;
261 }
262 /* check for duplicate table entry */
263 if (dfa->tables[table->td_id])
264 goto fail;
265 dfa->tables[table->td_id] = table;
266 data += table_size(table->td_lolen, table->td_flags);
267 size -= table_size(table->td_lolen, table->td_flags);
268 table = NULL;
269 }
270
271 error = verify_dfa(dfa, flags);
272 if (error)
273 goto fail;
274
275 return dfa;
276
277fail:
278 kvfree(table);
279 dfa_free(dfa);
280 return ERR_PTR(error);
281}
282
283/**
284 * aa_dfa_match_len - traverse @dfa to find state @str stops at
285 * @dfa: the dfa to match @str against (NOT NULL)
286 * @start: the state of the dfa to start matching in
287 * @str: the string of bytes to match against the dfa (NOT NULL)
288 * @len: length of the string of bytes to match
289 *
290 * aa_dfa_match_len will match @str against the dfa and return the state it
291 * finished matching in. The final state can be used to look up the accepting
292 * label, or as the start state of a continuing match.
293 *
294 * This function will happily match again the 0 byte and only finishes
295 * when @len input is consumed.
296 *
297 * Returns: final state reached after input is consumed
298 */
299unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
300 const char *str, int len)
301{
302 u16 *def = DEFAULT_TABLE(dfa);
303 u32 *base = BASE_TABLE(dfa);
304 u16 *next = NEXT_TABLE(dfa);
305 u16 *check = CHECK_TABLE(dfa);
306 unsigned int state = start, pos;
307
308 if (state == 0)
309 return 0;
310
311 /* current state is <state>, matching character *str */
312 if (dfa->tables[YYTD_ID_EC]) {
313 /* Equivalence class table defined */
314 u8 *equiv = EQUIV_TABLE(dfa);
315 /* default is direct to next state */
316 for (; len; len--) {
317 pos = base[state] + equiv[(u8) *str++];
318 if (check[pos] == state)
319 state = next[pos];
320 else
321 state = def[state];
322 }
323 } else {
324 /* default is direct to next state */
325 for (; len; len--) {
326 pos = base[state] + (u8) *str++;
327 if (check[pos] == state)
328 state = next[pos];
329 else
330 state = def[state];
331 }
332 }
333
334 return state;
335}
336
337/**
338 * aa_dfa_next_state - traverse @dfa to find state @str stops at
339 * @dfa: the dfa to match @str against (NOT NULL)
340 * @start: the state of the dfa to start matching in
341 * @str: the null terminated string of bytes to match against the dfa (NOT NULL)
342 *
343 * aa_dfa_next_state will match @str against the dfa and return the state it
344 * finished matching in. The final state can be used to look up the accepting
345 * label, or as the start state of a continuing match.
346 *
347 * Returns: final state reached after input is consumed
348 */
349unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
350 const char *str)
351{
352 return aa_dfa_match_len(dfa, start, str, strlen(str));
353}
diff --git a/security/apparmor/path.c b/security/apparmor/path.c
new file mode 100644
index 00000000000..96bab9469d4
--- /dev/null
+++ b/security/apparmor/path.c
@@ -0,0 +1,235 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor function for pathnames
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/magic.h>
16#include <linux/mnt_namespace.h>
17#include <linux/mount.h>
18#include <linux/namei.h>
19#include <linux/nsproxy.h>
20#include <linux/path.h>
21#include <linux/sched.h>
22#include <linux/slab.h>
23#include <linux/fs_struct.h>
24
25#include "include/apparmor.h"
26#include "include/path.h"
27#include "include/policy.h"
28
29
30/* modified from dcache.c */
31static int prepend(char **buffer, int buflen, const char *str, int namelen)
32{
33 buflen -= namelen;
34 if (buflen < 0)
35 return -ENAMETOOLONG;
36 *buffer -= namelen;
37 memcpy(*buffer, str, namelen);
38 return 0;
39}
40
41#define CHROOT_NSCONNECT (PATH_CHROOT_REL | PATH_CHROOT_NSCONNECT)
42
43/**
44 * d_namespace_path - lookup a name associated with a given path
45 * @path: path to lookup (NOT NULL)
46 * @buf: buffer to store path to (NOT NULL)
47 * @buflen: length of @buf
48 * @name: Returns - pointer for start of path name with in @buf (NOT NULL)
49 * @flags: flags controlling path lookup
50 *
51 * Handle path name lookup.
52 *
53 * Returns: %0 else error code if path lookup fails
54 * When no error the path name is returned in @name which points to
55 * to a position in @buf
56 */
57static int d_namespace_path(struct path *path, char *buf, int buflen,
58 char **name, int flags)
59{
60 struct path root, tmp;
61 char *res;
62 int deleted, connected;
63 int error = 0;
64
65 /* Get the root we want to resolve too */
66 if (flags & PATH_CHROOT_REL) {
67 /* resolve paths relative to chroot */
68 read_lock(&current->fs->lock);
69 root = current->fs->root;
70 /* released below */
71 path_get(&root);
72 read_unlock(&current->fs->lock);
73 } else {
74 /* resolve paths relative to namespace */
75 root.mnt = current->nsproxy->mnt_ns->root;
76 root.dentry = root.mnt->mnt_root;
77 /* released below */
78 path_get(&root);
79 }
80
81 spin_lock(&dcache_lock);
82 /* There is a race window between path lookup here and the
83 * need to strip the " (deleted) string that __d_path applies
84 * Detect the race and relookup the path
85 *
86 * The stripping of (deleted) is a hack that could be removed
87 * with an updated __d_path
88 */
89 do {
90 tmp = root;
91 deleted = d_unlinked(path->dentry);
92 res = __d_path(path, &tmp, buf, buflen);
93
94 } while (deleted != d_unlinked(path->dentry));
95 spin_unlock(&dcache_lock);
96
97 *name = res;
98 /* handle error conditions - and still allow a partial path to
99 * be returned.
100 */
101 if (IS_ERR(res)) {
102 error = PTR_ERR(res);
103 *name = buf;
104 goto out;
105 }
106 if (deleted) {
107 /* On some filesystems, newly allocated dentries appear to the
108 * security_path hooks as a deleted dentry except without an
109 * inode allocated.
110 *
111 * Remove the appended deleted text and return as string for
112 * normal mediation, or auditing. The (deleted) string is
113 * guaranteed to be added in this case, so just strip it.
114 */
115 buf[buflen - 11] = 0; /* - (len(" (deleted)") +\0) */
116
117 if (path->dentry->d_inode && !(flags & PATH_MEDIATE_DELETED)) {
118 error = -ENOENT;
119 goto out;
120 }
121 }
122
123 /* Determine if the path is connected to the expected root */
124 connected = tmp.dentry == root.dentry && tmp.mnt == root.mnt;
125
126 /* If the path is not connected,
127 * check if it is a sysctl and handle specially else remove any
128 * leading / that __d_path may have returned.
129 * Unless
130 * specifically directed to connect the path,
131 * OR
132 * if in a chroot and doing chroot relative paths and the path
133 * resolves to the namespace root (would be connected outside
134 * of chroot) and specifically directed to connect paths to
135 * namespace root.
136 */
137 if (!connected) {
138 /* is the disconnect path a sysctl? */
139 if (tmp.dentry->d_sb->s_magic == PROC_SUPER_MAGIC &&
140 strncmp(*name, "/sys/", 5) == 0) {
141 /* TODO: convert over to using a per namespace
142 * control instead of hard coded /proc
143 */
144 error = prepend(name, *name - buf, "/proc", 5);
145 } else if (!(flags & PATH_CONNECT_PATH) &&
146 !(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) &&
147 (tmp.mnt == current->nsproxy->mnt_ns->root &&
148 tmp.dentry == tmp.mnt->mnt_root))) {
149 /* disconnected path, don't return pathname starting
150 * with '/'
151 */
152 error = -ESTALE;
153 if (*res == '/')
154 *name = res + 1;
155 }
156 }
157
158out:
159 path_put(&root);
160
161 return error;
162}
163
164/**
165 * get_name_to_buffer - get the pathname to a buffer ensure dir / is appended
166 * @path: path to get name for (NOT NULL)
167 * @flags: flags controlling path lookup
168 * @buffer: buffer to put name in (NOT NULL)
169 * @size: size of buffer
170 * @name: Returns - contains position of path name in @buffer (NOT NULL)
171 *
172 * Returns: %0 else error on failure
173 */
174static int get_name_to_buffer(struct path *path, int flags, char *buffer,
175 int size, char **name)
176{
177 int adjust = (flags & PATH_IS_DIR) ? 1 : 0;
178 int error = d_namespace_path(path, buffer, size - adjust, name, flags);
179
180 if (!error && (flags & PATH_IS_DIR) && (*name)[1] != '\0')
181 /*
182 * Append "/" to the pathname. The root directory is a special
183 * case; it already ends in slash.
184 */
185 strcpy(&buffer[size - 2], "/");
186
187 return error;
188}
189
190/**
191 * aa_get_name - compute the pathname of a file
192 * @path: path the file (NOT NULL)
193 * @flags: flags controlling path name generation
194 * @buffer: buffer that aa_get_name() allocated (NOT NULL)
195 * @name: Returns - the generated path name if !error (NOT NULL)
196 *
197 * @name is a pointer to the beginning of the pathname (which usually differs
198 * from the beginning of the buffer), or NULL. If there is an error @name
199 * may contain a partial or invalid name that can be used for audit purposes,
200 * but it can not be used for mediation.
201 *
202 * We need PATH_IS_DIR to indicate whether the file is a directory or not
203 * because the file may not yet exist, and so we cannot check the inode's
204 * file type.
205 *
206 * Returns: %0 else error code if could retrieve name
207 */
208int aa_get_name(struct path *path, int flags, char **buffer, const char **name)
209{
210 char *buf, *str = NULL;
211 int size = 256;
212 int error;
213
214 *name = NULL;
215 *buffer = NULL;
216 for (;;) {
217 /* freed by caller */
218 buf = kmalloc(size, GFP_KERNEL);
219 if (!buf)
220 return -ENOMEM;
221
222 error = get_name_to_buffer(path, flags, buf, size, &str);
223 if (error != -ENAMETOOLONG)
224 break;
225
226 kfree(buf);
227 size <<= 1;
228 if (size > aa_g_path_max)
229 return -ENAMETOOLONG;
230 }
231 *buffer = buf;
232 *name = str;
233
234 return error;
235}
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
new file mode 100644
index 00000000000..3cdc1ad0787
--- /dev/null
+++ b/security/apparmor/policy.c
@@ -0,0 +1,1184 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor policy manipulation 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 * AppArmor policy is based around profiles, which contain the rules a
16 * task is confined by. Every task in the system has a profile attached
17 * to it determined either by matching "unconfined" tasks against the
18 * visible set of profiles or by following a profiles attachment rules.
19 *
20 * Each profile exists in a profile namespace which is a container of
21 * visible profiles. Each namespace contains a special "unconfined" profile,
22 * which doesn't enforce any confinement on a task beyond DAC.
23 *
24 * Namespace and profile names can be written together in either
25 * of two syntaxes.
26 * :namespace:profile - used by kernel interfaces for easy detection
27 * namespace://profile - used by policy
28 *
29 * Profile names can not start with : or @ or ^ and may not contain \0
30 *
31 * Reserved profile names
32 * unconfined - special automatically generated unconfined profile
33 * inherit - special name to indicate profile inheritance
34 * null-XXXX-YYYY - special automatically generated learning profiles
35 *
36 * Namespace names may not start with / or @ and may not contain \0 or :
37 * Reserved namespace names
38 * user-XXXX - user defined profiles
39 *
40 * a // in a profile or namespace name indicates a hierarchical name with the
41 * name before the // being the parent and the name after the child.
42 *
43 * Profile and namespace hierarchies serve two different but similar purposes.
44 * The namespace contains the set of visible profiles that are considered
45 * for attachment. The hierarchy of namespaces allows for virtualizing
46 * the namespace so that for example a chroot can have its own set of profiles
47 * which may define some local user namespaces.
48 * The profile hierarchy severs two distinct purposes,
49 * - it allows for sub profiles or hats, which allows an application to run
50 * subprograms under its own profile with different restriction than it
51 * self, and not have it use the system profile.
52 * eg. if a mail program starts an editor, the policy might make the
53 * restrictions tighter on the editor tighter than the mail program,
54 * and definitely different than general editor restrictions
55 * - it allows for binary hierarchy of profiles, so that execution history
56 * is preserved. This feature isn't exploited by AppArmor reference policy
57 * but is allowed. NOTE: this is currently suboptimal because profile
58 * aliasing is not currently implemented so that a profile for each
59 * level must be defined.
60 * eg. /bin/bash///bin/ls as a name would indicate /bin/ls was started
61 * from /bin/bash
62 *
63 * A profile or namespace name that can contain one or more // separators
64 * is referred to as an hname (hierarchical).
65 * eg. /bin/bash//bin/ls
66 *
67 * An fqname is a name that may contain both namespace and profile hnames.
68 * eg. :ns:/bin/bash//bin/ls
69 *
70 * NOTES:
71 * - locking of profile lists is currently fairly coarse. All profile
72 * lists within a namespace use the namespace lock.
73 * FIXME: move profile lists to using rcu_lists
74 */
75
76#include <linux/slab.h>
77#include <linux/spinlock.h>
78#include <linux/string.h>
79
80#include "include/apparmor.h"
81#include "include/capability.h"
82#include "include/context.h"
83#include "include/file.h"
84#include "include/ipc.h"
85#include "include/match.h"
86#include "include/path.h"
87#include "include/policy.h"
88#include "include/policy_unpack.h"
89#include "include/resource.h"
90#include "include/sid.h"
91
92
93/* root profile namespace */
94struct aa_namespace *root_ns;
95
96const char *profile_mode_names[] = {
97 "enforce",
98 "complain",
99 "kill",
100};
101
102/**
103 * hname_tail - find the last component of an hname
104 * @name: hname to find the base profile name component of (NOT NULL)
105 *
106 * Returns: the tail (base profile name) name component of an hname
107 */
108static const char *hname_tail(const char *hname)
109{
110 char *split;
111 hname = strim((char *)hname);
112 for (split = strstr(hname, "//"); split; split = strstr(hname, "//"))
113 hname = split + 2;
114
115 return hname;
116}
117
118/**
119 * policy_init - initialize a policy structure
120 * @policy: policy to initialize (NOT NULL)
121 * @prefix: prefix name if any is required. (MAYBE NULL)
122 * @name: name of the policy, init will make a copy of it (NOT NULL)
123 *
124 * Note: this fn creates a copy of strings passed in
125 *
126 * Returns: true if policy init successful
127 */
128static bool policy_init(struct aa_policy *policy, const char *prefix,
129 const char *name)
130{
131 /* freed by policy_free */
132 if (prefix) {
133 policy->hname = kmalloc(strlen(prefix) + strlen(name) + 3,
134 GFP_KERNEL);
135 if (policy->hname)
136 sprintf(policy->hname, "%s//%s", prefix, name);
137 } else
138 policy->hname = kstrdup(name, GFP_KERNEL);
139 if (!policy->hname)
140 return 0;
141 /* base.name is a substring of fqname */
142 policy->name = (char *)hname_tail(policy->hname);
143 INIT_LIST_HEAD(&policy->list);
144 INIT_LIST_HEAD(&policy->profiles);
145 kref_init(&policy->count);
146
147 return 1;
148}
149
150/**
151 * policy_destroy - free the elements referenced by @policy
152 * @policy: policy that is to have its elements freed (NOT NULL)
153 */
154static void policy_destroy(struct aa_policy *policy)
155{
156 /* still contains profiles -- invalid */
157 if (!list_empty(&policy->profiles)) {
158 AA_ERROR("%s: internal error, "
159 "policy '%s' still contains profiles\n",
160 __func__, policy->name);
161 BUG();
162 }
163 if (!list_empty(&policy->list)) {
164 AA_ERROR("%s: internal error, policy '%s' still on list\n",
165 __func__, policy->name);
166 BUG();
167 }
168
169 /* don't free name as its a subset of hname */
170 kzfree(policy->hname);
171}
172
173/**
174 * __policy_find - find a policy by @name on a policy list
175 * @head: list to search (NOT NULL)
176 * @name: name to search for (NOT NULL)
177 *
178 * Requires: correct locks for the @head list be held
179 *
180 * Returns: unrefcounted policy that match @name or NULL if not found
181 */
182static struct aa_policy *__policy_find(struct list_head *head, const char *name)
183{
184 struct aa_policy *policy;
185
186 list_for_each_entry(policy, head, list) {
187 if (!strcmp(policy->name, name))
188 return policy;
189 }
190 return NULL;
191}
192
193/**
194 * __policy_strn_find - find a policy that's name matches @len chars of @str
195 * @head: list to search (NOT NULL)
196 * @str: string to search for (NOT NULL)
197 * @len: length of match required
198 *
199 * Requires: correct locks for the @head list be held
200 *
201 * Returns: unrefcounted policy that match @str or NULL if not found
202 *
203 * if @len == strlen(@strlen) then this is equiv to __policy_find
204 * other wise it allows searching for policy by a partial match of name
205 */
206static struct aa_policy *__policy_strn_find(struct list_head *head,
207 const char *str, int len)
208{
209 struct aa_policy *policy;
210
211 list_for_each_entry(policy, head, list) {
212 if (aa_strneq(policy->name, str, len))
213 return policy;
214 }
215
216 return NULL;
217}
218
219/*
220 * Routines for AppArmor namespaces
221 */
222
223static const char *hidden_ns_name = "---";
224/**
225 * aa_ns_visible - test if @view is visible from @curr
226 * @curr: namespace to treat as the parent (NOT NULL)
227 * @view: namespace to test if visible from @curr (NOT NULL)
228 *
229 * Returns: true if @view is visible from @curr else false
230 */
231bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view)
232{
233 if (curr == view)
234 return true;
235
236 for ( ; view; view = view->parent) {
237 if (view->parent == curr)
238 return true;
239 }
240 return false;
241}
242
243/**
244 * aa_na_name - Find the ns name to display for @view from @curr
245 * @curr - current namespace (NOT NULL)
246 * @view - namespace attempting to view (NOT NULL)
247 *
248 * Returns: name of @view visible from @curr
249 */
250const char *aa_ns_name(struct aa_namespace *curr, struct aa_namespace *view)
251{
252 /* if view == curr then the namespace name isn't displayed */
253 if (curr == view)
254 return "";
255
256 if (aa_ns_visible(curr, view)) {
257 /* at this point if a ns is visible it is in a view ns
258 * thus the curr ns.hname is a prefix of its name.
259 * Only output the virtualized portion of the name
260 * Add + 2 to skip over // separating curr hname prefix
261 * from the visible tail of the views hname
262 */
263 return view->base.hname + strlen(curr->base.hname) + 2;
264 } else
265 return hidden_ns_name;
266}
267
268/**
269 * alloc_namespace - allocate, initialize and return a new namespace
270 * @prefix: parent namespace name (MAYBE NULL)
271 * @name: a preallocated name (NOT NULL)
272 *
273 * Returns: refcounted namespace or NULL on failure.
274 */
275static struct aa_namespace *alloc_namespace(const char *prefix,
276 const char *name)
277{
278 struct aa_namespace *ns;
279
280 ns = kzalloc(sizeof(*ns), GFP_KERNEL);
281 AA_DEBUG("%s(%p)\n", __func__, ns);
282 if (!ns)
283 return NULL;
284 if (!policy_init(&ns->base, prefix, name))
285 goto fail_ns;
286
287 INIT_LIST_HEAD(&ns->sub_ns);
288 rwlock_init(&ns->lock);
289
290 /* released by free_namespace */
291 ns->unconfined = aa_alloc_profile("unconfined");
292 if (!ns->unconfined)
293 goto fail_unconfined;
294
295 ns->unconfined->sid = aa_alloc_sid();
296 ns->unconfined->flags = PFLAG_UNCONFINED | PFLAG_IX_ON_NAME_ERROR |
297 PFLAG_IMMUTABLE;
298
299 /*
300 * released by free_namespace, however __remove_namespace breaks
301 * the cyclic references (ns->unconfined, and unconfined->ns) and
302 * replaces with refs to parent namespace unconfined
303 */
304 ns->unconfined->ns = aa_get_namespace(ns);
305
306 return ns;
307
308fail_unconfined:
309 kzfree(ns->base.name);
310fail_ns:
311 kzfree(ns);
312 return NULL;
313}
314
315/**
316 * free_namespace - free a profile namespace
317 * @ns: the namespace to free (MAYBE NULL)
318 *
319 * Requires: All references to the namespace must have been put, if the
320 * namespace was referenced by a profile confining a task,
321 */
322static void free_namespace(struct aa_namespace *ns)
323{
324 if (!ns)
325 return;
326
327 policy_destroy(&ns->base);
328 aa_put_namespace(ns->parent);
329
330 if (ns->unconfined && ns->unconfined->ns == ns)
331 ns->unconfined->ns = NULL;
332
333 aa_put_profile(ns->unconfined);
334 kzfree(ns);
335}
336
337/**
338 * aa_free_namespace_kref - free aa_namespace by kref (see aa_put_namespace)
339 * @kr: kref callback for freeing of a namespace (NOT NULL)
340 */
341void aa_free_namespace_kref(struct kref *kref)
342{
343 free_namespace(container_of(kref, struct aa_namespace, base.count));
344}
345
346/**
347 * __aa_find_namespace - find a namespace on a list by @name
348 * @head: list to search for namespace on (NOT NULL)
349 * @name: name of namespace to look for (NOT NULL)
350 *
351 * Returns: unrefcounted namespace
352 *
353 * Requires: ns lock be held
354 */
355static struct aa_namespace *__aa_find_namespace(struct list_head *head,
356 const char *name)
357{
358 return (struct aa_namespace *)__policy_find(head, name);
359}
360
361/**
362 * aa_find_namespace - look up a profile namespace on the namespace list
363 * @root: namespace to search in (NOT NULL)
364 * @name: name of namespace to find (NOT NULL)
365 *
366 * Returns: a refcounted namespace on the list, or NULL if no namespace
367 * called @name exists.
368 *
369 * refcount released by caller
370 */
371struct aa_namespace *aa_find_namespace(struct aa_namespace *root,
372 const char *name)
373{
374 struct aa_namespace *ns = NULL;
375
376 read_lock(&root->lock);
377 ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name));
378 read_unlock(&root->lock);
379
380 return ns;
381}
382
383/**
384 * aa_prepare_namespace - find an existing or create a new namespace of @name
385 * @name: the namespace to find or add (MAYBE NULL)
386 *
387 * Returns: refcounted namespace or NULL if failed to create one
388 */
389static struct aa_namespace *aa_prepare_namespace(const char *name)
390{
391 struct aa_namespace *ns, *root;
392
393 root = aa_current_profile()->ns;
394
395 write_lock(&root->lock);
396
397 /* if name isn't specified the profile is loaded to the current ns */
398 if (!name) {
399 /* released by caller */
400 ns = aa_get_namespace(root);
401 goto out;
402 }
403
404 /* try and find the specified ns and if it doesn't exist create it */
405 /* released by caller */
406 ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name));
407 if (!ns) {
408 /* namespace not found */
409 struct aa_namespace *new_ns;
410 write_unlock(&root->lock);
411 new_ns = alloc_namespace(root->base.hname, name);
412 if (!new_ns)
413 return NULL;
414 write_lock(&root->lock);
415 /* test for race when new_ns was allocated */
416 ns = __aa_find_namespace(&root->sub_ns, name);
417 if (!ns) {
418 /* add parent ref */
419 new_ns->parent = aa_get_namespace(root);
420
421 list_add(&new_ns->base.list, &root->sub_ns);
422 /* add list ref */
423 ns = aa_get_namespace(new_ns);
424 } else {
425 /* raced so free the new one */
426 free_namespace(new_ns);
427 /* get reference on namespace */
428 aa_get_namespace(ns);
429 }
430 }
431out:
432 write_unlock(&root->lock);
433
434 /* return ref */
435 return ns;
436}
437
438/**
439 * __list_add_profile - add a profile to a list
440 * @list: list to add it to (NOT NULL)
441 * @profile: the profile to add (NOT NULL)
442 *
443 * refcount @profile, should be put by __list_remove_profile
444 *
445 * Requires: namespace lock be held, or list not be shared
446 */
447static void __list_add_profile(struct list_head *list,
448 struct aa_profile *profile)
449{
450 list_add(&profile->base.list, list);
451 /* get list reference */
452 aa_get_profile(profile);
453}
454
455/**
456 * __list_remove_profile - remove a profile from the list it is on
457 * @profile: the profile to remove (NOT NULL)
458 *
459 * remove a profile from the list, warning generally removal should
460 * be done with __replace_profile as most profile removals are
461 * replacements to the unconfined profile.
462 *
463 * put @profile list refcount
464 *
465 * Requires: namespace lock be held, or list not have been live
466 */
467static void __list_remove_profile(struct aa_profile *profile)
468{
469 list_del_init(&profile->base.list);
470 if (!(profile->flags & PFLAG_NO_LIST_REF))
471 /* release list reference */
472 aa_put_profile(profile);
473}
474
475/**
476 * __replace_profile - replace @old with @new on a list
477 * @old: profile to be replaced (NOT NULL)
478 * @new: profile to replace @old with (NOT NULL)
479 *
480 * Will duplicate and refcount elements that @new inherits from @old
481 * and will inherit @old children.
482 *
483 * refcount @new for list, put @old list refcount
484 *
485 * Requires: namespace list lock be held, or list not be shared
486 */
487static void __replace_profile(struct aa_profile *old, struct aa_profile *new)
488{
489 struct aa_policy *policy;
490 struct aa_profile *child, *tmp;
491
492 if (old->parent)
493 policy = &old->parent->base;
494 else
495 policy = &old->ns->base;
496
497 /* released when @new is freed */
498 new->parent = aa_get_profile(old->parent);
499 new->ns = aa_get_namespace(old->ns);
500 new->sid = old->sid;
501 __list_add_profile(&policy->profiles, new);
502 /* inherit children */
503 list_for_each_entry_safe(child, tmp, &old->base.profiles, base.list) {
504 aa_put_profile(child->parent);
505 child->parent = aa_get_profile(new);
506 /* list refcount transferred to @new*/
507 list_move(&child->base.list, &new->base.profiles);
508 }
509
510 /* released by free_profile */
511 old->replacedby = aa_get_profile(new);
512 __list_remove_profile(old);
513}
514
515static void __profile_list_release(struct list_head *head);
516
517/**
518 * __remove_profile - remove old profile, and children
519 * @profile: profile to be replaced (NOT NULL)
520 *
521 * Requires: namespace list lock be held, or list not be shared
522 */
523static void __remove_profile(struct aa_profile *profile)
524{
525 /* release any children lists first */
526 __profile_list_release(&profile->base.profiles);
527 /* released by free_profile */
528 profile->replacedby = aa_get_profile(profile->ns->unconfined);
529 __list_remove_profile(profile);
530}
531
532/**
533 * __profile_list_release - remove all profiles on the list and put refs
534 * @head: list of profiles (NOT NULL)
535 *
536 * Requires: namespace lock be held
537 */
538static void __profile_list_release(struct list_head *head)
539{
540 struct aa_profile *profile, *tmp;
541 list_for_each_entry_safe(profile, tmp, head, base.list)
542 __remove_profile(profile);
543}
544
545static void __ns_list_release(struct list_head *head);
546
547/**
548 * destroy_namespace - remove everything contained by @ns
549 * @ns: namespace to have it contents removed (NOT NULL)
550 */
551static void destroy_namespace(struct aa_namespace *ns)
552{
553 if (!ns)
554 return;
555
556 write_lock(&ns->lock);
557 /* release all profiles in this namespace */
558 __profile_list_release(&ns->base.profiles);
559
560 /* release all sub namespaces */
561 __ns_list_release(&ns->sub_ns);
562
563 write_unlock(&ns->lock);
564}
565
566/**
567 * __remove_namespace - remove a namespace and all its children
568 * @ns: namespace to be removed (NOT NULL)
569 *
570 * Requires: ns->parent->lock be held and ns removed from parent.
571 */
572static void __remove_namespace(struct aa_namespace *ns)
573{
574 struct aa_profile *unconfined = ns->unconfined;
575
576 /* remove ns from namespace list */
577 list_del_init(&ns->base.list);
578
579 /*
580 * break the ns, unconfined profile cyclic reference and forward
581 * all new unconfined profiles requests to the parent namespace
582 * This will result in all confined tasks that have a profile
583 * being removed, inheriting the parent->unconfined profile.
584 */
585 if (ns->parent)
586 ns->unconfined = aa_get_profile(ns->parent->unconfined);
587
588 destroy_namespace(ns);
589
590 /* release original ns->unconfined ref */
591 aa_put_profile(unconfined);
592 /* release ns->base.list ref, from removal above */
593 aa_put_namespace(ns);
594}
595
596/**
597 * __ns_list_release - remove all profile namespaces on the list put refs
598 * @head: list of profile namespaces (NOT NULL)
599 *
600 * Requires: namespace lock be held
601 */
602static void __ns_list_release(struct list_head *head)
603{
604 struct aa_namespace *ns, *tmp;
605 list_for_each_entry_safe(ns, tmp, head, base.list)
606 __remove_namespace(ns);
607
608}
609
610/**
611 * aa_alloc_root_ns - allocate the root profile namespace
612 *
613 * Returns: %0 on success else error
614 *
615 */
616int __init aa_alloc_root_ns(void)
617{
618 /* released by aa_free_root_ns - used as list ref*/
619 root_ns = alloc_namespace(NULL, "root");
620 if (!root_ns)
621 return -ENOMEM;
622
623 return 0;
624}
625
626 /**
627 * aa_free_root_ns - free the root profile namespace
628 */
629void __init aa_free_root_ns(void)
630 {
631 struct aa_namespace *ns = root_ns;
632 root_ns = NULL;
633
634 destroy_namespace(ns);
635 aa_put_namespace(ns);
636}
637
638/**
639 * aa_alloc_profile - allocate, initialize and return a new profile
640 * @hname: name of the profile (NOT NULL)
641 *
642 * Returns: refcount profile or NULL on failure
643 */
644struct aa_profile *aa_alloc_profile(const char *hname)
645{
646 struct aa_profile *profile;
647
648 /* freed by free_profile - usually through aa_put_profile */
649 profile = kzalloc(sizeof(*profile), GFP_KERNEL);
650 if (!profile)
651 return NULL;
652
653 if (!policy_init(&profile->base, NULL, hname)) {
654 kzfree(profile);
655 return NULL;
656 }
657
658 /* refcount released by caller */
659 return profile;
660}
661
662/**
663 * aa_new_null_profile - create a new null-X learning profile
664 * @parent: profile that caused this profile to be created (NOT NULL)
665 * @hat: true if the null- learning profile is a hat
666 *
667 * Create a null- complain mode profile used in learning mode. The name of
668 * the profile is unique and follows the format of parent//null-sid.
669 *
670 * null profiles are added to the profile list but the list does not
671 * hold a count on them so that they are automatically released when
672 * not in use.
673 *
674 * Returns: new refcounted profile else NULL on failure
675 */
676struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat)
677{
678 struct aa_profile *profile = NULL;
679 char *name;
680 u32 sid = aa_alloc_sid();
681
682 /* freed below */
683 name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, GFP_KERNEL);
684 if (!name)
685 goto fail;
686 sprintf(name, "%s//null-%x", parent->base.hname, sid);
687
688 profile = aa_alloc_profile(name);
689 kfree(name);
690 if (!profile)
691 goto fail;
692
693 profile->sid = sid;
694 profile->mode = APPARMOR_COMPLAIN;
695 profile->flags = PFLAG_NULL;
696 if (hat)
697 profile->flags |= PFLAG_HAT;
698
699 /* released on free_profile */
700 profile->parent = aa_get_profile(parent);
701 profile->ns = aa_get_namespace(parent->ns);
702
703 write_lock(&profile->ns->lock);
704 __list_add_profile(&parent->base.profiles, profile);
705 write_unlock(&profile->ns->lock);
706
707 /* refcount released by caller */
708 return profile;
709
710fail:
711 aa_free_sid(sid);
712 return NULL;
713}
714
715/**
716 * free_profile - free a profile
717 * @profile: the profile to free (MAYBE NULL)
718 *
719 * Free a profile, its hats and null_profile. All references to the profile,
720 * its hats and null_profile must have been put.
721 *
722 * If the profile was referenced from a task context, free_profile() will
723 * be called from an rcu callback routine, so we must not sleep here.
724 */
725static void free_profile(struct aa_profile *profile)
726{
727 AA_DEBUG("%s(%p)\n", __func__, profile);
728
729 if (!profile)
730 return;
731
732 if (!list_empty(&profile->base.list)) {
733 AA_ERROR("%s: internal error, "
734 "profile '%s' still on ns list\n",
735 __func__, profile->base.name);
736 BUG();
737 }
738
739 /* free children profiles */
740 policy_destroy(&profile->base);
741 aa_put_profile(profile->parent);
742
743 aa_put_namespace(profile->ns);
744 kzfree(profile->rename);
745
746 aa_free_file_rules(&profile->file);
747 aa_free_cap_rules(&profile->caps);
748 aa_free_rlimit_rules(&profile->rlimits);
749
750 aa_free_sid(profile->sid);
751 aa_put_dfa(profile->xmatch);
752
753 aa_put_profile(profile->replacedby);
754
755 kzfree(profile);
756}
757
758/**
759 * aa_free_profile_kref - free aa_profile by kref (called by aa_put_profile)
760 * @kr: kref callback for freeing of a profile (NOT NULL)
761 */
762void aa_free_profile_kref(struct kref *kref)
763{
764 struct aa_profile *p = container_of(kref, struct aa_profile,
765 base.count);
766
767 free_profile(p);
768}
769
770/* TODO: profile accounting - setup in remove */
771
772/**
773 * __find_child - find a profile on @head list with a name matching @name
774 * @head: list to search (NOT NULL)
775 * @name: name of profile (NOT NULL)
776 *
777 * Requires: ns lock protecting list be held
778 *
779 * Returns: unrefcounted profile ptr, or NULL if not found
780 */
781static struct aa_profile *__find_child(struct list_head *head, const char *name)
782{
783 return (struct aa_profile *)__policy_find(head, name);
784}
785
786/**
787 * __strn_find_child - find a profile on @head list using substring of @name
788 * @head: list to search (NOT NULL)
789 * @name: name of profile (NOT NULL)
790 * @len: length of @name substring to match
791 *
792 * Requires: ns lock protecting list be held
793 *
794 * Returns: unrefcounted profile ptr, or NULL if not found
795 */
796static struct aa_profile *__strn_find_child(struct list_head *head,
797 const char *name, int len)
798{
799 return (struct aa_profile *)__policy_strn_find(head, name, len);
800}
801
802/**
803 * aa_find_child - find a profile by @name in @parent
804 * @parent: profile to search (NOT NULL)
805 * @name: profile name to search for (NOT NULL)
806 *
807 * Returns: a refcounted profile or NULL if not found
808 */
809struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name)
810{
811 struct aa_profile *profile;
812
813 read_lock(&parent->ns->lock);
814 profile = aa_get_profile(__find_child(&parent->base.profiles, name));
815 read_unlock(&parent->ns->lock);
816
817 /* refcount released by caller */
818 return profile;
819}
820
821/**
822 * __lookup_parent - lookup the parent of a profile of name @hname
823 * @ns: namespace to lookup profile in (NOT NULL)
824 * @hname: hierarchical profile name to find parent of (NOT NULL)
825 *
826 * Lookups up the parent of a fully qualified profile name, the profile
827 * that matches hname does not need to exist, in general this
828 * is used to load a new profile.
829 *
830 * Requires: ns->lock be held
831 *
832 * Returns: unrefcounted policy or NULL if not found
833 */
834static struct aa_policy *__lookup_parent(struct aa_namespace *ns,
835 const char *hname)
836{
837 struct aa_policy *policy;
838 struct aa_profile *profile = NULL;
839 char *split;
840
841 policy = &ns->base;
842
843 for (split = strstr(hname, "//"); split;) {
844 profile = __strn_find_child(&policy->profiles, hname,
845 split - hname);
846 if (!profile)
847 return NULL;
848 policy = &profile->base;
849 hname = split + 2;
850 split = strstr(hname, "//");
851 }
852 if (!profile)
853 return &ns->base;
854 return &profile->base;
855}
856
857/**
858 * __lookup_profile - lookup the profile matching @hname
859 * @base: base list to start looking up profile name from (NOT NULL)
860 * @hname: hierarchical profile name (NOT NULL)
861 *
862 * Requires: ns->lock be held
863 *
864 * Returns: unrefcounted profile pointer or NULL if not found
865 *
866 * Do a relative name lookup, recursing through profile tree.
867 */
868static struct aa_profile *__lookup_profile(struct aa_policy *base,
869 const char *hname)
870{
871 struct aa_profile *profile = NULL;
872 char *split;
873
874 for (split = strstr(hname, "//"); split;) {
875 profile = __strn_find_child(&base->profiles, hname,
876 split - hname);
877 if (!profile)
878 return NULL;
879
880 base = &profile->base;
881 hname = split + 2;
882 split = strstr(hname, "//");
883 }
884
885 profile = __find_child(&base->profiles, hname);
886
887 return profile;
888}
889
890/**
891 * aa_lookup_profile - find a profile by its full or partial name
892 * @ns: the namespace to start from (NOT NULL)
893 * @hname: name to do lookup on. Does not contain namespace prefix (NOT NULL)
894 *
895 * Returns: refcounted profile or NULL if not found
896 */
897struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *hname)
898{
899 struct aa_profile *profile;
900
901 read_lock(&ns->lock);
902 profile = aa_get_profile(__lookup_profile(&ns->base, hname));
903 read_unlock(&ns->lock);
904
905 /* refcount released by caller */
906 return profile;
907}
908
909/**
910 * replacement_allowed - test to see if replacement is allowed
911 * @profile: profile to test if it can be replaced (MAYBE NULL)
912 * @noreplace: true if replacement shouldn't be allowed but addition is okay
913 * @info: Returns - info about why replacement failed (NOT NULL)
914 *
915 * Returns: %0 if replacement allowed else error code
916 */
917static int replacement_allowed(struct aa_profile *profile, int noreplace,
918 const char **info)
919{
920 if (profile) {
921 if (profile->flags & PFLAG_IMMUTABLE) {
922 *info = "cannot replace immutible profile";
923 return -EPERM;
924 } else if (noreplace) {
925 *info = "profile already exists";
926 return -EEXIST;
927 }
928 }
929 return 0;
930}
931
932/**
933 * __add_new_profile - simple wrapper around __list_add_profile
934 * @ns: namespace that profile is being added to (NOT NULL)
935 * @policy: the policy container to add the profile to (NOT NULL)
936 * @profile: profile to add (NOT NULL)
937 *
938 * add a profile to a list and do other required basic allocations
939 */
940static void __add_new_profile(struct aa_namespace *ns, struct aa_policy *policy,
941 struct aa_profile *profile)
942{
943 if (policy != &ns->base)
944 /* released on profile replacement or free_profile */
945 profile->parent = aa_get_profile((struct aa_profile *) policy);
946 __list_add_profile(&policy->profiles, profile);
947 /* released on free_profile */
948 profile->sid = aa_alloc_sid();
949 profile->ns = aa_get_namespace(ns);
950}
951
952/**
953 * aa_audit_policy - Do auditing of policy changes
954 * @op: policy operation being performed
955 * @gfp: memory allocation flags
956 * @name: name of profile being manipulated (NOT NULL)
957 * @info: any extra information to be audited (MAYBE NULL)
958 * @error: error code
959 *
960 * Returns: the error to be returned after audit is done
961 */
962static int audit_policy(int op, gfp_t gfp, const char *name, const char *info,
963 int error)
964{
965 struct common_audit_data sa;
966 COMMON_AUDIT_DATA_INIT(&sa, NONE);
967 sa.aad.op = op;
968 sa.aad.name = name;
969 sa.aad.info = info;
970 sa.aad.error = error;
971
972 return aa_audit(AUDIT_APPARMOR_STATUS, __aa_current_profile(), gfp,
973 &sa, NULL);
974}
975
976/**
977 * aa_may_manage_policy - can the current task manage policy
978 * @op: the policy manipulation operation being done
979 *
980 * Returns: true if the task is allowed to manipulate policy
981 */
982bool aa_may_manage_policy(int op)
983{
984 /* check if loading policy is locked out */
985 if (aa_g_lock_policy) {
986 audit_policy(op, GFP_KERNEL, NULL, "policy_locked", -EACCES);
987 return 0;
988 }
989
990 if (!capable(CAP_MAC_ADMIN)) {
991 audit_policy(op, GFP_KERNEL, NULL, "not policy admin", -EACCES);
992 return 0;
993 }
994
995 return 1;
996}
997
998/**
999 * aa_replace_profiles - replace profile(s) on the profile list
1000 * @udata: serialized data stream (NOT NULL)
1001 * @size: size of the serialized data stream
1002 * @noreplace: true if only doing addition, no replacement allowed
1003 *
1004 * unpack and replace a profile on the profile list and uses of that profile
1005 * by any aa_task_cxt. If the profile does not exist on the profile list
1006 * it is added.
1007 *
1008 * Returns: size of data consumed else error code on failure.
1009 */
1010ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
1011{
1012 struct aa_policy *policy;
1013 struct aa_profile *old_profile = NULL, *new_profile = NULL;
1014 struct aa_profile *rename_profile = NULL;
1015 struct aa_namespace *ns = NULL;
1016 const char *ns_name, *name = NULL, *info = NULL;
1017 int op = OP_PROF_REPL;
1018 ssize_t error;
1019
1020 /* released below */
1021 new_profile = aa_unpack(udata, size, &ns_name);
1022 if (IS_ERR(new_profile)) {
1023 error = PTR_ERR(new_profile);
1024 new_profile = NULL;
1025 goto fail;
1026 }
1027
1028 /* released below */
1029 ns = aa_prepare_namespace(ns_name);
1030 if (!ns) {
1031 info = "failed to prepare namespace";
1032 error = -ENOMEM;
1033 name = ns_name;
1034 goto fail;
1035 }
1036
1037 name = new_profile->base.hname;
1038
1039 write_lock(&ns->lock);
1040 /* no ref on policy only use inside lock */
1041 policy = __lookup_parent(ns, new_profile->base.hname);
1042
1043 if (!policy) {
1044 info = "parent does not exist";
1045 error = -ENOENT;
1046 goto audit;
1047 }
1048
1049 old_profile = __find_child(&policy->profiles, new_profile->base.name);
1050 /* released below */
1051 aa_get_profile(old_profile);
1052
1053 if (new_profile->rename) {
1054 rename_profile = __lookup_profile(&ns->base,
1055 new_profile->rename);
1056 /* released below */
1057 aa_get_profile(rename_profile);
1058
1059 if (!rename_profile) {
1060 info = "profile to rename does not exist";
1061 name = new_profile->rename;
1062 error = -ENOENT;
1063 goto audit;
1064 }
1065 }
1066
1067 error = replacement_allowed(old_profile, noreplace, &info);
1068 if (error)
1069 goto audit;
1070
1071 error = replacement_allowed(rename_profile, noreplace, &info);
1072 if (error)
1073 goto audit;
1074
1075audit:
1076 if (!old_profile && !rename_profile)
1077 op = OP_PROF_LOAD;
1078
1079 error = audit_policy(op, GFP_ATOMIC, name, info, error);
1080
1081 if (!error) {
1082 if (rename_profile)
1083 __replace_profile(rename_profile, new_profile);
1084 if (old_profile) {
1085 /* when there are both rename and old profiles
1086 * inherit old profiles sid
1087 */
1088 if (rename_profile)
1089 aa_free_sid(new_profile->sid);
1090 __replace_profile(old_profile, new_profile);
1091 }
1092 if (!(old_profile || rename_profile))
1093 __add_new_profile(ns, policy, new_profile);
1094 }
1095 write_unlock(&ns->lock);
1096
1097out:
1098 aa_put_namespace(ns);
1099 aa_put_profile(rename_profile);
1100 aa_put_profile(old_profile);
1101 aa_put_profile(new_profile);
1102 if (error)
1103 return error;
1104 return size;
1105
1106fail:
1107 error = audit_policy(op, GFP_KERNEL, name, info, error);
1108 goto out;
1109}
1110
1111/**
1112 * aa_remove_profiles - remove profile(s) from the system
1113 * @fqname: name of the profile or namespace to remove (NOT NULL)
1114 * @size: size of the name
1115 *
1116 * Remove a profile or sub namespace from the current namespace, so that
1117 * they can not be found anymore and mark them as replaced by unconfined
1118 *
1119 * NOTE: removing confinement does not restore rlimits to preconfinemnet values
1120 *
1121 * Returns: size of data consume else error code if fails
1122 */
1123ssize_t aa_remove_profiles(char *fqname, size_t size)
1124{
1125 struct aa_namespace *root, *ns = NULL;
1126 struct aa_profile *profile = NULL;
1127 const char *name = fqname, *info = NULL;
1128 ssize_t error = 0;
1129
1130 if (*fqname == 0) {
1131 info = "no profile specified";
1132 error = -ENOENT;
1133 goto fail;
1134 }
1135
1136 root = aa_current_profile()->ns;
1137
1138 if (fqname[0] == ':') {
1139 char *ns_name;
1140 name = aa_split_fqname(fqname, &ns_name);
1141 if (ns_name) {
1142 /* released below */
1143 ns = aa_find_namespace(root, ns_name);
1144 if (!ns) {
1145 info = "namespace does not exist";
1146 error = -ENOENT;
1147 goto fail;
1148 }
1149 }
1150 } else
1151 /* released below */
1152 ns = aa_get_namespace(root);
1153
1154 write_lock(&ns->lock);
1155 if (!name) {
1156 /* remove namespace - can only happen if fqname[0] == ':' */
1157 __remove_namespace(ns);
1158 } else {
1159 /* remove profile */
1160 profile = aa_get_profile(__lookup_profile(&ns->base, name));
1161 if (!profile) {
1162 error = -ENOENT;
1163 info = "profile does not exist";
1164 goto fail_ns_lock;
1165 }
1166 name = profile->base.hname;
1167 __remove_profile(profile);
1168 }
1169 write_unlock(&ns->lock);
1170
1171 /* don't fail removal if audit fails */
1172 (void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error);
1173 aa_put_namespace(ns);
1174 aa_put_profile(profile);
1175 return size;
1176
1177fail_ns_lock:
1178 write_unlock(&ns->lock);
1179 aa_put_namespace(ns);
1180
1181fail:
1182 (void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error);
1183 return error;
1184}
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
new file mode 100644
index 00000000000..eb3700e9fd3
--- /dev/null
+++ b/security/apparmor/policy_unpack.c
@@ -0,0 +1,703 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor functions for unpacking policy loaded from
5 * userspace.
6 *
7 * Copyright (C) 1998-2008 Novell/SUSE
8 * Copyright 2009-2010 Canonical Ltd.
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation, version 2 of the
13 * License.
14 *
15 * AppArmor uses a serialized binary format for loading policy.
16 * To find policy format documentation look in Documentation/apparmor.txt
17 * All policy is validated before it is used.
18 */
19
20#include <asm/unaligned.h>
21#include <linux/ctype.h>
22#include <linux/errno.h>
23
24#include "include/apparmor.h"
25#include "include/audit.h"
26#include "include/context.h"
27#include "include/match.h"
28#include "include/policy.h"
29#include "include/policy_unpack.h"
30#include "include/sid.h"
31
32/*
33 * The AppArmor interface treats data as a type byte followed by the
34 * actual data. The interface has the notion of a a named entry
35 * which has a name (AA_NAME typecode followed by name string) followed by
36 * the entries typecode and data. Named types allow for optional
37 * elements and extensions to be added and tested for without breaking
38 * backwards compatibility.
39 */
40
41enum aa_code {
42 AA_U8,
43 AA_U16,
44 AA_U32,
45 AA_U64,
46 AA_NAME, /* same as string except it is items name */
47 AA_STRING,
48 AA_BLOB,
49 AA_STRUCT,
50 AA_STRUCTEND,
51 AA_LIST,
52 AA_LISTEND,
53 AA_ARRAY,
54 AA_ARRAYEND,
55};
56
57/*
58 * aa_ext is the read of the buffer containing the serialized profile. The
59 * data is copied into a kernel buffer in apparmorfs and then handed off to
60 * the unpack routines.
61 */
62struct aa_ext {
63 void *start;
64 void *end;
65 void *pos; /* pointer to current position in the buffer */
66 u32 version;
67};
68
69/* audit callback for unpack fields */
70static void audit_cb(struct audit_buffer *ab, void *va)
71{
72 struct common_audit_data *sa = va;
73 if (sa->aad.iface.target) {
74 struct aa_profile *name = sa->aad.iface.target;
75 audit_log_format(ab, " name=");
76 audit_log_untrustedstring(ab, name->base.hname);
77 }
78 if (sa->aad.iface.pos)
79 audit_log_format(ab, " offset=%ld", sa->aad.iface.pos);
80}
81
82/**
83 * audit_iface - do audit message for policy unpacking/load/replace/remove
84 * @new: profile if it has been allocated (MAYBE NULL)
85 * @name: name of the profile being manipulated (MAYBE NULL)
86 * @info: any extra info about the failure (MAYBE NULL)
87 * @e: buffer position info (NOT NULL)
88 * @error: error code
89 *
90 * Returns: %0 or error
91 */
92static int audit_iface(struct aa_profile *new, const char *name,
93 const char *info, struct aa_ext *e, int error)
94{
95 struct aa_profile *profile = __aa_current_profile();
96 struct common_audit_data sa;
97 COMMON_AUDIT_DATA_INIT(&sa, NONE);
98 sa.aad.iface.pos = e->pos - e->start;
99 sa.aad.iface.target = new;
100 sa.aad.name = name;
101 sa.aad.info = info;
102 sa.aad.error = error;
103
104 return aa_audit(AUDIT_APPARMOR_STATUS, profile, GFP_KERNEL, &sa,
105 audit_cb);
106}
107
108/* test if read will be in packed data bounds */
109static bool inbounds(struct aa_ext *e, size_t size)
110{
111 return (size <= e->end - e->pos);
112}
113
114/**
115 * aa_u16_chunck - test and do bounds checking for a u16 size based chunk
116 * @e: serialized data read head (NOT NULL)
117 * @chunk: start address for chunk of data (NOT NULL)
118 *
119 * Returns: the size of chunk found with the read head at the end of the chunk.
120 */
121static size_t unpack_u16_chunk(struct aa_ext *e, char **chunk)
122{
123 size_t size = 0;
124
125 if (!inbounds(e, sizeof(u16)))
126 return 0;
127 size = le16_to_cpu(get_unaligned((u16 *) e->pos));
128 e->pos += sizeof(u16);
129 if (!inbounds(e, size))
130 return 0;
131 *chunk = e->pos;
132 e->pos += size;
133 return size;
134}
135
136/* unpack control byte */
137static bool unpack_X(struct aa_ext *e, enum aa_code code)
138{
139 if (!inbounds(e, 1))
140 return 0;
141 if (*(u8 *) e->pos != code)
142 return 0;
143 e->pos++;
144 return 1;
145}
146
147/**
148 * unpack_nameX - check is the next element is of type X with a name of @name
149 * @e: serialized data extent information (NOT NULL)
150 * @code: type code
151 * @name: name to match to the serialized element. (MAYBE NULL)
152 *
153 * check that the next serialized data element is of type X and has a tag
154 * name @name. If @name is specified then there must be a matching
155 * name element in the stream. If @name is NULL any name element will be
156 * skipped and only the typecode will be tested.
157 *
158 * Returns 1 on success (both type code and name tests match) and the read
159 * head is advanced past the headers
160 *
161 * Returns: 0 if either match fails, the read head does not move
162 */
163static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
164{
165 /*
166 * May need to reset pos if name or type doesn't match
167 */
168 void *pos = e->pos;
169 /*
170 * Check for presence of a tagname, and if present name size
171 * AA_NAME tag value is a u16.
172 */
173 if (unpack_X(e, AA_NAME)) {
174 char *tag = NULL;
175 size_t size = unpack_u16_chunk(e, &tag);
176 /* if a name is specified it must match. otherwise skip tag */
177 if (name && (!size || strcmp(name, tag)))
178 goto fail;
179 } else if (name) {
180 /* if a name is specified and there is no name tag fail */
181 goto fail;
182 }
183
184 /* now check if type code matches */
185 if (unpack_X(e, code))
186 return 1;
187
188fail:
189 e->pos = pos;
190 return 0;
191}
192
193static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
194{
195 if (unpack_nameX(e, AA_U32, name)) {
196 if (!inbounds(e, sizeof(u32)))
197 return 0;
198 if (data)
199 *data = le32_to_cpu(get_unaligned((u32 *) e->pos));
200 e->pos += sizeof(u32);
201 return 1;
202 }
203 return 0;
204}
205
206static bool unpack_u64(struct aa_ext *e, u64 *data, const char *name)
207{
208 if (unpack_nameX(e, AA_U64, name)) {
209 if (!inbounds(e, sizeof(u64)))
210 return 0;
211 if (data)
212 *data = le64_to_cpu(get_unaligned((u64 *) e->pos));
213 e->pos += sizeof(u64);
214 return 1;
215 }
216 return 0;
217}
218
219static size_t unpack_array(struct aa_ext *e, const char *name)
220{
221 if (unpack_nameX(e, AA_ARRAY, name)) {
222 int size;
223 if (!inbounds(e, sizeof(u16)))
224 return 0;
225 size = (int)le16_to_cpu(get_unaligned((u16 *) e->pos));
226 e->pos += sizeof(u16);
227 return size;
228 }
229 return 0;
230}
231
232static size_t unpack_blob(struct aa_ext *e, char **blob, const char *name)
233{
234 if (unpack_nameX(e, AA_BLOB, name)) {
235 u32 size;
236 if (!inbounds(e, sizeof(u32)))
237 return 0;
238 size = le32_to_cpu(get_unaligned((u32 *) e->pos));
239 e->pos += sizeof(u32);
240 if (inbounds(e, (size_t) size)) {
241 *blob = e->pos;
242 e->pos += size;
243 return size;
244 }
245 }
246 return 0;
247}
248
249static int unpack_str(struct aa_ext *e, const char **string, const char *name)
250{
251 char *src_str;
252 size_t size = 0;
253 void *pos = e->pos;
254 *string = NULL;
255 if (unpack_nameX(e, AA_STRING, name)) {
256 size = unpack_u16_chunk(e, &src_str);
257 if (size) {
258 /* strings are null terminated, length is size - 1 */
259 if (src_str[size - 1] != 0)
260 goto fail;
261 *string = src_str;
262 }
263 }
264 return size;
265
266fail:
267 e->pos = pos;
268 return 0;
269}
270
271static int unpack_strdup(struct aa_ext *e, char **string, const char *name)
272{
273 const char *tmp;
274 void *pos = e->pos;
275 int res = unpack_str(e, &tmp, name);
276 *string = NULL;
277
278 if (!res)
279 return 0;
280
281 *string = kmemdup(tmp, res, GFP_KERNEL);
282 if (!*string) {
283 e->pos = pos;
284 return 0;
285 }
286
287 return res;
288}
289
290/**
291 * verify_accept - verify the accept tables of a dfa
292 * @dfa: dfa to verify accept tables of (NOT NULL)
293 * @flags: flags governing dfa
294 *
295 * Returns: 1 if valid accept tables else 0 if error
296 */
297static bool verify_accept(struct aa_dfa *dfa, int flags)
298{
299 int i;
300
301 /* verify accept permissions */
302 for (i = 0; i < dfa->tables[YYTD_ID_ACCEPT]->td_lolen; i++) {
303 int mode = ACCEPT_TABLE(dfa)[i];
304
305 if (mode & ~DFA_VALID_PERM_MASK)
306 return 0;
307
308 if (ACCEPT_TABLE2(dfa)[i] & ~DFA_VALID_PERM2_MASK)
309 return 0;
310 }
311 return 1;
312}
313
314/**
315 * unpack_dfa - unpack a file rule dfa
316 * @e: serialized data extent information (NOT NULL)
317 *
318 * returns dfa or ERR_PTR or NULL if no dfa
319 */
320static struct aa_dfa *unpack_dfa(struct aa_ext *e)
321{
322 char *blob = NULL;
323 size_t size;
324 struct aa_dfa *dfa = NULL;
325
326 size = unpack_blob(e, &blob, "aadfa");
327 if (size) {
328 /*
329 * The dfa is aligned with in the blob to 8 bytes
330 * from the beginning of the stream.
331 */
332 size_t sz = blob - (char *)e->start;
333 size_t pad = ALIGN(sz, 8) - sz;
334 int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) |
335 TO_ACCEPT2_FLAG(YYTD_DATA32);
336
337
338 if (aa_g_paranoid_load)
339 flags |= DFA_FLAG_VERIFY_STATES;
340
341 dfa = aa_dfa_unpack(blob + pad, size - pad, flags);
342
343 if (IS_ERR(dfa))
344 return dfa;
345
346 if (!verify_accept(dfa, flags))
347 goto fail;
348 }
349
350 return dfa;
351
352fail:
353 aa_put_dfa(dfa);
354 return ERR_PTR(-EPROTO);
355}
356
357/**
358 * unpack_trans_table - unpack a profile transition table
359 * @e: serialized data extent information (NOT NULL)
360 * @profile: profile to add the accept table to (NOT NULL)
361 *
362 * Returns: 1 if table succesfully unpacked
363 */
364static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
365{
366 void *pos = e->pos;
367
368 /* exec table is optional */
369 if (unpack_nameX(e, AA_STRUCT, "xtable")) {
370 int i, size;
371
372 size = unpack_array(e, NULL);
373 /* currently 4 exec bits and entries 0-3 are reserved iupcx */
374 if (size > 16 - 4)
375 goto fail;
376 profile->file.trans.table = kzalloc(sizeof(char *) * size,
377 GFP_KERNEL);
378 if (!profile->file.trans.table)
379 goto fail;
380
381 profile->file.trans.size = size;
382 for (i = 0; i < size; i++) {
383 char *str;
384 int c, j, size = unpack_strdup(e, &str, NULL);
385 /* unpack_strdup verifies that the last character is
386 * null termination byte.
387 */
388 if (!size)
389 goto fail;
390 profile->file.trans.table[i] = str;
391 /* verify that name doesn't start with space */
392 if (isspace(*str))
393 goto fail;
394
395 /* count internal # of internal \0 */
396 for (c = j = 0; j < size - 2; j++) {
397 if (!str[j])
398 c++;
399 }
400 if (*str == ':') {
401 /* beginning with : requires an embedded \0,
402 * verify that exactly 1 internal \0 exists
403 * trailing \0 already verified by unpack_strdup
404 */
405 if (c != 1)
406 goto fail;
407 /* first character after : must be valid */
408 if (!str[1])
409 goto fail;
410 } else if (c)
411 /* fail - all other cases with embedded \0 */
412 goto fail;
413 }
414 if (!unpack_nameX(e, AA_ARRAYEND, NULL))
415 goto fail;
416 if (!unpack_nameX(e, AA_STRUCTEND, NULL))
417 goto fail;
418 }
419 return 1;
420
421fail:
422 aa_free_domain_entries(&profile->file.trans);
423 e->pos = pos;
424 return 0;
425}
426
427static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
428{
429 void *pos = e->pos;
430
431 /* rlimits are optional */
432 if (unpack_nameX(e, AA_STRUCT, "rlimits")) {
433 int i, size;
434 u32 tmp = 0;
435 if (!unpack_u32(e, &tmp, NULL))
436 goto fail;
437 profile->rlimits.mask = tmp;
438
439 size = unpack_array(e, NULL);
440 if (size > RLIM_NLIMITS)
441 goto fail;
442 for (i = 0; i < size; i++) {
443 u64 tmp = 0;
444 int a = aa_map_resource(i);
445 if (!unpack_u64(e, &tmp, NULL))
446 goto fail;
447 profile->rlimits.limits[a].rlim_max = tmp;
448 }
449 if (!unpack_nameX(e, AA_ARRAYEND, NULL))
450 goto fail;
451 if (!unpack_nameX(e, AA_STRUCTEND, NULL))
452 goto fail;
453 }
454 return 1;
455
456fail:
457 e->pos = pos;
458 return 0;
459}
460
461/**
462 * unpack_profile - unpack a serialized profile
463 * @e: serialized data extent information (NOT NULL)
464 *
465 * NOTE: unpack profile sets audit struct if there is a failure
466 */
467static struct aa_profile *unpack_profile(struct aa_ext *e)
468{
469 struct aa_profile *profile = NULL;
470 const char *name = NULL;
471 int error = -EPROTO;
472 kernel_cap_t tmpcap;
473 u32 tmp;
474
475 /* check that we have the right struct being passed */
476 if (!unpack_nameX(e, AA_STRUCT, "profile"))
477 goto fail;
478 if (!unpack_str(e, &name, NULL))
479 goto fail;
480
481 profile = aa_alloc_profile(name);
482 if (!profile)
483 return ERR_PTR(-ENOMEM);
484
485 /* profile renaming is optional */
486 (void) unpack_str(e, &profile->rename, "rename");
487
488 /* xmatch is optional and may be NULL */
489 profile->xmatch = unpack_dfa(e);
490 if (IS_ERR(profile->xmatch)) {
491 error = PTR_ERR(profile->xmatch);
492 profile->xmatch = NULL;
493 goto fail;
494 }
495 /* xmatch_len is not optional if xmatch is set */
496 if (profile->xmatch) {
497 if (!unpack_u32(e, &tmp, NULL))
498 goto fail;
499 profile->xmatch_len = tmp;
500 }
501
502 /* per profile debug flags (complain, audit) */
503 if (!unpack_nameX(e, AA_STRUCT, "flags"))
504 goto fail;
505 if (!unpack_u32(e, &tmp, NULL))
506 goto fail;
507 if (tmp)
508 profile->flags |= PFLAG_HAT;
509 if (!unpack_u32(e, &tmp, NULL))
510 goto fail;
511 if (tmp)
512 profile->mode = APPARMOR_COMPLAIN;
513 if (!unpack_u32(e, &tmp, NULL))
514 goto fail;
515 if (tmp)
516 profile->audit = AUDIT_ALL;
517
518 if (!unpack_nameX(e, AA_STRUCTEND, NULL))
519 goto fail;
520
521 /* path_flags is optional */
522 if (unpack_u32(e, &profile->path_flags, "path_flags"))
523 profile->path_flags |= profile->flags & PFLAG_MEDIATE_DELETED;
524 else
525 /* set a default value if path_flags field is not present */
526 profile->path_flags = PFLAG_MEDIATE_DELETED;
527
528 if (!unpack_u32(e, &(profile->caps.allow.cap[0]), NULL))
529 goto fail;
530 if (!unpack_u32(e, &(profile->caps.audit.cap[0]), NULL))
531 goto fail;
532 if (!unpack_u32(e, &(profile->caps.quiet.cap[0]), NULL))
533 goto fail;
534 if (!unpack_u32(e, &tmpcap.cap[0], NULL))
535 goto fail;
536
537 if (unpack_nameX(e, AA_STRUCT, "caps64")) {
538 /* optional upper half of 64 bit caps */
539 if (!unpack_u32(e, &(profile->caps.allow.cap[1]), NULL))
540 goto fail;
541 if (!unpack_u32(e, &(profile->caps.audit.cap[1]), NULL))
542 goto fail;
543 if (!unpack_u32(e, &(profile->caps.quiet.cap[1]), NULL))
544 goto fail;
545 if (!unpack_u32(e, &(tmpcap.cap[1]), NULL))
546 goto fail;
547 if (!unpack_nameX(e, AA_STRUCTEND, NULL))
548 goto fail;
549 }
550
551 if (unpack_nameX(e, AA_STRUCT, "capsx")) {
552 /* optional extended caps mediation mask */
553 if (!unpack_u32(e, &(profile->caps.extended.cap[0]), NULL))
554 goto fail;
555 if (!unpack_u32(e, &(profile->caps.extended.cap[1]), NULL))
556 goto fail;
557 }
558
559 if (!unpack_rlimits(e, profile))
560 goto fail;
561
562 /* get file rules */
563 profile->file.dfa = unpack_dfa(e);
564 if (IS_ERR(profile->file.dfa)) {
565 error = PTR_ERR(profile->file.dfa);
566 profile->file.dfa = NULL;
567 goto fail;
568 }
569
570 if (!unpack_u32(e, &profile->file.start, "dfa_start"))
571 /* default start state */
572 profile->file.start = DFA_START;
573
574 if (!unpack_trans_table(e, profile))
575 goto fail;
576
577 if (!unpack_nameX(e, AA_STRUCTEND, NULL))
578 goto fail;
579
580 return profile;
581
582fail:
583 if (profile)
584 name = NULL;
585 else if (!name)
586 name = "unknown";
587 audit_iface(profile, name, "failed to unpack profile", e, error);
588 aa_put_profile(profile);
589
590 return ERR_PTR(error);
591}
592
593/**
594 * verify_head - unpack serialized stream header
595 * @e: serialized data read head (NOT NULL)
596 * @ns: Returns - namespace if one is specified else NULL (NOT NULL)
597 *
598 * Returns: error or 0 if header is good
599 */
600static int verify_header(struct aa_ext *e, const char **ns)
601{
602 int error = -EPROTONOSUPPORT;
603 /* get the interface version */
604 if (!unpack_u32(e, &e->version, "version")) {
605 audit_iface(NULL, NULL, "invalid profile format", e, error);
606 return error;
607 }
608
609 /* check that the interface version is currently supported */
610 if (e->version != 5) {
611 audit_iface(NULL, NULL, "unsupported interface version", e,
612 error);
613 return error;
614 }
615
616 /* read the namespace if present */
617 if (!unpack_str(e, ns, "namespace"))
618 *ns = NULL;
619
620 return 0;
621}
622
623static bool verify_xindex(int xindex, int table_size)
624{
625 int index, xtype;
626 xtype = xindex & AA_X_TYPE_MASK;
627 index = xindex & AA_X_INDEX_MASK;
628 if (xtype == AA_X_TABLE && index > table_size)
629 return 0;
630 return 1;
631}
632
633/* verify dfa xindexes are in range of transition tables */
634static bool verify_dfa_xindex(struct aa_dfa *dfa, int table_size)
635{
636 int i;
637 for (i = 0; i < dfa->tables[YYTD_ID_ACCEPT]->td_lolen; i++) {
638 if (!verify_xindex(dfa_user_xindex(dfa, i), table_size))
639 return 0;
640 if (!verify_xindex(dfa_other_xindex(dfa, i), table_size))
641 return 0;
642 }
643 return 1;
644}
645
646/**
647 * verify_profile - Do post unpack analysis to verify profile consistency
648 * @profile: profile to verify (NOT NULL)
649 *
650 * Returns: 0 if passes verification else error
651 */
652static int verify_profile(struct aa_profile *profile)
653{
654 if (aa_g_paranoid_load) {
655 if (profile->file.dfa &&
656 !verify_dfa_xindex(profile->file.dfa,
657 profile->file.trans.size)) {
658 audit_iface(profile, NULL, "Invalid named transition",
659 NULL, -EPROTO);
660 return -EPROTO;
661 }
662 }
663
664 return 0;
665}
666
667/**
668 * aa_unpack - unpack packed binary profile data loaded from user space
669 * @udata: user data copied to kmem (NOT NULL)
670 * @size: the size of the user data
671 * @ns: Returns namespace profile is in if specified else NULL (NOT NULL)
672 *
673 * Unpack user data and return refcounted allocated profile or ERR_PTR
674 *
675 * Returns: profile else error pointer if fails to unpack
676 */
677struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns)
678{
679 struct aa_profile *profile = NULL;
680 int error;
681 struct aa_ext e = {
682 .start = udata,
683 .end = udata + size,
684 .pos = udata,
685 };
686
687 error = verify_header(&e, ns);
688 if (error)
689 return ERR_PTR(error);
690
691 profile = unpack_profile(&e);
692 if (IS_ERR(profile))
693 return profile;
694
695 error = verify_profile(profile);
696 if (error) {
697 aa_put_profile(profile);
698 profile = ERR_PTR(error);
699 }
700
701 /* return refcount */
702 return profile;
703}
diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c
new file mode 100644
index 00000000000..04a2cf8d1b6
--- /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}
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c
new file mode 100644
index 00000000000..4a368f1fd36
--- /dev/null
+++ b/security/apparmor/resource.c
@@ -0,0 +1,134 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor resource mediation and attachment
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/audit.h>
16
17#include "include/audit.h"
18#include "include/resource.h"
19#include "include/policy.h"
20
21/*
22 * Table of rlimit names: we generate it from resource.h.
23 */
24#include "rlim_names.h"
25
26/* audit callback for resource specific fields */
27static void audit_cb(struct audit_buffer *ab, void *va)
28{
29 struct common_audit_data *sa = va;
30
31 audit_log_format(ab, " rlimit=%s value=%lu",
32 rlim_names[sa->aad.rlim.rlim], sa->aad.rlim.max);
33}
34
35/**
36 * audit_resource - audit setting resource limit
37 * @profile: profile being enforced (NOT NULL)
38 * @resoure: rlimit being auditing
39 * @value: value being set
40 * @error: error value
41 *
42 * Returns: 0 or sa->error else other error code on failure
43 */
44static int audit_resource(struct aa_profile *profile, unsigned int resource,
45 unsigned long value, int error)
46{
47 struct common_audit_data sa;
48
49 COMMON_AUDIT_DATA_INIT(&sa, NONE);
50 sa.aad.op = OP_SETRLIMIT,
51 sa.aad.rlim.rlim = resource;
52 sa.aad.rlim.max = value;
53 sa.aad.error = error;
54 return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_KERNEL, &sa,
55 audit_cb);
56}
57
58/**
59 * aa_map_resouce - map compiled policy resource to internal #
60 * @resource: flattened policy resource number
61 *
62 * Returns: resource # for the current architecture.
63 *
64 * rlimit resource can vary based on architecture, map the compiled policy
65 * resource # to the internal representation for the architecture.
66 */
67int aa_map_resource(int resource)
68{
69 return rlim_map[resource];
70}
71
72/**
73 * aa_task_setrlimit - test permission to set an rlimit
74 * @profile - profile confining the task (NOT NULL)
75 * @resource - the resource being set
76 * @new_rlim - the new resource limit (NOT NULL)
77 *
78 * Control raising the processes hard limit.
79 *
80 * Returns: 0 or error code if setting resource failed
81 */
82int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
83 struct rlimit *new_rlim)
84{
85 int error = 0;
86
87 if (profile->rlimits.mask & (1 << resource) &&
88 new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max)
89
90 error = audit_resource(profile, resource, new_rlim->rlim_max,
91 -EACCES);
92
93 return error;
94}
95
96/**
97 * __aa_transition_rlimits - apply new profile rlimits
98 * @old: old profile on task (NOT NULL)
99 * @new: new profile with rlimits to apply (NOT NULL)
100 */
101void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new)
102{
103 unsigned int mask = 0;
104 struct rlimit *rlim, *initrlim;
105 int i;
106
107 /* for any rlimits the profile controlled reset the soft limit
108 * to the less of the tasks hard limit and the init tasks soft limit
109 */
110 if (old->rlimits.mask) {
111 for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) {
112 if (old->rlimits.mask & mask) {
113 rlim = current->signal->rlim + i;
114 initrlim = init_task.signal->rlim + i;
115 rlim->rlim_cur = min(rlim->rlim_max,
116 initrlim->rlim_cur);
117 }
118 }
119 }
120
121 /* set any new hard limits as dictated by the new profile */
122 if (!new->rlimits.mask)
123 return;
124 for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) {
125 if (!(new->rlimits.mask & mask))
126 continue;
127
128 rlim = current->signal->rlim + i;
129 rlim->rlim_max = min(rlim->rlim_max,
130 new->rlimits.limits[i].rlim_max);
131 /* soft limit should not exceed hard limit */
132 rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max);
133 }
134}
diff --git a/security/apparmor/sid.c b/security/apparmor/sid.c
new file mode 100644
index 00000000000..f0b34f76ebe
--- /dev/null
+++ b/security/apparmor/sid.c
@@ -0,0 +1,55 @@
1/*
2 * AppArmor security module
3 *
4 * This file contains AppArmor security identifier (sid) manipulation fns
5 *
6 * Copyright 2009-2010 Canonical Ltd.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation, version 2 of the
11 * License.
12 *
13 *
14 * AppArmor allocates a unique sid for every profile loaded. If a profile
15 * is replaced it receives the sid of the profile it is replacing.
16 *
17 * The sid value of 0 is invalid.
18 */
19
20#include <linux/spinlock.h>
21#include <linux/errno.h>
22#include <linux/err.h>
23
24#include "include/sid.h"
25
26/* global counter from which sids are allocated */
27static u32 global_sid;
28static DEFINE_SPINLOCK(sid_lock);
29
30/* TODO FIXME: add sid to profile mapping, and sid recycling */
31
32/**
33 * aa_alloc_sid - allocate a new sid for a profile
34 */
35u32 aa_alloc_sid(void)
36{
37 u32 sid;
38
39 /*
40 * TODO FIXME: sid recycling - part of profile mapping table
41 */
42 spin_lock(&sid_lock);
43 sid = (++global_sid);
44 spin_unlock(&sid_lock);
45 return sid;
46}
47
48/**
49 * aa_free_sid - free a sid
50 * @sid: sid to free
51 */
52void aa_free_sid(u32 sid)
53{
54 ; /* NOP ATM */
55}