From patchwork Fri Sep 22 02:49:59 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?5Lit5p2R6ZuE5LiAIC8gTkFLQU1VUkHvvIxZVVVJQ0hJ?= X-Patchwork-Id: 9965207 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 401F56020C for ; Fri, 22 Sep 2017 06:11:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3032628923 for ; Fri, 22 Sep 2017 06:11:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2457C2915D; Fri, 22 Sep 2017 06:11:37 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.wl.linuxfoundation.org (Postfix) with SMTP id EBD1528923 for ; Fri, 22 Sep 2017 06:11:34 +0000 (UTC) Received: (qmail 20292 invoked by uid 550); 22 Sep 2017 06:11:33 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Delivered-To: moderator for kernel-hardening@lists.openwall.com Received: (qmail 19855 invoked from network); 22 Sep 2017 02:50:13 -0000 From: =?iso-2022-jp?B?GyRCQ2ZCPE06MGwbKEIgLyBOQUtBTVVSQRskQiEkGyhCWVVVSUNISQ==?= To: "kernel-hardening@lists.openwall.com" CC: "yamauchi@cs.okayama-u.ac.jp" Thread-Topic: [RFC] A method to prevent priviledge escalation Thread-Index: AdMy1fslLgwGRPLgQTK1BBw3uiFsFg== Date: Fri, 22 Sep 2017 02:49:59 +0000 Message-ID: Accept-Language: ja-JP, en-US Content-Language: ja-JP X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.215.64.220] MIME-Version: 1.0 X-TM-AS-GCONF: 00 Subject: [kernel-hardening] [RFC] A method to prevent priviledge escalation X-Virus-Scanned: ClamAV using ClamSMTP Hi. As we said in Linux Security Summit 2017, we would like to post a patch to prevent privilege escalation attack. The concept is here: http://events.linuxfoundation.org/sites/events/files/slides/nakamura_20170831_1.pdf This work is still work in progress and feedback is welcomed. Below patch works for linux-4.4.0, To see that it works (try it in a safe place!), * build vulnerable kernel on Ubuntu 16.04.1 source: https://launchpad.net/ubuntu/+source/linux/4.4.0-62.83 please enable "CONFIG_AKO" in kernel config. * try a poc code for kernel vulnerability https://github.com/xairy/kernel-exploits/blob/master/CVE-2017-6074/poc.c * look at kernel log, you can see a log that it detected attack like below: AKO: detected unauthorized change of UID. syscall=45 original: uid=1000, euid=1000, fsuid=1000, suid=1000 attempt: uid=0, euid=0, fsuid=0, suid=0 AKO: detected unauthorized change of gid. syscall=45 original: gid=1000, egid=1000, fsgid=1000, sgid=1000 attempt: gid=0, egid=0, fsgid=0, sgid=0 Regards, Yuichi Nakamura, Hitachi,Ltd. Toshihiro Yamauchi, Okayama University --- linux-4.4.0-62-83.orig/arch/x86/kernel/ako.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-4.4.0/arch/x86/kernel/ako.c 2017-07-02 17:43:15.780000000 +0900 @@ -0,0 +1,55 @@ +/* + * Additional Kernel Observer (AKO) + * CPU specific part + * Copyright 2017 Okayama-University + * Yohei Akao, Yamauchi Laboratory + * Copyright 2017 Hitachi,Ltd. + * Yuichi Nakamura + */ + +#include +#include +#include + +asmlinkage void AKO_before(struct ako_struct * ako_cred, unsigned long long ako_sysnum) +{ + /* Called at the entry of system calls, + credential data are saved to detect priviledge escalation attacks + that exploit vulnerabilites of system calls. + */ + + /*save system call number*/ + ako_cred->ako_sysnum = ako_sysnum; + + /*System calls that change credential are skipped*/ + if(!AKO_syscall_checked(ako_sysnum)) + return; + + /*credential data are saved*/ + AKO_save_creds(ako_cred,ako_sysnum); + /*addr_limit is saved*/ + ako_cred->ako_addr_limit = current_thread_info()->addr_limit.seg; + +} + + +asmlinkage void AKO_after(struct ako_struct * ako_cred) +{ + /*System calls that change credential are skipped*/ + if(!AKO_syscall_checked(ako_cred->ako_sysnum)) + return; + + /*check addr_limit, restore if changed*/ +/* if(current_thread_info()->addr_limit.seg != ako_cred->ako_addr_limit){ + audit_AKO_rlimit(ako_cred, current_thread_info()->addr_limit.seg); + current_thread_info()->addr_limit.seg = ako_cred->ako_addr_limit; + audit_AKO_restore(ako_cred, "addr_limit"); + return ; + } */ + + /*check credentials, and restore if changed*/ + AKO_check_creds(ako_cred); + + return; +} + --- linux-4.4.0-62-83.orig/kernel/ako.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-4.4.0/kernel/ako.c 2017-07-03 23:06:54.068000000 +0900 @@ -0,0 +1,389 @@ +/* + * Additional Kernel Observer (AKO) + * Common features + * Copyright 2017 Okayama-University + * Yohei Akao, Yamauchi Laboratory + * Copyright 2017 Hitachi,Ltd. + * Yuichi Nakamura + */ + +#include +#include +#include +#include + +#include +#include +#include "audit.h" + +void audit_AKO_rlimit(struct ako_struct * ako_cred, unsigned long current_addr_limit) { + /*This is called from arch/xx/ako.c*/ + struct audit_buffer *ab; + + printk(KERN_INFO "AKO: detected unauthorized change of addr_limit: syscall=%u original: 0x%lx, attempt: 0x%lx", ako_cred->ako_sysnum, ako_cred->ako_addr_limit,current_addr_limit); + if(!audit_enabled) { + return; + } + ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_SYSCALL); + if (unlikely(!ab)) + return; + + audit_log_format(ab, "AKO: detected unauthorized change of addr_limit: syscall=%u original: 0x%lx, attempt: 0x%lx", ako_cred->ako_sysnum, ako_cred->ako_addr_limit,current_addr_limit); + audit_log_d_path_exe(ab, current->mm); + audit_log_end(ab); + return; +} + +void audit_AKO_restore(struct ako_struct * ako_cred, const char * cred_type) +{ + struct audit_buffer *ab; + + printk(KERN_INFO "AKO: restored credential:%s syscall=%u", cred_type, ako_cred->ako_sysnum); + if(!audit_enabled) { + return; + } + ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_SYSCALL); + if (unlikely(!ab)) + return; + + audit_log_format(ab, "AKO: restored credential:%s syscall=%u", cred_type, + ako_cred->ako_sysnum); + + audit_log_d_path_exe(ab, current->mm); + audit_log_end(ab); +} + +static void audit_AKO_uid(struct ako_struct * ako_cred) +{ + struct audit_buffer *ab; + const struct cred *ccred; + ccred = current->cred; + + printk(KERN_INFO "AKO: detected unauthorized change of UID. syscall=%u original: uid=%u, euid=%u, fsuid=%u, suid=%u attempt: uid=%u, euid=%u, fsuid=%u, suid=%u", ako_cred->ako_sysnum, + ako_cred->ako_uid, ako_cred->ako_euid, ako_cred->ako_fsuid, ako_cred->ako_suid, + ccred->uid.val, ccred->euid.val, current_fsuid().val, ccred->suid.val); + + if(!audit_enabled) { + return; + } + + ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_SYSCALL); + if (unlikely(!ab)) + return; + audit_log_format(ab, "AKO: detected unauthorized change of UID. syscall=%u original: uid=%u, euid=%u, fsuid=%u, suid=%u attempt: uid=%u, euid=%u, fsuid=%u, suid=%u", ako_cred->ako_sysnum, + ako_cred->ako_uid, ako_cred->ako_euid, ako_cred->ako_fsuid, ako_cred->ako_suid, + ccred->uid.val, ccred->euid.val, ccred->fsuid.val, ccred->suid.val); + + audit_log_d_path_exe(ab, current->mm); + audit_log_end(ab); + + return; +} + +static void audit_AKO_gid(struct ako_struct * ako_cred) +{ + struct audit_buffer *ab; + const struct cred *ccred; + ccred = current->cred; + + printk(KERN_INFO "AKO: detected unauthorized change of gid. syscall=%u original: gid=%u, egid=%u, fsgid=%u, sgid=%u attempt: gid=%u, egid=%u, fsgid=%u, sgid=%u", ako_cred->ako_sysnum, + ako_cred->ako_gid, ako_cred->ako_egid, ako_cred->ako_fsgid, ako_cred->ako_sgid, + ccred->gid.val, ccred->egid.val, ccred->fsgid.val, ccred->sgid.val); + + if(!audit_enabled) { + return; + } + + ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_SYSCALL); + if (unlikely(!ab)) + return; + audit_log_format(ab, "AKO: detected unauthorized change of gid. syscall=%u original: gid=%u, egid=%u, fsgid=%u, sgid=%u attempt: gid=%u, egid=%u, fsgid=%u, sgid=%u", ako_cred->ako_sysnum, + ako_cred->ako_gid, ako_cred->ako_egid, ako_cred->ako_fsgid, ako_cred->ako_sgid, + ccred->gid.val, ccred->egid.val, ccred->fsgid.val, ccred->sgid.val); + + audit_log_d_path_exe(ab, current->mm); + audit_log_end(ab); + + return; +} + +static void audit_AKO_cap(struct ako_struct * ako_cred) +{ + struct audit_buffer *ab; + const struct cred *ccred; + ccred = current->cred; + + printk(KERN_INFO "AKO: detected unauthorized change of capability. syscall=%u original: inh[0]=%u inh[1]=%u per[0]=%u per[1]=%u eff[0]=%u eff[1]%u bset[0]=%u bset[1]=%u attempt: inh[0]=%u inh[1]=%u per[0]=%u per[1]=%u eff[0]=%u eff[1]%u bset[0]=%u bset[1]=%u", + ako_cred->ako_sysnum, + ako_cred->ako_inheritable[0], ako_cred->ako_inheritable[1], + ako_cred->ako_permitted[0], ako_cred->ako_permitted[1], + ako_cred->ako_effective[0], ako_cred->ako_effective[1], + ako_cred->ako_bset[0], ako_cred->ako_bset[1], + ccred->cap_inheritable.cap[0], ccred->cap_inheritable.cap[1], + ccred->cap_permitted.cap[0], ccred->cap_permitted.cap[1], + ccred->cap_effective.cap[0], ccred->cap_effective.cap[1], + ccred->cap_bset.cap[0], ccred->cap_bset.cap[1]); + + if (!audit_enabled) + return; + ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_SYSCALL); + if (unlikely(!ab)) + return; + + audit_log_format(ab, "AKO: detected unauthorized change of capability. syscall=%u original: inh[0]=%u inh[1]=%u per[0]=%u per[1]=%u eff[0]=%u eff[1]%u bset[0]=%u bset[1]=%u attempt: inh[0]=%u inh[1]=%u per[0]=%u per[1]=%u eff[0]=%u eff[1]%u bset[0]=%u bset[1]=%u", + ako_cred->ako_sysnum, + ako_cred->ako_inheritable[0], ako_cred->ako_inheritable[1], + ako_cred->ako_permitted[0], ako_cred->ako_permitted[1], + ako_cred->ako_effective[0], ako_cred->ako_effective[1], + ako_cred->ako_bset[0], ako_cred->ako_bset[1], + ccred->cap_inheritable.cap[0], ccred->cap_inheritable.cap[1], + ccred->cap_permitted.cap[0], ccred->cap_permitted.cap[1], + ccred->cap_effective.cap[0], ccred->cap_effective.cap[1], + ccred->cap_bset.cap[0], ccred->cap_bset.cap[1]); + + audit_log_d_path_exe(ab, current->mm); + audit_log_end(ab); + + return; +} + + + +void AKO_save_creds(struct ako_struct * ako_cred, int ako_sysnum) +{ + + /*Save credential information to be observed */ + /*UID and GID*/ + ako_cred->ako_uid = current->cred->uid.val; + ako_cred->ako_euid = current->cred->euid.val; + ako_cred->ako_fsuid = current->cred->fsuid.val; + ako_cred->ako_suid = current->cred->suid.val; + ako_cred->ako_gid = current->cred->gid.val; + ako_cred->ako_egid = current->cred->egid.val; + ako_cred->ako_fsgid = current->cred->fsgid.val; + ako_cred->ako_sgid = current->cred->sgid.val; + /*Capability*/ + ako_cred->ako_inheritable[0] = current->cred->cap_inheritable.cap[0]; + ako_cred->ako_inheritable[1] = current->cred->cap_inheritable.cap[1]; + ako_cred->ako_permitted[0] = current->cred->cap_permitted.cap[0]; + ako_cred->ako_permitted[1] = current->cred->cap_permitted.cap[1]; + ako_cred->ako_effective[0] = current->cred->cap_effective.cap[0]; + ako_cred->ako_effective[1] = current->cred->cap_effective.cap[1]; + ako_cred->ako_bset[0] = current->cred->cap_bset.cap[0]; + ako_cred->ako_bset[1] = current->cred->cap_bset.cap[1]; + + return; +} + +/*copy from sys.c*/ +static int set_user(struct cred *new) +{ + struct user_struct *new_user; + + new_user = alloc_uid(new->uid); + if (!new_user) + return -EAGAIN; + + /* + * We don't fail in case of NPROC limit excess here because too many + * poorly written programs don't check set*uid() return code, assuming + * it never fails if called by root. We may still enforce NPROC limit + * for programs doing set*uid()+execve() by harmlessly deferring the + * failure to the execve() stage. + */ + if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) && + new_user != INIT_USER) + current->flags |= PF_NPROC_EXCEEDED; + else + current->flags &= ~PF_NPROC_EXCEEDED; + + free_uid(new->user); + new->user = new_user; + return 0; +} + + +static int AKO_restore_uids(struct ako_struct * ako_cred) +{ + struct cred *new; + struct user_namespace *ns = current_user_ns(); + kuid_t uid; + kuid_t suid; + kuid_t euid; + kuid_t fsuid; + kernel_cap_t effective, permitted; + + new = prepare_creds(); + if (!new) + return -ENOMEM; + + uid = make_kuid(ns, ako_cred->ako_uid); + if (!uid_valid(uid)) + return -EINVAL; + suid = make_kuid(ns, ako_cred->ako_suid); + if (!uid_valid(suid)) + return -EINVAL; + euid = make_kuid(ns, ako_cred->ako_euid); + if (!uid_valid(euid)) + return -EINVAL; + fsuid = make_kuid(ns, ako_cred->ako_fsuid); + if (!uid_valid(fsuid)) + return -EINVAL; + new->uid = uid; + new->suid = suid; + new->euid = euid; + new->fsuid = fsuid; + + /*clear capabilities*/ + effective.cap[0] = 0; + effective.cap[1] = 0; + permitted.cap[0] = 0; + permitted.cap[1] = 0; + new->cap_effective = effective; + new->cap_permitted = permitted; + + set_user(new); + commit_creds(new); + return 0; +} + +static int AKO_restore_gids(struct ako_struct * ako_cred) +{ + struct cred *new; + struct user_namespace *ns = current_user_ns(); + kgid_t gid; + kgid_t sgid; + kgid_t egid; + kgid_t fsgid; + kernel_cap_t effective, permitted; + + new = prepare_creds(); + if (!new) + return -ENOMEM; + + gid = make_kgid(ns, ako_cred->ako_gid); + if (!gid_valid(gid)) + return -EINVAL; + sgid = make_kgid(ns, ako_cred->ako_sgid); + if (!gid_valid(sgid)) + return -EINVAL; + egid = make_kgid(ns, ako_cred->ako_egid); + if (!gid_valid(egid)) + return -EINVAL; + fsgid = make_kgid(ns, ako_cred->ako_fsgid); + if (!gid_valid(fsgid)) + return -EINVAL; + new->gid = gid; + new->sgid = sgid; + new->egid = egid; + new->fsgid = fsgid; + + /*clear capabilities*/ + effective.cap[0] = 0; + effective.cap[1] = 0; + permitted.cap[0] = 0; + permitted.cap[1] = 0; + new->cap_effective = effective; + new->cap_permitted = permitted; + + commit_creds(new); + + return 0; +} +static int AKO_restore_caps(struct ako_struct * ako_cred) +{ + struct cred *new; + kernel_cap_t inheritable, permitted, effective, bset; + unsigned i; + new = prepare_creds(); + if (!new) + return -ENOMEM; + + for (i = 0; i<2; i++) { + inheritable.cap[i] = ako_cred->ako_inheritable[i]; + permitted.cap[i] = ako_cred->ako_permitted[i]; + effective.cap[i] = ako_cred->ako_effective[i]; + bset.cap[i] = ako_cred->ako_bset[i]; + } + + new->cap_effective = effective; + new->cap_inheritable = inheritable; + new->cap_permitted = permitted; + new->cap_bset = bset; + + commit_creds(new); + + return 0; +} + +inline int AKO_syscall_checked(int sysnum) +{ + /*Since following system calls change credential information, + AKO does not detect attacks for them*/ + + if((sysnum == __NR_execve) || (sysnum == __NR_setuid) || (sysnum == __NR_setgid) || (sysnum == __NR_setreuid) || + (sysnum == __NR_setregid) || (sysnum == __NR_setresuid) || (sysnum == __NR_setresgid) || (sysnum == __NR_setfsuid) || + (sysnum == __NR_setfsgid) || (sysnum == __NR_capset) || (sysnum == __NR_prctl) || (sysnum == __NR_unshare) ){ + return 0; + } + return 1; + +} + +void AKO_check_creds(struct ako_struct * ako_cred) +{ + /*Called at the exit of system call */ + /*Compare credntial information before the systemcall + if changed, the information is restored and logged*/ + int uid_modified = 0; + int gid_modified = 0; + int cap_modified = 0; + + /*check uids*/ + if(ako_cred->ako_uid != current->cred->uid.val || ako_cred->ako_euid != current->cred->euid.val || ako_cred->ako_fsuid != current->cred->fsuid.val || + ako_cred->ako_suid != current->cred->suid.val){ + audit_AKO_uid(ako_cred); + uid_modified = 1; + } + + /*Check gids*/ + if(ako_cred->ako_gid != current->cred->gid.val || ako_cred->ako_egid != current->cred->egid.val || ako_cred->ako_fsgid != current->cred->fsgid.val || + ako_cred->ako_sgid != current->cred->sgid.val){ + audit_AKO_gid(ako_cred); + gid_modified = 1; + } + /*Check capabilities*/ + if(ako_cred->ako_inheritable[0] != current->cred->cap_inheritable.cap[0] || ako_cred->ako_inheritable[1] != current->cred->cap_inheritable.cap[1] || + ako_cred->ako_permitted[0] != current->cred->cap_permitted.cap[0] || ako_cred->ako_permitted[1] != current->cred->cap_permitted.cap[1] || + ako_cred->ako_effective[0] != current->cred->cap_effective.cap[0] || ako_cred->ako_effective[1] != current->cred->cap_effective.cap[1] || + ako_cred->ako_bset[0] != current->cred->cap_bset.cap[0] || ako_cred->ako_bset[1] != current->cred->cap_bset.cap[1] ){ + audit_AKO_cap(ako_cred); + cap_modified = 1; + } + + /*restore creds if modified*/ + if (uid_modified) { + /*Restore uids*/ + if(!AKO_restore_uids(ako_cred)) + audit_AKO_restore(ako_cred,"uids"); + else + do_exit(SIGKILL); + + } + if (gid_modified) { + /*Restore gids*/ + if(!AKO_restore_gids(ako_cred)) + audit_AKO_restore(ako_cred,"gids"); + else + do_exit(SIGKILL); + } + if (cap_modified) { + /*restore capabilities*/ + if(!AKO_restore_caps(ako_cred)) + audit_AKO_restore(ako_cred,"capabilities"); + else + do_exit(SIGKILL); + } + + return; +} --- linux-4.4.0-62-83.orig/include/linux/ako.h 1970-01-01 09:00:00.000000000 +0900 +++ linux-4.4.0/include/linux/ako.h 2017-07-04 22:33:45.188000000 +0900 @@ -0,0 +1,35 @@ +#ifndef __LINUX__AKO_H +#define __LINUX__AKO_H +/* + * Additional Kernel Observer (AKO) + * Copyright (c) 2017 Okayama-University + * Yohei Akao, Yamauchi Laboratory, Okayama University + * Copyright (c) 2017 Hitachi,Ltd. + * Yuichi Nakamura + */ + +struct ako_struct{ +int ako_sysnum; +/*Credential information to be observed*/ +unsigned long ako_addr_limit; +uid_t ako_uid; +uid_t ako_euid; +uid_t ako_fsuid; +uid_t ako_suid; +gid_t ako_gid; +gid_t ako_egid; +gid_t ako_fsgid; +gid_t ako_sgid; +__u32 ako_inheritable[2]; +__u32 ako_permitted[2]; +__u32 ako_effective[2]; +__u32 ako_bset[2]; +}; +extern void AKO_save_creds(struct ako_struct * ako_cred, int ako_sysnum); +extern void AKO_check_creds(struct ako_struct * ako_cred); +extern void AKO_save_addr_limit(struct ako_struct * ako_cred); +extern int AKO_syscall_checked(int sysnum); +extern void audit_AKO_rlimit(struct ako_struct * ako_cred, unsigned long current_addr_limit); +extern void audit_AKO_restore(struct ako_struct * ako_cred, const char * cred_type); + +#endif --- linux-4.4.0-62-83.orig/kernel/Makefile 2017-06-18 14:33:57.240000000 +0900 +++ linux-4.4.0/kernel/Makefile 2017-07-04 22:29:00.004000000 +0900 @@ -13,6 +13,8 @@ obj-$(CONFIG_MULTIUSER) += groups.o +obj-$(CONFIG_AKO) += ako.o + ifdef CONFIG_FUNCTION_TRACER # Do not trace debug files and internal ftrace files CFLAGS_REMOVE_cgroup-debug.o = $(CC_FLAGS_FTRACE) --- linux-4.4.0-62-83.orig/arch/x86/kernel/Makefile 2017-06-18 14:34:04.180000000 +0900 +++ linux-4.4.0/arch/x86/kernel/Makefile 2017-07-04 22:16:11.372000000 +0900 @@ -23,6 +23,7 @@ CFLAGS_irq.o := -I$(src)/../include/asm/trace obj-y := process_$(BITS).o signal.o +obj-$(CONFIG_AKO) += ako.o obj-$(CONFIG_COMPAT) += signal_compat.o obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o obj-y += time.o ioport.o dumpstack.o nmi.o --- linux-4.4.0-62-83.orig/init/Kconfig 2017-06-18 14:33:57.236000000 +0900 +++ linux-4.4.0/init/Kconfig 2017-07-04 22:14:43.080000000 +0900 @@ -333,6 +333,17 @@ depends on AUDITSYSCALL select FSNOTIFY +config HAVE_ARCH_AKO + bool + +config AKO + bool "Enable Additional Kernel Observer (AKO)" + depends on AUDIT && HAVE_ARCH_AKO + help + AKO detects and prevents priviledge escalation attacks + that exploit vulnerabilities of kernel + + source "kernel/irq/Kconfig" source "kernel/time/Kconfig" --- linux-4.4.0-62-83.orig/arch/x86/Kconfig 2017-06-18 14:34:03.924000000 +0900 +++ linux-4.4.0/arch/x86/Kconfig 2017-07-06 12:27:26.692000000 +0900 @@ -76,6 +76,7 @@ select HAVE_ACPI_APEI_NMI if ACPI select HAVE_ALIGNED_STRUCT_PAGE if SLUB select HAVE_AOUT if X86_32 + select HAVE_ARCH_AKO if X86_64 select HAVE_ARCH_AUDITSYSCALL select HAVE_ARCH_HUGE_VMAP if X86_64 || X86_PAE select HAVE_ARCH_JUMP_LABEL --- linux-4.4.0-62-83.orig/arch/x86/entry/entry_64.S 2017-06-18 14:34:04.008000000 +0900 +++ linux-4.4.0/arch/x86/entry/entry_64.S 2017-07-01 23:07:43.824000000 +0900 @@ -182,9 +182,43 @@ #endif ja 1f /* return -ENOSYS (already in pt_regs->ax) */ movq %r10, %rcx +/* + * Additional Kernel Observer (AKO) + * Copyright (c) 2017 Okayama-University + * Yohei Akao, Yamauchi Laboratory, Okayama University + */ + subq $6144,%rsp /*Allocate area in stack to save credential information*/ + ALLOC_PT_GPREGS_ON_STACK + SAVE_C_REGS + SAVE_EXTRA_REGS + leaq 15*8(%rsp), %rdi /* size of SAVE_C_REGS and size of SAVE_EXTRA_REGS is added to rsp, and start address of allocated area is saved in %rdi*/ + movq %rax, %rsi /* Syscall number(%rax) is saved in %rsi */ + call AKO_before /*credential information is saved*/ + RESTORE_EXTRA_REGS + RESTORE_C_REGS + REMOVE_PT_GPREGS_FROM_STACK + addq $6144,%rsp /*Allocate area in stack to save credential information*/ + /*end of AKO*/ call *sys_call_table(, %rax, 8) +/* + * Additional Kernel Observer (AKO) + * Copyright (c) 2017 Okayama-University + * Yohei Akao, Yamauchi Laboratory, Okayama University + */ + /*Start of AKO*/ + subq $6144,%rsp + ALLOC_PT_GPREGS_ON_STACK + SAVE_C_REGS + SAVE_EXTRA_REGS + leaq 15*8(%rsp), %rdi + call AKO_after + RESTORE_EXTRA_REGS + RESTORE_C_REGS + REMOVE_PT_GPREGS_FROM_STACK + /*Free area to store credential infomation*/ + addq $6144,%rsp + /*End of AKO*/ movq %rax, RAX(%rsp) -1: /* * Syscall return path ending with SYSRET (fast path). * Has incompletely filled pt_regs.