Skip to content

Commit 74c3cbe

Browse files
author
Al Viro
committed
[PATCH] audit: watching subtrees
New kind of audit rule predicates: "object is visible in given subtree". The part that can be sanely implemented, that is. Limitations: * if you have hardlink from outside of tree, you'd better watch it too (or just watch the object itself, obviously) * if you mount something under a watched tree, tell audit that new chunk should be added to watched subtrees * if you umount something in a watched tree and it's still mounted elsewhere, you will get matches on events happening there. New command tells audit to recalculate the trees, trimming such sources of false positives. Note that it's _not_ about path - if something mounted in several places (multiple mount, bindings, different namespaces, etc.), the match does _not_ depend on which one we are using for access. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
1 parent 455434d commit 74c3cbe

File tree

10 files changed

+1310
-10
lines changed

10 files changed

+1310
-10
lines changed

fs/dcache.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ int sysctl_vfs_cache_pressure __read_mostly = 100;
3838
EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure);
3939

4040
__cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lock);
41-
static __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock);
41+
__cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock);
4242

4343
EXPORT_SYMBOL(dcache_lock);
4444

include/linux/audit.h

+3
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@
6363
#define AUDIT_ADD_RULE 1011 /* Add syscall filtering rule */
6464
#define AUDIT_DEL_RULE 1012 /* Delete syscall filtering rule */
6565
#define AUDIT_LIST_RULES 1013 /* List syscall filtering rules */
66+
#define AUDIT_TRIM 1014 /* Trim junk from watched tree */
67+
#define AUDIT_MAKE_EQUIV 1015 /* Append to watched tree */
6668
#define AUDIT_TTY_GET 1016 /* Get TTY auditing status */
6769
#define AUDIT_TTY_SET 1017 /* Set TTY auditing status */
6870

@@ -203,6 +205,7 @@
203205
#define AUDIT_SUCCESS 104 /* exit >= 0; value ignored */
204206
#define AUDIT_WATCH 105
205207
#define AUDIT_PERM 106
208+
#define AUDIT_DIR 107
206209

207210
#define AUDIT_ARG0 200
208211
#define AUDIT_ARG1 (AUDIT_ARG0+1)

include/linux/dcache.h

+1
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ d_iput: no no no yes
178178
#define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 /* Parent inode is watched */
179179

180180
extern spinlock_t dcache_lock;
181+
extern seqlock_t rename_lock;
181182

182183
/**
183184
* d_drop - drop a dentry

init/Kconfig

+4
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,10 @@ config AUDITSYSCALL
234234
such as SELinux. To use audit's filesystem watch feature, please
235235
ensure that INOTIFY is configured.
236236

237+
config AUDIT_TREE
238+
def_bool y
239+
depends on AUDITSYSCALL && INOTIFY
240+
237241
config IKCONFIG
238242
tristate "Kernel .config support"
239243
---help---

kernel/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ obj-$(CONFIG_IKCONFIG) += configs.o
4646
obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
4747
obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
4848
obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
49+
obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
4950
obj-$(CONFIG_KPROBES) += kprobes.o
5051
obj-$(CONFIG_SYSFS) += ksysfs.o
5152
obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o

kernel/audit.c

+87
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,21 @@ int audit_send_list(void *_dest)
468468
return 0;
469469
}
470470

471+
#ifdef CONFIG_AUDIT_TREE
472+
static int prune_tree_thread(void *unused)
473+
{
474+
mutex_lock(&audit_cmd_mutex);
475+
audit_prune_trees();
476+
mutex_unlock(&audit_cmd_mutex);
477+
return 0;
478+
}
479+
480+
void audit_schedule_prune(void)
481+
{
482+
kthread_run(prune_tree_thread, NULL, "audit_prune_tree");
483+
}
484+
#endif
485+
471486
struct sk_buff *audit_make_reply(int pid, int seq, int type, int done,
472487
int multi, void *payload, int size)
473488
{
@@ -540,6 +555,8 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
540555
case AUDIT_SIGNAL_INFO:
541556
case AUDIT_TTY_GET:
542557
case AUDIT_TTY_SET:
558+
case AUDIT_TRIM:
559+
case AUDIT_MAKE_EQUIV:
543560
if (security_netlink_recv(skb, CAP_AUDIT_CONTROL))
544561
err = -EPERM;
545562
break;
@@ -756,6 +773,76 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
756773
uid, seq, data, nlmsg_len(nlh),
757774
loginuid, sid);
758775
break;
776+
case AUDIT_TRIM:
777+
audit_trim_trees();
778+
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
779+
if (!ab)
780+
break;
781+
audit_log_format(ab, "auid=%u", loginuid);
782+
if (sid) {
783+
u32 len;
784+
ctx = NULL;
785+
if (selinux_sid_to_string(sid, &ctx, &len))
786+
audit_log_format(ab, " ssid=%u", sid);
787+
else
788+
audit_log_format(ab, " subj=%s", ctx);
789+
kfree(ctx);
790+
}
791+
audit_log_format(ab, " op=trim res=1");
792+
audit_log_end(ab);
793+
break;
794+
case AUDIT_MAKE_EQUIV: {
795+
void *bufp = data;
796+
u32 sizes[2];
797+
size_t len = nlmsg_len(nlh);
798+
char *old, *new;
799+
800+
err = -EINVAL;
801+
if (len < 2 * sizeof(u32))
802+
break;
803+
memcpy(sizes, bufp, 2 * sizeof(u32));
804+
bufp += 2 * sizeof(u32);
805+
len -= 2 * sizeof(u32);
806+
old = audit_unpack_string(&bufp, &len, sizes[0]);
807+
if (IS_ERR(old)) {
808+
err = PTR_ERR(old);
809+
break;
810+
}
811+
new = audit_unpack_string(&bufp, &len, sizes[1]);
812+
if (IS_ERR(new)) {
813+
err = PTR_ERR(new);
814+
kfree(old);
815+
break;
816+
}
817+
/* OK, here comes... */
818+
err = audit_tag_tree(old, new);
819+
820+
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
821+
if (!ab) {
822+
kfree(old);
823+
kfree(new);
824+
break;
825+
}
826+
audit_log_format(ab, "auid=%u", loginuid);
827+
if (sid) {
828+
u32 len;
829+
ctx = NULL;
830+
if (selinux_sid_to_string(sid, &ctx, &len))
831+
audit_log_format(ab, " ssid=%u", sid);
832+
else
833+
audit_log_format(ab, " subj=%s", ctx);
834+
kfree(ctx);
835+
}
836+
audit_log_format(ab, " op=make_equiv old=");
837+
audit_log_untrustedstring(ab, old);
838+
audit_log_format(ab, " new=");
839+
audit_log_untrustedstring(ab, new);
840+
audit_log_format(ab, " res=%d", !err);
841+
audit_log_end(ab);
842+
kfree(old);
843+
kfree(new);
844+
break;
845+
}
759846
case AUDIT_SIGNAL_INFO:
760847
err = selinux_sid_to_string(audit_sig_sid, &ctx, &len);
761848
if (err)

kernel/audit.h

+33-1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ struct audit_field {
7373
struct selinux_audit_rule *se_rule;
7474
};
7575

76+
struct audit_tree;
77+
struct audit_chunk;
78+
7679
struct audit_krule {
7780
int vers_ops;
7881
u32 flags;
@@ -86,7 +89,8 @@ struct audit_krule {
8689
struct audit_field *arch_f; /* quick access to arch field */
8790
struct audit_field *inode_f; /* quick access to an inode field */
8891
struct audit_watch *watch; /* associated watch */
89-
struct list_head rlist; /* entry in audit_watch.rules list */
92+
struct audit_tree *tree; /* associated watched tree */
93+
struct list_head rlist; /* entry in audit_{watch,tree}.rules list */
9094
};
9195

9296
struct audit_entry {
@@ -130,6 +134,34 @@ extern void audit_handle_ievent(struct inotify_watch *, u32, u32, u32,
130134
const char *, struct inode *);
131135
extern int selinux_audit_rule_update(void);
132136

137+
extern struct mutex audit_filter_mutex;
138+
extern void audit_free_rule_rcu(struct rcu_head *);
139+
140+
#ifdef CONFIG_AUDIT_TREE
141+
extern struct audit_chunk *audit_tree_lookup(const struct inode *);
142+
extern void audit_put_chunk(struct audit_chunk *);
143+
extern int audit_tree_match(struct audit_chunk *, struct audit_tree *);
144+
extern int audit_make_tree(struct audit_krule *, char *, u32);
145+
extern int audit_add_tree_rule(struct audit_krule *);
146+
extern int audit_remove_tree_rule(struct audit_krule *);
147+
extern void audit_trim_trees(void);
148+
extern int audit_tag_tree(char *old, char *new);
149+
extern void audit_schedule_prune(void);
150+
extern void audit_prune_trees(void);
151+
extern const char *audit_tree_path(struct audit_tree *);
152+
extern void audit_put_tree(struct audit_tree *);
153+
#else
154+
#define audit_remove_tree_rule(rule) BUG()
155+
#define audit_add_tree_rule(rule) -EINVAL
156+
#define audit_make_tree(rule, str, op) -EINVAL
157+
#define audit_trim_trees() (void)0
158+
#define audit_put_tree(tree) (void)0
159+
#define audit_tag_tree(old, new) -EINVAL
160+
#define audit_tree_path(rule) "" /* never called */
161+
#endif
162+
163+
extern char *audit_unpack_string(void **, size_t *, size_t);
164+
133165
#ifdef CONFIG_AUDITSYSCALL
134166
extern int __audit_signal_info(int sig, struct task_struct *t);
135167
static inline int audit_signal_info(int sig, struct task_struct *t)

0 commit comments

Comments
 (0)