On Thu, 2005-06-23 at 15:16 -0400, Steve Grubb wrote:
However...I looked at the user filtering and it is not working. I
think I know
why. netlink is an async interface. This means that the task may not be alive
when the user message is processed. It currently detects the and returns
-ESRCH, but the sender is long gone.
This means that the generic audit_filter_rules() cannot be used. You can only
filter based on the credentials that netlink gathered from the caller at
reception of message, or move the filtering to the message entry point after
permission checks.
Although this is never actually a problem in practice, it turns out that
to 'fix' it is actually also a cleanup of the code, because it means we
don't have to find the task by its pid. I was concerned about
duplicating audit_filter_rules() but in fact we don't have to copy much
of it because there are so few criteria we can filter on. So here
goes...
--- linux-2.6.9/include/linux/audit.h.p20054 2005-06-24 14:04:23.000000000 +0100
+++ linux-2.6.9/include/linux/audit.h 2005-06-24 14:05:17.000000000 +0100
@@ -205,6 +205,7 @@ struct audit_sig_info {
struct audit_buffer;
struct audit_context;
struct inode;
+struct netlink_skb_parms;
#define AUDITSC_INVALID 0
#define AUDITSC_SUCCESS 1
@@ -236,7 +237,7 @@ extern int audit_socketcall(int nargs, u
extern int audit_sockaddr(int len, void *addr);
extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt);
extern void audit_signal_info(int sig, struct task_struct *t);
-extern int audit_filter_user(int pid, int type);
+extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
#else
#define audit_alloc(t) ({ 0; })
#define audit_free(t) do { ; } while (0)
@@ -252,7 +253,7 @@ extern int audit_filter_user(int pid, in
#define audit_sockaddr(len, addr) ({ 0; })
#define audit_avc_path(dentry, mnt) ({ 0; })
#define audit_signal_info(s,t) do { ; } while (0)
-#define audit_filter_user(p,t) ({ 1; })
+#define audit_filter_user(cb,t) ({ 1; })
#endif
#ifdef CONFIG_AUDIT
--- linux-2.6.9/kernel/audit.c 2005-06-24 12:41:15.000000000 +0100
+++ linux-2.6.9/kernel/audit.c 2005-06-24 12:31:13.000000000 +0100
@@ -465,7 +465,7 @@ static int audit_receive_msg(struct sk_b
if (!audit_enabled && msg_type != AUDIT_USER_AVC)
return 0;
- err = audit_filter_user(pid, msg_type);
+ err = audit_filter_user(&NETLINK_CB(skb), msg_type);
if (err == 1) {
err = 0;
ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
--- linux-2.6.9/kernel/auditsc.c 2005-06-24 12:41:15.000000000 +0100
+++ linux-2.6.9/kernel/auditsc.c 2005-06-24 12:41:59.000000000 +0100
@@ -40,6 +40,7 @@
#include <linux/personality.h>
#include <linux/time.h>
#include <linux/kthread.h>
+#include <linux/netlink.h>
#include <asm/unistd.h>
/* 0 = no checking
@@ -541,35 +542,62 @@ static enum audit_state audit_filter_sys
return AUDIT_BUILD_CONTEXT;
}
-int audit_filter_user(int pid, int type)
+static int audit_filter_user_rules(struct netlink_skb_parms *cb,
+ struct audit_rule *rule,
+ enum audit_state *state)
+{
+ int i;
+
+ for (i = 0; i < rule->field_count; i++) {
+ u32 field = rule->fields[i] & ~AUDIT_NEGATE;
+ u32 value = rule->values[i];
+ int result = 0;
+
+ switch (field) {
+ case AUDIT_PID:
+ result = (cb->creds.pid == value);
+ break;
+ case AUDIT_UID:
+ result = (cb->creds.uid == value);
+ break;
+ case AUDIT_GID:
+ result = (cb->creds.gid == value);
+ break;
+ case AUDIT_LOGINUID:
+ result = (cb->loginuid == value);
+ break;
+ }
+
+ if (rule->fields[i] & AUDIT_NEGATE)
+ result = !result;
+ if (!result)
+ return 0;
+ }
+ switch (rule->action) {
+ case AUDIT_NEVER: *state = AUDIT_DISABLED; break;
+ case AUDIT_POSSIBLE: *state = AUDIT_BUILD_CONTEXT; break;
+ case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break;
+ }
+ return 1;
+}
+
+int audit_filter_user(struct netlink_skb_parms *cb, int type)
{
- struct task_struct *tsk;
struct audit_entry *e;
enum audit_state state;
int ret = 1;
- read_lock(&tasklist_lock);
- tsk = find_task_by_pid(pid);
- if (tsk)
- get_task_struct(tsk);
- read_unlock(&tasklist_lock);
-
- if (!tsk)
- return -ESRCH;
-
rcu_read_lock();
list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) {
- if (audit_filter_rules(tsk, &e->rule, NULL, &state)) {
+ if (audit_filter_user_rules(cb, &e->rule, &state)) {
if (state == AUDIT_DISABLED)
ret = 0;
break;
}
}
rcu_read_unlock();
- put_task_struct(tsk);
return ret; /* Audit by default */
-
}
/* This should be called with task_lock() held. */
--
dwmw2