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 +#include +#include +#include +#include + +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 #include #include #include @@ -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 +#include 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 #include #include +#include #include #include @@ -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 #include +#include #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 #include #include +#include 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 #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 +#include #include #include #include @@ -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 #include #include +#include #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 #include #include +#include #include @@ -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) {