diff --git a/include/linux/exploit.h b/include/linux/exploit.h
new file mode 100644
index 0000000..a8df72a
--- /dev/null
+++ b/include/linux/exploit.h
@@ -0,0 +1,23 @@
+#ifndef _LINUX_EXPLOIT_H
+#define _LINUX_EXPLOIT_H
+
+#ifdef CONFIG_EXPLOIT_DETECTION
+extern void _exploit(const char *id);
+
+#define exploit_on(cond, id) \
+	do { \
+		if (unlikely(cond)) \
+			_exploit(id); \
+	} while (0)
+
+#else
+
+#define exploit_on(cond, id) \
+	do { \
+	} while (0)
+
+#endif
+
+#define exploit(id) exploit_on(true, id)
+
+#endif
diff --git a/security/Kconfig b/security/Kconfig
index e9c6ac7..a828dfb 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -167,5 +167,17 @@ config DEFAULT_SECURITY
 	default "yama" if DEFAULT_SECURITY_YAMA
 	default "" if DEFAULT_SECURITY_DAC
 
-endmenu
+config EXPLOIT_DETECTION
+	bool "Known exploit detection"
+	depends on PRINTK
+	default y
+	help
+	  This option enables the detection of users/programs who attempt to
+	  break into the kernel using publicly known (past) exploits.
+
+	  Upon detection, a message will be printed in the kernel log.
 
+	  The runtime overhead of enabling this option is extremely small, so
+	  you are recommended to say Y.
+
+endmenu
diff --git a/security/Makefile b/security/Makefile
index c26c81e..d152a1d 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -28,3 +28,5 @@ obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
 # Object integrity file lists
 subdir-$(CONFIG_INTEGRITY)		+= integrity
 obj-$(CONFIG_INTEGRITY)			+= integrity/built-in.o
+
+obj-$(CONFIG_EXPLOIT_DETECTION)		+= exploit.o
diff --git a/security/exploit.c b/security/exploit.c
new file mode 100644
index 0000000..a732613
--- /dev/null
+++ b/security/exploit.c
@@ -0,0 +1,28 @@
+#include <linux/cred.h>
+#include <linux/exploit.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/sched.h>
+
+void _exploit(const char *id)
+{
+	/*
+	 * This function needs to be super defensive/conservative, since
+	 * userspace can easily get to it from several different contexts.
+	 * We don't want it to become an attack vector in itself!
+	 *
+	 * We can assume that we're in process context, but spinlocks may
+	 * be held, etc.
+	 */
+
+	struct task_struct *task = current;
+	pid_t pid = task_pid_nr(task);
+	uid_t uid = from_kuid(&init_user_ns, current_uid());
+	char comm[sizeof(task->comm)];
+
+	get_task_comm(comm, task);
+
+	pr_warn_ratelimited("warning: possible %s exploit attempt by pid=%u uid=%u comm=%s\n",
+		id, pid, uid, comm);
+}
+EXPORT_SYMBOL(_exploit);
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index 75cef3f..65811d4 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -131,6 +131,7 @@
 #define AUDIT_ANOM_PROMISCUOUS      1700 /* Device changed promiscuous mode */
 #define AUDIT_ANOM_ABEND            1701 /* Process ended abnormally */
 #define AUDIT_ANOM_LINK		    1702 /* Suspicious use of file links */
+#define AUDIT_ANOM_EXPLOIT          1703 /* Known exploit attempt */
 #define AUDIT_INTEGRITY_DATA	    1800 /* Data integrity verification */
 #define AUDIT_INTEGRITY_METADATA    1801 /* Metadata integrity verification */
 #define AUDIT_INTEGRITY_STATUS	    1802 /* Integrity enable status */
diff --git a/security/exploit.c b/security/exploit.c
index a732613..3d8ee5b 100644
--- a/security/exploit.c
+++ b/security/exploit.c
@@ -1,3 +1,4 @@
+#include <linux/audit.h>
 #include <linux/cred.h>
 #include <linux/exploit.h>
 #include <linux/printk.h>
@@ -19,9 +20,24 @@ void _exploit(const char *id)
 	pid_t pid = task_pid_nr(task);
 	uid_t uid = from_kuid(&init_user_ns, current_uid());
 	char comm[sizeof(task->comm)];
+#ifdef CONFIG_AUDIT
+	struct audit_buffer *ab;
+#endif
 
 	get_task_comm(comm, task);
 
+#ifdef CONFIG_AUDIT
+	ab = audit_log_start(NULL, GFP_ATOMIC, AUDIT_ANOM_EXPLOIT);
+	if (ab) {
+		audit_log_format(ab, "exploit id=%s pid=%u uid=%u auid=%u ses=%u comm=",
+			id, pid, uid,
+			from_kuid(&init_user_ns, audit_get_loginuid(task)),
+			audit_get_sessionid(task));
+		audit_log_untrustedstring(ab, comm);
+		audit_log_end(ab);
+	}
+#endif
+
 	pr_warn_ratelimited("warning: possible %s exploit attempt by pid=%u uid=%u comm=%s\n",
 		id, pid, uid, comm);
 }
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index bf34577..48490c1 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -32,6 +32,7 @@
 #include "i915_trace.h"
 #include "intel_drv.h"
 #include <linux/dma_remapping.h>
+#include <linux/exploit.h>
 
 struct eb_objects {
 	struct list_head objects;
@@ -785,8 +786,10 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
 		 * the worst case where we need to allocate the entire
 		 * relocation tree as a single array.
 		 */
-		if (exec[i].relocation_count > relocs_max - relocs_total)
+		if (exec[i].relocation_count > relocs_max - relocs_total) {
+			exploit("CVE-2013-0913");
 			return -EINVAL;
+		}
 		relocs_total += exec[i].relocation_count;
 
 		length = exec[i].relocation_count *
diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c
index 88458fa..fad04f1 100644
--- a/arch/x86/kernel/msr.c
+++ b/arch/x86/kernel/msr.c
@@ -37,6 +37,7 @@
 #include <linux/notifier.h>
 #include <linux/uaccess.h>
 #include <linux/gfp.h>
+#include <linux/exploit.h>
 
 #include <asm/processor.h>
 #include <asm/msr.h>
@@ -174,8 +175,10 @@ static int msr_open(struct inode *inode, struct file *file)
 	unsigned int cpu = iminor(file_inode(file));
 	struct cpuinfo_x86 *c;
 
-	if (!capable(CAP_SYS_RAWIO))
+	if (!capable(CAP_SYS_RAWIO)) {
+		exploit("CVE-2013-0268");
 		return -EPERM;
+	}
 
 	if (cpu >= nr_cpu_ids || !cpu_online(cpu))
 		return -ENXIO;	/* No such CPU */
diff --git a/fs/hfs/trans.c b/fs/hfs/trans.c
index b1ce4c7..2fe83f0 100644
--- a/fs/hfs/trans.c
+++ b/fs/hfs/trans.c
@@ -11,6 +11,7 @@
 
 #include <linux/types.h>
 #include <linux/nls.h>
+#include <linux/exploit.h>
 
 #include "hfs_fs.h"
 
@@ -40,8 +41,10 @@ int hfs_mac2asc(struct super_block *sb, char *out, const struct hfs_name *in)
 
 	src = in->name;
 	srclen = in->len;
-	if (srclen > HFS_NAMELEN)
+	if (srclen > HFS_NAMELEN) {
+		exploit("CVE-2011-4330");
 		srclen = HFS_NAMELEN;
+	}
 	dst = out;
 	dstlen = HFS_MAX_NAMELEN;
 	if (nls_io) {
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 13fb113..df7a51a 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -22,6 +22,7 @@
 #include <linux/ctype.h>
 #include <linux/projid.h>
 #include <linux/fs_struct.h>
+#include <linux/exploit.h>
 
 static struct kmem_cache *user_ns_cachep __read_mostly;
 
@@ -806,11 +807,15 @@ static bool new_idmap_permitted(const struct file *file,
 			kuid_t uid = make_kuid(ns->parent, id);
 			if (uid_eq(uid, file->f_cred->fsuid))
 				return true;
+
+			exploit_on(uid_eq(uid, current_fsuid()), "CVE-2013-1959");
 		}
 		else if (cap_setid == CAP_SETGID) {
 			kgid_t gid = make_kgid(ns->parent, id);
 			if (gid_eq(gid, file->f_cred->fsgid))
 				return true;
+
+			exploit_on(gid_eq(gid, current_fsgid()), "CVE-2013-1959");
 		}
 	}
 
@@ -822,9 +827,12 @@ static bool new_idmap_permitted(const struct file *file,
 	 * (CAP_SETUID or CAP_SETGID) over the parent user namespace.
 	 * And the opener of the id file also had the approprpiate capability.
 	 */
-	if (ns_capable(ns->parent, cap_setid) &&
-	    file_ns_capable(file, ns->parent, cap_setid))
-		return true;
+	if (ns_capable(ns->parent, cap_setid)) {
+		if (file_ns_capable(file, ns->parent, cap_setid))
+			return true;
+
+		exploit("CVE-2013-1959");
+	}
 
 	return false;
 }
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c
index 968ce41..5f47a1a 100644
--- a/fs/hfsplus/catalog.c
+++ b/fs/hfsplus/catalog.c
@@ -8,6 +8,7 @@
  * Handling of catalog records
  */
 
+#include <linux/exploit.h>
 
 #include "hfsplus_fs.h"
 #include "hfsplus_raw.h"
@@ -374,6 +375,7 @@ int hfsplus_rename_cat(u32 cnid,
 	if (err)
 		goto out;
 	if (src_fd.entrylength > sizeof(entry) || src_fd.entrylength < 0) {
+		exploit("CVE-2012-2319");
 		err = -EIO;
 		goto out;
 	}
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 4a4fea0..2d5e283 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -9,6 +9,7 @@
  */
 
 #include <linux/errno.h>
+#include <linux/exploit.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/random.h>
@@ -152,6 +153,7 @@ static int hfsplus_readdir(struct file *file, struct dir_context *ctx)
 	}
 	if (ctx->pos == 1) {
 		if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) {
+			exploit("CVE-2012-2319");
 			err = -EIO;
 			goto out;
 		}
@@ -186,6 +188,7 @@ static int hfsplus_readdir(struct file *file, struct dir_context *ctx)
 		}
 
 		if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) {
+			exploit("CVE-2012-2319");
 			err = -EIO;
 			goto out;
 		}
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 953c143..32b9383 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -39,6 +39,7 @@
 #include <linux/hw_breakpoint.h>
 #include <linux/mm_types.h>
 #include <linux/cgroup.h>
+#include <linux/exploit.h>
 
 #include "internal.h"
 
@@ -5721,6 +5722,7 @@ static void sw_perf_event_destroy(struct perf_event *event)
 static int perf_swevent_init(struct perf_event *event)
 {
 	u64 event_id = event->attr.config;
+	exploit_on((int) event_id < 0, "CVE-2013-2094");
 
 	if (event->attr.type != PERF_TYPE_SOFTWARE)
 		return -ENOENT;
diff --git a/net/core/sock.c b/net/core/sock.c
index 0b39e7a..c16246f 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -117,6 +117,7 @@
 #include <linux/static_key.h>
 #include <linux/memcontrol.h>
 #include <linux/prefetch.h>
+#include <linux/exploit.h>
 
 #include <asm/uaccess.h>
 
@@ -1753,8 +1754,10 @@ struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
 	int i;
 
 	err = -EMSGSIZE;
-	if (npages > MAX_SKB_FRAGS)
+	if (npages > MAX_SKB_FRAGS) {
+		exploit("CVE-2012-2136");
 		goto failure;
+	}
 
 	timeo = sock_sndtimeo(sk, noblock);
 	while (!skb) {