When the specified path is an existing file or when it is a symlink, audit
collects the wrong inode number, which causes it to miss the open() event.
Adding a second hook to the open() path fixes this.
Also add audit_copy_inode() to consolidate some code.
Signed-off-by: Amy Griffis <amy.griffis(a)hp.com>
---
fs/namei.c | 2 ++
include/linux/audit.h | 7 +++++
kernel/auditsc.c | 63 ++++++++++++++++++++++++++++++++-----------------
3 files changed, 50 insertions(+), 22 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 184fe4a..8904b4f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1659,6 +1659,7 @@ do_last:
* It already exists.
*/
mutex_unlock(&dir->d_inode->i_mutex);
+ audit_inode_update(path.dentry->d_inode);
error = -EEXIST;
if (flag & O_EXCL)
@@ -1669,6 +1670,7 @@ do_last:
if (flag & O_NOFOLLOW)
goto exit_dput;
}
+
error = -ENOENT;
if (!path.dentry->d_inode)
goto exit_dput;
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 9fcafaf..c63f204 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -328,6 +328,7 @@ extern void audit_putname(const char *na
extern void __audit_inode(const char *name, const struct inode *inode);
extern void __audit_inode_child(const char *dname, const struct inode *inode,
unsigned long pino);
+extern void __audit_inode_update(const struct inode *inode);
static inline void audit_getname(const char *name)
{
if (unlikely(current->audit_context))
@@ -343,6 +344,10 @@ static inline void audit_inode_child(con
if (unlikely(current->audit_context))
__audit_inode_child(dname, inode, pino);
}
+static inline void audit_inode_update(const struct inode *inode) {
+ if (unlikely(current->audit_context))
+ __audit_inode_update(inode);
+}
/* Private API (for audit.c only) */
extern unsigned int audit_serial(void);
@@ -414,8 +419,10 @@ #define audit_getname(n) do { ; } while
#define audit_putname(n) do { ; } while (0)
#define __audit_inode(n,i) do { ; } while (0)
#define __audit_inode_child(d,i,p) do { ; } while (0)
+#define __audit_inode_update(i) do { ; } while (0)
#define audit_inode(n,i) do { ; } while (0)
#define audit_inode_child(d,i,p) do { ; } while (0)
+#define audit_inode_update(i) do { ; } while (0)
#define auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
#define audit_get_loginuid(c) ({ -1; })
#define audit_ipc_obj(i) ({ 0; })
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 53d2d74..0bc584d 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1200,14 +1200,18 @@ #if AUDIT_DEBUG
#endif
}
-static void audit_inode_context(int idx, const struct inode *inode)
+/* Copy inode data into an audit_names. */
+static void audit_copy_inode(struct audit_names *name, const struct inode *inode)
{
- struct audit_context *context = current->audit_context;
-
- selinux_get_inode_sid(inode, &context->names[idx].osid);
+ name->ino = inode->i_ino;
+ name->dev = inode->i_sb->s_dev;
+ name->mode = inode->i_mode;
+ name->uid = inode->i_uid;
+ name->gid = inode->i_gid;
+ name->rdev = inode->i_rdev;
+ selinux_get_inode_sid(inode, &name->osid);
}
-
/**
* audit_inode - store the inode and device from a lookup
* @name: name being audited
@@ -1241,13 +1245,7 @@ #if AUDIT_DEBUG
++context->ino_count;
#endif
}
- context->names[idx].ino = inode->i_ino;
- context->names[idx].dev = inode->i_sb->s_dev;
- context->names[idx].mode = inode->i_mode;
- context->names[idx].uid = inode->i_uid;
- context->names[idx].gid = inode->i_gid;
- context->names[idx].rdev = inode->i_rdev;
- audit_inode_context(idx, inode);
+ audit_copy_inode(&context->names[idx], inode);
}
/**
@@ -1303,16 +1301,37 @@ #endif
context->names[idx].name_len = AUDIT_NAME_FULL;
context->names[idx].name_put = 0; /* don't call __putname() */
- if (inode) {
- context->names[idx].ino = inode->i_ino;
- context->names[idx].dev = inode->i_sb->s_dev;
- context->names[idx].mode = inode->i_mode;
- context->names[idx].uid = inode->i_uid;
- context->names[idx].gid = inode->i_gid;
- context->names[idx].rdev = inode->i_rdev;
- audit_inode_context(idx, inode);
- } else
- context->names[idx].ino = (unsigned long)-1;
+ if (!inode)
+ context->names[idx].ino = (unsigned long)-1;
+ else
+ audit_copy_inode(&context->names[idx], inode);
+}
+
+/**
+ * audit_inode_update - update inode info for last collected name
+ * @inode: inode being audited
+ *
+ * When open() is called on an existing object with the O_CREAT flag, the inode
+ * data audit initially collects is incorrect. This additional hook ensures
+ * audit has the inode data for the actual object to be opened.
+ */
+void __audit_inode_update(const struct inode *inode)
+{
+ struct audit_context *context = current->audit_context;
+ int idx;
+
+ if (!context->in_syscall || !inode)
+ return;
+
+ if (context->name_count == 0) {
+ context->name_count++;
+#if AUDIT_DEBUG
+ context->ino_count++;
+#endif
+ }
+ idx = context->name_count - 1;
+
+ audit_copy_inode(&context->names[idx], inode);
}
/**
--
1.4.0