Skip to content

Commit

Permalink
[PATCH] audit: watching subtrees
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
Al Viro committed Oct 21, 2007
1 parent 455434d commit 74c3cbe
Show file tree
Hide file tree
Showing 10 changed files with 1,310 additions and 10 deletions.
2 changes: 1 addition & 1 deletion fs/dcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ int sysctl_vfs_cache_pressure __read_mostly = 100;
EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure);

__cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lock);
static __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock);
__cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock);

EXPORT_SYMBOL(dcache_lock);

Expand Down
3 changes: 3 additions & 0 deletions include/linux/audit.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@
#define AUDIT_ADD_RULE 1011 /* Add syscall filtering rule */
#define AUDIT_DEL_RULE 1012 /* Delete syscall filtering rule */
#define AUDIT_LIST_RULES 1013 /* List syscall filtering rules */
#define AUDIT_TRIM 1014 /* Trim junk from watched tree */
#define AUDIT_MAKE_EQUIV 1015 /* Append to watched tree */
#define AUDIT_TTY_GET 1016 /* Get TTY auditing status */
#define AUDIT_TTY_SET 1017 /* Set TTY auditing status */

Expand Down Expand Up @@ -203,6 +205,7 @@
#define AUDIT_SUCCESS 104 /* exit >= 0; value ignored */
#define AUDIT_WATCH 105
#define AUDIT_PERM 106
#define AUDIT_DIR 107

#define AUDIT_ARG0 200
#define AUDIT_ARG1 (AUDIT_ARG0+1)
Expand Down
1 change: 1 addition & 0 deletions include/linux/dcache.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ d_iput: no no no yes
#define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 /* Parent inode is watched */

extern spinlock_t dcache_lock;
extern seqlock_t rename_lock;

/**
* d_drop - drop a dentry
Expand Down
4 changes: 4 additions & 0 deletions init/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,10 @@ config AUDITSYSCALL
such as SELinux. To use audit's filesystem watch feature, please
ensure that INOTIFY is configured.

config AUDIT_TREE
def_bool y
depends on AUDITSYSCALL && INOTIFY

config IKCONFIG
tristate "Kernel .config support"
---help---
Expand Down
1 change: 1 addition & 0 deletions kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ obj-$(CONFIG_IKCONFIG) += configs.o
obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_SYSFS) += ksysfs.o
obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
Expand Down
87 changes: 87 additions & 0 deletions kernel/audit.c
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,21 @@ int audit_send_list(void *_dest)
return 0;
}

#ifdef CONFIG_AUDIT_TREE
static int prune_tree_thread(void *unused)
{
mutex_lock(&audit_cmd_mutex);
audit_prune_trees();
mutex_unlock(&audit_cmd_mutex);
return 0;
}

void audit_schedule_prune(void)
{
kthread_run(prune_tree_thread, NULL, "audit_prune_tree");
}
#endif

struct sk_buff *audit_make_reply(int pid, int seq, int type, int done,
int multi, void *payload, int size)
{
Expand Down Expand Up @@ -540,6 +555,8 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
case AUDIT_SIGNAL_INFO:
case AUDIT_TTY_GET:
case AUDIT_TTY_SET:
case AUDIT_TRIM:
case AUDIT_MAKE_EQUIV:
if (security_netlink_recv(skb, CAP_AUDIT_CONTROL))
err = -EPERM;
break;
Expand Down Expand Up @@ -756,6 +773,76 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
uid, seq, data, nlmsg_len(nlh),
loginuid, sid);
break;
case AUDIT_TRIM:
audit_trim_trees();
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
if (!ab)
break;
audit_log_format(ab, "auid=%u", loginuid);
if (sid) {
u32 len;
ctx = NULL;
if (selinux_sid_to_string(sid, &ctx, &len))
audit_log_format(ab, " ssid=%u", sid);
else
audit_log_format(ab, " subj=%s", ctx);
kfree(ctx);
}
audit_log_format(ab, " op=trim res=1");
audit_log_end(ab);
break;
case AUDIT_MAKE_EQUIV: {
void *bufp = data;
u32 sizes[2];
size_t len = nlmsg_len(nlh);
char *old, *new;

err = -EINVAL;
if (len < 2 * sizeof(u32))
break;
memcpy(sizes, bufp, 2 * sizeof(u32));
bufp += 2 * sizeof(u32);
len -= 2 * sizeof(u32);
old = audit_unpack_string(&bufp, &len, sizes[0]);
if (IS_ERR(old)) {
err = PTR_ERR(old);
break;
}
new = audit_unpack_string(&bufp, &len, sizes[1]);
if (IS_ERR(new)) {
err = PTR_ERR(new);
kfree(old);
break;
}
/* OK, here comes... */
err = audit_tag_tree(old, new);

ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
if (!ab) {
kfree(old);
kfree(new);
break;
}
audit_log_format(ab, "auid=%u", loginuid);
if (sid) {
u32 len;
ctx = NULL;
if (selinux_sid_to_string(sid, &ctx, &len))
audit_log_format(ab, " ssid=%u", sid);
else
audit_log_format(ab, " subj=%s", ctx);
kfree(ctx);
}
audit_log_format(ab, " op=make_equiv old=");
audit_log_untrustedstring(ab, old);
audit_log_format(ab, " new=");
audit_log_untrustedstring(ab, new);
audit_log_format(ab, " res=%d", !err);
audit_log_end(ab);
kfree(old);
kfree(new);
break;
}
case AUDIT_SIGNAL_INFO:
err = selinux_sid_to_string(audit_sig_sid, &ctx, &len);
if (err)
Expand Down
34 changes: 33 additions & 1 deletion kernel/audit.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ struct audit_field {
struct selinux_audit_rule *se_rule;
};

struct audit_tree;
struct audit_chunk;

struct audit_krule {
int vers_ops;
u32 flags;
Expand All @@ -86,7 +89,8 @@ struct audit_krule {
struct audit_field *arch_f; /* quick access to arch field */
struct audit_field *inode_f; /* quick access to an inode field */
struct audit_watch *watch; /* associated watch */
struct list_head rlist; /* entry in audit_watch.rules list */
struct audit_tree *tree; /* associated watched tree */
struct list_head rlist; /* entry in audit_{watch,tree}.rules list */
};

struct audit_entry {
Expand Down Expand Up @@ -130,6 +134,34 @@ extern void audit_handle_ievent(struct inotify_watch *, u32, u32, u32,
const char *, struct inode *);
extern int selinux_audit_rule_update(void);

extern struct mutex audit_filter_mutex;
extern void audit_free_rule_rcu(struct rcu_head *);

#ifdef CONFIG_AUDIT_TREE
extern struct audit_chunk *audit_tree_lookup(const struct inode *);
extern void audit_put_chunk(struct audit_chunk *);
extern int audit_tree_match(struct audit_chunk *, struct audit_tree *);
extern int audit_make_tree(struct audit_krule *, char *, u32);
extern int audit_add_tree_rule(struct audit_krule *);
extern int audit_remove_tree_rule(struct audit_krule *);
extern void audit_trim_trees(void);
extern int audit_tag_tree(char *old, char *new);
extern void audit_schedule_prune(void);
extern void audit_prune_trees(void);
extern const char *audit_tree_path(struct audit_tree *);
extern void audit_put_tree(struct audit_tree *);
#else
#define audit_remove_tree_rule(rule) BUG()
#define audit_add_tree_rule(rule) -EINVAL
#define audit_make_tree(rule, str, op) -EINVAL
#define audit_trim_trees() (void)0
#define audit_put_tree(tree) (void)0
#define audit_tag_tree(old, new) -EINVAL
#define audit_tree_path(rule) "" /* never called */
#endif

extern char *audit_unpack_string(void **, size_t *, size_t);

#ifdef CONFIG_AUDITSYSCALL
extern int __audit_signal_info(int sig, struct task_struct *t);
static inline int audit_signal_info(int sig, struct task_struct *t)
Expand Down
Loading

0 comments on commit 74c3cbe

Please sign in to comment.