[RFC] Create an audit record of USB specific details

From: wmealing
Date: Mon Apr 04 2016 - 00:04:02 EST


From: Wade Mealing <wmealing@xxxxxxxxxx>

Gday,

I'm looking to create an audit trail for when devices are added or removed
from the system.

The audit subsystem is a logging subsystem in kernel space that can be
used to create advanced filters on generated events. It has partnered userspace
utilities ausearch, auditd, aureport, auditctl which work exclusively on audit
records.

These tools are able to set filters to "trigger" on specific in-kernel events
specified by privileged users. While the userspace tools can create audit
events these are not able to be handled intelligently (decoded,filtered or
ignored) as kernel generated audit events are.

I have this working at the moment with the USB subsystem (as an example).
Its been suggested that I use systemd-udev however this means that the audit
tools (ausearch) will not be able to index these records.

Here is an example of picking out the AUDIT_DEVICE record type for example.

> # ausearch -l -i -ts today -m AUDIT_DEVICE
> ----
> type=AUDIT_DEVICE msg=audit(31/03/16 16:37:15.642:2) : action=add
> manufacturer=Linux 4.4.0-ktest ehci_hcd product=EHCI Host Controller
> serial=0000:00:06.7 major=189 minor=0 bus="usb"

Admittedly this is only the USB device type at the moment, but I'd like to break
this
out into other bus types at some time in the future, gotta start somewhere.

Thanks,

Wade Mealing

---
include/uapi/linux/audit.h | 1 +
init/Kconfig | 10 ++++++
kernel/Makefile | 1 +
kernel/audit_device.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 102 insertions(+)
create mode 100644 kernel/audit_device.c

diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index 843540c..344c97b 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -110,6 +110,7 @@
#define AUDIT_SECCOMP 1326 /* Secure Computing event */
#define AUDIT_PROCTITLE 1327 /* Proctitle emit event */
#define AUDIT_FEATURE_CHANGE 1328 /* audit log listing feature changes */
+#define AUDIT_DEVICE_CHANGE 1330 /* Device added/removed to the system */

#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
diff --git a/init/Kconfig b/init/Kconfig
index 2232080..e171f74 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -309,6 +309,16 @@ config AUDITSYSCALL
def_bool y
depends on AUDIT && HAVE_ARCH_AUDITSYSCALL

+config DEVICE_AUDIT
+ bool "Create audit records for devices added to the systems"
+ depends on AUDIT && USB
+ default y
+ help
+ Generate audit events in the system for USB devices that
+ are added or removed from the system from boot time onwards.
+ Records the manufacturer, product serial number, device major
+ and minor number and bus which the device was added to.
+
config AUDIT_WATCH
def_bool y
depends on AUDITSYSCALL
diff --git a/kernel/Makefile b/kernel/Makefile
index 53abf00..909c869 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o audit_fsnotify.o
obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
+obj-$(CONFIG_DEVICE_AUDIT) += audit_device.o
obj-$(CONFIG_GCOV_KERNEL) += gcov/
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_KGDB) += debug/
diff --git a/kernel/audit_device.c b/kernel/audit_device.c
new file mode 100644
index 0000000..8dfdf04
--- /dev/null
+++ b/kernel/audit_device.c
@@ -0,0 +1,90 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/usb.h>
+#include <linux/audit.h>
+#include <linux/kdev_t.h>
+
+static void log_string(struct audit_buffer *ab, char *key, char *val)
+{
+ if (val) {
+ audit_log_format(ab, " %s=", key);
+ audit_log_untrustedstring(ab, val);
+ }
+ else {
+ audit_log_format(ab, " %s=%s", key, "?");
+ }
+
+}
+
+static void log_major_minor(struct audit_buffer *ab, struct device *dev)
+{
+ if (dev && dev->devt) {
+ audit_log_format(ab, " major=%d", MAJOR(dev->devt));
+ audit_log_format(ab, " minor=%d", MINOR(dev->devt));
+ }
+}
+
+/* Blocking call when device has reference and will keep reference until
+ * all notifiers are done, no usb_dev_get/ usb_dev_put required.
+ */
+static int audit_notify(struct notifier_block *self,
+ unsigned long action, void *d)
+{
+ struct usb_device *usbdev = (struct usb_device *)d;
+ char *op;
+ struct audit_buffer *ab;
+
+ switch (action) {
+ case USB_DEVICE_ADD:
+ op = "add";
+ break;
+ case USB_DEVICE_REMOVE:
+ op = "remove";
+ break;
+ default: /* ignore any other USB events */
+ return NOTIFY_DONE;
+ }
+
+ ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_DEVICE_CHANGE);
+
+ if (ab) {
+ audit_log_format(ab, "action=%s", op);
+ log_string(ab, "manufacturer", usbdev->manufacturer);
+ log_string(ab, "product", usbdev->product);
+ log_string(ab, "serial", usbdev->serial);
+ log_major_minor(ab, &usbdev->dev);
+ log_string(ab, "bus", "usb");
+ audit_log_end(ab);
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block audit_nb = {
+ .notifier_call = audit_notify,
+ .priority = INT_MIN
+};
+
+static int __init audit_device_init(void)
+{
+ pr_info("Registering usb audit notification callback\n");
+ usb_register_notify(&audit_nb);
+ return 0;
+}
+
+static void __exit audit_device_exit(void)
+{
+ pr_info("Unregistering usb audit notification callback\n");
+ usb_unregister_notify(&audit_nb);
+}
+
+module_init(audit_device_init);
+module_exit(audit_device_exit);
+
+MODULE_LICENSE("GPL");
--
1.8.3.1