aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/auditfilter.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/auditfilter.c')
-rw-r--r--kernel/auditfilter.c64
1 files changed, 57 insertions, 7 deletions
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index df66a21fb360..5d96f2cc7be8 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -87,7 +87,7 @@ struct list_head audit_filter_list[AUDIT_NR_FILTERS] = {
87#endif 87#endif
88}; 88};
89 89
90static DEFINE_MUTEX(audit_filter_mutex); 90DEFINE_MUTEX(audit_filter_mutex);
91 91
92/* Inotify handle */ 92/* Inotify handle */
93extern struct inotify_handle *audit_ih; 93extern struct inotify_handle *audit_ih;
@@ -145,7 +145,7 @@ static inline void audit_free_rule(struct audit_entry *e)
145 kfree(e); 145 kfree(e);
146} 146}
147 147
148static inline void audit_free_rule_rcu(struct rcu_head *head) 148void audit_free_rule_rcu(struct rcu_head *head)
149{ 149{
150 struct audit_entry *e = container_of(head, struct audit_entry, rcu); 150 struct audit_entry *e = container_of(head, struct audit_entry, rcu);
151 audit_free_rule(e); 151 audit_free_rule(e);
@@ -217,7 +217,7 @@ static inline struct audit_entry *audit_init_entry(u32 field_count)
217 217
218/* Unpack a filter field's string representation from user-space 218/* Unpack a filter field's string representation from user-space
219 * buffer. */ 219 * buffer. */
220static char *audit_unpack_string(void **bufp, size_t *remain, size_t len) 220char *audit_unpack_string(void **bufp, size_t *remain, size_t len)
221{ 221{
222 char *str; 222 char *str;
223 223
@@ -247,7 +247,7 @@ static inline int audit_to_inode(struct audit_krule *krule,
247 struct audit_field *f) 247 struct audit_field *f)
248{ 248{
249 if (krule->listnr != AUDIT_FILTER_EXIT || 249 if (krule->listnr != AUDIT_FILTER_EXIT ||
250 krule->watch || krule->inode_f) 250 krule->watch || krule->inode_f || krule->tree)
251 return -EINVAL; 251 return -EINVAL;
252 252
253 krule->inode_f = f; 253 krule->inode_f = f;
@@ -266,7 +266,7 @@ static int audit_to_watch(struct audit_krule *krule, char *path, int len,
266 if (path[0] != '/' || path[len-1] == '/' || 266 if (path[0] != '/' || path[len-1] == '/' ||
267 krule->listnr != AUDIT_FILTER_EXIT || 267 krule->listnr != AUDIT_FILTER_EXIT ||
268 op & ~AUDIT_EQUAL || 268 op & ~AUDIT_EQUAL ||
269 krule->inode_f || krule->watch) /* 1 inode # per rule, for hash */ 269 krule->inode_f || krule->watch || krule->tree)
270 return -EINVAL; 270 return -EINVAL;
271 271
272 watch = audit_init_watch(path); 272 watch = audit_init_watch(path);
@@ -622,6 +622,17 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
622 goto exit_free; 622 goto exit_free;
623 } 623 }
624 break; 624 break;
625 case AUDIT_DIR:
626 str = audit_unpack_string(&bufp, &remain, f->val);
627 if (IS_ERR(str))
628 goto exit_free;
629 entry->rule.buflen += f->val;
630
631 err = audit_make_tree(&entry->rule, str, f->op);
632 kfree(str);
633 if (err)
634 goto exit_free;
635 break;
625 case AUDIT_INODE: 636 case AUDIT_INODE:
626 err = audit_to_inode(&entry->rule, f); 637 err = audit_to_inode(&entry->rule, f);
627 if (err) 638 if (err)
@@ -668,7 +679,7 @@ exit_free:
668} 679}
669 680
670/* Pack a filter field's string representation into data block. */ 681/* Pack a filter field's string representation into data block. */
671static inline size_t audit_pack_string(void **bufp, char *str) 682static inline size_t audit_pack_string(void **bufp, const char *str)
672{ 683{
673 size_t len = strlen(str); 684 size_t len = strlen(str);
674 685
@@ -747,6 +758,11 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
747 data->buflen += data->values[i] = 758 data->buflen += data->values[i] =
748 audit_pack_string(&bufp, krule->watch->path); 759 audit_pack_string(&bufp, krule->watch->path);
749 break; 760 break;
761 case AUDIT_DIR:
762 data->buflen += data->values[i] =
763 audit_pack_string(&bufp,
764 audit_tree_path(krule->tree));
765 break;
750 case AUDIT_FILTERKEY: 766 case AUDIT_FILTERKEY:
751 data->buflen += data->values[i] = 767 data->buflen += data->values[i] =
752 audit_pack_string(&bufp, krule->filterkey); 768 audit_pack_string(&bufp, krule->filterkey);
@@ -795,6 +811,11 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
795 if (strcmp(a->watch->path, b->watch->path)) 811 if (strcmp(a->watch->path, b->watch->path))
796 return 1; 812 return 1;
797 break; 813 break;
814 case AUDIT_DIR:
815 if (strcmp(audit_tree_path(a->tree),
816 audit_tree_path(b->tree)))
817 return 1;
818 break;
798 case AUDIT_FILTERKEY: 819 case AUDIT_FILTERKEY:
799 /* both filterkeys exist based on above type compare */ 820 /* both filterkeys exist based on above type compare */
800 if (strcmp(a->filterkey, b->filterkey)) 821 if (strcmp(a->filterkey, b->filterkey))
@@ -897,6 +918,14 @@ static struct audit_entry *audit_dupe_rule(struct audit_krule *old,
897 new->inode_f = old->inode_f; 918 new->inode_f = old->inode_f;
898 new->watch = NULL; 919 new->watch = NULL;
899 new->field_count = old->field_count; 920 new->field_count = old->field_count;
921 /*
922 * note that we are OK with not refcounting here; audit_match_tree()
923 * never dereferences tree and we can't get false positives there
924 * since we'd have to have rule gone from the list *and* removed
925 * before the chunks found by lookup had been allocated, i.e. before
926 * the beginning of list scan.
927 */
928 new->tree = old->tree;
900 memcpy(new->fields, old->fields, sizeof(struct audit_field) * fcount); 929 memcpy(new->fields, old->fields, sizeof(struct audit_field) * fcount);
901 930
902 /* deep copy this information, updating the se_rule fields, because 931 /* deep copy this information, updating the se_rule fields, because
@@ -1217,6 +1246,7 @@ static inline int audit_add_rule(struct audit_entry *entry,
1217 struct audit_entry *e; 1246 struct audit_entry *e;
1218 struct audit_field *inode_f = entry->rule.inode_f; 1247 struct audit_field *inode_f = entry->rule.inode_f;
1219 struct audit_watch *watch = entry->rule.watch; 1248 struct audit_watch *watch = entry->rule.watch;
1249 struct audit_tree *tree = entry->rule.tree;
1220 struct nameidata *ndp = NULL, *ndw = NULL; 1250 struct nameidata *ndp = NULL, *ndw = NULL;
1221 int h, err; 1251 int h, err;
1222#ifdef CONFIG_AUDITSYSCALL 1252#ifdef CONFIG_AUDITSYSCALL
@@ -1238,6 +1268,9 @@ static inline int audit_add_rule(struct audit_entry *entry,
1238 mutex_unlock(&audit_filter_mutex); 1268 mutex_unlock(&audit_filter_mutex);
1239 if (e) { 1269 if (e) {
1240 err = -EEXIST; 1270 err = -EEXIST;
1271 /* normally audit_add_tree_rule() will free it on failure */
1272 if (tree)
1273 audit_put_tree(tree);
1241 goto error; 1274 goto error;
1242 } 1275 }
1243 1276
@@ -1259,6 +1292,13 @@ static inline int audit_add_rule(struct audit_entry *entry,
1259 h = audit_hash_ino((u32)watch->ino); 1292 h = audit_hash_ino((u32)watch->ino);
1260 list = &audit_inode_hash[h]; 1293 list = &audit_inode_hash[h];
1261 } 1294 }
1295 if (tree) {
1296 err = audit_add_tree_rule(&entry->rule);
1297 if (err) {
1298 mutex_unlock(&audit_filter_mutex);
1299 goto error;
1300 }
1301 }
1262 1302
1263 if (entry->rule.flags & AUDIT_FILTER_PREPEND) { 1303 if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
1264 list_add_rcu(&entry->list, list); 1304 list_add_rcu(&entry->list, list);
@@ -1292,6 +1332,7 @@ static inline int audit_del_rule(struct audit_entry *entry,
1292 struct audit_entry *e; 1332 struct audit_entry *e;
1293 struct audit_field *inode_f = entry->rule.inode_f; 1333 struct audit_field *inode_f = entry->rule.inode_f;
1294 struct audit_watch *watch, *tmp_watch = entry->rule.watch; 1334 struct audit_watch *watch, *tmp_watch = entry->rule.watch;
1335 struct audit_tree *tree = entry->rule.tree;
1295 LIST_HEAD(inotify_list); 1336 LIST_HEAD(inotify_list);
1296 int h, ret = 0; 1337 int h, ret = 0;
1297#ifdef CONFIG_AUDITSYSCALL 1338#ifdef CONFIG_AUDITSYSCALL
@@ -1336,6 +1377,9 @@ static inline int audit_del_rule(struct audit_entry *entry,
1336 } 1377 }
1337 } 1378 }
1338 1379
1380 if (e->rule.tree)
1381 audit_remove_tree_rule(&e->rule);
1382
1339 list_del_rcu(&e->list); 1383 list_del_rcu(&e->list);
1340 call_rcu(&e->rcu, audit_free_rule_rcu); 1384 call_rcu(&e->rcu, audit_free_rule_rcu);
1341 1385
@@ -1354,6 +1398,8 @@ static inline int audit_del_rule(struct audit_entry *entry,
1354out: 1398out:
1355 if (tmp_watch) 1399 if (tmp_watch)
1356 audit_put_watch(tmp_watch); /* match initial get */ 1400 audit_put_watch(tmp_watch); /* match initial get */
1401 if (tree)
1402 audit_put_tree(tree); /* that's the temporary one */
1357 1403
1358 return ret; 1404 return ret;
1359} 1405}
@@ -1737,6 +1783,7 @@ int selinux_audit_rule_update(void)
1737{ 1783{
1738 struct audit_entry *entry, *n, *nentry; 1784 struct audit_entry *entry, *n, *nentry;
1739 struct audit_watch *watch; 1785 struct audit_watch *watch;
1786 struct audit_tree *tree;
1740 int i, err = 0; 1787 int i, err = 0;
1741 1788
1742 /* audit_filter_mutex synchronizes the writers */ 1789 /* audit_filter_mutex synchronizes the writers */
@@ -1748,6 +1795,7 @@ int selinux_audit_rule_update(void)
1748 continue; 1795 continue;
1749 1796
1750 watch = entry->rule.watch; 1797 watch = entry->rule.watch;
1798 tree = entry->rule.tree;
1751 nentry = audit_dupe_rule(&entry->rule, watch); 1799 nentry = audit_dupe_rule(&entry->rule, watch);
1752 if (unlikely(IS_ERR(nentry))) { 1800 if (unlikely(IS_ERR(nentry))) {
1753 /* save the first error encountered for the 1801 /* save the first error encountered for the
@@ -1763,7 +1811,9 @@ int selinux_audit_rule_update(void)
1763 list_add(&nentry->rule.rlist, 1811 list_add(&nentry->rule.rlist,
1764 &watch->rules); 1812 &watch->rules);
1765 list_del(&entry->rule.rlist); 1813 list_del(&entry->rule.rlist);
1766 } 1814 } else if (tree)
1815 list_replace_init(&entry->rule.rlist,
1816 &nentry->rule.rlist);
1767 list_replace_rcu(&entry->list, &nentry->list); 1817 list_replace_rcu(&entry->list, &nentry->list);
1768 } 1818 }
1769 call_rcu(&entry->rcu, audit_free_rule_rcu); 1819 call_rcu(&entry->rcu, audit_free_rule_rcu);