aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2017-01-16 03:42:55 -0500
committerJohn Johansen <john.johansen@canonical.com>2017-01-16 04:18:42 -0500
commit5ac8c355ae0013d82b3a07b49aebeadfce9b6e52 (patch)
tree41f24f5f9198ef4ba7a34624938e51b2305e21f0
parentfc1c9fd10a53a17abb3348adb2ec5d29813a0397 (diff)
apparmor: allow introspecting the loaded policy pre internal transform
Store loaded policy and allow introspecting it through apparmorfs. This has several uses from debugging, policy validation, and policy checkpoint and restore for containers. Signed-off-by: John Johansen <john.johansen@canonical.com>
-rw-r--r--security/apparmor/apparmorfs.c213
-rw-r--r--security/apparmor/crypto.c39
-rw-r--r--security/apparmor/include/apparmorfs.h5
-rw-r--r--security/apparmor/include/crypto.h5
-rw-r--r--security/apparmor/include/policy.h5
-rw-r--r--security/apparmor/include/policy_unpack.h27
-rw-r--r--security/apparmor/policy.c14
-rw-r--r--security/apparmor/policy_unpack.c28
8 files changed, 278 insertions, 58 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index cc6ee1ee2b42..2e6790cf54da 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -33,6 +33,7 @@
33#include "include/policy.h" 33#include "include/policy.h"
34#include "include/policy_ns.h" 34#include "include/policy_ns.h"
35#include "include/resource.h" 35#include "include/resource.h"
36#include "include/policy_unpack.h"
36 37
37/** 38/**
38 * aa_mangle_name - mangle a profile name to std profile layout form 39 * aa_mangle_name - mangle a profile name to std profile layout form
@@ -84,11 +85,13 @@ static int mangle_name(const char *name, char *target)
84 * Returns: kernel buffer containing copy of user buffer data or an 85 * Returns: kernel buffer containing copy of user buffer data or an
85 * ERR_PTR on failure. 86 * ERR_PTR on failure.
86 */ 87 */
87static char *aa_simple_write_to_buffer(int op, const char __user *userbuf, 88static struct aa_loaddata *aa_simple_write_to_buffer(int op,
88 size_t alloc_size, size_t copy_size, 89 const char __user *userbuf,
89 loff_t *pos) 90 size_t alloc_size,
91 size_t copy_size,
92 loff_t *pos)
90{ 93{
91 char *data; 94 struct aa_loaddata *data;
92 95
93 BUG_ON(copy_size > alloc_size); 96 BUG_ON(copy_size > alloc_size);
94 97
@@ -96,19 +99,16 @@ static char *aa_simple_write_to_buffer(int op, const char __user *userbuf,
96 /* only writes from pos 0, that is complete writes */ 99 /* only writes from pos 0, that is complete writes */
97 return ERR_PTR(-ESPIPE); 100 return ERR_PTR(-ESPIPE);
98 101
99 /*
100 * Don't allow profile load/replace/remove from profiles that don't
101 * have CAP_MAC_ADMIN
102 */
103 if (!aa_may_manage_policy(__aa_current_profile(), NULL, op))
104 return ERR_PTR(-EACCES);
105
106 /* freed by caller to simple_write_to_buffer */ 102 /* freed by caller to simple_write_to_buffer */
107 data = kvmalloc(alloc_size); 103 data = kvmalloc(sizeof(*data) + alloc_size);
108 if (data == NULL) 104 if (data == NULL)
109 return ERR_PTR(-ENOMEM); 105 return ERR_PTR(-ENOMEM);
106 kref_init(&data->count);
107 data->size = copy_size;
108 data->hash = NULL;
109 data->abi = 0;
110 110
111 if (copy_from_user(data, userbuf, copy_size)) { 111 if (copy_from_user(data->data, userbuf, copy_size)) {
112 kvfree(data); 112 kvfree(data);
113 return ERR_PTR(-EFAULT); 113 return ERR_PTR(-EFAULT);
114 } 114 }
@@ -116,26 +116,38 @@ static char *aa_simple_write_to_buffer(int op, const char __user *userbuf,
116 return data; 116 return data;
117} 117}
118 118
119 119static ssize_t policy_update(int binop, const char __user *buf, size_t size,
120/* .load file hook fn to load policy */ 120 loff_t *pos)
121static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
122 loff_t *pos)
123{ 121{
124 char *data;
125 ssize_t error; 122 ssize_t error;
123 struct aa_loaddata *data;
124 struct aa_profile *profile = aa_current_profile();
125 int op = binop == PROF_ADD ? OP_PROF_LOAD : OP_PROF_REPL;
126 /* high level check about policy management - fine grained in
127 * below after unpack
128 */
129 error = aa_may_manage_policy(profile, profile->ns, op);
130 if (error)
131 return error;
126 132
127 data = aa_simple_write_to_buffer(OP_PROF_LOAD, buf, size, size, pos); 133 data = aa_simple_write_to_buffer(op, buf, size, size, pos);
128
129 error = PTR_ERR(data); 134 error = PTR_ERR(data);
130 if (!IS_ERR(data)) { 135 if (!IS_ERR(data)) {
131 error = aa_replace_profiles(__aa_current_profile()->ns, data, 136 error = aa_replace_profiles(profile->ns, binop, data);
132 size, PROF_ADD); 137 aa_put_loaddata(data);
133 kvfree(data);
134 } 138 }
135 139
136 return error; 140 return error;
137} 141}
138 142
143static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
144 loff_t *pos)
145{
146 int error = policy_update(PROF_ADD, buf, size, pos);
147
148 return error;
149}
150
139static const struct file_operations aa_fs_profile_load = { 151static const struct file_operations aa_fs_profile_load = {
140 .write = profile_load, 152 .write = profile_load,
141 .llseek = default_llseek, 153 .llseek = default_llseek,
@@ -145,16 +157,7 @@ static const struct file_operations aa_fs_profile_load = {
145static ssize_t profile_replace(struct file *f, const char __user *buf, 157static ssize_t profile_replace(struct file *f, const char __user *buf,
146 size_t size, loff_t *pos) 158 size_t size, loff_t *pos)
147{ 159{
148 char *data; 160 int error = policy_update(PROF_REPLACE, buf, size, pos);
149 ssize_t error;
150
151 data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos);
152 error = PTR_ERR(data);
153 if (!IS_ERR(data)) {
154 error = aa_replace_profiles(__aa_current_profile()->ns, data,
155 size, PROF_REPLACE);
156 kvfree(data);
157 }
158 161
159 return error; 162 return error;
160} 163}
@@ -164,27 +167,35 @@ static const struct file_operations aa_fs_profile_replace = {
164 .llseek = default_llseek, 167 .llseek = default_llseek,
165}; 168};
166 169
167/* .remove file hook fn to remove loaded policy */
168static ssize_t profile_remove(struct file *f, const char __user *buf, 170static ssize_t profile_remove(struct file *f, const char __user *buf,
169 size_t size, loff_t *pos) 171 size_t size, loff_t *pos)
170{ 172{
171 char *data; 173 struct aa_loaddata *data;
174 struct aa_profile *profile;
172 ssize_t error; 175 ssize_t error;
173 176
177 profile = aa_current_profile();
178 /* high level check about policy management - fine grained in
179 * below after unpack
180 */
181 error = aa_may_manage_policy(profile, profile->ns, OP_PROF_RM);
182 if (error)
183 goto out;
184
174 /* 185 /*
175 * aa_remove_profile needs a null terminated string so 1 extra 186 * aa_remove_profile needs a null terminated string so 1 extra
176 * byte is allocated and the copied data is null terminated. 187 * byte is allocated and the copied data is null terminated.
177 */ 188 */
178 data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size, pos); 189 data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size,
190 pos);
179 191
180 error = PTR_ERR(data); 192 error = PTR_ERR(data);
181 if (!IS_ERR(data)) { 193 if (!IS_ERR(data)) {
182 data[size] = 0; 194 data->data[size] = 0;
183 error = aa_remove_profiles(__aa_current_profile()->ns, data, 195 error = aa_remove_profiles(profile->ns, data->data, size);
184 size); 196 aa_put_loaddata(data);
185 kvfree(data);
186 } 197 }
187 198 out:
188 return error; 199 return error;
189} 200}
190 201
@@ -401,6 +412,100 @@ static const struct file_operations aa_fs_ns_name = {
401 .release = single_release, 412 .release = single_release,
402}; 413};
403 414
415static int rawdata_release(struct inode *inode, struct file *file)
416{
417 /* TODO: switch to loaddata when profile switched to symlink */
418 aa_put_loaddata(file->private_data);
419
420 return 0;
421}
422
423static int aa_fs_seq_raw_abi_show(struct seq_file *seq, void *v)
424{
425 struct aa_proxy *proxy = seq->private;
426 struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
427
428 if (profile->rawdata->abi) {
429 seq_printf(seq, "v%d", profile->rawdata->abi);
430 seq_puts(seq, "\n");
431 }
432 aa_put_profile(profile);
433
434 return 0;
435}
436
437static int aa_fs_seq_raw_abi_open(struct inode *inode, struct file *file)
438{
439 return aa_fs_seq_profile_open(inode, file, aa_fs_seq_raw_abi_show);
440}
441
442static const struct file_operations aa_fs_seq_raw_abi_fops = {
443 .owner = THIS_MODULE,
444 .open = aa_fs_seq_raw_abi_open,
445 .read = seq_read,
446 .llseek = seq_lseek,
447 .release = aa_fs_seq_profile_release,
448};
449
450static int aa_fs_seq_raw_hash_show(struct seq_file *seq, void *v)
451{
452 struct aa_proxy *proxy = seq->private;
453 struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
454 unsigned int i, size = aa_hash_size();
455
456 if (profile->rawdata->hash) {
457 for (i = 0; i < size; i++)
458 seq_printf(seq, "%.2x", profile->rawdata->hash[i]);
459 seq_puts(seq, "\n");
460 }
461 aa_put_profile(profile);
462
463 return 0;
464}
465
466static int aa_fs_seq_raw_hash_open(struct inode *inode, struct file *file)
467{
468 return aa_fs_seq_profile_open(inode, file, aa_fs_seq_raw_hash_show);
469}
470
471static const struct file_operations aa_fs_seq_raw_hash_fops = {
472 .owner = THIS_MODULE,
473 .open = aa_fs_seq_raw_hash_open,
474 .read = seq_read,
475 .llseek = seq_lseek,
476 .release = aa_fs_seq_profile_release,
477};
478
479static ssize_t rawdata_read(struct file *file, char __user *buf, size_t size,
480 loff_t *ppos)
481{
482 struct aa_loaddata *rawdata = file->private_data;
483
484 return simple_read_from_buffer(buf, size, ppos, rawdata->data,
485 rawdata->size);
486}
487
488static int rawdata_open(struct inode *inode, struct file *file)
489{
490 struct aa_proxy *proxy = inode->i_private;
491 struct aa_profile *profile;
492
493 if (!policy_view_capable(NULL))
494 return -EACCES;
495 profile = aa_get_profile_rcu(&proxy->profile);
496 file->private_data = aa_get_loaddata(profile->rawdata);
497 aa_put_profile(profile);
498
499 return 0;
500}
501
502static const struct file_operations aa_fs_rawdata_fops = {
503 .open = rawdata_open,
504 .read = rawdata_read,
505 .llseek = generic_file_llseek,
506 .release = rawdata_release,
507};
508
404/** fns to setup dynamic per profile/namespace files **/ 509/** fns to setup dynamic per profile/namespace files **/
405void __aa_fs_profile_rmdir(struct aa_profile *profile) 510void __aa_fs_profile_rmdir(struct aa_profile *profile)
406{ 511{
@@ -512,6 +617,29 @@ int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
512 profile->dents[AAFS_PROF_HASH] = dent; 617 profile->dents[AAFS_PROF_HASH] = dent;
513 } 618 }
514 619
620 if (profile->rawdata) {
621 dent = create_profile_file(dir, "raw_sha1", profile,
622 &aa_fs_seq_raw_hash_fops);
623 if (IS_ERR(dent))
624 goto fail;
625 profile->dents[AAFS_PROF_RAW_HASH] = dent;
626
627 dent = create_profile_file(dir, "raw_abi", profile,
628 &aa_fs_seq_raw_abi_fops);
629 if (IS_ERR(dent))
630 goto fail;
631 profile->dents[AAFS_PROF_RAW_ABI] = dent;
632
633 dent = securityfs_create_file("raw_data", S_IFREG | 0444, dir,
634 profile->proxy,
635 &aa_fs_rawdata_fops);
636 if (IS_ERR(dent))
637 goto fail;
638 profile->dents[AAFS_PROF_RAW_DATA] = dent;
639 d_inode(dent)->i_size = profile->rawdata->size;
640 aa_get_proxy(profile->proxy);
641 }
642
515 list_for_each_entry(child, &profile->base.profiles, base.list) { 643 list_for_each_entry(child, &profile->base.profiles, base.list) {
516 error = __aa_fs_profile_mkdir(child, prof_child_dir(profile)); 644 error = __aa_fs_profile_mkdir(child, prof_child_dir(profile));
517 if (error) 645 if (error)
@@ -817,6 +945,9 @@ static const struct seq_operations aa_fs_profiles_op = {
817 945
818static int profiles_open(struct inode *inode, struct file *file) 946static int profiles_open(struct inode *inode, struct file *file)
819{ 947{
948 if (!policy_view_capable(NULL))
949 return -EACCES;
950
820 return seq_open(file, &aa_fs_profiles_op); 951 return seq_open(file, &aa_fs_profiles_op);
821} 952}
822 953
diff --git a/security/apparmor/crypto.c b/security/apparmor/crypto.c
index b75dab0df1cb..de8dc78b6144 100644
--- a/security/apparmor/crypto.c
+++ b/security/apparmor/crypto.c
@@ -29,6 +29,43 @@ unsigned int aa_hash_size(void)
29 return apparmor_hash_size; 29 return apparmor_hash_size;
30} 30}
31 31
32char *aa_calc_hash(void *data, size_t len)
33{
34 struct {
35 struct shash_desc shash;
36 char ctx[crypto_shash_descsize(apparmor_tfm)];
37 } desc;
38 char *hash = NULL;
39 int error = -ENOMEM;
40
41 if (!apparmor_tfm)
42 return NULL;
43
44 hash = kzalloc(apparmor_hash_size, GFP_KERNEL);
45 if (!hash)
46 goto fail;
47
48 desc.shash.tfm = apparmor_tfm;
49 desc.shash.flags = 0;
50
51 error = crypto_shash_init(&desc.shash);
52 if (error)
53 goto fail;
54 error = crypto_shash_update(&desc.shash, (u8 *) data, len);
55 if (error)
56 goto fail;
57 error = crypto_shash_final(&desc.shash, hash);
58 if (error)
59 goto fail;
60
61 return hash;
62
63fail:
64 kfree(hash);
65
66 return ERR_PTR(error);
67}
68
32int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start, 69int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
33 size_t len) 70 size_t len)
34{ 71{
@@ -37,7 +74,7 @@ int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
37 char ctx[crypto_shash_descsize(apparmor_tfm)]; 74 char ctx[crypto_shash_descsize(apparmor_tfm)];
38 } desc; 75 } desc;
39 int error = -ENOMEM; 76 int error = -ENOMEM;
40 u32 le32_version = cpu_to_le32(version); 77 __le32 le32_version = cpu_to_le32(version);
41 78
42 if (!aa_g_hash_policy) 79 if (!aa_g_hash_policy)
43 return 0; 80 return 0;
diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h
index eeeae5b0cc36..a593e75b3b03 100644
--- a/security/apparmor/include/apparmorfs.h
+++ b/security/apparmor/include/apparmorfs.h
@@ -70,6 +70,7 @@ enum aafs_ns_type {
70 AAFS_NS_DIR, 70 AAFS_NS_DIR,
71 AAFS_NS_PROFS, 71 AAFS_NS_PROFS,
72 AAFS_NS_NS, 72 AAFS_NS_NS,
73 AAFS_NS_RAW_DATA,
73 AAFS_NS_COUNT, 74 AAFS_NS_COUNT,
74 AAFS_NS_MAX_COUNT, 75 AAFS_NS_MAX_COUNT,
75 AAFS_NS_SIZE, 76 AAFS_NS_SIZE,
@@ -85,12 +86,16 @@ enum aafs_prof_type {
85 AAFS_PROF_MODE, 86 AAFS_PROF_MODE,
86 AAFS_PROF_ATTACH, 87 AAFS_PROF_ATTACH,
87 AAFS_PROF_HASH, 88 AAFS_PROF_HASH,
89 AAFS_PROF_RAW_DATA,
90 AAFS_PROF_RAW_HASH,
91 AAFS_PROF_RAW_ABI,
88 AAFS_PROF_SIZEOF, 92 AAFS_PROF_SIZEOF,
89}; 93};
90 94
91#define ns_dir(X) ((X)->dents[AAFS_NS_DIR]) 95#define ns_dir(X) ((X)->dents[AAFS_NS_DIR])
92#define ns_subns_dir(X) ((X)->dents[AAFS_NS_NS]) 96#define ns_subns_dir(X) ((X)->dents[AAFS_NS_NS])
93#define ns_subprofs_dir(X) ((X)->dents[AAFS_NS_PROFS]) 97#define ns_subprofs_dir(X) ((X)->dents[AAFS_NS_PROFS])
98#define ns_subdata_dir(X) ((X)->dents[AAFS_NS_RAW_DATA])
94 99
95#define prof_dir(X) ((X)->dents[AAFS_PROF_DIR]) 100#define prof_dir(X) ((X)->dents[AAFS_PROF_DIR])
96#define prof_child_dir(X) ((X)->dents[AAFS_PROF_PROFS]) 101#define prof_child_dir(X) ((X)->dents[AAFS_PROF_PROFS])
diff --git a/security/apparmor/include/crypto.h b/security/apparmor/include/crypto.h
index dc418e5024d9..c1469f8db174 100644
--- a/security/apparmor/include/crypto.h
+++ b/security/apparmor/include/crypto.h
@@ -18,9 +18,14 @@
18 18
19#ifdef CONFIG_SECURITY_APPARMOR_HASH 19#ifdef CONFIG_SECURITY_APPARMOR_HASH
20unsigned int aa_hash_size(void); 20unsigned int aa_hash_size(void);
21char *aa_calc_hash(void *data, size_t len);
21int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start, 22int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
22 size_t len); 23 size_t len);
23#else 24#else
25static inline char *aa_calc_hash(void *data, size_t len)
26{
27 return NULL;
28}
24static inline int aa_calc_profile_hash(struct aa_profile *profile, u32 version, 29static inline int aa_calc_profile_hash(struct aa_profile *profile, u32 version,
25 void *start, size_t len) 30 void *start, size_t len)
26{ 31{
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index 95641e235d47..fbbc8677f527 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -161,6 +161,7 @@ struct aa_profile {
161 struct aa_caps caps; 161 struct aa_caps caps;
162 struct aa_rlimit rlimits; 162 struct aa_rlimit rlimits;
163 163
164 struct aa_loaddata *rawdata;
164 unsigned char *hash; 165 unsigned char *hash;
165 char *dirname; 166 char *dirname;
166 struct dentry *dents[AAFS_PROF_SIZEOF]; 167 struct dentry *dents[AAFS_PROF_SIZEOF];
@@ -187,8 +188,8 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base,
187 const char *fqname, size_t n); 188 const char *fqname, size_t n);
188struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name); 189struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name);
189 190
190ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, 191ssize_t aa_replace_profiles(struct aa_ns *view, bool noreplace,
191 bool noreplace); 192 struct aa_loaddata *udata);
192ssize_t aa_remove_profiles(struct aa_ns *view, char *name, size_t size); 193ssize_t aa_remove_profiles(struct aa_ns *view, char *name, size_t size);
193void __aa_profile_list_release(struct list_head *head); 194void __aa_profile_list_release(struct list_head *head);
194 195
diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h
index c214fb88b1bc..7b675b6f7f02 100644
--- a/security/apparmor/include/policy_unpack.h
+++ b/security/apparmor/include/policy_unpack.h
@@ -16,6 +16,7 @@
16#define __POLICY_INTERFACE_H 16#define __POLICY_INTERFACE_H
17 17
18#include <linux/list.h> 18#include <linux/list.h>
19#include <linux/kref.h>
19 20
20struct aa_load_ent { 21struct aa_load_ent {
21 struct list_head list; 22 struct list_head list;
@@ -34,6 +35,30 @@ struct aa_load_ent *aa_load_ent_alloc(void);
34#define PACKED_MODE_KILL 2 35#define PACKED_MODE_KILL 2
35#define PACKED_MODE_UNCONFINED 3 36#define PACKED_MODE_UNCONFINED 3
36 37
37int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns); 38/* struct aa_loaddata - buffer of policy load data set */
39struct aa_loaddata {
40 struct kref count;
41 size_t size;
42 int abi;
43 unsigned char *hash;
44 char data[];
45};
46
47int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, const char **ns);
48
49static inline struct aa_loaddata *
50aa_get_loaddata(struct aa_loaddata *data)
51{
52 if (data)
53 kref_get(&(data->count));
54 return data;
55}
56
57void aa_loaddata_kref(struct kref *kref);
58static inline void aa_put_loaddata(struct aa_loaddata *data)
59{
60 if (data)
61 kref_put(&data->count, aa_loaddata_kref);
62}
38 63
39#endif /* __POLICY_INTERFACE_H */ 64#endif /* __POLICY_INTERFACE_H */
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index 3c5c0b28eac5..ff29b606f2b3 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -228,6 +228,7 @@ void aa_free_profile(struct aa_profile *profile)
228 aa_put_proxy(profile->proxy); 228 aa_put_proxy(profile->proxy);
229 229
230 kzfree(profile->hash); 230 kzfree(profile->hash);
231 aa_put_loaddata(profile->rawdata);
231 kzfree(profile); 232 kzfree(profile);
232} 233}
233 234
@@ -802,10 +803,8 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname,
802/** 803/**
803 * aa_replace_profiles - replace profile(s) on the profile list 804 * aa_replace_profiles - replace profile(s) on the profile list
804 * @view: namespace load is viewed from 805 * @view: namespace load is viewed from
805 * @profile: profile that is attempting to load/replace policy
806 * @udata: serialized data stream (NOT NULL)
807 * @size: size of the serialized data stream
808 * @noreplace: true if only doing addition, no replacement allowed 806 * @noreplace: true if only doing addition, no replacement allowed
807 * @udata: serialized data stream (NOT NULL)
809 * 808 *
810 * unpack and replace a profile on the profile list and uses of that profile 809 * unpack and replace a profile on the profile list and uses of that profile
811 * by any aa_task_cxt. If the profile does not exist on the profile list 810 * by any aa_task_cxt. If the profile does not exist on the profile list
@@ -813,8 +812,8 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname,
813 * 812 *
814 * Returns: size of data consumed else error code on failure. 813 * Returns: size of data consumed else error code on failure.
815 */ 814 */
816ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, 815ssize_t aa_replace_profiles(struct aa_ns *view, bool noreplace,
817 bool noreplace) 816 struct aa_loaddata *udata)
818{ 817{
819 const char *ns_name, *info = NULL; 818 const char *ns_name, *info = NULL;
820 struct aa_ns *ns = NULL; 819 struct aa_ns *ns = NULL;
@@ -824,7 +823,7 @@ ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size,
824 LIST_HEAD(lh); 823 LIST_HEAD(lh);
825 824
826 /* released below */ 825 /* released below */
827 error = aa_unpack(udata, size, &lh, &ns_name); 826 error = aa_unpack(udata, &lh, &ns_name);
828 if (error) 827 if (error)
829 goto out; 828 goto out;
830 829
@@ -841,6 +840,7 @@ ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size,
841 /* setup parent and ns info */ 840 /* setup parent and ns info */
842 list_for_each_entry(ent, &lh, list) { 841 list_for_each_entry(ent, &lh, list) {
843 struct aa_policy *policy; 842 struct aa_policy *policy;
843 ent->new->rawdata = aa_get_loaddata(udata);
844 error = __lookup_replace(ns, ent->new->base.hname, noreplace, 844 error = __lookup_replace(ns, ent->new->base.hname, noreplace,
845 &ent->old, &info); 845 &ent->old, &info);
846 if (error) 846 if (error)
@@ -957,7 +957,7 @@ out:
957 957
958 if (error) 958 if (error)
959 return error; 959 return error;
960 return size; 960 return udata->size;
961 961
962fail_lock: 962fail_lock:
963 mutex_unlock(&ns->lock); 963 mutex_unlock(&ns->lock);
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 51a7f9fc8a3e..fb4ef84b88e1 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -117,6 +117,16 @@ static int audit_iface(struct aa_profile *new, const char *name,
117 audit_cb); 117 audit_cb);
118} 118}
119 119
120void aa_loaddata_kref(struct kref *kref)
121{
122 struct aa_loaddata *d = container_of(kref, struct aa_loaddata, count);
123
124 if (d) {
125 kzfree(d->hash);
126 kvfree(d);
127 }
128}
129
120/* test if read will be in packed data bounds */ 130/* test if read will be in packed data bounds */
121static bool inbounds(struct aa_ext *e, size_t size) 131static bool inbounds(struct aa_ext *e, size_t size)
122{ 132{
@@ -749,7 +759,6 @@ struct aa_load_ent *aa_load_ent_alloc(void)
749/** 759/**
750 * aa_unpack - unpack packed binary profile(s) data loaded from user space 760 * aa_unpack - unpack packed binary profile(s) data loaded from user space
751 * @udata: user data copied to kmem (NOT NULL) 761 * @udata: user data copied to kmem (NOT NULL)
752 * @size: the size of the user data
753 * @lh: list to place unpacked profiles in a aa_repl_ws 762 * @lh: list to place unpacked profiles in a aa_repl_ws
754 * @ns: Returns namespace profile is in if specified else NULL (NOT NULL) 763 * @ns: Returns namespace profile is in if specified else NULL (NOT NULL)
755 * 764 *
@@ -759,15 +768,16 @@ struct aa_load_ent *aa_load_ent_alloc(void)
759 * 768 *
760 * Returns: profile(s) on @lh else error pointer if fails to unpack 769 * Returns: profile(s) on @lh else error pointer if fails to unpack
761 */ 770 */
762int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns) 771int aa_unpack(struct aa_loaddata *udata, struct list_head *lh,
772 const char **ns)
763{ 773{
764 struct aa_load_ent *tmp, *ent; 774 struct aa_load_ent *tmp, *ent;
765 struct aa_profile *profile = NULL; 775 struct aa_profile *profile = NULL;
766 int error; 776 int error;
767 struct aa_ext e = { 777 struct aa_ext e = {
768 .start = udata, 778 .start = udata->data,
769 .end = udata + size, 779 .end = udata->data + udata->size,
770 .pos = udata, 780 .pos = udata->data,
771 }; 781 };
772 782
773 *ns = NULL; 783 *ns = NULL;
@@ -802,7 +812,13 @@ int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns)
802 ent->new = profile; 812 ent->new = profile;
803 list_add_tail(&ent->list, lh); 813 list_add_tail(&ent->list, lh);
804 } 814 }
805 815 udata->abi = e.version & K_ABI_MASK;
816 udata->hash = aa_calc_hash(udata->data, udata->size);
817 if (IS_ERR(udata->hash)) {
818 error = PTR_ERR(udata->hash);
819 udata->hash = NULL;
820 goto fail;
821 }
806 return 0; 822 return 0;
807 823
808fail_profile: 824fail_profile: