audit.49 kernel
by David Woodhouse
Uploading now...
* Wed May 25 2005 David Woodhouse <dwmw2(a)redhat.com> audit.49
- Clean up logging of untrusted strings in avc.c (Stephen Smalley)
- auditfs update (Tim Chavez)
--
dwmw2
19 years, 7 months
Oops while checking file system auditing
by Steve Grubb
Hello,
I was testing file system auditing (kernel .46) and got the following when
removing a watch. First symptom was blinking keyboard lights.
-Steve
May 24 11:49:09 localhost kernel: kernel BUG at mm/slab.c:2787!
May 24 11:49:09 localhost kernel: invalid operand: 0000 [#1]
May 24 11:49:09 localhost kernel: Modules linked in: parport_pc lp parport
autofs4 i2c_dev i2c_core ipt_REJECT ipt_state ip_conntrack iptable_filter
ip_tables dm_mod button battery ac md5 ipv6 uhci_hcd snd_emu10k1 snd_rawmidi
snd_pcm_oss snd_mixer_oss snd_pcm snd_timer snd_seq_device snd_ac97_codec
snd_page_alloc snd_util_mem snd_hwdep snd soundcore 3c59x floppy ext3 jbd
May 24 11:49:09 localhost kernel: CPU: 0
May 24 11:49:09 localhost kernel: EIP: 0060:[<c014c67f>] Not tainted VLI
May 24 11:49:09 localhost kernel: EFLAGS: 00010002
(2.6.9-5.0.3.EL.audit.46.sg.2)
May 24 11:49:09 localhost kernel: EIP is at cache_reap+0x111/0x273
May 24 11:49:09 localhost kernel: eax: effefa7c ebx: effefa60 ecx:
e612c180 edx: 0000003d
May 24 11:49:09 localhost kernel: esi: effefae8 edi: 00000001 ebp:
c03feae0 esp: eff18f5c
May 24 11:49:09 localhost kernel: ds: 007b es: 007b ss: 0068
May 24 11:49:09 localhost kernel: Process events/0 (pid: 3,
threadinfo=eff18000 task=efe20bd0)
May 24 11:49:09 localhost kernel: Stack: c03feb20 c03feb20 00000283 00000000
c16ff160 c01321a4 c014c56e ffffffff
May 24 11:49:09 localhost kernel: ffffffff 00000001 00000000 c011b9f2
00010000 00000000 efe20bd0 eff18fcc
May 24 11:49:09 localhost kernel: c0301651 00000000 efe20bd0 c011b9f2
00100100 00200200 00000004 efe20bd0
May 24 11:49:09 localhost kernel: Call Trace:
May 24 11:49:09 localhost kernel: [<c01321a4>] worker_thread+0x1eb/0x2f0
May 24 11:49:09 localhost kernel: [<c014c56e>] cache_reap+0x0/0x273
May 24 11:49:09 localhost kernel: [<c011b9f2>] default_wake_function+0x0/0xc
May 24 11:49:09 localhost kernel: [<c0301651>] schedule+0x431/0x544
May 24 11:49:09 localhost kernel: [<c011b9f2>] default_wake_function+0x0/0xc
May 24 11:49:09 localhost kernel: [<c0131fb9>] worker_thread+0x0/0x2f0
May 24 11:49:09 localhost kernel: [<c0136f81>] kthread+0x69/0x91
May 24 11:49:09 localhost kernel: [<c0136f18>] kthread+0x0/0x91
May 24 11:49:09 localhost kernel: [<c01041d9>] kernel_thread_helper+0x5/0xb
May 24 11:49:09 localhost kernel: Code: e9 05 01 00 00 6b 4b 3c 05 8b 53 40 01
ca 4a 89 d0 31 d2 f7 f1 89 c7 8b 4b 1c 8d 43 1c 39 c1 0f 84 e5 00 00 00 83 79
10 00 74 08 <0f> 0b e3 0a 97 43 31 c0 8b 01 8b 51 04 89 50 04 89 02 c7 41 04
19 years, 7 months
audit 0.9 released
by Steve Grubb
Hello,
I've just released a new version of the audit daemon. It can be downloaded
from http://people.redhat.com/sgrubb/audit It will also be in rawhide
tomorrow. The Changelog is:
- Translate numeric info to human readable for ausearch output
- add '-if' option to ausearch to select input file
- add '-c' option to ausearch to allow searching by comm filed
- init script now deletes all rules when daemon stops
- Make auditctl display perms correctly in watch listings
- Make auditctl -D remove all watches
The big improvement in this release is the -i parameter for ausearch. This
turns the audit events into something more understandable by interpreting all
numeric information.
The ausearch utility can now take a '-if' parameter to have it search or
display a particular file.
Let me know if there are any problems.
-Steve
19 years, 7 months
[PATCH] Fix remaining cases of direct logging of untrusted strings by avc_audit
by Stephen Smalley
Per Steve Grubb's observation that there are some remaining cases where
avc_audit() directly logs untrusted strings without escaping them, here
is a patch that changes avc_audit() to use audit_log_untrustedstring()
or audit_log_hex() as appropriate. Note that d_name.name is nul-
terminated by d_alloc(), and that sun_path is nul-terminated by
unix_mkname(), so it is not necessary for the AVC to create nul-
terminated copies or to alter audit_log_untrustedstring to take a length
argument. In the case of an abstract name, we use audit_log_hex() with
an explicit length.
Signed-off-by: Stephen Smalley <sds(a)tycho.nsa.gov>
---
selinux/avc.c | 22 +++++++++-------------
1 files changed, 9 insertions(+), 13 deletions(-)
Index: security/selinux/avc.c
===================================================================
--- 6cad4f59214ed4563ddc189bc98f05d1e2b1a5cc/security/selinux/avc.c (mode:100644)
+++ uncommitted/security/selinux/avc.c (mode:100644)
@@ -575,16 +575,16 @@
struct dentry *dentry = a->u.fs.dentry;
if (a->u.fs.mnt)
audit_avc_path(dentry, a->u.fs.mnt);
- audit_log_format(ab, " name=%s",
- dentry->d_name.name);
+ audit_log_format(ab, " name=");
+ audit_log_untrustedstring(ab, dentry->d_name.name);
inode = dentry->d_inode;
} else if (a->u.fs.inode) {
struct dentry *dentry;
inode = a->u.fs.inode;
dentry = d_find_alias(inode);
if (dentry) {
- audit_log_format(ab, " name=%s",
- dentry->d_name.name);
+ audit_log_format(ab, " name=");
+ audit_log_untrustedstring(ab, dentry->d_name.name);
dput(dentry);
}
}
@@ -628,23 +628,19 @@
u = unix_sk(sk);
if (u->dentry) {
audit_avc_path(u->dentry, u->mnt);
- audit_log_format(ab, " name=%s",
- u->dentry->d_name.name);
-
+ audit_log_format(ab, " name=");
+ audit_log_untrustedstring(ab, u->dentry->d_name.name);
break;
}
if (!u->addr)
break;
len = u->addr->len-sizeof(short);
p = &u->addr->name->sun_path[0];
+ audit_log_format(ab, " path=");
if (*p)
- audit_log_format(ab,
- "path=%*.*s", len,
- len, p);
+ audit_log_untrustedstring(ab, p);
else
- audit_log_format(ab,
- "path=(a)%*.*s", len-1,
- len-1, p+1);
+ audit_log_hex(ab, p, len);
break;
}
}
--
Stephen Smalley
National Security Agency
19 years, 7 months
audit.48 kernel
by David Woodhouse
* Mon May 23 2005 David Woodhouse <dwmw2(a)redhat.com> audit.48
- Drop keys from syscall rules, since nobody could justify them
- Unify 'auid=' and put arch= before syscall= (Steve Grubb)
--
dwmw2
19 years, 7 months
[PATCH] more message updates
by Steve Grubb
Hello,
I was working on the ausearch utility and have it interpreting the logs
nicely. There were a couple issues that popped up where some messages did not
fall into similar patterns. There are several cases where auid does not have
an '=' between it and the loginuid.
Also, I ran into a problem interpreting syscalls because arch comes after the
syscall. Life would be so much easier if arch was before syscall. The
attached patch fixes this. Its against the .46 kernel.
-Steve
19 years, 7 months
audit.47 kernel -- add serial number to non-syscall messages.
by David Woodhouse
Steve pointed out that all user messages are getting logged with a
serial number of zero -- so in the relatively unlikely event that more
than one such message is generated with precisely the same timestamp
(i.e. in the same millisecond), they'd have the same stamp.
He provided a patch which I mangled somewhat till I was happy with it,
and the result is in the audit.47 kernel which is uploading to the yum
repository now. What's below is the version I committed to the git tree,
which is slightly different because there were related changes in that
area already. The resulting code should be the same in each case.
Index: include/linux/audit.h
===================================================================
--- 8ab8eef2e8c3629c46d29ffb9c618d87c5e1a02c/include/linux/audit.h (mode:100644)
+++ uncommitted/include/linux/audit.h (mode:100644)
@@ -219,8 +219,9 @@
/* Private API (for audit.c only) */
extern int audit_receive_filter(int type, int pid, int uid, int seq,
void *data, uid_t loginuid);
-extern int audit_get_stamp(struct audit_context *ctx,
- struct timespec *t, unsigned int *serial);
+extern unsigned int audit_serial(void);
+extern void auditsc_get_stamp(struct audit_context *ctx,
+ struct timespec *t, unsigned int *serial);
extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid);
extern uid_t audit_get_loginuid(struct audit_context *ctx);
extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
@@ -237,7 +238,7 @@
#define audit_putname(n) do { ; } while (0)
#define audit_inode(n,i) do { ; } while (0)
#define audit_receive_filter(t,p,u,s,d,l) ({ -EOPNOTSUPP; })
-#define audit_get_stamp(c,t,s) ({ 0; })
+#define auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
#define audit_get_loginuid(c) ({ -1; })
#define audit_ipc_perms(q,u,g,m) ({ 0; })
#define audit_socketcall(n,a) ({ 0; })
Index: kernel/audit.c
===================================================================
--- 8ab8eef2e8c3629c46d29ffb9c618d87c5e1a02c/kernel/audit.c (mode:100644)
+++ uncommitted/kernel/audit.c (mode:100644)
@@ -597,6 +597,47 @@
return NULL;
}
+/* Compute a serial number for the audit record. Audit records are
+ * written to user-space as soon as they are generated, so a complete
+ * audit record may be written in several pieces. The timestamp of the
+ * record and this serial number are used by the user-space tools to
+ * determine which pieces belong to the same audit record. The
+ * (timestamp,serial) tuple is unique for each syscall and is live from
+ * syscall entry to syscall exit.
+ *
+ * Atomic values are only guaranteed to be 24-bit, so we count down.
+ *
+ * NOTE: Another possibility is to store the formatted records off the
+ * audit context (for those records that have a context), and emit them
+ * all at syscall exit. However, this could delay the reporting of
+ * significant errors until syscall exit (or never, if the system
+ * halts). */
+unsigned int audit_serial(void)
+{
+ static atomic_t serial = ATOMIC_INIT(0xffffff);
+ unsigned int a, b;
+
+ do {
+ a = atomic_read(&serial);
+ if (atomic_dec_and_test(&serial))
+ atomic_set(&serial, 0xffffff);
+ b = atomic_read(&serial);
+ } while (b != a - 1);
+
+ return 0xffffff - b;
+}
+
+static inline void audit_get_stamp(struct audit_context *ctx,
+ struct timespec *t, unsigned int *serial)
+{
+ if (ctx)
+ auditsc_get_stamp(ctx, t, serial);
+ else {
+ *t = CURRENT_TIME;
+ *serial = audit_serial();
+ }
+}
+
/* Obtain an audit buffer. This routine does locking to obtain the
* audit buffer, but then no locking is required for calls to
* audit_log_*format. If the tsk is a task that is currently in a
@@ -630,10 +671,7 @@
return NULL;
}
- if (!audit_get_stamp(ab->ctx, &t, &serial)) {
- t = CURRENT_TIME;
- serial = 0;
- }
+ audit_get_stamp(ab->ctx, &t, &serial);
audit_log_format(ab, "audit(%lu.%03lu:%u): ",
t.tv_sec, t.tv_nsec/1000000, serial);
Index: kernel/auditsc.c
===================================================================
--- 8ab8eef2e8c3629c46d29ffb9c618d87c5e1a02c/kernel/auditsc.c (mode:100644)
+++ uncommitted/kernel/auditsc.c (mode:100644)
@@ -795,36 +795,6 @@
audit_free_context(context);
}
-/* Compute a serial number for the audit record. Audit records are
- * written to user-space as soon as they are generated, so a complete
- * audit record may be written in several pieces. The timestamp of the
- * record and this serial number are used by the user-space tools to
- * determine which pieces belong to the same audit record. The
- * (timestamp,serial) tuple is unique for each syscall and is live from
- * syscall entry to syscall exit.
- *
- * Atomic values are only guaranteed to be 24-bit, so we count down.
- *
- * NOTE: Another possibility is to store the formatted records off the
- * audit context (for those records that have a context), and emit them
- * all at syscall exit. However, this could delay the reporting of
- * significant errors until syscall exit (or never, if the system
- * halts). */
-static inline unsigned int audit_serial(void)
-{
- static atomic_t serial = ATOMIC_INIT(0xffffff);
- unsigned int a, b;
-
- do {
- a = atomic_read(&serial);
- if (atomic_dec_and_test(&serial))
- atomic_set(&serial, 0xffffff);
- b = atomic_read(&serial);
- } while (b != a - 1);
-
- return 0xffffff - b;
-}
-
/* Fill in audit context at syscall entry. This only happens if the
* audit context was created when the task was created and the state or
* filters demand the audit context be built. If the state from the
@@ -1042,17 +1012,13 @@
context->names[idx].rdev = inode->i_rdev;
}
-int audit_get_stamp(struct audit_context *ctx,
- struct timespec *t, unsigned int *serial)
+void auditsc_get_stamp(struct audit_context *ctx,
+ struct timespec *t, unsigned int *serial)
{
- if (ctx) {
- t->tv_sec = ctx->ctime.tv_sec;
- t->tv_nsec = ctx->ctime.tv_nsec;
- *serial = ctx->serial;
- ctx->auditable = 1;
- return 1;
- }
- return 0;
+ t->tv_sec = ctx->ctime.tv_sec;
+ t->tv_nsec = ctx->ctime.tv_nsec;
+ *serial = ctx->serial;
+ ctx->auditable = 1;
}
int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
--
dwmw2
19 years, 7 months
audit.46 kernel
by David Woodhouse
The new audit-0.8.2 package is now in the yum repository too. Other
userspace packages should be following shortly (Mon/Tue hopefully).
* Fri May 20 2005 David Woodhouse <dwmw2(a)redhat.com> audit.46
- Defer d_path in AVC audit (Stephen Smalley)
- Clean up use of loginuid/auid and %d/%u (Steve Grubb)
- auditfs update (Tim Chavez)
- Fix AUDIT_USER messages (Steve Grubb)
This is the full list of patches which are in the kernel now, sorted
according to what's upstream and what's in -mm so far. Those which are
in the -mm tree are also in the FC4 kernel as of last night.
# Audit patches
# First, those which are already upstream....
Patch20000: linux-2.6.9-audit-retcode.patch
Patch20001: linux-2.6.9-audit-caps.patch
Patch20002: linux-2.6.9-auditcongestion.patch
Patch20003: linux-2.6.9-auditlost.patch
Patch20004: linux-2.6.9-audit-loginuid-proc.patch
Patch20005: linux-2.6.9-ppc64-auditsyscall.patch
Patch20006: linux-2.6.9-auditinonum.patch
Patch20007: linux-2.6.9-audit-netlinkfix.patch
Patch20008: linux-2.6.9-auditdev.patch
Patch20009: linux-2.6.9-auditipc.patch
Patch20010: linux-2.6.9-auditstr.patch
Patch20011: linux-2.6.9-auditaltroot.patch
Patch20012: linux-2.6.9-auditarch.patch
Patch20013: linux-2.6.11-rc3.stamp.patch
Patch20014: linux-2.6.9-auditoneliners.patch
Patch20015: linux-2.6.9-ia64-audit-syscall.patch
Patch20016: linux-2.6.9-audit-comm-exe.patch
Patch20017: linux-2.6.9-audit-netlink-loginuid.patch
Patch20018: linux-2.6.9-audit-netlink-perms.patch
Patch20019: linux-2.6.9-auditrequeue.patch
Patch20020: linux-2.6.9-audit-fix-setluid.patch
Patch20021: linux-2.6.9-audit-reuse-skb.patch
Patch20022: linux-2.6.9-audit-x86_64-compat.patch
Patch20023: linux-2.6.9-missing-audit_h.patch
Patch20024: linux-2.6.9-netlink-orphan.patch
Patch20025: linux-2.6.9-netlink-unshare.patch
# Then the ones in audit-2.6-mm which are pending...
Patch20030: linux-2.6.9-audit-signal.patch
Patch20031: linux-2.6.9-audit-to-skb-1.patch
Patch20032: linux-2.6.9-audit-to-skb-2.patch
Patch20033: linux-2.6.9-audit-to-skb-3.patch
Patch20034: linux-2.6.9-audit-va-abuse.patch
Patch20035: linux-2.6.9-avc-deadlock.patch
Patch20036: linux-2.6.9-audit-types.patch
Patch20037: linux-2.6.9-audit-spelling.patch
Patch20038: linux-2.6.9-audit-socketcalls.patch
Patch20039: linux-2.6.9-audit-untrusted.patch
Patch20040: linux-2.6.9-audit-kthread.patch
Patch20041: linux-2.6.9-audit-not-auditd.patch
Patch20042: linux-2.6.9-avc-path.patch
Patch20043: linux-2.6.9-fix-user.patch
Patch20044: linux-2.6.9-auid.patch
# ... then the new stuff...
Patch20046: linux-2.6.9-auditsc-key.patch
Patch20047: linux-2.6.9-auditfs.patch
--
dwmw2
19 years, 7 months
key in syscall audit rules.
by David Woodhouse
I'm building an audit.40 with this in. Steve, does it look OK to you?
--- linux-2.6.9/include/linux/audit.h~ 2005-05-17 14:43:57.000000000 +0100
+++ linux-2.6.9/include/linux/audit.h 2005-05-17 15:10:33.000000000 +0100
@@ -128,6 +128,8 @@ struct atomic_t;
#define AUDIT_ARG2 (AUDIT_ARG0+2)
#define AUDIT_ARG3 (AUDIT_ARG0+3)
+#define AUDIT_KEY 0x1000 /* Identifying key for rule */
+
#define AUDIT_NEGATE 0x80000000
--- linux-2.6.9/kernel/auditsc.c~ 2005-05-17 15:17:40.000000000 +0100
+++ linux-2.6.9/kernel/auditsc.c 2005-05-17 15:15:11.000000000 +0100
@@ -140,6 +140,7 @@ struct audit_context {
unsigned int serial; /* serial number for record */
struct timespec ctime; /* time of syscall entry */
uid_t loginuid; /* login uid (identity) */
+ uint32_t key; /* Key of rule which triggered auditing */
int major; /* syscall number */
unsigned long argv[4]; /* syscall arguments */
int return_valid; /* return code is valid */
@@ -334,9 +335,11 @@ int audit_receive_filter(int type, int p
static int audit_filter_rules(struct task_struct *tsk,
struct audit_rule *rule,
struct audit_context *ctx,
- enum audit_state *state)
+ enum audit_state *state,
+ uint32_t *key)
{
int i, j;
+ uint32_t localkey = 0;
for (i = 0; i < rule->field_count; i++) {
u32 field = rule->fields[i] & ~AUDIT_NEGATE;
@@ -429,8 +432,9 @@ static int audit_filter_rules(struct tas
if (ctx)
result = (ctx->argv[field-AUDIT_ARG0]==value);
break;
+ case AUDIT_KEY:
+ localkey = value;
}
-
if (rule->fields[i] & AUDIT_NEGATE)
result = !result;
if (!result)
@@ -441,6 +445,8 @@ static int audit_filter_rules(struct tas
case AUDIT_POSSIBLE: *state = AUDIT_BUILD_CONTEXT; break;
case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break;
}
+ if (key)
+ *key = localkey;
return 1;
}
@@ -451,11 +457,11 @@ static int audit_filter_rules(struct tas
static enum audit_state audit_filter_task(struct task_struct *tsk)
{
struct audit_entry *e;
- enum audit_state state;
+ enum audit_state state;
rcu_read_lock();
list_for_each_entry_rcu(e, &audit_tsklist, list) {
- if (audit_filter_rules(tsk, &e->rule, NULL, &state)) {
+ if (audit_filter_rules(tsk, &e->rule, NULL, &state, NULL)) {
rcu_read_unlock();
return state;
}
@@ -475,13 +481,13 @@ static enum audit_state audit_filter_sys
{
struct audit_entry *e;
enum audit_state state;
- int word = AUDIT_WORD(ctx->major);
- int bit = AUDIT_BIT(ctx->major);
+ int word = AUDIT_WORD(ctx->major);
+ int bit = AUDIT_BIT(ctx->major);
rcu_read_lock();
list_for_each_entry_rcu(e, list, list) {
if ((e->rule.mask[word] & bit) == bit
- && audit_filter_rules(tsk, &e->rule, ctx, &state)) {
+ && audit_filter_rules(tsk, &e->rule, ctx, &state, &ctx->key)) {
rcu_read_unlock();
return state;
}
@@ -677,6 +683,8 @@ static void audit_log_exit(struct audit_
if (!ab)
return; /* audit_panic has been called */
audit_log_format(ab, "syscall=%d", context->major);
+ if (context->key)
+ audit_log_format(ab, " key=%x", context->key);
if (context->personality != PER_LINUX)
audit_log_format(ab, " per=%lx", context->personality);
audit_log_format(ab, " arch=%x", context->arch);
--
dwmw2
19 years, 7 months
updated audit.39 with fixes for sleeping, missing watches, and spinlocks
by Timothy R. Chavez
Hello,
This is the patch I just tested using the audit.39 SRPM on an Opteron.
Everything appears to be in order. We're going to have the performance
team here run the audit code including auditfs on a PPC 15-way with hopes
of flushing memory errors/corruption, deadlock, etc and to also get some
performance [impact] numbers as a nice "to-have".
Hopefully the patch applies cleanly to audit.39 (I just forwarded it to
myself and stripped the quotations :-))
-tim
diff -Nurp linux-2.6.9/fs/dcache.c /var/log/kernel-2.6.9/linux-2.6.9/fs/dcache.c
--- linux-2.6.9/fs/dcache.c 2005-05-18 15:50:17.182181000 -0500
+++ /var/log/kernel-2.6.9/linux-2.6.9/fs/dcache.c 2005-05-17 16:29:47.000000000 -0500
@@ -1109,14 +1109,14 @@ out:
void d_delete(struct dentry * dentry)
{
+ audit_dentry_unpin(dentry);
+
/*
* Are we the only user?
*/
spin_lock(&dcache_lock);
spin_lock(&dentry->d_lock);
- audit_dentry_unpin(dentry);
-
if (atomic_read(&dentry->d_count) == 1) {
dentry_iput(dentry);
return;
diff -Nurp linux-2.6.9/fs/namei.c /var/log/kernel-2.6.9/linux-2.6.9/fs/namei.c
--- linux-2.6.9/fs/namei.c 2005-05-18 15:50:17.184180696 -0500
+++ /var/log/kernel-2.6.9/linux-2.6.9/fs/namei.c 2005-05-18 15:26:11.000000000 -0500
@@ -163,8 +163,6 @@ int vfs_permission(struct inode * inode,
{
umode_t mode = inode->i_mode;
- audit_notify_watch(inode, mask);
-
if (mask & MAY_WRITE) {
/*
* Nobody gets write access to a read-only fs.
@@ -217,6 +215,8 @@ int permission(struct inode * inode,int
/* Ordinary permission routines do not understand MAY_APPEND. */
submask = mask & ~MAY_APPEND;
+
+ audit_notify_watch(inode, mask);
if (inode->i_op && inode->i_op->permission)
retval = inode->i_op->permission(inode, submask, nd);
diff -Nurp linux-2.6.9/kernel/auditfs.c /var/log/kernel-2.6.9/linux-2.6.9/kernel/auditfs.c
--- linux-2.6.9/kernel/auditfs.c 2005-05-18 15:50:17.186180392 -0500
+++ /var/log/kernel-2.6.9/linux-2.6.9/kernel/auditfs.c 2005-05-18 16:57:43.760007664 -0500
@@ -41,9 +41,14 @@ static kmem_cache_t *audit_watch_cache;
static kmem_cache_t *audit_wentry_cache;
/* Read-heavy list */
-HLIST_HEAD(audit_master_watchlist);
-static spinlock_t audit_master_watchlist_lock = SPIN_LOCK_UNLOCKED;
+HLIST_HEAD(master_watchlist);
+static spinlock_t master_watchlist_lock = SPIN_LOCK_UNLOCKED;
+struct audit_skb_list {
+ struct hlist_node list;
+ void *memblk;
+ size_t size;
+};
/* Private Interface */
@@ -65,7 +70,7 @@ static inline void audit_pin(struct audi
}
static inline struct audit_wentry *audit_wentry_fetch(const char *name,
- struct audit_inode_data *data)
+ struct audit_inode_data *data)
{
struct audit_wentry *wentry, *ret = NULL;
struct hlist_node *pos;
@@ -166,7 +171,7 @@ static inline void *audit_to_transport(s
struct watch_transport t;
void *memblk;
- memblk = kmalloc(size, GFP_KERNEL);
+ memblk = kmalloc(size, GFP_ATOMIC);
if (!memblk)
goto audit_to_transport_exit;
@@ -300,9 +305,9 @@ static inline int audit_create_wentry(co
write_lock(&data->lock);
hlist_add_head(&new->w_node, &data->watchlist);
- spin_lock(&audit_master_watchlist_lock);
- hlist_add_head_rcu(&new->w_master, &audit_master_watchlist);
- spin_unlock(&audit_master_watchlist_lock);
+ spin_lock(&master_watchlist_lock);
+ hlist_add_head_rcu(&new->w_master, &master_watchlist);
+ spin_unlock(&master_watchlist_lock);
write_unlock(&data->lock);
audit_create_wentry_exit:
@@ -338,10 +343,10 @@ static inline void audit_destroy_wentry(
if (wentry) {
hlist_del_init(&wentry->w_node);
audit_wentry_put(wentry);
- spin_lock(&audit_master_watchlist_lock);
+ spin_lock(&master_watchlist_lock);
hlist_del_rcu(&wentry->w_master);
call_rcu(&wentry->w_rcu, audit_wentry_rcu_put);
- spin_unlock(&audit_master_watchlist_lock);
+ spin_unlock(&master_watchlist_lock);
}
}
@@ -531,27 +536,33 @@ void audit_update_watch(struct dentry *d
audit_wentry_put(wentry);
}
-int audit_send_watch(int pid, int seq, struct audit_watch *watch)
+/* Convert a watch to a audit_skb_list */
+struct audit_skb_list *audit_to_skb(struct audit_watch *watch)
{
- int ret;
size_t size;
void *memblk;
-
+ struct audit_skb_list *entry;
+
/* We must include space for both "\0" */
size = sizeof(struct watch_transport) + strlen(watch->path) +
- strlen(watch->filterkey) + 2;
-
- ret = -ENOMEM;
+ strlen(watch->filterkey) + 2;
+
+ entry = ERR_PTR(-ENOMEM);
memblk = audit_to_transport(watch, size);
if (!memblk)
- goto audit_send_watch_exit;
+ goto audit_queue_watch_exit;
- ret = 0;
- audit_send_reply(pid, seq, AUDIT_WATCH_LIST, 0, 1, memblk, size);
- kfree(memblk);
+ entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry) {
+ entry = ERR_PTR(-ENOMEM);
+ goto audit_queue_watch_exit;
+ }
+
+ entry->memblk = memblk;
+ entry->size = size;
-audit_send_watch_exit:
- return ret;
+audit_queue_watch_exit:
+ return entry;
}
/*
@@ -568,19 +579,40 @@ audit_send_watch_exit:
int audit_list_watches(int pid, int seq)
{
int ret = 0;
+ struct hlist_head skb_list;
+ struct hlist_node *tmp, *pos;
+ struct audit_skb_list *entry;
struct audit_wentry *wentry;
- struct hlist_node *pos;
+
+ INIT_HLIST_HEAD(&skb_list);
rcu_read_lock();
- hlist_for_each_entry_rcu(wentry, pos, &audit_master_watchlist, w_master) {
- ret = audit_send_watch(pid, seq, wentry->w_watch);
- if (ret < 0)
- break;
+ hlist_for_each_entry_rcu(wentry, pos, &master_watchlist, w_master) {
+ entry = audit_to_skb(wentry->w_watch);
+ if (IS_ERR(entry)) {
+ ret = PTR_ERR(entry);
+ goto audit_list_watches_fail;
+ }
+ hlist_add_head(&entry->list, &skb_list);
}
rcu_read_unlock();
- audit_send_reply(pid, seq, AUDIT_WATCH_LIST, 1, 1, NULL, 0);
+ hlist_for_each_entry_safe(entry, pos, tmp, &skb_list, list) {
+ audit_send_reply(pid, seq, AUDIT_WATCH_LIST, 0, 1,
+ entry->memblk, entry->size);
+ kfree(entry->memblk);
+ kfree(entry);
+ }
+ audit_send_reply(pid, seq, AUDIT_WATCH_LIST, 1, 1, NULL, 0);
+ goto audit_list_watches_exit;
+
+audit_list_watches_fail:
+ hlist_for_each_entry_safe(entry, pos, tmp, &skb_list, list) {
+ kfree(entry->memblk);
+ kfree(entry);
+ }
+audit_list_watches_exit:
return ret;
}
19 years, 7 months