summaryrefslogtreecommitdiff
path: root/3.2.69
diff options
context:
space:
mode:
authorAnthony G. Basile <blueness@gentoo.org>2015-07-26 10:58:55 -0400
committerAnthony G. Basile <blueness@gentoo.org>2015-07-26 19:43:08 -0400
commitc87afd661b02b834186274edcada73b95b8425c2 (patch)
treedb21faea01247167672967e4e210a0f7ede984ce /3.2.69
parentGrsec/PaX: 3.1-{3.2.69,3.14.48,4.0.8}-201507111211 (diff)
downloadhardened-patchset-c87afd661b02b834186274edcada73b95b8425c2.tar.gz
hardened-patchset-c87afd661b02b834186274edcada73b95b8425c2.tar.bz2
hardened-patchset-c87afd661b02b834186274edcada73b95b8425c2.zip
grsecurity-{3.2.69,3.14.48,4.1.3}-201507251419
Diffstat (limited to '3.2.69')
-rw-r--r--3.2.69/0000_README2
-rw-r--r--3.2.69/4420_grsecurity-3.1-3.2.69-201507251415.patch (renamed from 3.2.69/4420_grsecurity-3.1-3.2.69-201507111207.patch)4612
2 files changed, 4112 insertions, 502 deletions
diff --git a/3.2.69/0000_README b/3.2.69/0000_README
index 0df9a58..9b79be0 100644
--- a/3.2.69/0000_README
+++ b/3.2.69/0000_README
@@ -194,7 +194,7 @@ Patch: 1068_linux-3.2.69.patch
From: http://www.kernel.org
Desc: Linux 3.2.69
-Patch: 4420_grsecurity-3.1-3.2.69-201507111207.patch
+Patch: 4420_grsecurity-3.1-3.2.69-201507251415.patch
From: http://www.grsecurity.net
Desc: hardened-sources base patch from upstream grsecurity
diff --git a/3.2.69/4420_grsecurity-3.1-3.2.69-201507111207.patch b/3.2.69/4420_grsecurity-3.1-3.2.69-201507251415.patch
index d2caf34..11686d8 100644
--- a/3.2.69/4420_grsecurity-3.1-3.2.69-201507111207.patch
+++ b/3.2.69/4420_grsecurity-3.1-3.2.69-201507251415.patch
@@ -281,6 +281,39 @@ index 88fd7f5..b318a78 100644
==============================================================
+diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
+index 2a68089..b3300e1 100644
+--- a/Documentation/sysctl/kernel.txt
++++ b/Documentation/sysctl/kernel.txt
+@@ -36,6 +36,7 @@ show up in /proc/sys/kernel:
+ - kptr_restrict
+ - kstack_depth_to_print [ X86 only ]
+ - l2cr [ PPC only ]
++- modify_ldt [ X86 only ]
+ - modprobe ==> Documentation/debugging-modules.txt
+ - modules_disabled
+ - msgmax
+@@ -318,6 +319,20 @@ This flag controls the L2 cache of G3 processor boards. If
+
+ ==============================================================
+
++modify_ldt: (X86 only)
++
++Enables (1) or disables (0) the modify_ldt syscall. Modifying the LDT
++(Local Descriptor Table) may be needed to run a 16-bit or segmented code
++such as Dosemu or Wine. This is done via a system call which is not needed
++to run portable applications, and which can sometimes be abused to exploit
++some weaknesses of the architecture, opening new vulnerabilities.
++
++This sysctl allows one to increase the system's security by disabling the
++system call, or to restore compatibility with specific applications when it
++was already disabled.
++
++==============================================================
++
+ modules_disabled:
+
+ A toggle value indicating if modules are allowed to be loaded
diff --git a/Makefile b/Makefile
index 8071888..b024b7b 100644
--- a/Makefile
@@ -10454,7 +10487,7 @@ index ad8f795..2c7eec6 100644
/*
* Memory returned by kmalloc() may be used for DMA, so we must make
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
-index 28a1bca..6eebf04 100644
+index 28a1bca..0443883 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -75,6 +75,7 @@ config X86
@@ -10554,6 +10587,29 @@ index 28a1bca..6eebf04 100644
---help---
Map the 32-bit VDSO to the predictable old-style address too.
+@@ -1720,6 +1728,22 @@ config CMDLINE_OVERRIDE
+ This is used to work around broken boot loaders. This should
+ be set to 'N' under normal conditions.
+
++config DEFAULT_MODIFY_LDT_SYSCALL
++ bool "Allow userspace to modify the LDT by default"
++ default y
++
++ ---help---
++ Modifying the LDT (Local Descriptor Table) may be needed to run a
++ 16-bit or segmented code such as Dosemu or Wine. This is done via
++ a system call which is not needed to run portable applications,
++ and which can sometimes be abused to exploit some weaknesses of
++ the architecture, opening new vulnerabilities.
++
++ For this reason this option allows one to enable or disable the
++ feature at runtime. It is recommended to say 'N' here to leave
++ the system protected, and to enable it at runtime only if needed
++ by setting the sys.kernel.modify_ldt sysctl.
++
+ endmenu
+
+ config ARCH_ENABLE_MEMORY_HOTPLUG
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index e3ca7e0..b30b28a 100644
--- a/arch/x86/Kconfig.cpu
@@ -22436,10 +22492,33 @@ index 4b6701e..1a3dcdb 100644
};
#endif
diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c
-index 0a8e65e..6e8de34 100644
+index 0a8e65e..563640b 100644
--- a/arch/x86/kernel/ldt.c
+++ b/arch/x86/kernel/ldt.c
-@@ -67,13 +67,13 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
+@@ -11,6 +11,7 @@
+ #include <linux/sched.h>
+ #include <linux/string.h>
+ #include <linux/mm.h>
++#include <linux/ratelimit.h>
+ #include <linux/smp.h>
+ #include <linux/vmalloc.h>
+ #include <linux/uaccess.h>
+@@ -21,6 +22,14 @@
+ #include <asm/mmu_context.h>
+ #include <asm/syscalls.h>
+
++#ifdef CONFIG_GRKERNSEC
++int sysctl_modify_ldt __read_only = 0;
++#elif defined(CONFIG_DEFAULT_MODIFY_LDT_SYSCALL)
++int sysctl_modify_ldt __read_only = 1;
++#else
++int sysctl_modify_ldt __read_only = 0;
++#endif
++
+ #ifdef CONFIG_SMP
+ static void flush_ldt(void *current_mm)
+ {
+@@ -67,13 +76,13 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
if (reload) {
#ifdef CONFIG_SMP
preempt_disable();
@@ -22455,7 +22534,7 @@ index 0a8e65e..6e8de34 100644
#endif
}
if (oldsize) {
-@@ -95,7 +95,7 @@ static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
+@@ -95,7 +104,7 @@ static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
return err;
for (i = 0; i < old->size; i++)
@@ -22464,7 +22543,7 @@ index 0a8e65e..6e8de34 100644
return 0;
}
-@@ -116,6 +116,24 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+@@ -116,6 +125,24 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
retval = copy_ldt(&mm->context, &old_mm->context);
mutex_unlock(&old_mm->context.lock);
}
@@ -22489,7 +22568,7 @@ index 0a8e65e..6e8de34 100644
return retval;
}
-@@ -230,6 +248,13 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode)
+@@ -230,6 +257,13 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode)
}
}
@@ -22503,6 +22582,21 @@ index 0a8e65e..6e8de34 100644
if (!IS_ENABLED(CONFIG_X86_16BIT) && !ldt_info.seg_32bit) {
error = -EINVAL;
goto out_unlock;
+@@ -255,6 +289,14 @@ asmlinkage int sys_modify_ldt(int func, void __user *ptr,
+ {
+ int ret = -ENOSYS;
+
++ if (!sysctl_modify_ldt) {
++ printk_ratelimited(KERN_INFO
++ "Denied a call to modify_ldt() from %s[%d] (uid: %d)."
++ " Adjust sysctl if this was not an exploit attempt.\n",
++ current->comm, task_pid_nr(current), current_uid());
++ return ret;
++ }
++
+ switch (func) {
+ case 0:
+ ret = read_ldt(ptr, bytecount);
diff --git a/arch/x86/kernel/machine_kexec_32.c b/arch/x86/kernel/machine_kexec_32.c
index a3fa43b..8966f4c 100644
--- a/arch/x86/kernel/machine_kexec_32.c
@@ -46312,7 +46406,7 @@ index fed39de..8adf3152 100644
};
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
-index 7300447..fa23d39 100644
+index 7300447..cb83d3e 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -351,7 +351,7 @@ static void macvtap_setup(struct net_device *dev)
@@ -46342,6 +46436,14 @@ index 7300447..fa23d39 100644
.notifier_call = macvtap_device_event,
};
+@@ -1151,6 +1151,7 @@ static void macvtap_exit(void)
+ class_unregister(macvtap_class);
+ cdev_del(&macvtap_cdev);
+ unregister_chrdev_region(macvtap_major, MACVTAP_NUM_DEVS);
++ idr_destroy(&minor_idr);
+ }
+ module_exit(macvtap_exit);
+
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 83a5a5a..9a9d0ae 100644
--- a/drivers/net/phy/phy_device.c
@@ -46804,6 +46906,51 @@ index 3d21742..b8e03e7 100644
// waiting for all pending urbs to complete?
if (dev->wait) {
if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {
+diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
+index 28ceef2..655b059 100644
+--- a/drivers/net/vmxnet3/vmxnet3_drv.c
++++ b/drivers/net/vmxnet3/vmxnet3_drv.c
+@@ -1140,7 +1140,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
+ static const u32 rxprod_reg[2] = {
+ VMXNET3_REG_RXPROD, VMXNET3_REG_RXPROD2
+ };
+- u32 num_rxd = 0;
++ u32 num_pkts = 0;
+ bool skip_page_frags = false;
+ struct Vmxnet3_RxCompDesc *rcd;
+ struct vmxnet3_rx_ctx *ctx = &rq->rx_ctx;
+@@ -1158,13 +1158,12 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
+ struct Vmxnet3_RxDesc *rxd;
+ u32 idx, ring_idx;
+ struct vmxnet3_cmd_ring *ring = NULL;
+- if (num_rxd >= quota) {
++ if (num_pkts >= quota) {
+ /* we may stop even before we see the EOP desc of
+ * the current pkt
+ */
+ break;
+ }
+- num_rxd++;
+ BUG_ON(rcd->rqID != rq->qid && rcd->rqID != rq->qid2);
+ idx = rcd->rxdIdx;
+ ring_idx = rcd->rqID < adapter->num_rx_queues ? 0 : 1;
+@@ -1288,6 +1287,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
+ napi_gro_receive(&rq->napi, skb);
+
+ ctx->skb = NULL;
++ num_pkts++;
+ }
+
+ rcd_done:
+@@ -1319,7 +1319,7 @@ rcd_done:
+ &rq->comp_ring.base[rq->comp_ring.next2proc].rcd, &rxComp);
+ }
+
+- return num_rxd;
++ return num_pkts;
+ }
+
+
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index e662cbc..8d4a102 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -56737,10 +56884,20 @@ index 2524e4c..2962cc6a 100644
if (retval > 0)
retval = 0;
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
-index 879ed88..bc03a01 100644
+index 879ed88..dbaf762 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
-@@ -1286,7 +1286,7 @@ static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+@@ -527,8 +527,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb,
+ unlock_new_inode(inode);
+ return inode;
+ error:
+- unlock_new_inode(inode);
+- iput(inode);
++ iget_failed(inode);
+ return ERR_PTR(retval);
+
+ }
+@@ -1286,7 +1285,7 @@ static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
void
v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
{
@@ -56749,6 +56906,20 @@ index 879ed88..bc03a01 100644
P9_DPRINTK(P9_DEBUG_VFS, " %s %s\n", dentry->d_name.name,
IS_ERR(s) ? "<error>" : s);
+diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
+index 30d4fa8..dbbc83f 100644
+--- a/fs/9p/vfs_inode_dotl.c
++++ b/fs/9p/vfs_inode_dotl.c
+@@ -169,8 +169,7 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb,
+ unlock_new_inode(inode);
+ return inode;
+ error:
+- unlock_new_inode(inode);
+- iput(inode);
++ iget_failed(inode);
+ return ERR_PTR(retval);
+
+ }
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index c70251d..fe305fd 100644
--- a/fs/9p/vfs_super.c
@@ -59166,7 +59337,7 @@ index 739fb59..5385976 100644
static int __init init_cramfs_fs(void)
{
diff --git a/fs/dcache.c b/fs/dcache.c
-index 8bc98af..2cc0298 100644
+index 8bc98af..68601d9 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -103,11 +103,11 @@ static unsigned int d_hash_shift __read_mostly;
@@ -59185,7 +59356,31 @@ index 8bc98af..2cc0298 100644
return dentry_hashtable + (hash & D_HASHMASK);
}
-@@ -1016,13 +1016,13 @@ ascend:
+@@ -478,15 +478,18 @@ repeat:
+ return;
+ }
+
+- if (dentry->d_flags & DCACHE_OP_DELETE) {
++ /* Unreachable? Get rid of it */
++ if (unlikely(d_unhashed(dentry)))
++ goto kill_it;
++
++ if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED))
++ goto kill_it;
++
++ if (unlikely(dentry->d_flags & DCACHE_OP_DELETE)) {
+ if (dentry->d_op->d_delete(dentry))
+ goto kill_it;
+ }
+
+- /* Unreachable? Get rid of it */
+- if (d_unhashed(dentry))
+- goto kill_it;
+-
+ /*
+ * If this dentry needs lookup, don't set the referenced flag so that it
+ * is more likely to be cleaned up by the dcache shrinker in case of
+@@ -1016,13 +1019,13 @@ ascend:
/* might go back up the wrong parent if we have had a rename */
if (!locked && read_seqretry(&rename_lock, seq))
goto rename_retry;
@@ -59203,7 +59398,7 @@ index 8bc98af..2cc0298 100644
rcu_read_unlock();
goto resume;
}
-@@ -1235,6 +1235,9 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
+@@ -1235,6 +1238,9 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
dentry->d_sb = sb;
dentry->d_op = NULL;
dentry->d_fsdata = NULL;
@@ -59213,7 +59408,7 @@ index 8bc98af..2cc0298 100644
INIT_HLIST_BL_NODE(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_lru);
INIT_LIST_HEAD(&dentry->d_subdirs);
-@@ -3082,7 +3085,8 @@ void __init vfs_caches_init(unsigned long mempages)
+@@ -3082,7 +3088,8 @@ void __init vfs_caches_init(unsigned long mempages)
mempages -= reserve;
names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
@@ -73953,7 +74148,7 @@ index 0000000..25f54ef
+};
diff --git a/grsecurity/gracl_policy.c b/grsecurity/gracl_policy.c
new file mode 100644
-index 0000000..62916b2
+index 0000000..edcb09b
--- /dev/null
+++ b/grsecurity/gracl_policy.c
@@ -0,0 +1,1780 @@
@@ -74411,7 +74606,7 @@ index 0000000..62916b2
+ get_fs_root(reaper->fs, &gr_real_root);
+
+#ifdef CONFIG_GRKERNSEC_RBAC_DEBUG
-+ printk(KERN_ALERT "Obtained real root device=%d, inode=%lu\n", __get_dev(gr_real_root.dentry), gr_real_root.dentry->d_inode->i_ino);
++ printk(KERN_ALERT "Obtained real root device=%d, inode=%lu\n", gr_get_dev_from_dentry(gr_real_root.dentry), gr_get_ino_from_dentry(gr_real_root.dentry));
+#endif
+
+ fakefs_obj_rw = kzalloc(sizeof(struct acl_object_label), GFP_KERNEL);
@@ -77353,7 +77548,7 @@ index 0000000..8ca18bf
+}
diff --git a/grsecurity/grsec_init.c b/grsecurity/grsec_init.c
new file mode 100644
-index 0000000..b09101d
+index 0000000..68121e2
--- /dev/null
+++ b/grsecurity/grsec_init.c
@@ -0,0 +1,290 @@
@@ -77366,61 +77561,61 @@ index 0000000..b09101d
+#include <linux/percpu.h>
+#include <linux/module.h>
+
-+int grsec_enable_ptrace_readexec;
-+int grsec_enable_setxid;
-+int grsec_enable_symlinkown;
-+int grsec_symlinkown_gid;
-+int grsec_enable_brute;
-+int grsec_enable_link;
-+int grsec_enable_dmesg;
-+int grsec_enable_harden_ptrace;
-+int grsec_enable_harden_ipc;
-+int grsec_enable_fifo;
-+int grsec_enable_execlog;
-+int grsec_enable_signal;
-+int grsec_enable_forkfail;
-+int grsec_enable_audit_ptrace;
-+int grsec_enable_time;
-+int grsec_enable_group;
-+int grsec_audit_gid;
-+int grsec_enable_chdir;
-+int grsec_enable_mount;
-+int grsec_enable_rofs;
-+int grsec_deny_new_usb;
-+int grsec_enable_chroot_findtask;
-+int grsec_enable_chroot_mount;
-+int grsec_enable_chroot_shmat;
-+int grsec_enable_chroot_fchdir;
-+int grsec_enable_chroot_double;
-+int grsec_enable_chroot_pivot;
-+int grsec_enable_chroot_chdir;
-+int grsec_enable_chroot_chmod;
-+int grsec_enable_chroot_mknod;
-+int grsec_enable_chroot_nice;
-+int grsec_enable_chroot_execlog;
-+int grsec_enable_chroot_caps;
-+int grsec_enable_chroot_rename;
-+int grsec_enable_chroot_sysctl;
-+int grsec_enable_chroot_unix;
-+int grsec_enable_tpe;
-+int grsec_tpe_gid;
-+int grsec_enable_blackhole;
++int grsec_enable_ptrace_readexec __read_only;
++int grsec_enable_setxid __read_only;
++int grsec_enable_symlinkown __read_only;
++int grsec_symlinkown_gid __read_only;
++int grsec_enable_brute __read_only;
++int grsec_enable_link __read_only;
++int grsec_enable_dmesg __read_only;
++int grsec_enable_harden_ptrace __read_only;
++int grsec_enable_harden_ipc __read_only;
++int grsec_enable_fifo __read_only;
++int grsec_enable_execlog __read_only;
++int grsec_enable_signal __read_only;
++int grsec_enable_forkfail __read_only;
++int grsec_enable_audit_ptrace __read_only;
++int grsec_enable_time __read_only;
++int grsec_enable_group __read_only;
++int grsec_audit_gid __read_only;
++int grsec_enable_chdir __read_only;
++int grsec_enable_mount __read_only;
++int grsec_enable_rofs __read_only;
++int grsec_deny_new_usb __read_only;
++int grsec_enable_chroot_findtask __read_only;
++int grsec_enable_chroot_mount __read_only;
++int grsec_enable_chroot_shmat __read_only;
++int grsec_enable_chroot_fchdir __read_only;
++int grsec_enable_chroot_double __read_only;
++int grsec_enable_chroot_pivot __read_only;
++int grsec_enable_chroot_chdir __read_only;
++int grsec_enable_chroot_chmod __read_only;
++int grsec_enable_chroot_mknod __read_only;
++int grsec_enable_chroot_nice __read_only;
++int grsec_enable_chroot_execlog __read_only;
++int grsec_enable_chroot_caps __read_only;
++int grsec_enable_chroot_rename __read_only;
++int grsec_enable_chroot_sysctl __read_only;
++int grsec_enable_chroot_unix __read_only;
++int grsec_enable_tpe __read_only;
++int grsec_tpe_gid __read_only;
++int grsec_enable_blackhole __read_only;
+#ifdef CONFIG_IPV6_MODULE
+EXPORT_SYMBOL_GPL(grsec_enable_blackhole);
+#endif
-+int grsec_lastack_retries;
-+int grsec_enable_tpe_all;
-+int grsec_enable_tpe_invert;
-+int grsec_enable_socket_all;
-+int grsec_socket_all_gid;
-+int grsec_enable_socket_client;
-+int grsec_socket_client_gid;
-+int grsec_enable_socket_server;
-+int grsec_socket_server_gid;
-+int grsec_resource_logging;
-+int grsec_disable_privio;
-+int grsec_enable_log_rwxmaps;
-+int grsec_lock;
++int grsec_lastack_retries __read_only;
++int grsec_enable_tpe_all __read_only;
++int grsec_enable_tpe_invert __read_only;
++int grsec_enable_socket_all __read_only;
++int grsec_socket_all_gid __read_only;
++int grsec_enable_socket_client __read_only;
++int grsec_socket_client_gid __read_only;
++int grsec_enable_socket_server __read_only;
++int grsec_socket_server_gid __read_only;
++int grsec_resource_logging __read_only;
++int grsec_disable_privio __read_only;
++int grsec_enable_log_rwxmaps __read_only;
++int grsec_lock __read_only;
+
+DEFINE_SPINLOCK(grsec_alert_lock);
+unsigned long grsec_alert_wtime = 0;
@@ -78849,7 +79044,7 @@ index 0000000..a523bd2
+}
diff --git a/grsecurity/grsec_sysctl.c b/grsecurity/grsec_sysctl.c
new file mode 100644
-index 0000000..a51b175
+index 0000000..a3b8942
--- /dev/null
+++ b/grsecurity/grsec_sysctl.c
@@ -0,0 +1,486 @@
@@ -78886,7 +79081,7 @@ index 0000000..a51b175
+ .data = &grsec_disable_privio,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#endif
@@ -78896,7 +79091,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_link,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_SYMLINKOWN
@@ -78905,14 +79100,14 @@ index 0000000..a51b175
+ .data = &grsec_enable_symlinkown,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+ {
+ .procname = "symlinkown_gid",
+ .data = &grsec_symlinkown_gid,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_BRUTE
@@ -78921,7 +79116,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_brute,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_FIFO
@@ -78930,7 +79125,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_fifo,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_PTRACE_READEXEC
@@ -78939,7 +79134,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_ptrace_readexec,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_SETXID
@@ -78948,7 +79143,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_setxid,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_BLACKHOLE
@@ -78957,14 +79152,14 @@ index 0000000..a51b175
+ .data = &grsec_enable_blackhole,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+ {
+ .procname = "lastack_retries",
+ .data = &grsec_lastack_retries,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_EXECLOG
@@ -78973,7 +79168,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_execlog,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_RWXMAP_LOG
@@ -78982,7 +79177,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_log_rwxmaps,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_SIGNAL
@@ -78991,7 +79186,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_signal,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_FORKFAIL
@@ -79000,7 +79195,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_forkfail,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_TIME
@@ -79009,7 +79204,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_time,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_CHROOT_SHMAT
@@ -79018,7 +79213,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_chroot_shmat,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_CHROOT_UNIX
@@ -79027,7 +79222,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_chroot_unix,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_CHROOT_MOUNT
@@ -79036,7 +79231,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_chroot_mount,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_CHROOT_FCHDIR
@@ -79045,7 +79240,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_chroot_fchdir,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_CHROOT_DOUBLE
@@ -79054,7 +79249,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_chroot_double,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_CHROOT_PIVOT
@@ -79063,7 +79258,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_chroot_pivot,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_CHROOT_CHDIR
@@ -79072,7 +79267,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_chroot_chdir,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_CHROOT_CHMOD
@@ -79081,7 +79276,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_chroot_chmod,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_CHROOT_MKNOD
@@ -79090,7 +79285,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_chroot_mknod,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_CHROOT_NICE
@@ -79099,7 +79294,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_chroot_nice,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_CHROOT_EXECLOG
@@ -79108,7 +79303,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_chroot_execlog,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_CHROOT_CAPS
@@ -79117,7 +79312,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_chroot_caps,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_CHROOT_RENAME
@@ -79126,7 +79321,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_chroot_rename,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_CHROOT_SYSCTL
@@ -79135,7 +79330,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_chroot_sysctl,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_TPE
@@ -79144,14 +79339,14 @@ index 0000000..a51b175
+ .data = &grsec_enable_tpe,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+ {
+ .procname = "tpe_gid",
+ .data = &grsec_tpe_gid,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_TPE_INVERT
@@ -79160,7 +79355,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_tpe_invert,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_TPE_ALL
@@ -79169,7 +79364,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_tpe_all,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_SOCKET_ALL
@@ -79178,14 +79373,14 @@ index 0000000..a51b175
+ .data = &grsec_enable_socket_all,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+ {
+ .procname = "socket_all_gid",
+ .data = &grsec_socket_all_gid,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_SOCKET_CLIENT
@@ -79194,14 +79389,14 @@ index 0000000..a51b175
+ .data = &grsec_enable_socket_client,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+ {
+ .procname = "socket_client_gid",
+ .data = &grsec_socket_client_gid,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_SOCKET_SERVER
@@ -79210,14 +79405,14 @@ index 0000000..a51b175
+ .data = &grsec_enable_socket_server,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+ {
+ .procname = "socket_server_gid",
+ .data = &grsec_socket_server_gid,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_AUDIT_GROUP
@@ -79226,14 +79421,14 @@ index 0000000..a51b175
+ .data = &grsec_enable_group,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+ {
+ .procname = "audit_gid",
+ .data = &grsec_audit_gid,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_AUDIT_CHDIR
@@ -79242,7 +79437,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_chdir,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_AUDIT_MOUNT
@@ -79251,7 +79446,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_mount,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_DMESG
@@ -79260,7 +79455,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_dmesg,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_CHROOT_FINDTASK
@@ -79269,7 +79464,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_chroot_findtask,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_RESLOG
@@ -79278,7 +79473,7 @@ index 0000000..a51b175
+ .data = &grsec_resource_logging,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_AUDIT_PTRACE
@@ -79287,7 +79482,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_audit_ptrace,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_HARDEN_PTRACE
@@ -79296,7 +79491,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_harden_ptrace,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_HARDEN_IPC
@@ -79305,7 +79500,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_harden_ipc,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+ {
@@ -79313,7 +79508,7 @@ index 0000000..a51b175
+ .data = &grsec_lock,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+#ifdef CONFIG_GRKERNSEC_ROFS
@@ -79322,7 +79517,7 @@ index 0000000..a51b175
+ .data = &grsec_enable_rofs,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec_minmax,
++ .proc_handler = &proc_dointvec_minmax_secure,
+ .extra1 = &one,
+ .extra2 = &one,
+ },
@@ -79333,7 +79528,7 @@ index 0000000..a51b175
+ .data = &grsec_deny_new_usb,
+ .maxlen = sizeof(int),
+ .mode = 0600,
-+ .proc_handler = &proc_dointvec,
++ .proc_handler = &proc_dointvec_secure,
+ },
+#endif
+ { }
@@ -80750,6 +80945,19 @@ index 04ffb2e..6799180 100644
extern struct cleancache_ops
cleancache_register_ops(struct cleancache_ops *ops);
+diff --git a/include/linux/clkdev.h b/include/linux/clkdev.h
+index d9a4fd0..13edc9f 100644
+--- a/include/linux/clkdev.h
++++ b/include/linux/clkdev.h
+@@ -32,7 +32,7 @@ struct clk_lookup {
+ }
+
+ struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id,
+- const char *dev_fmt, ...);
++ const char *dev_fmt, ...) __printf(3, 4);
+
+ void clkdev_add(struct clk_lookup *cl);
+ void clkdev_drop(struct clk_lookup *cl);
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 081147d..da89543 100644
--- a/include/linux/clocksource.h
@@ -80764,7 +80972,7 @@ index 081147d..da89543 100644
extern void
diff --git a/include/linux/compat.h b/include/linux/compat.h
-index d42bd48..a20850d 100644
+index d42bd48..f651bd9 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -240,10 +240,10 @@ long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
@@ -80780,6 +80988,15 @@ index d42bd48..a20850d 100644
asmlinkage long compat_sys_keyctl(u32 option,
u32 arg2, u32 arg3, u32 arg4, u32 arg5);
asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u32);
+@@ -320,7 +320,7 @@ asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv,
+
+ asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp);
+
+-extern int compat_printk(const char *fmt, ...);
++extern __printf(1, 2) int compat_printk(const char *fmt, ...);
+ extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat);
+
+ asmlinkage long compat_sys_migrate_pages(compat_pid_t pid,
@@ -334,7 +334,7 @@ extern int compat_ptrace_request(struct task_struct *child,
extern long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
compat_ulong_t addr, compat_ulong_t data);
@@ -80833,10 +81050,10 @@ index 59a7e4c..8feb590 100644
#if __GNUC_MINOR__ > 0
diff --git a/include/linux/compiler-gcc5.h b/include/linux/compiler-gcc5.h
-index cdd1cc2..9c1ee22 100644
+index cdd1cc2..d062745 100644
--- a/include/linux/compiler-gcc5.h
+++ b/include/linux/compiler-gcc5.h
-@@ -28,6 +28,31 @@
+@@ -28,6 +28,30 @@
# define __compiletime_error(message) __attribute__((error(message)))
#endif /* __CHECKER__ */
@@ -80856,7 +81073,6 @@ index cdd1cc2..9c1ee22 100644
+#endif
+
+#ifdef SIZE_OVERFLOW_PLUGIN
-+#error not yet
+#define __size_overflow(...) __attribute__((size_overflow(__VA_ARGS__)))
+#define __intentional_overflow(...) __attribute__((intentional_overflow(__VA_ARGS__)))
+#endif
@@ -80868,7 +81084,7 @@ index cdd1cc2..9c1ee22 100644
/*
* Mark a position in code as unreachable. This can be used to
* suppress control flow warnings after asm blocks that transfer
-@@ -53,7 +78,6 @@
+@@ -53,7 +77,6 @@
* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670
*
* Work it around via a compiler barrier quirk suggested by Jakub Jelinek.
@@ -81066,19 +81282,20 @@ index 51494e6..340575ab 100644
extern bool completion_done(struct completion *x);
diff --git a/include/linux/configfs.h b/include/linux/configfs.h
-index 3081c58..5a0b545 100644
+index 3081c58..80789a0 100644
--- a/include/linux/configfs.h
+++ b/include/linux/configfs.h
-@@ -64,7 +64,7 @@ struct config_item {
+@@ -64,7 +64,8 @@ struct config_item {
struct dentry *ci_dentry;
};
-extern int config_item_set_name(struct config_item *, const char *, ...);
-+extern __printf(2, 3) int config_item_set_name(struct config_item *, const char *, ...);
++extern __printf(2, 3)
++int config_item_set_name(struct config_item *, const char *, ...);
static inline char *config_item_name(struct config_item * item)
{
-@@ -125,7 +125,7 @@ struct configfs_attribute {
+@@ -125,7 +126,7 @@ struct configfs_attribute {
const char *ca_name;
struct module *ca_owner;
mode_t ca_mode;
@@ -81279,7 +81496,7 @@ index 8acfe31..6ffccd63 100644
return c | 0x20;
}
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
-index 99374de..ac23d39 100644
+index 99374de..01feff6 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -132,6 +132,9 @@ struct dentry {
@@ -81301,6 +81518,16 @@ index 99374de..ac23d39 100644
/*
* dentry->d_lock spinlock nesting subclasses:
+@@ -340,7 +343,8 @@ extern int d_validate(struct dentry *, struct dentry *);
+ /*
+ * helper function for dentry_operations.d_dname() members
+ */
+-extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
++extern __printf(4, 5)
++char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
+
+ extern char *__d_path(const struct path *, const struct path *, char *, int);
+ extern char *d_absolute_path(const struct path *, char *, int);
diff --git a/include/linux/decompress/mm.h b/include/linux/decompress/mm.h
index 7925bf0..d5143d2 100644
--- a/include/linux/decompress/mm.h
@@ -81315,7 +81542,7 @@ index 7925bf0..d5143d2 100644
#define large_malloc(a) vmalloc(a)
diff --git a/include/linux/device.h b/include/linux/device.h
-index a31c5d0..ff3d03b 100644
+index a31c5d0..e9e8aac 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -427,7 +427,7 @@ struct device_type {
@@ -81335,6 +81562,23 @@ index a31c5d0..ff3d03b 100644
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
+@@ -757,12 +758,10 @@ extern int __must_check device_reprobe(struct device *dev);
+ /*
+ * Easy functions for dynamically creating devices on the fly
+ */
+-extern struct device *device_create_vargs(struct class *cls,
+- struct device *parent,
+- dev_t devt,
+- void *drvdata,
+- const char *fmt,
+- va_list vargs);
++extern __printf(5, 0)
++struct device *device_create_vargs(struct class *cls, struct device *parent,
++ dev_t devt, void *drvdata,
++ const char *fmt, va_list vargs);
+ extern __printf(5, 6)
+ struct device *device_create(struct class *cls, struct device *parent,
+ dev_t devt, void *drvdata,
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index e13117c..e9fc938 100644
--- a/include/linux/dma-mapping.h
@@ -83441,10 +83685,42 @@ index 3875719..4663bc3 100644
/* This macro allows us to keep printk typechecking */
static __printf(1, 2)
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
-index dcf6a8b..e1f7aa5 100644
+index dcf6a8b..a182533 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
-@@ -698,24 +698,30 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
+@@ -326,7 +326,8 @@ extern __printf(3, 0)
+ int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
+ extern __printf(2, 3)
+ char *kasprintf(gfp_t gfp, const char *fmt, ...);
+-extern char *kvasprintf(gfp_t gfp, const char *fmt, va_list args);
++extern __printf(2, 0)
++char *kvasprintf(gfp_t gfp, const char *fmt, va_list args);
+
+ extern int sscanf(const char *, const char *, ...)
+ __attribute__ ((format (scanf, 2, 3)));
+@@ -514,10 +515,10 @@ do { \
+ __ftrace_vprintk(_THIS_IP_, fmt, vargs); \
+ } while (0)
+
+-extern int
++extern __printf(2, 0) int
+ __ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap);
+
+-extern int
++extern __printf(2, 0) int
+ __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap);
+
+ extern void ftrace_dump(enum ftrace_dump_mode oops_dump_mode);
+@@ -534,7 +535,7 @@ trace_printk(const char *fmt, ...)
+ {
+ return 0;
+ }
+-static inline int
++static __printf(1, 0) inline int
+ ftrace_vprintk(const char *fmt, va_list ap)
+ {
+ return 0;
+@@ -698,24 +699,30 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
* @condition: the condition which the compiler should know is false.
*
* If you have some code which relies on certain constants being equal, or
@@ -83560,10 +83836,22 @@ index f8d4b27..8560882 100644
char **envp;
enum umh_wait wait;
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
-index 445f978..24e427c 100644
+index 445f978..6b3fc2c 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
-@@ -111,7 +111,7 @@ struct kobj_type {
+@@ -74,8 +74,9 @@ struct kobject {
+
+ extern __printf(2, 3)
+ int kobject_set_name(struct kobject *kobj, const char *name, ...);
+-extern int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
+- va_list vargs);
++extern __printf(2, 0)
++int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
++ va_list vargs);
+
+ static inline const char *kobject_name(const struct kobject *kobj)
+ {
+@@ -111,7 +112,7 @@ struct kobj_type {
struct attribute **default_attrs;
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject *kobj);
@@ -83572,7 +83860,7 @@ index 445f978..24e427c 100644
struct kobj_uevent_env {
char *envp[UEVENT_NUM_ENVP];
-@@ -134,6 +134,7 @@ struct kobj_attribute {
+@@ -134,6 +135,7 @@ struct kobj_attribute {
ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count);
};
@@ -83580,7 +83868,7 @@ index 445f978..24e427c 100644
extern const struct sysfs_ops kobj_sysfs_ops;
-@@ -161,7 +162,7 @@ struct kset {
+@@ -161,7 +163,7 @@ struct kset {
spinlock_t list_lock;
struct kobject kobj;
const struct kset_uevent_ops *uevent_ops;
@@ -84064,7 +84352,7 @@ index 174a844..11483c2 100644
/*
* Standard errno values are used for errors, but some have specific
diff --git a/include/linux/mmiotrace.h b/include/linux/mmiotrace.h
-index c5d5278..f0b68c8 100644
+index c5d5278..85cd5ce 100644
--- a/include/linux/mmiotrace.h
+++ b/include/linux/mmiotrace.h
@@ -46,7 +46,7 @@ extern int kmmio_handler(struct pt_regs *regs, unsigned long addr);
@@ -84085,6 +84373,14 @@ index c5d5278..f0b68c8 100644
{
}
+@@ -106,6 +106,6 @@ extern void enable_mmiotrace(void);
+ extern void disable_mmiotrace(void);
+ extern void mmio_trace_rw(struct mmiotrace_rw *rw);
+ extern void mmio_trace_mapping(struct mmiotrace_map *map);
+-extern int mmio_trace_printk(const char *fmt, va_list args);
++extern __printf(1, 0) int mmio_trace_printk(const char *fmt, va_list args);
+
+ #endif /* _LINUX_MMIOTRACE_H */
diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
index ee2baf0..e24a58c 100644
--- a/include/linux/mmu_notifier.h
@@ -86448,7 +86744,7 @@ index 27b3b0b..e093dd9 100644
extern void register_syscore_ops(struct syscore_ops *ops);
extern void unregister_syscore_ops(struct syscore_ops *ops);
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
-index 703cfa33..305427e 100644
+index 703cfa33..98e3375 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -155,8 +155,6 @@ enum
@@ -86460,7 +86756,7 @@ index 703cfa33..305427e 100644
/* CTL_VM names: */
enum
{
-@@ -961,13 +959,13 @@ extern void sysctl_head_finish(struct ctl_table_header *prev);
+@@ -961,17 +959,21 @@ extern void sysctl_head_finish(struct ctl_table_header *prev);
extern int sysctl_perm(struct ctl_table_root *root,
struct ctl_table *table, int op);
@@ -86475,8 +86771,16 @@ index 703cfa33..305427e 100644
+ void __user *, size_t *, loff_t *);
extern int proc_dointvec(struct ctl_table *, int,
void __user *, size_t *, loff_t *);
++extern int proc_dointvec_secure(struct ctl_table *, int,
++ void __user *, size_t *, loff_t *);
extern int proc_dointvec_minmax(struct ctl_table *, int,
-@@ -1045,7 +1043,9 @@ struct ctl_table
+ void __user *, size_t *, loff_t *);
++extern int proc_dointvec_minmax_secure(struct ctl_table *, int,
++ void __user *, size_t *, loff_t *);
+ extern int proc_dointvec_jiffies(struct ctl_table *, int,
+ void __user *, size_t *, loff_t *);
+ extern int proc_dointvec_userhz_jiffies(struct ctl_table *, int,
+@@ -1045,7 +1047,9 @@ struct ctl_table
struct ctl_table_poll *poll;
void *extra1;
void *extra2;
@@ -90107,7 +90411,7 @@ index f56af55..657c675 100644
#ifdef CONFIG_MODULE_UNLOAD
{
diff --git a/kernel/events/core.c b/kernel/events/core.c
-index 4277095..836fd7d 100644
+index 4277095..c1440e1 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -146,8 +146,15 @@ static struct srcu_struct pmus_srcu;
@@ -90118,11 +90422,11 @@ index 4277095..836fd7d 100644
*/
-int sysctl_perf_event_paranoid __read_mostly = 1;
+#ifdef CONFIG_GRKERNSEC_PERF_HARDEN
-+int sysctl_perf_event_legitimately_concerned __read_mostly = 3;
++int sysctl_perf_event_legitimately_concerned __read_only = 3;
+#elif defined(CONFIG_GRKERNSEC_HIDESYM)
-+int sysctl_perf_event_legitimately_concerned __read_mostly = 2;
++int sysctl_perf_event_legitimately_concerned __read_only = 2;
+#else
-+int sysctl_perf_event_legitimately_concerned __read_mostly = 1;
++int sysctl_perf_event_legitimately_concerned __read_only = 1;
+#endif
/* Minimum for 512 kiB + 1 user control page */
@@ -91612,7 +91916,7 @@ index 91c32a0..7b88d63 100644
seq_printf(m, "%40s %14lu %29s %pS\n",
name, stats->contending_point[i],
diff --git a/kernel/module.c b/kernel/module.c
-index 95ecd9f..dfa3a9b 100644
+index 95ecd9f..db549a6 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -58,6 +58,7 @@
@@ -91623,6 +91927,15 @@ index 95ecd9f..dfa3a9b 100644
#define CREATE_TRACE_POINTS
#include <trace/events/module.h>
+@@ -110,7 +111,7 @@ struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
+
+
+ /* Block module loading/unloading? */
+-int modules_disabled = 0;
++int modules_disabled __read_only = 0;
+
+ /* Waiting for a module to finish initializing? */
+ static DECLARE_WAIT_QUEUE_HEAD(module_wq);
@@ -119,7 +120,8 @@ static BLOCKING_NOTIFIER_HEAD(module_notify_list);
/* Bounds of module allocation, for speeding __module_address.
@@ -92941,6 +93254,2924 @@ index c073f43..ced569b 100644
if (syslog_action_restricted(type)) {
if (capable(CAP_SYSLOG))
return 0;
+diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
+new file mode 100644
+index 0000000..ba98f34
+--- /dev/null
++++ b/kernel/printk/printk.c
+@@ -0,0 +1,2912 @@
++/*
++ * linux/kernel/printk.c
++ *
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ *
++ * Modified to make sys_syslog() more flexible: added commands to
++ * return the last 4k of kernel messages, regardless of whether
++ * they've been read or not. Added option to suppress kernel printk's
++ * to the console. Added hook for sending the console messages
++ * elsewhere, in preparation for a serial line console (someday).
++ * Ted Ts'o, 2/11/93.
++ * Modified for sysctl support, 1/8/97, Chris Horn.
++ * Fixed SMP synchronization, 08/08/99, Manfred Spraul
++ * manfred@colorfullife.com
++ * Rewrote bits to get rid of console_lock
++ * 01Mar01 Andrew Morton
++ */
++
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/tty.h>
++#include <linux/tty_driver.h>
++#include <linux/console.h>
++#include <linux/init.h>
++#include <linux/jiffies.h>
++#include <linux/nmi.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/interrupt.h> /* For in_interrupt() */
++#include <linux/delay.h>
++#include <linux/smp.h>
++#include <linux/security.h>
++#include <linux/bootmem.h>
++#include <linux/memblock.h>
++#include <linux/aio.h>
++#include <linux/syscalls.h>
++#include <linux/kexec.h>
++#include <linux/kdb.h>
++#include <linux/ratelimit.h>
++#include <linux/kmsg_dump.h>
++#include <linux/syslog.h>
++#include <linux/cpu.h>
++#include <linux/notifier.h>
++#include <linux/rculist.h>
++#include <linux/poll.h>
++#include <linux/irq_work.h>
++#include <linux/utsname.h>
++
++#include <asm/uaccess.h>
++
++#define CREATE_TRACE_POINTS
++#include <trace/events/printk.h>
++
++#include "console_cmdline.h"
++#include "braille.h"
++
++/* printk's without a loglevel use this.. */
++#define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL
++
++/* We show everything that is MORE important than this.. */
++#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
++#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */
++
++int console_printk[4] = {
++ DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */
++ DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */
++ MINIMUM_CONSOLE_LOGLEVEL, /* minimum_console_loglevel */
++ DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */
++};
++
++/*
++ * Low level drivers may need that to know if they can schedule in
++ * their unblank() callback or not. So let's export it.
++ */
++int oops_in_progress;
++EXPORT_SYMBOL(oops_in_progress);
++
++/*
++ * console_sem protects the console_drivers list, and also
++ * provides serialisation for access to the entire console
++ * driver system.
++ */
++static DEFINE_SEMAPHORE(console_sem);
++struct console *console_drivers;
++EXPORT_SYMBOL_GPL(console_drivers);
++
++#ifdef CONFIG_LOCKDEP
++static struct lockdep_map console_lock_dep_map = {
++ .name = "console_lock"
++};
++#endif
++
++/*
++ * This is used for debugging the mess that is the VT code by
++ * keeping track if we have the console semaphore held. It's
++ * definitely not the perfect debug tool (we don't know if _WE_
++ * hold it are racing, but it helps tracking those weird code
++ * path in the console code where we end up in places I want
++ * locked without the console sempahore held
++ */
++static int console_locked, console_suspended;
++
++/*
++ * If exclusive_console is non-NULL then only this console is to be printed to.
++ */
++static struct console *exclusive_console;
++
++/*
++ * Array of consoles built from command line options (console=)
++ */
++
++#define MAX_CMDLINECONSOLES 8
++
++static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
++
++static int selected_console = -1;
++static int preferred_console = -1;
++int console_set_on_cmdline;
++EXPORT_SYMBOL(console_set_on_cmdline);
++
++/* Flag: console code may call schedule() */
++static int console_may_schedule;
++
++/*
++ * The printk log buffer consists of a chain of concatenated variable
++ * length records. Every record starts with a record header, containing
++ * the overall length of the record.
++ *
++ * The heads to the first and last entry in the buffer, as well as the
++ * sequence numbers of these both entries are maintained when messages
++ * are stored..
++ *
++ * If the heads indicate available messages, the length in the header
++ * tells the start next message. A length == 0 for the next message
++ * indicates a wrap-around to the beginning of the buffer.
++ *
++ * Every record carries the monotonic timestamp in microseconds, as well as
++ * the standard userspace syslog level and syslog facility. The usual
++ * kernel messages use LOG_KERN; userspace-injected messages always carry
++ * a matching syslog facility, by default LOG_USER. The origin of every
++ * message can be reliably determined that way.
++ *
++ * The human readable log message directly follows the message header. The
++ * length of the message text is stored in the header, the stored message
++ * is not terminated.
++ *
++ * Optionally, a message can carry a dictionary of properties (key/value pairs),
++ * to provide userspace with a machine-readable message context.
++ *
++ * Examples for well-defined, commonly used property names are:
++ * DEVICE=b12:8 device identifier
++ * b12:8 block dev_t
++ * c127:3 char dev_t
++ * n8 netdev ifindex
++ * +sound:card0 subsystem:devname
++ * SUBSYSTEM=pci driver-core subsystem name
++ *
++ * Valid characters in property names are [a-zA-Z0-9.-_]. The plain text value
++ * follows directly after a '=' character. Every property is terminated by
++ * a '\0' character. The last property is not terminated.
++ *
++ * Example of a message structure:
++ * 0000 ff 8f 00 00 00 00 00 00 monotonic time in nsec
++ * 0008 34 00 record is 52 bytes long
++ * 000a 0b 00 text is 11 bytes long
++ * 000c 1f 00 dictionary is 23 bytes long
++ * 000e 03 00 LOG_KERN (facility) LOG_ERR (level)
++ * 0010 69 74 27 73 20 61 20 6c "it's a l"
++ * 69 6e 65 "ine"
++ * 001b 44 45 56 49 43 "DEVIC"
++ * 45 3d 62 38 3a 32 00 44 "E=b8:2\0D"
++ * 52 49 56 45 52 3d 62 75 "RIVER=bu"
++ * 67 "g"
++ * 0032 00 00 00 padding to next message header
++ *
++ * The 'struct printk_log' buffer header must never be directly exported to
++ * userspace, it is a kernel-private implementation detail that might
++ * need to be changed in the future, when the requirements change.
++ *
++ * /dev/kmsg exports the structured data in the following line format:
++ * "level,sequnum,timestamp;<message text>\n"
++ *
++ * The optional key/value pairs are attached as continuation lines starting
++ * with a space character and terminated by a newline. All possible
++ * non-prinatable characters are escaped in the "\xff" notation.
++ *
++ * Users of the export format should ignore possible additional values
++ * separated by ',', and find the message after the ';' character.
++ */
++
++enum log_flags {
++ LOG_NOCONS = 1, /* already flushed, do not print to console */
++ LOG_NEWLINE = 2, /* text ended with a newline */
++ LOG_PREFIX = 4, /* text started with a prefix */
++ LOG_CONT = 8, /* text is a fragment of a continuation line */
++};
++
++struct printk_log {
++ u64 ts_nsec; /* timestamp in nanoseconds */
++ u16 len; /* length of entire record */
++ u16 text_len; /* length of text buffer */
++ u16 dict_len; /* length of dictionary buffer */
++ u8 facility; /* syslog facility */
++ u8 flags:5; /* internal record flags */
++ u8 level:3; /* syslog level */
++};
++
++/*
++ * The logbuf_lock protects kmsg buffer, indices, counters. It is also
++ * used in interesting ways to provide interlocking in console_unlock();
++ */
++static DEFINE_RAW_SPINLOCK(logbuf_lock);
++
++#ifdef CONFIG_PRINTK
++DECLARE_WAIT_QUEUE_HEAD(log_wait);
++/* the next printk record to read by syslog(READ) or /proc/kmsg */
++static u64 syslog_seq;
++static u32 syslog_idx;
++static enum log_flags syslog_prev;
++static size_t syslog_partial;
++
++/* index and sequence number of the first record stored in the buffer */
++static u64 log_first_seq;
++static u32 log_first_idx;
++
++/* index and sequence number of the next record to store in the buffer */
++static u64 log_next_seq;
++static u32 log_next_idx;
++
++/* the next printk record to write to the console */
++static u64 console_seq;
++static u32 console_idx;
++static enum log_flags console_prev;
++
++/* the next printk record to read after the last 'clear' command */
++static u64 clear_seq;
++static u32 clear_idx;
++
++#define PREFIX_MAX 32
++#define LOG_LINE_MAX 1024 - PREFIX_MAX
++
++/* record buffer */
++#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
++#define LOG_ALIGN 4
++#else
++#define LOG_ALIGN __alignof__(struct printk_log)
++#endif
++#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
++static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
++static char *log_buf = __log_buf;
++static u32 log_buf_len = __LOG_BUF_LEN;
++
++/* cpu currently holding logbuf_lock */
++static volatile unsigned int logbuf_cpu = UINT_MAX;
++
++/* human readable text of the record */
++static char *log_text(const struct printk_log *msg)
++{
++ return (char *)msg + sizeof(struct printk_log);
++}
++
++/* optional key/value pair dictionary attached to the record */
++static char *log_dict(const struct printk_log *msg)
++{
++ return (char *)msg + sizeof(struct printk_log) + msg->text_len;
++}
++
++/* get record by index; idx must point to valid msg */
++static struct printk_log *log_from_idx(u32 idx)
++{
++ struct printk_log *msg = (struct printk_log *)(log_buf + idx);
++
++ /*
++ * A length == 0 record is the end of buffer marker. Wrap around and
++ * read the message at the start of the buffer.
++ */
++ if (!msg->len)
++ return (struct printk_log *)log_buf;
++ return msg;
++}
++
++/* get next record; idx must point to valid msg */
++static u32 log_next(u32 idx)
++{
++ struct printk_log *msg = (struct printk_log *)(log_buf + idx);
++
++ /* length == 0 indicates the end of the buffer; wrap */
++ /*
++ * A length == 0 record is the end of buffer marker. Wrap around and
++ * read the message at the start of the buffer as *this* one, and
++ * return the one after that.
++ */
++ if (!msg->len) {
++ msg = (struct printk_log *)log_buf;
++ return msg->len;
++ }
++ return idx + msg->len;
++}
++
++/* insert record into the buffer, discard old ones, update heads */
++static void log_store(int facility, int level,
++ enum log_flags flags, u64 ts_nsec,
++ const char *dict, u16 dict_len,
++ const char *text, u16 text_len)
++{
++ struct printk_log *msg;
++ u32 size, pad_len;
++
++ /* number of '\0' padding bytes to next message */
++ size = sizeof(struct printk_log) + text_len + dict_len;
++ pad_len = (-size) & (LOG_ALIGN - 1);
++ size += pad_len;
++
++ while (log_first_seq < log_next_seq) {
++ u32 free;
++
++ if (log_next_idx > log_first_idx)
++ free = max(log_buf_len - log_next_idx, log_first_idx);
++ else
++ free = log_first_idx - log_next_idx;
++
++ if (free > size + sizeof(struct printk_log))
++ break;
++
++ /* drop old messages until we have enough contiuous space */
++ log_first_idx = log_next(log_first_idx);
++ log_first_seq++;
++ }
++
++ if (log_next_idx + size + sizeof(struct printk_log) >= log_buf_len) {
++ /*
++ * This message + an additional empty header does not fit
++ * at the end of the buffer. Add an empty header with len == 0
++ * to signify a wrap around.
++ */
++ memset(log_buf + log_next_idx, 0, sizeof(struct printk_log));
++ log_next_idx = 0;
++ }
++
++ /* fill message */
++ msg = (struct printk_log *)(log_buf + log_next_idx);
++ memcpy(log_text(msg), text, text_len);
++ msg->text_len = text_len;
++ memcpy(log_dict(msg), dict, dict_len);
++ msg->dict_len = dict_len;
++ msg->facility = facility;
++ msg->level = level & 7;
++ msg->flags = flags & 0x1f;
++ if (ts_nsec > 0)
++ msg->ts_nsec = ts_nsec;
++ else
++ msg->ts_nsec = local_clock();
++ memset(log_dict(msg) + dict_len, 0, pad_len);
++ msg->len = sizeof(struct printk_log) + text_len + dict_len + pad_len;
++
++ /* insert message */
++ log_next_idx += msg->len;
++ log_next_seq++;
++}
++
++#ifdef CONFIG_SECURITY_DMESG_RESTRICT
++int dmesg_restrict __read_only = 1;
++#else
++int dmesg_restrict __read_only;
++#endif
++
++static int syslog_action_restricted(int type)
++{
++ if (dmesg_restrict)
++ return 1;
++ /*
++ * Unless restricted, we allow "read all" and "get buffer size"
++ * for everybody.
++ */
++ return type != SYSLOG_ACTION_READ_ALL &&
++ type != SYSLOG_ACTION_SIZE_BUFFER;
++}
++
++static int check_syslog_permissions(int type, bool from_file)
++{
++ /*
++ * If this is from /proc/kmsg and we've already opened it, then we've
++ * already done the capabilities checks at open time.
++ */
++ if (from_file && type != SYSLOG_ACTION_OPEN)
++ return 0;
++
++#ifdef CONFIG_GRKERNSEC_DMESG
++ if (grsec_enable_dmesg && !capable(CAP_SYSLOG) && !capable_nolog(CAP_SYS_ADMIN))
++ return -EPERM;
++#endif
++
++ if (syslog_action_restricted(type)) {
++ if (capable(CAP_SYSLOG))
++ return 0;
++ /*
++ * For historical reasons, accept CAP_SYS_ADMIN too, with
++ * a warning.
++ */
++ if (capable(CAP_SYS_ADMIN)) {
++ pr_warn_once("%s (%d): Attempt to access syslog with "
++ "CAP_SYS_ADMIN but no CAP_SYSLOG "
++ "(deprecated).\n",
++ current->comm, task_pid_nr(current));
++ return 0;
++ }
++ return -EPERM;
++ }
++ return security_syslog(type);
++}
++
++
++/* /dev/kmsg - userspace message inject/listen interface */
++struct devkmsg_user {
++ u64 seq;
++ u32 idx;
++ enum log_flags prev;
++ struct mutex lock;
++ char buf[8192];
++};
++
++static ssize_t devkmsg_writev(struct kiocb *iocb, const struct iovec *iv,
++ unsigned long count, loff_t pos)
++{
++ char *buf, *line;
++ int i;
++ int level = default_message_loglevel;
++ int facility = 1; /* LOG_USER */
++ size_t len = iov_length(iv, count);
++ ssize_t ret = len;
++
++ if (len > LOG_LINE_MAX)
++ return -EINVAL;
++ buf = kmalloc(len+1, GFP_KERNEL);
++ if (buf == NULL)
++ return -ENOMEM;
++
++ line = buf;
++ for (i = 0; i < count; i++) {
++ if (copy_from_user(line, iv[i].iov_base, iv[i].iov_len)) {
++ ret = -EFAULT;
++ goto out;
++ }
++ line += iv[i].iov_len;
++ }
++
++ /*
++ * Extract and skip the syslog prefix <[0-9]*>. Coming from userspace
++ * the decimal value represents 32bit, the lower 3 bit are the log
++ * level, the rest are the log facility.
++ *
++ * If no prefix or no userspace facility is specified, we
++ * enforce LOG_USER, to be able to reliably distinguish
++ * kernel-generated messages from userspace-injected ones.
++ */
++ line = buf;
++ if (line[0] == '<') {
++ char *endp = NULL;
++
++ i = simple_strtoul(line+1, &endp, 10);
++ if (endp && endp[0] == '>') {
++ level = i & 7;
++ if (i >> 3)
++ facility = i >> 3;
++ endp++;
++ len -= endp - line;
++ line = endp;
++ }
++ }
++ line[len] = '\0';
++
++ printk_emit(facility, level, NULL, 0, "%s", line);
++out:
++ kfree(buf);
++ return ret;
++}
++
++static ssize_t devkmsg_read(struct file *file, char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ struct devkmsg_user *user = file->private_data;
++ struct printk_log *msg;
++ u64 ts_usec;
++ size_t i;
++ char cont = '-';
++ size_t len;
++ ssize_t ret;
++
++ if (!user)
++ return -EBADF;
++
++ ret = mutex_lock_interruptible(&user->lock);
++ if (ret)
++ return ret;
++ raw_spin_lock_irq(&logbuf_lock);
++ while (user->seq == log_next_seq) {
++ if (file->f_flags & O_NONBLOCK) {
++ ret = -EAGAIN;
++ raw_spin_unlock_irq(&logbuf_lock);
++ goto out;
++ }
++
++ raw_spin_unlock_irq(&logbuf_lock);
++ ret = wait_event_interruptible(log_wait,
++ user->seq != log_next_seq);
++ if (ret)
++ goto out;
++ raw_spin_lock_irq(&logbuf_lock);
++ }
++
++ if (user->seq < log_first_seq) {
++ /* our last seen message is gone, return error and reset */
++ user->idx = log_first_idx;
++ user->seq = log_first_seq;
++ ret = -EPIPE;
++ raw_spin_unlock_irq(&logbuf_lock);
++ goto out;
++ }
++
++ msg = log_from_idx(user->idx);
++ ts_usec = msg->ts_nsec;
++ do_div(ts_usec, 1000);
++
++ /*
++ * If we couldn't merge continuation line fragments during the print,
++ * export the stored flags to allow an optional external merge of the
++ * records. Merging the records isn't always neccessarily correct, like
++ * when we hit a race during printing. In most cases though, it produces
++ * better readable output. 'c' in the record flags mark the first
++ * fragment of a line, '+' the following.
++ */
++ if (msg->flags & LOG_CONT && !(user->prev & LOG_CONT))
++ cont = 'c';
++ else if ((msg->flags & LOG_CONT) ||
++ ((user->prev & LOG_CONT) && !(msg->flags & LOG_PREFIX)))
++ cont = '+';
++
++ len = sprintf(user->buf, "%u,%llu,%llu,%c;",
++ (msg->facility << 3) | msg->level,
++ user->seq, ts_usec, cont);
++ user->prev = msg->flags;
++
++ /* escape non-printable characters */
++ for (i = 0; i < msg->text_len; i++) {
++ unsigned char c = log_text(msg)[i];
++
++ if (c < ' ' || c >= 127 || c == '\\')
++ len += sprintf(user->buf + len, "\\x%02x", c);
++ else
++ user->buf[len++] = c;
++ }
++ user->buf[len++] = '\n';
++
++ if (msg->dict_len) {
++ bool line = true;
++
++ for (i = 0; i < msg->dict_len; i++) {
++ unsigned char c = log_dict(msg)[i];
++
++ if (line) {
++ user->buf[len++] = ' ';
++ line = false;
++ }
++
++ if (c == '\0') {
++ user->buf[len++] = '\n';
++ line = true;
++ continue;
++ }
++
++ if (c < ' ' || c >= 127 || c == '\\') {
++ len += sprintf(user->buf + len, "\\x%02x", c);
++ continue;
++ }
++
++ user->buf[len++] = c;
++ }
++ user->buf[len++] = '\n';
++ }
++
++ user->idx = log_next(user->idx);
++ user->seq++;
++ raw_spin_unlock_irq(&logbuf_lock);
++
++ if (len > count) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ if (copy_to_user(buf, user->buf, len)) {
++ ret = -EFAULT;
++ goto out;
++ }
++ ret = len;
++out:
++ mutex_unlock(&user->lock);
++ return ret;
++}
++
++static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
++{
++ struct devkmsg_user *user = file->private_data;
++ loff_t ret = 0;
++
++ if (!user)
++ return -EBADF;
++ if (offset)
++ return -ESPIPE;
++
++ raw_spin_lock_irq(&logbuf_lock);
++ switch (whence) {
++ case SEEK_SET:
++ /* the first record */
++ user->idx = log_first_idx;
++ user->seq = log_first_seq;
++ break;
++ case SEEK_DATA:
++ /*
++ * The first record after the last SYSLOG_ACTION_CLEAR,
++ * like issued by 'dmesg -c'. Reading /dev/kmsg itself
++ * changes no global state, and does not clear anything.
++ */
++ user->idx = clear_idx;
++ user->seq = clear_seq;
++ break;
++ case SEEK_END:
++ /* after the last record */
++ user->idx = log_next_idx;
++ user->seq = log_next_seq;
++ break;
++ default:
++ ret = -EINVAL;
++ }
++ raw_spin_unlock_irq(&logbuf_lock);
++ return ret;
++}
++
++static unsigned int devkmsg_poll(struct file *file, poll_table *wait)
++{
++ struct devkmsg_user *user = file->private_data;
++ int ret = 0;
++
++ if (!user)
++ return POLLERR|POLLNVAL;
++
++ poll_wait(file, &log_wait, wait);
++
++ raw_spin_lock_irq(&logbuf_lock);
++ if (user->seq < log_next_seq) {
++ /* return error when data has vanished underneath us */
++ if (user->seq < log_first_seq)
++ ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI;
++ else
++ ret = POLLIN|POLLRDNORM;
++ }
++ raw_spin_unlock_irq(&logbuf_lock);
++
++ return ret;
++}
++
++static int devkmsg_open(struct inode *inode, struct file *file)
++{
++ struct devkmsg_user *user;
++ int err;
++
++ /* write-only does not need any file context */
++ if ((file->f_flags & O_ACCMODE) == O_WRONLY)
++ return 0;
++
++ err = check_syslog_permissions(SYSLOG_ACTION_READ_ALL,
++ SYSLOG_FROM_READER);
++ if (err)
++ return err;
++
++ user = kmalloc(sizeof(struct devkmsg_user), GFP_KERNEL);
++ if (!user)
++ return -ENOMEM;
++
++ mutex_init(&user->lock);
++
++ raw_spin_lock_irq(&logbuf_lock);
++ user->idx = log_first_idx;
++ user->seq = log_first_seq;
++ raw_spin_unlock_irq(&logbuf_lock);
++
++ file->private_data = user;
++ return 0;
++}
++
++static int devkmsg_release(struct inode *inode, struct file *file)
++{
++ struct devkmsg_user *user = file->private_data;
++
++ if (!user)
++ return 0;
++
++ mutex_destroy(&user->lock);
++ kfree(user);
++ return 0;
++}
++
++const struct file_operations kmsg_fops = {
++ .open = devkmsg_open,
++ .read = devkmsg_read,
++ .aio_write = devkmsg_writev,
++ .llseek = devkmsg_llseek,
++ .poll = devkmsg_poll,
++ .release = devkmsg_release,
++};
++
++#ifdef CONFIG_KEXEC
++/*
++ * This appends the listed symbols to /proc/vmcore
++ *
++ * /proc/vmcore is used by various utilities, like crash and makedumpfile to
++ * obtain access to symbols that are otherwise very difficult to locate. These
++ * symbols are specifically used so that utilities can access and extract the
++ * dmesg log from a vmcore file after a crash.
++ */
++void log_buf_kexec_setup(void)
++{
++ VMCOREINFO_SYMBOL(log_buf);
++ VMCOREINFO_SYMBOL(log_buf_len);
++ VMCOREINFO_SYMBOL(log_first_idx);
++ VMCOREINFO_SYMBOL(log_next_idx);
++ /*
++ * Export struct printk_log size and field offsets. User space tools can
++ * parse it and detect any changes to structure down the line.
++ */
++ VMCOREINFO_STRUCT_SIZE(printk_log);
++ VMCOREINFO_OFFSET(printk_log, ts_nsec);
++ VMCOREINFO_OFFSET(printk_log, len);
++ VMCOREINFO_OFFSET(printk_log, text_len);
++ VMCOREINFO_OFFSET(printk_log, dict_len);
++}
++#endif
++
++/* requested log_buf_len from kernel cmdline */
++static unsigned long __initdata new_log_buf_len;
++
++/* save requested log_buf_len since it's too early to process it */
++static int __init log_buf_len_setup(char *str)
++{
++ unsigned size = memparse(str, &str);
++
++ if (size)
++ size = roundup_pow_of_two(size);
++ if (size > log_buf_len)
++ new_log_buf_len = size;
++
++ return 0;
++}
++early_param("log_buf_len", log_buf_len_setup);
++
++void __init setup_log_buf(int early)
++{
++ unsigned long flags;
++ char *new_log_buf;
++ int free;
++
++ if (!new_log_buf_len)
++ return;
++
++ if (early) {
++ new_log_buf =
++ memblock_virt_alloc(new_log_buf_len, PAGE_SIZE);
++ } else {
++ new_log_buf = memblock_virt_alloc_nopanic(new_log_buf_len, 0);
++ }
++
++ if (unlikely(!new_log_buf)) {
++ pr_err("log_buf_len: %ld bytes not available\n",
++ new_log_buf_len);
++ return;
++ }
++
++ raw_spin_lock_irqsave(&logbuf_lock, flags);
++ log_buf_len = new_log_buf_len;
++ log_buf = new_log_buf;
++ new_log_buf_len = 0;
++ free = __LOG_BUF_LEN - log_next_idx;
++ memcpy(log_buf, __log_buf, __LOG_BUF_LEN);
++ raw_spin_unlock_irqrestore(&logbuf_lock, flags);
++
++ pr_info("log_buf_len: %d\n", log_buf_len);
++ pr_info("early log buf free: %d(%d%%)\n",
++ free, (free * 100) / __LOG_BUF_LEN);
++}
++
++static bool __read_mostly ignore_loglevel;
++
++static int __init ignore_loglevel_setup(char *str)
++{
++ ignore_loglevel = 1;
++ pr_info("debug: ignoring loglevel setting.\n");
++
++ return 0;
++}
++
++early_param("ignore_loglevel", ignore_loglevel_setup);
++module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(ignore_loglevel, "ignore loglevel setting, to"
++ "print all kernel messages to the console.");
++
++#ifdef CONFIG_BOOT_PRINTK_DELAY
++
++static int boot_delay; /* msecs delay after each printk during bootup */
++static unsigned long long loops_per_msec; /* based on boot_delay */
++
++static int __init boot_delay_setup(char *str)
++{
++ unsigned long lpj;
++
++ lpj = preset_lpj ? preset_lpj : 1000000; /* some guess */
++ loops_per_msec = (unsigned long long)lpj / 1000 * HZ;
++
++ get_option(&str, &boot_delay);
++ if (boot_delay > 10 * 1000)
++ boot_delay = 0;
++
++ pr_debug("boot_delay: %u, preset_lpj: %ld, lpj: %lu, "
++ "HZ: %d, loops_per_msec: %llu\n",
++ boot_delay, preset_lpj, lpj, HZ, loops_per_msec);
++ return 0;
++}
++early_param("boot_delay", boot_delay_setup);
++
++static void boot_delay_msec(int level)
++{
++ unsigned long long k;
++ unsigned long timeout;
++
++ if ((boot_delay == 0 || system_state != SYSTEM_BOOTING)
++ || (level >= console_loglevel && !ignore_loglevel)) {
++ return;
++ }
++
++ k = (unsigned long long)loops_per_msec * boot_delay;
++
++ timeout = jiffies + msecs_to_jiffies(boot_delay);
++ while (k) {
++ k--;
++ cpu_relax();
++ /*
++ * use (volatile) jiffies to prevent
++ * compiler reduction; loop termination via jiffies
++ * is secondary and may or may not happen.
++ */
++ if (time_after(jiffies, timeout))
++ break;
++ touch_nmi_watchdog();
++ }
++}
++#else
++static inline void boot_delay_msec(int level)
++{
++}
++#endif
++
++#if defined(CONFIG_PRINTK_TIME)
++static bool printk_time = 1;
++#else
++static bool printk_time;
++#endif
++module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR);
++
++static size_t print_time(u64 ts, char *buf)
++{
++ unsigned long rem_nsec;
++
++ if (!printk_time)
++ return 0;
++
++ rem_nsec = do_div(ts, 1000000000);
++
++ if (!buf)
++ return snprintf(NULL, 0, "[%5lu.000000] ", (unsigned long)ts);
++
++ return sprintf(buf, "[%5lu.%06lu] ",
++ (unsigned long)ts, rem_nsec / 1000);
++}
++
++static size_t print_prefix(const struct printk_log *msg, bool syslog, char *buf)
++{
++ size_t len = 0;
++ unsigned int prefix = (msg->facility << 3) | msg->level;
++
++ if (syslog) {
++ if (buf) {
++ len += sprintf(buf, "<%u>", prefix);
++ } else {
++ len += 3;
++ if (prefix > 999)
++ len += 3;
++ else if (prefix > 99)
++ len += 2;
++ else if (prefix > 9)
++ len++;
++ }
++ }
++
++ len += print_time(msg->ts_nsec, buf ? buf + len : NULL);
++ return len;
++}
++
++static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev,
++ bool syslog, char *buf, size_t size)
++{
++ const char *text = log_text(msg);
++ size_t text_size = msg->text_len;
++ bool prefix = true;
++ bool newline = true;
++ size_t len = 0;
++
++ if ((prev & LOG_CONT) && !(msg->flags & LOG_PREFIX))
++ prefix = false;
++
++ if (msg->flags & LOG_CONT) {
++ if ((prev & LOG_CONT) && !(prev & LOG_NEWLINE))
++ prefix = false;
++
++ if (!(msg->flags & LOG_NEWLINE))
++ newline = false;
++ }
++
++ do {
++ const char *next = memchr(text, '\n', text_size);
++ size_t text_len;
++
++ if (next) {
++ text_len = next - text;
++ next++;
++ text_size -= next - text;
++ } else {
++ text_len = text_size;
++ }
++
++ if (buf) {
++ if (print_prefix(msg, syslog, NULL) +
++ text_len + 1 >= size - len)
++ break;
++
++ if (prefix)
++ len += print_prefix(msg, syslog, buf + len);
++ memcpy(buf + len, text, text_len);
++ len += text_len;
++ if (next || newline)
++ buf[len++] = '\n';
++ } else {
++ /* SYSLOG_ACTION_* buffer size only calculation */
++ if (prefix)
++ len += print_prefix(msg, syslog, NULL);
++ len += text_len;
++ if (next || newline)
++ len++;
++ }
++
++ prefix = true;
++ text = next;
++ } while (text);
++
++ return len;
++}
++
++static int syslog_print(char __user *buf, int size)
++{
++ char *text;
++ struct printk_log *msg;
++ int len = 0;
++
++ text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL);
++ if (!text)
++ return -ENOMEM;
++
++ while (size > 0) {
++ size_t n;
++ size_t skip;
++
++ raw_spin_lock_irq(&logbuf_lock);
++ if (syslog_seq < log_first_seq) {
++ /* messages are gone, move to first one */
++ syslog_seq = log_first_seq;
++ syslog_idx = log_first_idx;
++ syslog_prev = 0;
++ syslog_partial = 0;
++ }
++ if (syslog_seq == log_next_seq) {
++ raw_spin_unlock_irq(&logbuf_lock);
++ break;
++ }
++
++ skip = syslog_partial;
++ msg = log_from_idx(syslog_idx);
++ n = msg_print_text(msg, syslog_prev, true, text,
++ LOG_LINE_MAX + PREFIX_MAX);
++ if (n - syslog_partial <= size) {
++ /* message fits into buffer, move forward */
++ syslog_idx = log_next(syslog_idx);
++ syslog_seq++;
++ syslog_prev = msg->flags;
++ n -= syslog_partial;
++ syslog_partial = 0;
++ } else if (!len){
++ /* partial read(), remember position */
++ n = size;
++ syslog_partial += n;
++ } else
++ n = 0;
++ raw_spin_unlock_irq(&logbuf_lock);
++
++ if (!n)
++ break;
++
++ if (copy_to_user(buf, text + skip, n)) {
++ if (!len)
++ len = -EFAULT;
++ break;
++ }
++
++ len += n;
++ size -= n;
++ buf += n;
++ }
++
++ kfree(text);
++ return len;
++}
++
++static int syslog_print_all(char __user *buf, int size, bool clear)
++{
++ char *text;
++ int len = 0;
++
++ text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL);
++ if (!text)
++ return -ENOMEM;
++
++ raw_spin_lock_irq(&logbuf_lock);
++ if (buf) {
++ u64 next_seq;
++ u64 seq;
++ u32 idx;
++ enum log_flags prev;
++
++ if (clear_seq < log_first_seq) {
++ /* messages are gone, move to first available one */
++ clear_seq = log_first_seq;
++ clear_idx = log_first_idx;
++ }
++
++ /*
++ * Find first record that fits, including all following records,
++ * into the user-provided buffer for this dump.
++ */
++ seq = clear_seq;
++ idx = clear_idx;
++ prev = 0;
++ while (seq < log_next_seq) {
++ struct printk_log *msg = log_from_idx(idx);
++
++ len += msg_print_text(msg, prev, true, NULL, 0);
++ prev = msg->flags;
++ idx = log_next(idx);
++ seq++;
++ }
++
++ /* move first record forward until length fits into the buffer */
++ seq = clear_seq;
++ idx = clear_idx;
++ prev = 0;
++ while (len > size && seq < log_next_seq) {
++ struct printk_log *msg = log_from_idx(idx);
++
++ len -= msg_print_text(msg, prev, true, NULL, 0);
++ prev = msg->flags;
++ idx = log_next(idx);
++ seq++;
++ }
++
++ /* last message fitting into this dump */
++ next_seq = log_next_seq;
++
++ len = 0;
++ while (len >= 0 && seq < next_seq) {
++ struct printk_log *msg = log_from_idx(idx);
++ int textlen;
++
++ textlen = msg_print_text(msg, prev, true, text,
++ LOG_LINE_MAX + PREFIX_MAX);
++ if (textlen < 0) {
++ len = textlen;
++ break;
++ }
++ idx = log_next(idx);
++ seq++;
++ prev = msg->flags;
++
++ raw_spin_unlock_irq(&logbuf_lock);
++ if (copy_to_user(buf + len, text, textlen))
++ len = -EFAULT;
++ else
++ len += textlen;
++ raw_spin_lock_irq(&logbuf_lock);
++
++ if (seq < log_first_seq) {
++ /* messages are gone, move to next one */
++ seq = log_first_seq;
++ idx = log_first_idx;
++ prev = 0;
++ }
++ }
++ }
++
++ if (clear) {
++ clear_seq = log_next_seq;
++ clear_idx = log_next_idx;
++ }
++ raw_spin_unlock_irq(&logbuf_lock);
++
++ kfree(text);
++ return len;
++}
++
++int do_syslog(int type, char __user *buf, int len, bool from_file)
++{
++ bool clear = false;
++ static int saved_console_loglevel = -1;
++ int error;
++
++ error = check_syslog_permissions(type, from_file);
++ if (error)
++ goto out;
++
++ error = security_syslog(type);
++ if (error)
++ return error;
++
++ switch (type) {
++ case SYSLOG_ACTION_CLOSE: /* Close log */
++ break;
++ case SYSLOG_ACTION_OPEN: /* Open log */
++ break;
++ case SYSLOG_ACTION_READ: /* Read from log */
++ error = -EINVAL;
++ if (!buf || len < 0)
++ goto out;
++ error = 0;
++ if (!len)
++ goto out;
++ if (!access_ok(VERIFY_WRITE, buf, len)) {
++ error = -EFAULT;
++ goto out;
++ }
++ error = wait_event_interruptible(log_wait,
++ syslog_seq != log_next_seq);
++ if (error)
++ goto out;
++ error = syslog_print(buf, len);
++ break;
++ /* Read/clear last kernel messages */
++ case SYSLOG_ACTION_READ_CLEAR:
++ clear = true;
++ /* FALL THRU */
++ /* Read last kernel messages */
++ case SYSLOG_ACTION_READ_ALL:
++ error = -EINVAL;
++ if (!buf || len < 0)
++ goto out;
++ error = 0;
++ if (!len)
++ goto out;
++ if (!access_ok(VERIFY_WRITE, buf, len)) {
++ error = -EFAULT;
++ goto out;
++ }
++ error = syslog_print_all(buf, len, clear);
++ break;
++ /* Clear ring buffer */
++ case SYSLOG_ACTION_CLEAR:
++ syslog_print_all(NULL, 0, true);
++ break;
++ /* Disable logging to console */
++ case SYSLOG_ACTION_CONSOLE_OFF:
++ if (saved_console_loglevel == -1)
++ saved_console_loglevel = console_loglevel;
++ console_loglevel = minimum_console_loglevel;
++ break;
++ /* Enable logging to console */
++ case SYSLOG_ACTION_CONSOLE_ON:
++ if (saved_console_loglevel != -1) {
++ console_loglevel = saved_console_loglevel;
++ saved_console_loglevel = -1;
++ }
++ break;
++ /* Set level of messages printed to console */
++ case SYSLOG_ACTION_CONSOLE_LEVEL:
++ error = -EINVAL;
++ if (len < 1 || len > 8)
++ goto out;
++ if (len < minimum_console_loglevel)
++ len = minimum_console_loglevel;
++ console_loglevel = len;
++ /* Implicitly re-enable logging to console */
++ saved_console_loglevel = -1;
++ error = 0;
++ break;
++ /* Number of chars in the log buffer */
++ case SYSLOG_ACTION_SIZE_UNREAD:
++ raw_spin_lock_irq(&logbuf_lock);
++ if (syslog_seq < log_first_seq) {
++ /* messages are gone, move to first one */
++ syslog_seq = log_first_seq;
++ syslog_idx = log_first_idx;
++ syslog_prev = 0;
++ syslog_partial = 0;
++ }
++ if (from_file) {
++ /*
++ * Short-cut for poll(/"proc/kmsg") which simply checks
++ * for pending data, not the size; return the count of
++ * records, not the length.
++ */
++ error = log_next_idx - syslog_idx;
++ } else {
++ u64 seq = syslog_seq;
++ u32 idx = syslog_idx;
++ enum log_flags prev = syslog_prev;
++
++ error = 0;
++ while (seq < log_next_seq) {
++ struct printk_log *msg = log_from_idx(idx);
++
++ error += msg_print_text(msg, prev, true, NULL, 0);
++ idx = log_next(idx);
++ seq++;
++ prev = msg->flags;
++ }
++ error -= syslog_partial;
++ }
++ raw_spin_unlock_irq(&logbuf_lock);
++ break;
++ /* Size of the log buffer */
++ case SYSLOG_ACTION_SIZE_BUFFER:
++ error = log_buf_len;
++ break;
++ default:
++ error = -EINVAL;
++ break;
++ }
++out:
++ return error;
++}
++
++SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
++{
++ return do_syslog(type, buf, len, SYSLOG_FROM_READER);
++}
++
++/*
++ * Call the console drivers, asking them to write out
++ * log_buf[start] to log_buf[end - 1].
++ * The console_lock must be held.
++ */
++static void call_console_drivers(int level, const char *text, size_t len)
++{
++ struct console *con;
++
++ trace_console(text, len);
++
++ if (level >= console_loglevel && !ignore_loglevel)
++ return;
++ if (!console_drivers)
++ return;
++
++ for_each_console(con) {
++ if (exclusive_console && con != exclusive_console)
++ continue;
++ if (!(con->flags & CON_ENABLED))
++ continue;
++ if (!con->write)
++ continue;
++ if (!cpu_online(smp_processor_id()) &&
++ !(con->flags & CON_ANYTIME))
++ continue;
++ con->write(con, text, len);
++ }
++}
++
++/*
++ * Zap console related locks when oopsing. Only zap at most once
++ * every 10 seconds, to leave time for slow consoles to print a
++ * full oops.
++ */
++static void zap_locks(void)
++{
++ static unsigned long oops_timestamp;
++
++ if (time_after_eq(jiffies, oops_timestamp) &&
++ !time_after(jiffies, oops_timestamp + 30 * HZ))
++ return;
++
++ oops_timestamp = jiffies;
++
++ debug_locks_off();
++ /* If a crash is occurring, make sure we can't deadlock */
++ raw_spin_lock_init(&logbuf_lock);
++ /* And make sure that we print immediately */
++ sema_init(&console_sem, 1);
++}
++
++/* Check if we have any console registered that can be called early in boot. */
++static int have_callable_console(void)
++{
++ struct console *con;
++
++ for_each_console(con)
++ if (con->flags & CON_ANYTIME)
++ return 1;
++
++ return 0;
++}
++
++/*
++ * Can we actually use the console at this time on this cpu?
++ *
++ * Console drivers may assume that per-cpu resources have
++ * been allocated. So unless they're explicitly marked as
++ * being able to cope (CON_ANYTIME) don't call them until
++ * this CPU is officially up.
++ */
++static inline int can_use_console(unsigned int cpu)
++{
++ return cpu_online(cpu) || have_callable_console();
++}
++
++/*
++ * Try to get console ownership to actually show the kernel
++ * messages from a 'printk'. Return true (and with the
++ * console_lock held, and 'console_locked' set) if it
++ * is successful, false otherwise.
++ *
++ * This gets called with the 'logbuf_lock' spinlock held and
++ * interrupts disabled. It should return with 'lockbuf_lock'
++ * released but interrupts still disabled.
++ */
++static int console_trylock_for_printk(unsigned int cpu)
++ __releases(&logbuf_lock)
++{
++ int retval = 0, wake = 0;
++
++ if (console_trylock()) {
++ retval = 1;
++
++ /*
++ * If we can't use the console, we need to release
++ * the console semaphore by hand to avoid flushing
++ * the buffer. We need to hold the console semaphore
++ * in order to do this test safely.
++ */
++ if (!can_use_console(cpu)) {
++ console_locked = 0;
++ wake = 1;
++ retval = 0;
++ }
++ }
++ logbuf_cpu = UINT_MAX;
++ raw_spin_unlock(&logbuf_lock);
++ if (wake)
++ up(&console_sem);
++ return retval;
++}
++
++int printk_delay_msec __read_mostly;
++
++static inline void printk_delay(void)
++{
++ if (unlikely(printk_delay_msec)) {
++ int m = printk_delay_msec;
++
++ while (m--) {
++ mdelay(1);
++ touch_nmi_watchdog();
++ }
++ }
++}
++
++/*
++ * Continuation lines are buffered, and not committed to the record buffer
++ * until the line is complete, or a race forces it. The line fragments
++ * though, are printed immediately to the consoles to ensure everything has
++ * reached the console in case of a kernel crash.
++ */
++static struct cont {
++ char buf[LOG_LINE_MAX];
++ size_t len; /* length == 0 means unused buffer */
++ size_t cons; /* bytes written to console */
++ struct task_struct *owner; /* task of first print*/
++ u64 ts_nsec; /* time of first print */
++ u8 level; /* log level of first message */
++ u8 facility; /* log level of first message */
++ enum log_flags flags; /* prefix, newline flags */
++ bool flushed:1; /* buffer sealed and committed */
++} cont;
++
++static void cont_flush(enum log_flags flags)
++{
++ if (cont.flushed)
++ return;
++ if (cont.len == 0)
++ return;
++
++ if (cont.cons) {
++ /*
++ * If a fragment of this line was directly flushed to the
++ * console; wait for the console to pick up the rest of the
++ * line. LOG_NOCONS suppresses a duplicated output.
++ */
++ log_store(cont.facility, cont.level, flags | LOG_NOCONS,
++ cont.ts_nsec, NULL, 0, cont.buf, cont.len);
++ cont.flags = flags;
++ cont.flushed = true;
++ } else {
++ /*
++ * If no fragment of this line ever reached the console,
++ * just submit it to the store and free the buffer.
++ */
++ log_store(cont.facility, cont.level, flags, 0,
++ NULL, 0, cont.buf, cont.len);
++ cont.len = 0;
++ }
++}
++
++static bool cont_add(int facility, int level, const char *text, size_t len)
++{
++ if (cont.len && cont.flushed)
++ return false;
++
++ if (cont.len + len > sizeof(cont.buf)) {
++ /* the line gets too long, split it up in separate records */
++ cont_flush(LOG_CONT);
++ return false;
++ }
++
++ if (!cont.len) {
++ cont.facility = facility;
++ cont.level = level;
++ cont.owner = current;
++ cont.ts_nsec = local_clock();
++ cont.flags = 0;
++ cont.cons = 0;
++ cont.flushed = false;
++ }
++
++ memcpy(cont.buf + cont.len, text, len);
++ cont.len += len;
++
++ if (cont.len > (sizeof(cont.buf) * 80) / 100)
++ cont_flush(LOG_CONT);
++
++ return true;
++}
++
++static size_t cont_print_text(char *text, size_t size)
++{
++ size_t textlen = 0;
++ size_t len;
++
++ if (cont.cons == 0 && (console_prev & LOG_NEWLINE)) {
++ textlen += print_time(cont.ts_nsec, text);
++ size -= textlen;
++ }
++
++ len = cont.len - cont.cons;
++ if (len > 0) {
++ if (len+1 > size)
++ len = size-1;
++ memcpy(text + textlen, cont.buf + cont.cons, len);
++ textlen += len;
++ cont.cons = cont.len;
++ }
++
++ if (cont.flushed) {
++ if (cont.flags & LOG_NEWLINE)
++ text[textlen++] = '\n';
++ /* got everything, release buffer */
++ cont.len = 0;
++ }
++ return textlen;
++}
++
++asmlinkage int vprintk_emit(int facility, int level,
++ const char *dict, size_t dictlen,
++ const char *fmt, va_list args)
++{
++ static int recursion_bug;
++ static char textbuf[LOG_LINE_MAX];
++ char *text = textbuf;
++ size_t text_len;
++ enum log_flags lflags = 0;
++ unsigned long flags;
++ int this_cpu;
++ int printed_len = 0;
++
++ boot_delay_msec(level);
++ printk_delay();
++
++ /* This stops the holder of console_sem just where we want him */
++ local_irq_save(flags);
++ this_cpu = smp_processor_id();
++
++ /*
++ * Ouch, printk recursed into itself!
++ */
++ if (unlikely(logbuf_cpu == this_cpu)) {
++ /*
++ * If a crash is occurring during printk() on this CPU,
++ * then try to get the crash message out but make sure
++ * we can't deadlock. Otherwise just return to avoid the
++ * recursion and return - but flag the recursion so that
++ * it can be printed at the next appropriate moment:
++ */
++ if (!oops_in_progress && !lockdep_recursing(current)) {
++ recursion_bug = 1;
++ goto out_restore_irqs;
++ }
++ zap_locks();
++ }
++
++ lockdep_off();
++ raw_spin_lock(&logbuf_lock);
++ logbuf_cpu = this_cpu;
++
++ if (recursion_bug) {
++ static const char recursion_msg[] =
++ "BUG: recent printk recursion!";
++
++ recursion_bug = 0;
++ printed_len += strlen(recursion_msg);
++ /* emit KERN_CRIT message */
++ log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,
++ NULL, 0, recursion_msg, printed_len);
++ }
++
++ /*
++ * The printf needs to come first; we need the syslog
++ * prefix which might be passed-in as a parameter.
++ */
++ text_len = vscnprintf(text, sizeof(textbuf), fmt, args);
++
++ /* mark and strip a trailing newline */
++ if (text_len && text[text_len-1] == '\n') {
++ text_len--;
++ lflags |= LOG_NEWLINE;
++ }
++
++ /* strip kernel syslog prefix and extract log level or control flags */
++ if (facility == 0) {
++ int kern_level = printk_get_level(text);
++
++ if (kern_level) {
++ const char *end_of_header = printk_skip_level(text);
++ switch (kern_level) {
++ case '0' ... '7':
++ if (level == -1)
++ level = kern_level - '0';
++ case 'd': /* KERN_DEFAULT */
++ lflags |= LOG_PREFIX;
++ case 'c': /* KERN_CONT */
++ break;
++ }
++ text_len -= end_of_header - text;
++ text = (char *)end_of_header;
++ }
++ }
++
++ if (level == -1)
++ level = default_message_loglevel;
++
++ if (dict)
++ lflags |= LOG_PREFIX|LOG_NEWLINE;
++
++ if (!(lflags & LOG_NEWLINE)) {
++ /*
++ * Flush the conflicting buffer. An earlier newline was missing,
++ * or another task also prints continuation lines.
++ */
++ if (cont.len && (lflags & LOG_PREFIX || cont.owner != current))
++ cont_flush(LOG_NEWLINE);
++
++ /* buffer line if possible, otherwise store it right away */
++ if (!cont_add(facility, level, text, text_len))
++ log_store(facility, level, lflags | LOG_CONT, 0,
++ dict, dictlen, text, text_len);
++ } else {
++ bool stored = false;
++
++ /*
++ * If an earlier newline was missing and it was the same task,
++ * either merge it with the current buffer and flush, or if
++ * there was a race with interrupts (prefix == true) then just
++ * flush it out and store this line separately.
++ * If the preceding printk was from a different task and missed
++ * a newline, flush and append the newline.
++ */
++ if (cont.len) {
++ if (cont.owner == current && !(lflags & LOG_PREFIX))
++ stored = cont_add(facility, level, text,
++ text_len);
++ cont_flush(LOG_NEWLINE);
++ }
++
++ if (!stored)
++ log_store(facility, level, lflags, 0,
++ dict, dictlen, text, text_len);
++ }
++ printed_len += text_len;
++
++ /*
++ * Try to acquire and then immediately release the console semaphore.
++ * The release will print out buffers and wake up /dev/kmsg and syslog()
++ * users.
++ *
++ * The console_trylock_for_printk() function will release 'logbuf_lock'
++ * regardless of whether it actually gets the console semaphore or not.
++ */
++ if (console_trylock_for_printk(this_cpu))
++ console_unlock();
++
++ lockdep_on();
++out_restore_irqs:
++ local_irq_restore(flags);
++
++ return printed_len;
++}
++EXPORT_SYMBOL(vprintk_emit);
++
++asmlinkage int vprintk(const char *fmt, va_list args)
++{
++ return vprintk_emit(0, -1, NULL, 0, fmt, args);
++}
++EXPORT_SYMBOL(vprintk);
++
++asmlinkage int printk_emit(int facility, int level,
++ const char *dict, size_t dictlen,
++ const char *fmt, ...)
++{
++ va_list args;
++ int r;
++
++ va_start(args, fmt);
++ r = vprintk_emit(facility, level, dict, dictlen, fmt, args);
++ va_end(args);
++
++ return r;
++}
++EXPORT_SYMBOL(printk_emit);
++
++/**
++ * printk - print a kernel message
++ * @fmt: format string
++ *
++ * This is printk(). It can be called from any context. We want it to work.
++ *
++ * We try to grab the console_lock. If we succeed, it's easy - we log the
++ * output and call the console drivers. If we fail to get the semaphore, we
++ * place the output into the log buffer and return. The current holder of
++ * the console_sem will notice the new output in console_unlock(); and will
++ * send it to the consoles before releasing the lock.
++ *
++ * One effect of this deferred printing is that code which calls printk() and
++ * then changes console_loglevel may break. This is because console_loglevel
++ * is inspected when the actual printing occurs.
++ *
++ * See also:
++ * printf(3)
++ *
++ * See the vsnprintf() documentation for format string extensions over C99.
++ */
++asmlinkage int printk(const char *fmt, ...)
++{
++ va_list args;
++ int r;
++
++#ifdef CONFIG_KGDB_KDB
++ if (unlikely(kdb_trap_printk)) {
++ va_start(args, fmt);
++ r = vkdb_printf(fmt, args);
++ va_end(args);
++ return r;
++ }
++#endif
++ va_start(args, fmt);
++ r = vprintk_emit(0, -1, NULL, 0, fmt, args);
++ va_end(args);
++
++ return r;
++}
++EXPORT_SYMBOL(printk);
++
++#else /* CONFIG_PRINTK */
++
++#define LOG_LINE_MAX 0
++#define PREFIX_MAX 0
++#define LOG_LINE_MAX 0
++static u64 syslog_seq;
++static u32 syslog_idx;
++static u64 console_seq;
++static u32 console_idx;
++static enum log_flags syslog_prev;
++static u64 log_first_seq;
++static u32 log_first_idx;
++static u64 log_next_seq;
++static enum log_flags console_prev;
++static struct cont {
++ size_t len;
++ size_t cons;
++ u8 level;
++ bool flushed:1;
++} cont;
++static struct printk_log *log_from_idx(u32 idx) { return NULL; }
++static u32 log_next(u32 idx) { return 0; }
++static void call_console_drivers(int level, const char *text, size_t len) {}
++static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev,
++ bool syslog, char *buf, size_t size) { return 0; }
++static size_t cont_print_text(char *text, size_t size) { return 0; }
++
++#endif /* CONFIG_PRINTK */
++
++#ifdef CONFIG_EARLY_PRINTK
++struct console *early_console;
++
++void early_vprintk(const char *fmt, va_list ap)
++{
++ if (early_console) {
++ char buf[512];
++ int n = vscnprintf(buf, sizeof(buf), fmt, ap);
++
++ early_console->write(early_console, buf, n);
++ }
++}
++
++asmlinkage void early_printk(const char *fmt, ...)
++{
++ va_list ap;
++
++ va_start(ap, fmt);
++ early_vprintk(fmt, ap);
++ va_end(ap);
++}
++#endif
++
++static int __add_preferred_console(char *name, int idx, char *options,
++ char *brl_options)
++{
++ struct console_cmdline *c;
++ int i;
++
++ /*
++ * See if this tty is not yet registered, and
++ * if we have a slot free.
++ */
++ for (i = 0, c = console_cmdline;
++ i < MAX_CMDLINECONSOLES && c->name[0];
++ i++, c++) {
++ if (strcmp(c->name, name) == 0 && c->index == idx) {
++ if (!brl_options)
++ selected_console = i;
++ return 0;
++ }
++ }
++ if (i == MAX_CMDLINECONSOLES)
++ return -E2BIG;
++ if (!brl_options)
++ selected_console = i;
++ strlcpy(c->name, name, sizeof(c->name));
++ c->options = options;
++ braille_set_options(c, brl_options);
++
++ c->index = idx;
++ return 0;
++}
++/*
++ * Set up a list of consoles. Called from init/main.c
++ */
++static int __init console_setup(char *str)
++{
++ char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for index */
++ char *s, *options, *brl_options = NULL;
++ int idx;
++
++ if (_braille_console_setup(&str, &brl_options))
++ return 1;
++
++ /*
++ * Decode str into name, index, options.
++ */
++ if (str[0] >= '0' && str[0] <= '9') {
++ strcpy(buf, "ttyS");
++ strncpy(buf + 4, str, sizeof(buf) - 5);
++ } else {
++ strncpy(buf, str, sizeof(buf) - 1);
++ }
++ buf[sizeof(buf) - 1] = 0;
++ if ((options = strchr(str, ',')) != NULL)
++ *(options++) = 0;
++#ifdef __sparc__
++ if (!strcmp(str, "ttya"))
++ strcpy(buf, "ttyS0");
++ if (!strcmp(str, "ttyb"))
++ strcpy(buf, "ttyS1");
++#endif
++ for (s = buf; *s; s++)
++ if ((*s >= '0' && *s <= '9') || *s == ',')
++ break;
++ idx = simple_strtoul(s, NULL, 10);
++ *s = 0;
++
++ __add_preferred_console(buf, idx, options, brl_options);
++ console_set_on_cmdline = 1;
++ return 1;
++}
++__setup("console=", console_setup);
++
++/**
++ * add_preferred_console - add a device to the list of preferred consoles.
++ * @name: device name
++ * @idx: device index
++ * @options: options for this console
++ *
++ * The last preferred console added will be used for kernel messages
++ * and stdin/out/err for init. Normally this is used by console_setup
++ * above to handle user-supplied console arguments; however it can also
++ * be used by arch-specific code either to override the user or more
++ * commonly to provide a default console (ie from PROM variables) when
++ * the user has not supplied one.
++ */
++int add_preferred_console(char *name, int idx, char *options)
++{
++ return __add_preferred_console(name, idx, options, NULL);
++}
++
++int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, char *options)
++{
++ struct console_cmdline *c;
++ int i;
++
++ for (i = 0, c = console_cmdline;
++ i < MAX_CMDLINECONSOLES && c->name[0];
++ i++, c++)
++ if (strcmp(c->name, name) == 0 && c->index == idx) {
++ strlcpy(c->name, name_new, sizeof(c->name));
++ c->name[sizeof(c->name) - 1] = 0;
++ c->options = options;
++ c->index = idx_new;
++ return i;
++ }
++ /* not found */
++ return -1;
++}
++
++bool console_suspend_enabled = 1;
++EXPORT_SYMBOL(console_suspend_enabled);
++
++static int __init console_suspend_disable(char *str)
++{
++ console_suspend_enabled = 0;
++ return 1;
++}
++__setup("no_console_suspend", console_suspend_disable);
++module_param_named(console_suspend, console_suspend_enabled,
++ bool, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(console_suspend, "suspend console during suspend"
++ " and hibernate operations");
++
++/**
++ * suspend_console - suspend the console subsystem
++ *
++ * This disables printk() while we go into suspend states
++ */
++void suspend_console(void)
++{
++ if (!console_suspend_enabled)
++ return;
++ printk("Suspending console(s) (use no_console_suspend to debug)\n");
++ console_lock();
++ console_suspended = 1;
++ up(&console_sem);
++}
++
++void resume_console(void)
++{
++ if (!console_suspend_enabled)
++ return;
++ down(&console_sem);
++ console_suspended = 0;
++ console_unlock();
++}
++
++/**
++ * console_cpu_notify - print deferred console messages after CPU hotplug
++ * @self: notifier struct
++ * @action: CPU hotplug event
++ * @hcpu: unused
++ *
++ * If printk() is called from a CPU that is not online yet, the messages
++ * will be spooled but will not show up on the console. This function is
++ * called when a new CPU comes online (or fails to come up), and ensures
++ * that any such output gets printed.
++ */
++static int console_cpu_notify(struct notifier_block *self,
++ unsigned long action, void *hcpu)
++{
++ switch (action) {
++ case CPU_ONLINE:
++ case CPU_DEAD:
++ case CPU_DOWN_FAILED:
++ case CPU_UP_CANCELED:
++ console_lock();
++ console_unlock();
++ }
++ return NOTIFY_OK;
++}
++
++/**
++ * console_lock - lock the console system for exclusive use.
++ *
++ * Acquires a lock which guarantees that the caller has
++ * exclusive access to the console system and the console_drivers list.
++ *
++ * Can sleep, returns nothing.
++ */
++void console_lock(void)
++{
++ might_sleep();
++
++ down(&console_sem);
++ if (console_suspended)
++ return;
++ console_locked = 1;
++ console_may_schedule = 1;
++ mutex_acquire(&console_lock_dep_map, 0, 0, _RET_IP_);
++}
++EXPORT_SYMBOL(console_lock);
++
++/**
++ * console_trylock - try to lock the console system for exclusive use.
++ *
++ * Tried to acquire a lock which guarantees that the caller has
++ * exclusive access to the console system and the console_drivers list.
++ *
++ * returns 1 on success, and 0 on failure to acquire the lock.
++ */
++int console_trylock(void)
++{
++ if (down_trylock(&console_sem))
++ return 0;
++ if (console_suspended) {
++ up(&console_sem);
++ return 0;
++ }
++ console_locked = 1;
++ console_may_schedule = 0;
++ mutex_acquire(&console_lock_dep_map, 0, 1, _RET_IP_);
++ return 1;
++}
++EXPORT_SYMBOL(console_trylock);
++
++int is_console_locked(void)
++{
++ return console_locked;
++}
++
++static void console_cont_flush(char *text, size_t size)
++{
++ unsigned long flags;
++ size_t len;
++
++ raw_spin_lock_irqsave(&logbuf_lock, flags);
++
++ if (!cont.len)
++ goto out;
++
++ /*
++ * We still queue earlier records, likely because the console was
++ * busy. The earlier ones need to be printed before this one, we
++ * did not flush any fragment so far, so just let it queue up.
++ */
++ if (console_seq < log_next_seq && !cont.cons)
++ goto out;
++
++ len = cont_print_text(text, size);
++ raw_spin_unlock(&logbuf_lock);
++ stop_critical_timings();
++ call_console_drivers(cont.level, text, len);
++ start_critical_timings();
++ local_irq_restore(flags);
++ return;
++out:
++ raw_spin_unlock_irqrestore(&logbuf_lock, flags);
++}
++
++/**
++ * console_unlock - unlock the console system
++ *
++ * Releases the console_lock which the caller holds on the console system
++ * and the console driver list.
++ *
++ * While the console_lock was held, console output may have been buffered
++ * by printk(). If this is the case, console_unlock(); emits
++ * the output prior to releasing the lock.
++ *
++ * If there is output waiting, we wake /dev/kmsg and syslog() users.
++ *
++ * console_unlock(); may be called from any context.
++ */
++void console_unlock(void)
++{
++ static char text[LOG_LINE_MAX + PREFIX_MAX];
++ static u64 seen_seq;
++ unsigned long flags;
++ bool wake_klogd = false;
++ bool retry;
++
++ if (console_suspended) {
++ up(&console_sem);
++ return;
++ }
++
++ console_may_schedule = 0;
++
++ /* flush buffered message fragment immediately to console */
++ console_cont_flush(text, sizeof(text));
++again:
++ for (;;) {
++ struct printk_log *msg;
++ size_t len;
++ int level;
++
++ raw_spin_lock_irqsave(&logbuf_lock, flags);
++ if (seen_seq != log_next_seq) {
++ wake_klogd = true;
++ seen_seq = log_next_seq;
++ }
++
++ if (console_seq < log_first_seq) {
++ /* messages are gone, move to first one */
++ console_seq = log_first_seq;
++ console_idx = log_first_idx;
++ console_prev = 0;
++ }
++skip:
++ if (console_seq == log_next_seq)
++ break;
++
++ msg = log_from_idx(console_idx);
++ if (msg->flags & LOG_NOCONS) {
++ /*
++ * Skip record we have buffered and already printed
++ * directly to the console when we received it.
++ */
++ console_idx = log_next(console_idx);
++ console_seq++;
++ /*
++ * We will get here again when we register a new
++ * CON_PRINTBUFFER console. Clear the flag so we
++ * will properly dump everything later.
++ */
++ msg->flags &= ~LOG_NOCONS;
++ console_prev = msg->flags;
++ goto skip;
++ }
++
++ level = msg->level;
++ len = msg_print_text(msg, console_prev, false,
++ text, sizeof(text));
++ console_idx = log_next(console_idx);
++ console_seq++;
++ console_prev = msg->flags;
++ raw_spin_unlock(&logbuf_lock);
++
++ stop_critical_timings(); /* don't trace print latency */
++ call_console_drivers(level, text, len);
++ start_critical_timings();
++ local_irq_restore(flags);
++ }
++ console_locked = 0;
++ mutex_release(&console_lock_dep_map, 1, _RET_IP_);
++
++ /* Release the exclusive_console once it is used */
++ if (unlikely(exclusive_console))
++ exclusive_console = NULL;
++
++ raw_spin_unlock(&logbuf_lock);
++
++ up(&console_sem);
++
++ /*
++ * Someone could have filled up the buffer again, so re-check if there's
++ * something to flush. In case we cannot trylock the console_sem again,
++ * there's a new owner and the console_unlock() from them will do the
++ * flush, no worries.
++ */
++ raw_spin_lock(&logbuf_lock);
++ retry = console_seq != log_next_seq;
++ raw_spin_unlock_irqrestore(&logbuf_lock, flags);
++
++ if (retry && console_trylock())
++ goto again;
++
++ if (wake_klogd)
++ wake_up_klogd();
++}
++EXPORT_SYMBOL(console_unlock);
++
++/**
++ * console_conditional_schedule - yield the CPU if required
++ *
++ * If the console code is currently allowed to sleep, and
++ * if this CPU should yield the CPU to another task, do
++ * so here.
++ *
++ * Must be called within console_lock();.
++ */
++void __sched console_conditional_schedule(void)
++{
++ if (console_may_schedule)
++ cond_resched();
++}
++EXPORT_SYMBOL(console_conditional_schedule);
++
++void console_unblank(void)
++{
++ struct console *c;
++
++ /*
++ * console_unblank can no longer be called in interrupt context unless
++ * oops_in_progress is set to 1..
++ */
++ if (oops_in_progress) {
++ if (down_trylock(&console_sem) != 0)
++ return;
++ } else
++ console_lock();
++
++ console_locked = 1;
++ console_may_schedule = 0;
++ for_each_console(c)
++ if ((c->flags & CON_ENABLED) && c->unblank)
++ c->unblank();
++ console_unlock();
++}
++
++/*
++ * Return the console tty driver structure and its associated index
++ */
++struct tty_driver *console_device(int *index)
++{
++ struct console *c;
++ struct tty_driver *driver = NULL;
++
++ console_lock();
++ for_each_console(c) {
++ if (!c->device)
++ continue;
++ driver = c->device(c, index);
++ if (driver)
++ break;
++ }
++ console_unlock();
++ return driver;
++}
++
++/*
++ * Prevent further output on the passed console device so that (for example)
++ * serial drivers can disable console output before suspending a port, and can
++ * re-enable output afterwards.
++ */
++void console_stop(struct console *console)
++{
++ console_lock();
++ console->flags &= ~CON_ENABLED;
++ console_unlock();
++}
++EXPORT_SYMBOL(console_stop);
++
++void console_start(struct console *console)
++{
++ console_lock();
++ console->flags |= CON_ENABLED;
++ console_unlock();
++}
++EXPORT_SYMBOL(console_start);
++
++static int __read_mostly keep_bootcon;
++
++static int __init keep_bootcon_setup(char *str)
++{
++ keep_bootcon = 1;
++ pr_info("debug: skip boot console de-registration.\n");
++
++ return 0;
++}
++
++early_param("keep_bootcon", keep_bootcon_setup);
++
++/*
++ * The console driver calls this routine during kernel initialization
++ * to register the console printing procedure with printk() and to
++ * print any messages that were printed by the kernel before the
++ * console driver was initialized.
++ *
++ * This can happen pretty early during the boot process (because of
++ * early_printk) - sometimes before setup_arch() completes - be careful
++ * of what kernel features are used - they may not be initialised yet.
++ *
++ * There are two types of consoles - bootconsoles (early_printk) and
++ * "real" consoles (everything which is not a bootconsole) which are
++ * handled differently.
++ * - Any number of bootconsoles can be registered at any time.
++ * - As soon as a "real" console is registered, all bootconsoles
++ * will be unregistered automatically.
++ * - Once a "real" console is registered, any attempt to register a
++ * bootconsoles will be rejected
++ */
++void register_console(struct console *newcon)
++{
++ int i;
++ unsigned long flags;
++ struct console *bcon = NULL;
++ struct console_cmdline *c;
++
++ if (console_drivers)
++ for_each_console(bcon)
++ if (WARN(bcon == newcon,
++ "console '%s%d' already registered\n",
++ bcon->name, bcon->index))
++ return;
++
++ /*
++ * before we register a new CON_BOOT console, make sure we don't
++ * already have a valid console
++ */
++ if (console_drivers && newcon->flags & CON_BOOT) {
++ /* find the last or real console */
++ for_each_console(bcon) {
++ if (!(bcon->flags & CON_BOOT)) {
++ pr_info("Too late to register bootconsole %s%d\n",
++ newcon->name, newcon->index);
++ return;
++ }
++ }
++ }
++
++ if (console_drivers && console_drivers->flags & CON_BOOT)
++ bcon = console_drivers;
++
++ if (preferred_console < 0 || bcon || !console_drivers)
++ preferred_console = selected_console;
++
++ if (newcon->early_setup)
++ newcon->early_setup();
++
++ /*
++ * See if we want to use this console driver. If we
++ * didn't select a console we take the first one
++ * that registers here.
++ */
++ if (preferred_console < 0) {
++ if (newcon->index < 0)
++ newcon->index = 0;
++ if (newcon->setup == NULL ||
++ newcon->setup(newcon, NULL) == 0) {
++ newcon->flags |= CON_ENABLED;
++ if (newcon->device) {
++ newcon->flags |= CON_CONSDEV;
++ preferred_console = 0;
++ }
++ }
++ }
++
++ /*
++ * See if this console matches one we selected on
++ * the command line.
++ */
++ for (i = 0, c = console_cmdline;
++ i < MAX_CMDLINECONSOLES && c->name[0];
++ i++, c++) {
++ BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name));
++ if (strcmp(c->name, newcon->name) != 0)
++ continue;
++ if (newcon->index >= 0 &&
++ newcon->index != c->index)
++ continue;
++ if (newcon->index < 0)
++ newcon->index = c->index;
++
++ if (_braille_register_console(newcon, c))
++ return;
++
++ if (newcon->setup &&
++ newcon->setup(newcon, console_cmdline[i].options) != 0)
++ break;
++ newcon->flags |= CON_ENABLED;
++ newcon->index = c->index;
++ if (i == selected_console) {
++ newcon->flags |= CON_CONSDEV;
++ preferred_console = selected_console;
++ }
++ break;
++ }
++
++ if (!(newcon->flags & CON_ENABLED))
++ return;
++
++ /*
++ * If we have a bootconsole, and are switching to a real console,
++ * don't print everything out again, since when the boot console, and
++ * the real console are the same physical device, it's annoying to
++ * see the beginning boot messages twice
++ */
++ if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV))
++ newcon->flags &= ~CON_PRINTBUFFER;
++
++ /*
++ * Put this console in the list - keep the
++ * preferred driver at the head of the list.
++ */
++ console_lock();
++ if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) {
++ newcon->next = console_drivers;
++ console_drivers = newcon;
++ if (newcon->next)
++ newcon->next->flags &= ~CON_CONSDEV;
++ } else {
++ newcon->next = console_drivers->next;
++ console_drivers->next = newcon;
++ }
++ if (newcon->flags & CON_PRINTBUFFER) {
++ /*
++ * console_unlock(); will print out the buffered messages
++ * for us.
++ */
++ raw_spin_lock_irqsave(&logbuf_lock, flags);
++ console_seq = syslog_seq;
++ console_idx = syslog_idx;
++ console_prev = syslog_prev;
++ raw_spin_unlock_irqrestore(&logbuf_lock, flags);
++ /*
++ * We're about to replay the log buffer. Only do this to the
++ * just-registered console to avoid excessive message spam to
++ * the already-registered consoles.
++ */
++ exclusive_console = newcon;
++ }
++ console_unlock();
++ console_sysfs_notify();
++
++ /*
++ * By unregistering the bootconsoles after we enable the real console
++ * we get the "console xxx enabled" message on all the consoles -
++ * boot consoles, real consoles, etc - this is to ensure that end
++ * users know there might be something in the kernel's log buffer that
++ * went to the bootconsole (that they do not see on the real console)
++ */
++ pr_info("%sconsole [%s%d] enabled\n",
++ (newcon->flags & CON_BOOT) ? "boot" : "" ,
++ newcon->name, newcon->index);
++ if (bcon &&
++ ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV) &&
++ !keep_bootcon) {
++ /* We need to iterate through all boot consoles, to make
++ * sure we print everything out, before we unregister them.
++ */
++ for_each_console(bcon)
++ if (bcon->flags & CON_BOOT)
++ unregister_console(bcon);
++ }
++}
++EXPORT_SYMBOL(register_console);
++
++int unregister_console(struct console *console)
++{
++ struct console *a, *b;
++ int res;
++
++ pr_info("%sconsole [%s%d] disabled\n",
++ (console->flags & CON_BOOT) ? "boot" : "" ,
++ console->name, console->index);
++
++ res = _braille_unregister_console(console);
++ if (res)
++ return res;
++
++ res = 1;
++ console_lock();
++ if (console_drivers == console) {
++ console_drivers=console->next;
++ res = 0;
++ } else if (console_drivers) {
++ for (a=console_drivers->next, b=console_drivers ;
++ a; b=a, a=b->next) {
++ if (a == console) {
++ b->next = a->next;
++ res = 0;
++ break;
++ }
++ }
++ }
++
++ /*
++ * If this isn't the last console and it has CON_CONSDEV set, we
++ * need to set it on the next preferred console.
++ */
++ if (console_drivers != NULL && console->flags & CON_CONSDEV)
++ console_drivers->flags |= CON_CONSDEV;
++
++ console_unlock();
++ console_sysfs_notify();
++ return res;
++}
++EXPORT_SYMBOL(unregister_console);
++
++static int __init printk_late_init(void)
++{
++ struct console *con;
++
++ for_each_console(con) {
++ if (!keep_bootcon && con->flags & CON_BOOT) {
++ unregister_console(con);
++ }
++ }
++ hotcpu_notifier(console_cpu_notify, 0);
++ return 0;
++}
++late_initcall(printk_late_init);
++
++#if defined CONFIG_PRINTK
++/*
++ * Delayed printk version, for scheduler-internal messages:
++ */
++#define PRINTK_BUF_SIZE 512
++
++#define PRINTK_PENDING_WAKEUP 0x01
++#define PRINTK_PENDING_SCHED 0x02
++
++static DEFINE_PER_CPU(int, printk_pending);
++static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf);
++
++static void wake_up_klogd_work_func(struct irq_work *irq_work)
++{
++ int pending = __this_cpu_xchg(printk_pending, 0);
++
++ if (pending & PRINTK_PENDING_SCHED) {
++ char *buf = __get_cpu_var(printk_sched_buf);
++ pr_warn("[sched_delayed] %s", buf);
++ }
++
++ if (pending & PRINTK_PENDING_WAKEUP)
++ wake_up_interruptible(&log_wait);
++}
++
++static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = {
++ .func = wake_up_klogd_work_func,
++ .flags = IRQ_WORK_LAZY,
++};
++
++void wake_up_klogd(void)
++{
++ preempt_disable();
++ if (waitqueue_active(&log_wait)) {
++ this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
++ irq_work_queue(&__get_cpu_var(wake_up_klogd_work));
++ }
++ preempt_enable();
++}
++
++int printk_deferred(const char *fmt, ...)
++{
++ unsigned long flags;
++ va_list args;
++ char *buf;
++ int r;
++
++ local_irq_save(flags);
++ buf = __get_cpu_var(printk_sched_buf);
++
++ va_start(args, fmt);
++ r = vsnprintf(buf, PRINTK_BUF_SIZE, fmt, args);
++ va_end(args);
++
++ __this_cpu_or(printk_pending, PRINTK_PENDING_SCHED);
++ irq_work_queue(&__get_cpu_var(wake_up_klogd_work));
++ local_irq_restore(flags);
++
++ return r;
++}
++
++/*
++ * printk rate limiting, lifted from the networking subsystem.
++ *
++ * This enforces a rate limit: not more than 10 kernel messages
++ * every 5s to make a denial-of-service attack impossible.
++ */
++DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10);
++
++int __printk_ratelimit(const char *func)
++{
++ return ___ratelimit(&printk_ratelimit_state, func);
++}
++EXPORT_SYMBOL(__printk_ratelimit);
++
++/**
++ * printk_timed_ratelimit - caller-controlled printk ratelimiting
++ * @caller_jiffies: pointer to caller's state
++ * @interval_msecs: minimum interval between prints
++ *
++ * printk_timed_ratelimit() returns true if more than @interval_msecs
++ * milliseconds have elapsed since the last time printk_timed_ratelimit()
++ * returned true.
++ */
++bool printk_timed_ratelimit(unsigned long *caller_jiffies,
++ unsigned int interval_msecs)
++{
++ if (*caller_jiffies == 0
++ || !time_in_range(jiffies, *caller_jiffies,
++ *caller_jiffies
++ + msecs_to_jiffies(interval_msecs))) {
++ *caller_jiffies = jiffies;
++ return true;
++ }
++ return false;
++}
++EXPORT_SYMBOL(printk_timed_ratelimit);
++
++static DEFINE_SPINLOCK(dump_list_lock);
++static LIST_HEAD(dump_list);
++
++/**
++ * kmsg_dump_register - register a kernel log dumper.
++ * @dumper: pointer to the kmsg_dumper structure
++ *
++ * Adds a kernel log dumper to the system. The dump callback in the
++ * structure will be called when the kernel oopses or panics and must be
++ * set. Returns zero on success and %-EINVAL or %-EBUSY otherwise.
++ */
++int kmsg_dump_register(struct kmsg_dumper *dumper)
++{
++ unsigned long flags;
++ int err = -EBUSY;
++
++ /* The dump callback needs to be set */
++ if (!dumper->dump)
++ return -EINVAL;
++
++ spin_lock_irqsave(&dump_list_lock, flags);
++ /* Don't allow registering multiple times */
++ if (!dumper->registered) {
++ dumper->registered = 1;
++ list_add_tail_rcu(&dumper->list, &dump_list);
++ err = 0;
++ }
++ spin_unlock_irqrestore(&dump_list_lock, flags);
++
++ return err;
++}
++EXPORT_SYMBOL_GPL(kmsg_dump_register);
++
++/**
++ * kmsg_dump_unregister - unregister a kmsg dumper.
++ * @dumper: pointer to the kmsg_dumper structure
++ *
++ * Removes a dump device from the system. Returns zero on success and
++ * %-EINVAL otherwise.
++ */
++int kmsg_dump_unregister(struct kmsg_dumper *dumper)
++{
++ unsigned long flags;
++ int err = -EINVAL;
++
++ spin_lock_irqsave(&dump_list_lock, flags);
++ if (dumper->registered) {
++ dumper->registered = 0;
++ list_del_rcu(&dumper->list);
++ err = 0;
++ }
++ spin_unlock_irqrestore(&dump_list_lock, flags);
++ synchronize_rcu();
++
++ return err;
++}
++EXPORT_SYMBOL_GPL(kmsg_dump_unregister);
++
++static bool always_kmsg_dump;
++module_param_named(always_kmsg_dump, always_kmsg_dump, bool, S_IRUGO | S_IWUSR);
++
++/**
++ * kmsg_dump - dump kernel log to kernel message dumpers.
++ * @reason: the reason (oops, panic etc) for dumping
++ *
++ * Call each of the registered dumper's dump() callback, which can
++ * retrieve the kmsg records with kmsg_dump_get_line() or
++ * kmsg_dump_get_buffer().
++ */
++void kmsg_dump(enum kmsg_dump_reason reason)
++{
++ struct kmsg_dumper *dumper;
++ unsigned long flags;
++
++ if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump)
++ return;
++
++ rcu_read_lock();
++ list_for_each_entry_rcu(dumper, &dump_list, list) {
++ if (dumper->max_reason && reason > dumper->max_reason)
++ continue;
++
++ /* initialize iterator with data about the stored records */
++ dumper->active = true;
++
++ raw_spin_lock_irqsave(&logbuf_lock, flags);
++ dumper->cur_seq = clear_seq;
++ dumper->cur_idx = clear_idx;
++ dumper->next_seq = log_next_seq;
++ dumper->next_idx = log_next_idx;
++ raw_spin_unlock_irqrestore(&logbuf_lock, flags);
++
++ /* invoke dumper which will iterate over records */
++ dumper->dump(dumper, reason);
++
++ /* reset iterator */
++ dumper->active = false;
++ }
++ rcu_read_unlock();
++}
++
++/**
++ * kmsg_dump_get_line_nolock - retrieve one kmsg log line (unlocked version)
++ * @dumper: registered kmsg dumper
++ * @syslog: include the "<4>" prefixes
++ * @line: buffer to copy the line to
++ * @size: maximum size of the buffer
++ * @len: length of line placed into buffer
++ *
++ * Start at the beginning of the kmsg buffer, with the oldest kmsg
++ * record, and copy one record into the provided buffer.
++ *
++ * Consecutive calls will return the next available record moving
++ * towards the end of the buffer with the youngest messages.
++ *
++ * A return value of FALSE indicates that there are no more records to
++ * read.
++ *
++ * The function is similar to kmsg_dump_get_line(), but grabs no locks.
++ */
++bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog,
++ char *line, size_t size, size_t *len)
++{
++ struct printk_log *msg;
++ size_t l = 0;
++ bool ret = false;
++
++ if (!dumper->active)
++ goto out;
++
++ if (dumper->cur_seq < log_first_seq) {
++ /* messages are gone, move to first available one */
++ dumper->cur_seq = log_first_seq;
++ dumper->cur_idx = log_first_idx;
++ }
++
++ /* last entry */
++ if (dumper->cur_seq >= log_next_seq)
++ goto out;
++
++ msg = log_from_idx(dumper->cur_idx);
++ l = msg_print_text(msg, 0, syslog, line, size);
++
++ dumper->cur_idx = log_next(dumper->cur_idx);
++ dumper->cur_seq++;
++ ret = true;
++out:
++ if (len)
++ *len = l;
++ return ret;
++}
++
++/**
++ * kmsg_dump_get_line - retrieve one kmsg log line
++ * @dumper: registered kmsg dumper
++ * @syslog: include the "<4>" prefixes
++ * @line: buffer to copy the line to
++ * @size: maximum size of the buffer
++ * @len: length of line placed into buffer
++ *
++ * Start at the beginning of the kmsg buffer, with the oldest kmsg
++ * record, and copy one record into the provided buffer.
++ *
++ * Consecutive calls will return the next available record moving
++ * towards the end of the buffer with the youngest messages.
++ *
++ * A return value of FALSE indicates that there are no more records to
++ * read.
++ */
++bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
++ char *line, size_t size, size_t *len)
++{
++ unsigned long flags;
++ bool ret;
++
++ raw_spin_lock_irqsave(&logbuf_lock, flags);
++ ret = kmsg_dump_get_line_nolock(dumper, syslog, line, size, len);
++ raw_spin_unlock_irqrestore(&logbuf_lock, flags);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(kmsg_dump_get_line);
++
++/**
++ * kmsg_dump_get_buffer - copy kmsg log lines
++ * @dumper: registered kmsg dumper
++ * @syslog: include the "<4>" prefixes
++ * @buf: buffer to copy the line to
++ * @size: maximum size of the buffer
++ * @len: length of line placed into buffer
++ *
++ * Start at the end of the kmsg buffer and fill the provided buffer
++ * with as many of the the *youngest* kmsg records that fit into it.
++ * If the buffer is large enough, all available kmsg records will be
++ * copied with a single call.
++ *
++ * Consecutive calls will fill the buffer with the next block of
++ * available older records, not including the earlier retrieved ones.
++ *
++ * A return value of FALSE indicates that there are no more records to
++ * read.
++ */
++bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
++ char *buf, size_t size, size_t *len)
++{
++ unsigned long flags;
++ u64 seq;
++ u32 idx;
++ u64 next_seq;
++ u32 next_idx;
++ enum log_flags prev;
++ size_t l = 0;
++ bool ret = false;
++
++ if (!dumper->active)
++ goto out;
++
++ raw_spin_lock_irqsave(&logbuf_lock, flags);
++ if (dumper->cur_seq < log_first_seq) {
++ /* messages are gone, move to first available one */
++ dumper->cur_seq = log_first_seq;
++ dumper->cur_idx = log_first_idx;
++ }
++
++ /* last entry */
++ if (dumper->cur_seq >= dumper->next_seq) {
++ raw_spin_unlock_irqrestore(&logbuf_lock, flags);
++ goto out;
++ }
++
++ /* calculate length of entire buffer */
++ seq = dumper->cur_seq;
++ idx = dumper->cur_idx;
++ prev = 0;
++ while (seq < dumper->next_seq) {
++ struct printk_log *msg = log_from_idx(idx);
++
++ l += msg_print_text(msg, prev, true, NULL, 0);
++ idx = log_next(idx);
++ seq++;
++ prev = msg->flags;
++ }
++
++ /* move first record forward until length fits into the buffer */
++ seq = dumper->cur_seq;
++ idx = dumper->cur_idx;
++ prev = 0;
++ while (l > size && seq < dumper->next_seq) {
++ struct printk_log *msg = log_from_idx(idx);
++
++ l -= msg_print_text(msg, prev, true, NULL, 0);
++ idx = log_next(idx);
++ seq++;
++ prev = msg->flags;
++ }
++
++ /* last message in next interation */
++ next_seq = seq;
++ next_idx = idx;
++
++ l = 0;
++ while (seq < dumper->next_seq) {
++ struct printk_log *msg = log_from_idx(idx);
++
++ l += msg_print_text(msg, prev, syslog, buf + l, size - l);
++ idx = log_next(idx);
++ seq++;
++ prev = msg->flags;
++ }
++
++ dumper->next_seq = next_seq;
++ dumper->next_idx = next_idx;
++ ret = true;
++ raw_spin_unlock_irqrestore(&logbuf_lock, flags);
++out:
++ if (len)
++ *len = l;
++ return ret;
++}
++EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer);
++
++/**
++ * kmsg_dump_rewind_nolock - reset the interator (unlocked version)
++ * @dumper: registered kmsg dumper
++ *
++ * Reset the dumper's iterator so that kmsg_dump_get_line() and
++ * kmsg_dump_get_buffer() can be called again and used multiple
++ * times within the same dumper.dump() callback.
++ *
++ * The function is similar to kmsg_dump_rewind(), but grabs no locks.
++ */
++void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper)
++{
++ dumper->cur_seq = clear_seq;
++ dumper->cur_idx = clear_idx;
++ dumper->next_seq = log_next_seq;
++ dumper->next_idx = log_next_idx;
++}
++
++/**
++ * kmsg_dump_rewind - reset the interator
++ * @dumper: registered kmsg dumper
++ *
++ * Reset the dumper's iterator so that kmsg_dump_get_line() and
++ * kmsg_dump_get_buffer() can be called again and used multiple
++ * times within the same dumper.dump() callback.
++ */
++void kmsg_dump_rewind(struct kmsg_dumper *dumper)
++{
++ unsigned long flags;
++
++ raw_spin_lock_irqsave(&logbuf_lock, flags);
++ kmsg_dump_rewind_nolock(dumper);
++ raw_spin_unlock_irqrestore(&logbuf_lock, flags);
++}
++EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
++
++static char dump_stack_arch_desc_str[128];
++
++/**
++ * dump_stack_set_arch_desc - set arch-specific str to show with task dumps
++ * @fmt: printf-style format string
++ * @...: arguments for the format string
++ *
++ * The configured string will be printed right after utsname during task
++ * dumps. Usually used to add arch-specific system identifiers. If an
++ * arch wants to make use of such an ID string, it should initialize this
++ * as soon as possible during boot.
++ */
++void __init dump_stack_set_arch_desc(const char *fmt, ...)
++{
++ va_list args;
++
++ va_start(args, fmt);
++ vsnprintf(dump_stack_arch_desc_str, sizeof(dump_stack_arch_desc_str),
++ fmt, args);
++ va_end(args);
++}
++
++/**
++ * dump_stack_print_info - print generic debug info for dump_stack()
++ * @log_lvl: log level
++ *
++ * Arch-specific dump_stack() implementations can use this function to
++ * print out the same debug information as the generic dump_stack().
++ */
++void dump_stack_print_info(const char *log_lvl)
++{
++ printk("%sCPU: %d PID: %d Comm: %.20s %s %s %.*s\n",
++ log_lvl, raw_smp_processor_id(), current->pid, current->comm,
++ print_tainted(), init_utsname()->release,
++ (int)strcspn(init_utsname()->version, " "),
++ init_utsname()->version);
++
++ if (dump_stack_arch_desc_str[0] != '\0')
++ printk("%sHardware name: %s\n",
++ log_lvl, dump_stack_arch_desc_str);
++
++ print_worker_info(log_lvl, current);
++}
++
++/**
++ * show_regs_print_info - print generic debug info for show_regs()
++ * @log_lvl: log level
++ *
++ * show_regs() implementations can use this function to print out generic
++ * debug information.
++ */
++void show_regs_print_info(const char *log_lvl)
++{
++ dump_stack_print_info(log_lvl);
++
++ printk("%stask: %p ti: %p task.ti: %p\n",
++ log_lvl, current, current_thread_info(),
++ task_thread_info(current));
++}
++
++#endif
diff --git a/kernel/profile.c b/kernel/profile.c
index 76b8e77..a2930e8 100644
--- a/kernel/profile.c
@@ -94920,7 +98151,7 @@ index 9d557df..7207dae 100644
error = -EINVAL;
break;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
-index ea7ec7f..798623e 100644
+index ea7ec7f..da588ba 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -86,6 +86,13 @@
@@ -94937,7 +98168,11 @@ index ea7ec7f..798623e 100644
/* External variables not in a header file. */
extern int sysctl_overcommit_memory;
-@@ -112,18 +119,18 @@ extern int blk_iopoll_enabled;
+@@ -109,21 +116,22 @@ extern int sysctl_nr_trim_pages;
+ #ifdef CONFIG_BLOCK
+ extern int blk_iopoll_enabled;
+ #endif
++extern int sysctl_modify_ldt;
/* Constants used for minimum and maximum */
#ifdef CONFIG_LOCKUP_DETECTOR
@@ -94965,12 +98200,13 @@ index ea7ec7f..798623e 100644
#endif
/* this is needed for the proc_doulongvec_minmax of vm_dirty_bytes */
-@@ -165,10 +172,13 @@ static int proc_taint(struct ctl_table *table, int write,
+@@ -165,10 +173,13 @@ static int proc_taint(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos);
#endif
-#ifdef CONFIG_PRINTK
- static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write,
+-static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write,
++static int proc_dointvec_minmax_secure_sysadmin(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos);
-#endif
+
@@ -94981,7 +98217,7 @@ index ea7ec7f..798623e 100644
#ifdef CONFIG_MAGIC_SYSRQ
/* Note: sysrq code uses it's own private copy */
-@@ -191,6 +201,7 @@ static int sysrq_sysctl_handler(ctl_table *table, int write,
+@@ -191,6 +202,7 @@ static int sysrq_sysctl_handler(ctl_table *table, int write,
}
#endif
@@ -94989,7 +98225,7 @@ index ea7ec7f..798623e 100644
static struct ctl_table root_table[];
static struct ctl_table_root sysctl_table_root;
-@@ -220,6 +231,20 @@ extern struct ctl_table epoll_table[];
+@@ -220,6 +232,20 @@ extern struct ctl_table epoll_table[];
int sysctl_legacy_va_layout;
#endif
@@ -95010,7 +98246,7 @@ index ea7ec7f..798623e 100644
/* The default sysctl tables: */
static struct ctl_table root_table[] = {
-@@ -266,6 +291,22 @@ static int max_extfrag_threshold = 1000;
+@@ -266,6 +292,22 @@ static int max_extfrag_threshold = 1000;
#endif
static struct ctl_table kern_table[] = {
@@ -95033,7 +98269,7 @@ index ea7ec7f..798623e 100644
{
.procname = "sched_child_runs_first",
.data = &sysctl_sched_child_runs_first,
-@@ -420,7 +461,7 @@ static struct ctl_table kern_table[] = {
+@@ -420,7 +462,7 @@ static struct ctl_table kern_table[] = {
.data = core_pattern,
.maxlen = CORENAME_MAX_SIZE,
.mode = 0644,
@@ -95042,7 +98278,7 @@ index ea7ec7f..798623e 100644
},
{
.procname = "core_pipe_limit",
-@@ -550,7 +591,7 @@ static struct ctl_table kern_table[] = {
+@@ -550,7 +592,7 @@ static struct ctl_table kern_table[] = {
.data = &modprobe_path,
.maxlen = KMOD_PATH_LEN,
.mode = 0644,
@@ -95051,7 +98287,21 @@ index ea7ec7f..798623e 100644
},
{
.procname = "modules_disabled",
-@@ -717,16 +758,20 @@ static struct ctl_table kern_table[] = {
+@@ -558,7 +600,7 @@ static struct ctl_table kern_table[] = {
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ /* only handle a transition from default "0" to "1" */
+- .proc_handler = proc_dointvec_minmax,
++ .proc_handler = proc_dointvec_minmax_secure,
+ .extra1 = &one,
+ .extra2 = &one,
+ },
+@@ -713,20 +755,24 @@ static struct ctl_table kern_table[] = {
+ .data = &dmesg_restrict,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+- .proc_handler = proc_dointvec_minmax_sysadmin,
++ .proc_handler = proc_dointvec_minmax_secure_sysadmin,
.extra1 = &zero,
.extra2 = &one,
},
@@ -95061,7 +98311,8 @@ index ea7ec7f..798623e 100644
.data = &kptr_restrict,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = proc_dointvec_minmax_sysadmin,
+- .proc_handler = proc_dointvec_minmax_sysadmin,
++ .proc_handler = proc_dointvec_minmax_secure_sysadmin,
+#ifdef CONFIG_GRKERNSEC_HIDESYM
+ .extra1 = &two,
+#else
@@ -95073,7 +98324,23 @@ index ea7ec7f..798623e 100644
{
.procname = "ngroups_max",
.data = &ngroups_max,
-@@ -957,10 +1002,17 @@ static struct ctl_table kern_table[] = {
+@@ -831,6 +877,15 @@ static struct ctl_table kern_table[] = {
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
++ {
++ .procname = "modify_ldt",
++ .data = &sysctl_modify_ldt,
++ .maxlen = sizeof(int),
++ .mode = 0644,
++ .proc_handler = proc_dointvec_minmax_secure_sysadmin,
++ .extra1 = &zero,
++ .extra2 = &one,
++ },
+ #endif
+ #if defined(CONFIG_MMU)
+ {
+@@ -957,10 +1012,17 @@ static struct ctl_table kern_table[] = {
*/
{
.procname = "perf_event_paranoid",
@@ -95084,7 +98351,7 @@ index ea7ec7f..798623e 100644
.mode = 0644,
- .proc_handler = proc_dointvec,
+ /* go ahead, be a hero */
-+ .proc_handler = proc_dointvec_minmax_sysadmin,
++ .proc_handler = proc_dointvec_minmax_secure_sysadmin,
+ .extra1 = &neg_one,
+#ifdef CONFIG_GRKERNSEC_PERF_HARDEN
+ .extra2 = &three,
@@ -95094,7 +98361,7 @@ index ea7ec7f..798623e 100644
},
{
.procname = "perf_event_mlock_kb",
-@@ -1216,6 +1268,13 @@ static struct ctl_table vm_table[] = {
+@@ -1216,6 +1278,13 @@ static struct ctl_table vm_table[] = {
.proc_handler = proc_dointvec_minmax,
.extra1 = &zero,
},
@@ -95108,7 +98375,7 @@ index ea7ec7f..798623e 100644
#else
{
.procname = "nr_trim_pages",
-@@ -1499,7 +1558,7 @@ static struct ctl_table fs_table[] = {
+@@ -1499,7 +1568,7 @@ static struct ctl_table fs_table[] = {
.data = &suid_dumpable,
.maxlen = sizeof(int),
.mode = 0644,
@@ -95117,7 +98384,7 @@ index ea7ec7f..798623e 100644
.extra1 = &zero,
.extra2 = &two,
},
-@@ -1720,6 +1779,17 @@ static int test_perm(int mode, int op)
+@@ -1720,6 +1789,17 @@ static int test_perm(int mode, int op)
int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op)
{
int mode;
@@ -95135,7 +98402,7 @@ index ea7ec7f..798623e 100644
if (root->permissions)
mode = root->permissions(root, current->nsproxy, table);
-@@ -1732,7 +1802,9 @@ int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op)
+@@ -1732,7 +1812,9 @@ int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op)
static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table)
{
for (; table->procname; table++) {
@@ -95146,7 +98413,7 @@ index ea7ec7f..798623e 100644
if (table->child)
sysctl_set_parent(table, table->child);
}
-@@ -1856,7 +1928,8 @@ struct ctl_table_header *__register_sysctl_paths(
+@@ -1856,7 +1938,8 @@ struct ctl_table_header *__register_sysctl_paths(
const struct ctl_path *path, struct ctl_table *table)
{
struct ctl_table_header *header;
@@ -95156,7 +98423,7 @@ index ea7ec7f..798623e 100644
unsigned int n, npath;
struct ctl_table_set *set;
-@@ -1877,7 +1950,7 @@ struct ctl_table_header *__register_sysctl_paths(
+@@ -1877,7 +1960,7 @@ struct ctl_table_header *__register_sysctl_paths(
if (!header)
return NULL;
@@ -95165,7 +98432,7 @@ index ea7ec7f..798623e 100644
/* Now connect the dots */
prevp = &header->ctl_table;
-@@ -2124,6 +2197,16 @@ int proc_dostring(struct ctl_table *table, int write,
+@@ -2124,6 +2207,16 @@ int proc_dostring(struct ctl_table *table, int write,
buffer, lenp, ppos);
}
@@ -95182,7 +98449,7 @@ index ea7ec7f..798623e 100644
static size_t proc_skip_spaces(char **buf)
{
size_t ret;
-@@ -2229,6 +2312,8 @@ static int proc_put_long(void __user **buf, size_t *size, unsigned long val,
+@@ -2229,6 +2322,8 @@ static int proc_put_long(void __user **buf, size_t *size, unsigned long val,
len = strlen(tmp);
if (len > *size)
len = *size;
@@ -95191,7 +98458,52 @@ index ea7ec7f..798623e 100644
if (copy_to_user(*buf, tmp, len))
return -EFAULT;
*size -= len;
-@@ -2393,7 +2478,7 @@ int proc_dointvec(struct ctl_table *table, int write,
+@@ -2386,6 +2481,44 @@ int proc_dointvec(struct ctl_table *table, int write,
+ NULL,NULL);
+ }
+
++static int do_proc_dointvec_conv_secure(bool *negp, unsigned long *lvalp,
++ int *valp,
++ int write, void *data)
++{
++ if (write) {
++ if (*negp) {
++ if (*lvalp > (unsigned long) INT_MAX + 1)
++ return -EINVAL;
++ pax_open_kernel();
++ *valp = -*lvalp;
++ pax_close_kernel();
++ } else {
++ if (*lvalp > (unsigned long) INT_MAX)
++ return -EINVAL;
++ pax_open_kernel();
++ *valp = *lvalp;
++ pax_close_kernel();
++ }
++ } else {
++ int val = *valp;
++ if (val < 0) {
++ *negp = true;
++ *lvalp = (unsigned long)-val;
++ } else {
++ *negp = false;
++ *lvalp = (unsigned long)val;
++ }
++ }
++ return 0;
++}
++
++int proc_dointvec_secure(struct ctl_table *table, int write,
++ void __user *buffer, size_t *lenp, loff_t *ppos)
++{
++ return do_proc_dointvec(table,write,buffer,lenp,ppos,
++ do_proc_dointvec_conv_secure,NULL);
++}
++
+ /*
+ * Taint values can only be increased
+ * This means we can safely use a temporary.
+@@ -2393,7 +2526,7 @@ int proc_dointvec(struct ctl_table *table, int write,
static int proc_taint(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
@@ -95200,26 +98512,73 @@ index ea7ec7f..798623e 100644
unsigned long tmptaint = get_taint();
int err;
-@@ -2421,7 +2506,6 @@ static int proc_taint(struct ctl_table *table, int write,
+@@ -2421,16 +2554,14 @@ static int proc_taint(struct ctl_table *table, int write,
return err;
}
-#ifdef CONFIG_PRINTK
- static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write,
+-static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write,
++static int proc_dointvec_minmax_secure_sysadmin(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
-@@ -2430,7 +2514,6 @@ static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write,
+ if (write && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
- return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+- return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
++ return proc_dointvec_minmax_secure(table, write, buffer, lenp, ppos);
}
-#endif
struct do_proc_dointvec_minmax_conv_param {
int *min;
-@@ -2488,6 +2571,34 @@ int proc_dointvec_minmax(struct ctl_table *table, int write,
+@@ -2461,6 +2592,32 @@ static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp,
+ return 0;
+ }
+
++static int do_proc_dointvec_minmax_conv_secure(bool *negp, unsigned long *lvalp,
++ int *valp,
++ int write, void *data)
++{
++ struct do_proc_dointvec_minmax_conv_param *param = data;
++ if (write) {
++ int val = *negp ? -*lvalp : *lvalp;
++ if ((param->min && *param->min > val) ||
++ (param->max && *param->max < val))
++ return -EINVAL;
++ pax_open_kernel();
++ *valp = val;
++ pax_close_kernel();
++ } else {
++ int val = *valp;
++ if (val < 0) {
++ *negp = true;
++ *lvalp = (unsigned long)-val;
++ } else {
++ *negp = false;
++ *lvalp = (unsigned long)val;
++ }
++ }
++ return 0;
++}
++
+ /**
+ * proc_dointvec_minmax - read a vector of integers with min/max values
+ * @table: the sysctl table
+@@ -2488,6 +2645,45 @@ int proc_dointvec_minmax(struct ctl_table *table, int write,
do_proc_dointvec_minmax_conv, &param);
}
++int proc_dointvec_minmax_secure(struct ctl_table *table, int write,
++ void __user *buffer, size_t *lenp, loff_t *ppos)
++{
++ struct do_proc_dointvec_minmax_conv_param param = {
++ .min = (int *) table->extra1,
++ .max = (int *) table->extra2,
++ };
++ return do_proc_dointvec(table, write, buffer, lenp, ppos,
++ do_proc_dointvec_minmax_conv_secure, &param);
++}
++
+static void validate_coredump_safety(void)
+{
+ if (suid_dumpable == SUID_DUMPABLE_SAFE &&
@@ -95251,7 +98610,7 @@ index ea7ec7f..798623e 100644
static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int write,
void __user *buffer,
size_t *lenp, loff_t *ppos,
-@@ -2545,8 +2656,11 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
+@@ -2545,8 +2741,11 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
*i = val;
} else {
val = convdiv * (*i) / convmul;
@@ -95264,7 +98623,7 @@ index ea7ec7f..798623e 100644
err = proc_put_long(&buffer, &left, val, false);
if (err)
break;
-@@ -2941,6 +3055,12 @@ int proc_dostring(struct ctl_table *table, int write,
+@@ -2941,6 +3140,12 @@ int proc_dostring(struct ctl_table *table, int write,
return -ENOSYS;
}
@@ -95277,7 +98636,7 @@ index ea7ec7f..798623e 100644
int proc_dointvec(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
-@@ -2997,6 +3117,7 @@ EXPORT_SYMBOL(proc_dointvec_minmax);
+@@ -2997,6 +3202,7 @@ EXPORT_SYMBOL(proc_dointvec_minmax);
EXPORT_SYMBOL(proc_dointvec_userhz_jiffies);
EXPORT_SYMBOL(proc_dointvec_ms_jiffies);
EXPORT_SYMBOL(proc_dostring);
@@ -96783,10 +100142,22 @@ index bd2bea9..6b3c95e 100644
return false;
diff --git a/lib/kobject.c b/lib/kobject.c
-index 83bd5b3..8a0c75f 100644
+index 83bd5b3..757af67 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
-@@ -844,7 +844,7 @@ static struct kset *kset_create(const char *name,
+@@ -296,8 +296,9 @@ error:
+ }
+ EXPORT_SYMBOL(kobject_init);
+
+-static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
+- const char *fmt, va_list vargs)
++static __printf(3, 0) int kobject_add_varg(struct kobject *kobj,
++ struct kobject *parent,
++ const char *fmt, va_list vargs)
+ {
+ int retval;
+
+@@ -844,7 +845,7 @@ static struct kset *kset_create(const char *name,
kset = kzalloc(sizeof(*kset), GFP_KERNEL);
if (!kset)
return NULL;
@@ -96795,7 +100166,7 @@ index 83bd5b3..8a0c75f 100644
if (retval) {
kfree(kset);
return NULL;
-@@ -898,9 +898,9 @@ EXPORT_SYMBOL_GPL(kset_create_and_add);
+@@ -898,9 +899,9 @@ EXPORT_SYMBOL_GPL(kset_create_and_add);
static DEFINE_SPINLOCK(kobj_ns_type_lock);
@@ -97566,7 +100937,7 @@ index 1f44bdc..009bfe8 100644
+}
+#endif
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
-index ae02e42..4ffc938 100644
+index ae02e42..cd72015 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -16,6 +16,9 @@
@@ -97592,10 +100963,11 @@ index ae02e42..4ffc938 100644
return string(buf, end, uuid, spec);
}
+-int kptr_restrict __read_mostly;
+#ifdef CONFIG_GRKERNSEC_HIDESYM
-+int kptr_restrict __read_mostly = 2;
++int kptr_restrict __read_only = 2;
+#else
- int kptr_restrict __read_mostly;
++int kptr_restrict __read_only;
+#endif
/*
@@ -103475,6 +106847,18 @@ index 23f45ce..c748f1a 100644
__AAL_STAT_ITEMS
#undef __HANDLE_ITEM
}
+diff --git a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c
+index c6715ee..69745c0 100644
+--- a/net/ax25/ax25_subr.c
++++ b/net/ax25/ax25_subr.c
+@@ -265,6 +265,7 @@ void ax25_disconnect(ax25_cb *ax25, int reason)
+ {
+ ax25_clear_queues(ax25);
+
++ ax25_stop_heartbeat(ax25);
+ ax25_stop_t1timer(ax25);
+ ax25_stop_t2timer(ax25);
+ ax25_stop_t3timer(ax25);
diff --git a/net/ax25/sysctl_net_ax25.c b/net/ax25/sysctl_net_ax25.c
index ebe0ef3..d5b0a8e 100644
--- a/net/ax25/sysctl_net_ax25.c
@@ -104847,7 +108231,7 @@ index 80aeac9..b08d0a8 100644
return -ENODEV;
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
-index 5b412f0..e251eea 100644
+index 5b412f0..595dfcd 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -57,7 +57,7 @@ struct rtnl_link {
@@ -104885,6 +108269,24 @@ index 5b412f0..e251eea 100644
}
EXPORT_SYMBOL_GPL(__rtnl_link_unregister);
+@@ -1484,10 +1487,13 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
+ goto errout;
+
+ nla_for_each_nested(attr, tb[IFLA_VF_PORTS], rem) {
+- if (nla_type(attr) != IFLA_VF_PORT)
+- continue;
+- err = nla_parse_nested(port, IFLA_PORT_MAX,
+- attr, ifla_port_policy);
++ if (nla_type(attr) != IFLA_VF_PORT ||
++ nla_len(attr) < NLA_HDRLEN) {
++ err = -EINVAL;
++ goto errout;
++ }
++ err = nla_parse_nested(port, IFLA_PORT_MAX, attr,
++ ifla_port_policy);
+ if (err < 0)
+ goto errout;
+ if (!port[IFLA_PORT_VF]) {
diff --git a/net/core/scm.c b/net/core/scm.c
index ff52ad0..aff1c0f 100644
--- a/net/core/scm.c
@@ -116088,10 +119490,10 @@ index 0000000..0c96d8a
+}
diff --git a/tools/gcc/constify_plugin.c b/tools/gcc/constify_plugin.c
new file mode 100644
-index 0000000..da184c5
+index 0000000..c5de280
--- /dev/null
+++ b/tools/gcc/constify_plugin.c
-@@ -0,0 +1,564 @@
+@@ -0,0 +1,568 @@
+/*
+ * Copyright 2011 by Emese Revfy <re.emese@gmail.com>
+ * Copyright 2011-2015 by PaX Team <pageexec@freemail.hu>
@@ -116533,7 +119935,7 @@ index 0000000..da184c5
+ .optinfo_flags = OPTGROUP_NONE,
+#endif
+#if BUILDING_GCC_VERSION >= 5000
-+#elif BUILDING_GCC_VERSION >= 4009
++#elif BUILDING_GCC_VERSION == 4009
+ .has_gate = false,
+ .has_execute = true,
+#else
@@ -116558,7 +119960,11 @@ index 0000000..da184c5
+class check_local_variables_pass : public gimple_opt_pass {
+public:
+ check_local_variables_pass() : gimple_opt_pass(check_local_variables_pass_data, g) {}
++#if BUILDING_GCC_VERSION >= 5000
++ virtual unsigned int execute(function *) { return check_local_variables(); }
++#else
+ unsigned int execute() { return check_local_variables(); }
++#endif
+};
+}
+
@@ -116658,10 +120064,10 @@ index 0000000..da184c5
+}
diff --git a/tools/gcc/gcc-common.h b/tools/gcc/gcc-common.h
new file mode 100644
-index 0000000..1d20e32
+index 0000000..70924d4
--- /dev/null
+++ b/tools/gcc/gcc-common.h
-@@ -0,0 +1,689 @@
+@@ -0,0 +1,787 @@
+#ifndef GCC_COMMON_H_INCLUDED
+#define GCC_COMMON_H_INCLUDED
+
@@ -116740,6 +120146,8 @@ index 0000000..1d20e32
+#include "tree-flow.h"
+#else
+#include "tree-cfgcleanup.h"
++#include "tree-ssa-operands.h"
++#include "tree-into-ssa.h"
+#endif
+
+#if BUILDING_GCC_VERSION >= 4008
@@ -117070,6 +120478,76 @@ index 0000000..1d20e32
+typedef union gimple_statement_d gdebug;
+typedef union gimple_statement_d gphi;
+typedef union gimple_statement_d greturn;
++
++static inline gasm *as_a_gasm(gimple stmt)
++{
++ return stmt;
++}
++
++static inline const gasm *as_a_const_gasm(const_gimple stmt)
++{
++ return stmt;
++}
++
++static inline gassign *as_a_gassign(gimple stmt)
++{
++ return stmt;
++}
++
++static inline const gassign *as_a_const_gassign(const_gimple stmt)
++{
++ return stmt;
++}
++
++static inline gcall *as_a_gcall(gimple stmt)
++{
++ return stmt;
++}
++
++static inline const gcall *as_a_const_gcall(const_gimple stmt)
++{
++ return stmt;
++}
++
++static inline gcond *as_a_gcond(gimple stmt)
++{
++ return stmt;
++}
++
++static inline const gcond *as_a_const_gcond(const_gimple stmt)
++{
++ return stmt;
++}
++
++static inline gdebug *as_a_gdebug(gimple stmt)
++{
++ return stmt;
++}
++
++static inline const gdebug *as_a_const_gdebug(const_gimple stmt)
++{
++ return stmt;
++}
++
++static inline gphi *as_a_gphi(gimple stmt)
++{
++ return stmt;
++}
++
++static inline const gphi *as_a_const_gphi(const_gimple stmt)
++{
++ return stmt;
++}
++
++static inline greturn *as_a_greturn(gimple stmt)
++{
++ return stmt;
++}
++
++static inline const greturn *as_a_const_greturn(const_gimple stmt)
++{
++ return stmt;
++}
+#endif
+
+#if BUILDING_GCC_VERSION == 4008
@@ -117089,34 +120567,35 @@ index 0000000..1d20e32
+#if BUILDING_GCC_VERSION <= 4009
+#define TODO_verify_il 0
+#define AVAIL_INTERPOSABLE AVAIL_OVERWRITABLE
-+#endif
+
-+#if BUILDING_GCC_VERSION == 4009
-+typedef struct gimple_statement_base gasm;
-+typedef struct gimple_statement_base gassign;
-+typedef struct gimple_statement_base gcall;
-+typedef struct gimple_statement_base gcond;
-+typedef struct gimple_statement_base gdebug;
-+typedef struct gimple_statement_base gphi;
-+typedef struct gimple_statement_base greturn;
-+#endif
++#define section_name_prefix LTO_SECTION_NAME_PREFIX
++#define fatal_error(loc, gmsgid, ...) fatal_error((gmsgid), __VA_ARGS__)
+
-+#if BUILDING_GCC_VERSION <= 4009
+typedef struct rtx_def rtx_insn;
+
+static inline void set_decl_section_name(tree node, const char *value)
+{
+ DECL_SECTION_NAME(node) = build_string(strlen(value) + 1, value);
+}
++#endif
++
++#if BUILDING_GCC_VERSION == 4009
++typedef struct gimple_statement_asm gasm;
++typedef struct gimple_statement_base gassign;
++typedef struct gimple_statement_call gcall;
++typedef struct gimple_statement_base gcond;
++typedef struct gimple_statement_base gdebug;
++typedef struct gimple_statement_phi gphi;
++typedef struct gimple_statement_base greturn;
+
+static inline gasm *as_a_gasm(gimple stmt)
+{
-+ return stmt;
++ return as_a<gasm>(stmt);
+}
+
+static inline const gasm *as_a_const_gasm(const_gimple stmt)
+{
-+ return stmt;
++ return as_a<const gasm>(stmt);
+}
+
+static inline gassign *as_a_gassign(gimple stmt)
@@ -117131,24 +120610,44 @@ index 0000000..1d20e32
+
+static inline gcall *as_a_gcall(gimple stmt)
+{
-+ return stmt;
++ return as_a<gcall>(stmt);
+}
+
+static inline const gcall *as_a_const_gcall(const_gimple stmt)
+{
++ return as_a<const gcall>(stmt);
++}
++
++static inline gcond *as_a_gcond(gimple stmt)
++{
+ return stmt;
+}
+
-+static inline gphi *as_a_gphi(gimple stmt)
++static inline const gcond *as_a_const_gcond(const_gimple stmt)
+{
+ return stmt;
+}
+
-+static inline const gphi *as_a_const_gphi(const_gimple stmt)
++static inline gdebug *as_a_gdebug(gimple stmt)
+{
+ return stmt;
+}
+
++static inline const gdebug *as_a_const_gdebug(const_gimple stmt)
++{
++ return stmt;
++}
++
++static inline gphi *as_a_gphi(gimple stmt)
++{
++ return as_a<gphi>(stmt);
++}
++
++static inline const gphi *as_a_const_gphi(const_gimple stmt)
++{
++ return as_a<const gphi>(stmt);
++}
++
+static inline greturn *as_a_greturn(gimple stmt)
+{
+ return stmt;
@@ -117210,6 +120709,11 @@ index 0000000..1d20e32
+ varpool_node::add(decl);
+}
+
++static inline unsigned int rebuild_cgraph_edges(void)
++{
++ return cgraph_edge::rebuild_edges();
++}
++
+static inline cgraph_node_ptr cgraph_function_node(cgraph_node_ptr node, enum availability *availability)
+{
+ return node->function_symbol(availability);
@@ -118594,10 +122098,10 @@ index 0000000..ac6f9b4
+}
diff --git a/tools/gcc/randomize_layout_plugin.c b/tools/gcc/randomize_layout_plugin.c
new file mode 100644
-index 0000000..713be61
+index 0000000..40dcfa9
--- /dev/null
+++ b/tools/gcc/randomize_layout_plugin.c
-@@ -0,0 +1,918 @@
+@@ -0,0 +1,922 @@
+/*
+ * Copyright 2014,2015 by Open Source Security, Inc., Brad Spengler <spender@grsecurity.net>
+ * and PaX Team <pageexec@freemail.hu>
@@ -119443,7 +122947,11 @@ index 0000000..713be61
+class randomize_layout_bad_cast : public gimple_opt_pass {
+public:
+ randomize_layout_bad_cast() : gimple_opt_pass(randomize_layout_bad_cast_data, g) {}
++#if BUILDING_GCC_VERSION >= 5000
++ virtual unsigned int execute(function *) { return find_bad_casts(); }
++#else
+ unsigned int execute() { return find_bad_casts(); }
++#endif
+};
+}
+#endif
@@ -119660,15 +123168,16 @@ index 0000000..12b1e3b
+exit 0
diff --git a/tools/gcc/size_overflow_plugin/insert_size_overflow_asm.c b/tools/gcc/size_overflow_plugin/insert_size_overflow_asm.c
new file mode 100644
-index 0000000..c43901f
+index 0000000..495983ff
--- /dev/null
+++ b/tools/gcc/size_overflow_plugin/insert_size_overflow_asm.c
-@@ -0,0 +1,748 @@
+@@ -0,0 +1,762 @@
+/*
-+ * Copyright 2011-2014 by Emese Revfy <re.emese@gmail.com>
++ * Copyright 2011-2015 by Emese Revfy <re.emese@gmail.com>
+ * Licensed under the GPL v2, or (at your option) v3
+ *
+ * Homepage:
++ * https://github.com/ephox-gcc-plugins
+ * http://www.grsecurity.net/~ephox/overflow_plugin/
+ *
+ * Documentation:
@@ -119686,8 +123195,8 @@ index 0000000..c43901f
+#include "gcc-common.h"
+#include "size_overflow.h"
+
-+static void search_size_overflow_attribute(struct pointer_set_t *visited, tree lhs);
-+static enum mark search_intentional(struct pointer_set_t *visited, const_tree lhs);
++static void search_size_overflow_attribute(gimple_set *visited, tree lhs);
++static enum mark search_intentional(gimple_set *visited, const_tree lhs);
+
+// data for the size_overflow asm stmt
+struct asm_data {
@@ -119721,7 +123230,7 @@ index 0000000..c43901f
+
+static void create_asm_stmt(const char *str, tree str_input, tree str_output, struct asm_data *asm_data)
+{
-+ gimple asm_stmt;
++ gasm *asm_stmt;
+ gimple_stmt_iterator gsi;
+#if BUILDING_GCC_VERSION <= 4007
+ VEC(tree, gc) *input, *output = NULL;
@@ -119734,7 +123243,7 @@ index 0000000..c43901f
+ if (asm_data->output)
+ output = create_asm_io_list(str_output, asm_data->output);
+
-+ asm_stmt = gimple_build_asm_vec(str, input, output, NULL, NULL);
++ asm_stmt = as_a_gasm(gimple_build_asm_vec(str, input, output, NULL, NULL));
+ gsi = gsi_for_stmt(asm_data->def_stmt);
+ gsi_insert_after(&gsi, asm_stmt, GSI_NEW_STMT);
+
@@ -119749,13 +123258,13 @@ index 0000000..c43901f
+ SSA_NAME_DEF_STMT(asm_data->input) = asm_data->def_stmt;
+}
+
-+static enum mark search_intentional_phi(struct pointer_set_t *visited, const_tree result)
++static enum mark search_intentional_phi(gimple_set *visited, const_tree result)
+{
+ enum mark cur_fndecl_attr;
-+ gimple phi = get_def_stmt(result);
++ gphi *phi = as_a_gphi(get_def_stmt(result));
+ unsigned int i, n = gimple_phi_num_args(phi);
+
-+ pointer_set_insert(visited, phi);
++ pointer_set_insert(visited, (gimple)phi);
+ for (i = 0; i < n; i++) {
+ tree arg = gimple_phi_arg_def(phi, i);
+
@@ -119766,11 +123275,11 @@ index 0000000..c43901f
+ return MARK_NO;
+}
+
-+static enum mark search_intentional_binary(struct pointer_set_t *visited, const_tree lhs)
++static enum mark search_intentional_binary(gimple_set *visited, const_tree lhs)
+{
+ enum mark cur_fndecl_attr;
+ const_tree rhs1, rhs2;
-+ gimple def_stmt = get_def_stmt(lhs);
++ gassign *def_stmt = as_a_gassign(get_def_stmt(lhs));
+
+ rhs1 = gimple_assign_rhs1(def_stmt);
+ rhs2 = gimple_assign_rhs2(def_stmt);
@@ -119782,7 +123291,7 @@ index 0000000..c43901f
+}
+
+// Look up the intentional_overflow attribute on the caller and the callee functions.
-+static enum mark search_intentional(struct pointer_set_t *visited, const_tree lhs)
++static enum mark search_intentional(gimple_set *visited, const_tree lhs)
+{
+ const_gimple def_stmt;
+
@@ -119800,7 +123309,7 @@ index 0000000..c43901f
+ case GIMPLE_NOP:
+ return search_intentional(visited, SSA_NAME_VAR(lhs));
+ case GIMPLE_ASM:
-+ if (is_size_overflow_intentional_asm_turn_off(def_stmt))
++ if (is_size_overflow_intentional_asm_turn_off(as_a_const_gasm(def_stmt)))
+ return MARK_TURN_OFF;
+ return MARK_NO;
+ case GIMPLE_CALL:
@@ -119810,7 +123319,7 @@ index 0000000..c43901f
+ case GIMPLE_ASSIGN:
+ switch (gimple_num_ops(def_stmt)) {
+ case 2:
-+ return search_intentional(visited, gimple_assign_rhs1(def_stmt));
++ return search_intentional(visited, gimple_assign_rhs1(as_a_const_gassign(def_stmt)));
+ case 3:
+ return search_intentional_binary(visited, lhs);
+ }
@@ -119827,7 +123336,7 @@ index 0000000..c43901f
+static enum mark check_intentional_attribute_gimple(const_tree arg, const_gimple stmt, unsigned int argnum)
+{
+ const_tree fndecl;
-+ struct pointer_set_t *visited;
++ gimple_set *visited;
+ enum mark cur_fndecl_attr, decl_attr = MARK_NO;
+
+ fndecl = get_interesting_orig_fndecl(stmt, argnum);
@@ -119870,7 +123379,7 @@ index 0000000..c43901f
+ is_missing_function(orig_fndecl, num);
+}
+
-+static void search_size_overflow_attribute_phi(struct pointer_set_t *visited, const_tree result)
++static void search_size_overflow_attribute_phi(gimple_set *visited, const_tree result)
+{
+ gimple phi = get_def_stmt(result);
+ unsigned int i, n = gimple_phi_num_args(phi);
@@ -119883,7 +123392,7 @@ index 0000000..c43901f
+ }
+}
+
-+static void search_size_overflow_attribute_binary(struct pointer_set_t *visited, const_tree lhs)
++static void search_size_overflow_attribute_binary(gimple_set *visited, const_tree lhs)
+{
+ const_gimple def_stmt = get_def_stmt(lhs);
+ tree rhs1, rhs2;
@@ -119895,7 +123404,7 @@ index 0000000..c43901f
+ search_size_overflow_attribute(visited, rhs2);
+}
+
-+static void search_size_overflow_attribute(struct pointer_set_t *visited, tree lhs)
++static void search_size_overflow_attribute(gimple_set *visited, tree lhs)
+{
+ const_gimple def_stmt;
+
@@ -119945,18 +123454,20 @@ index 0000000..c43901f
+{
+ tree fndecl = NULL_TREE;
+ tree lhs;
-+ struct pointer_set_t *visited;
++ gimple_set *visited;
+
+ if (is_turn_off_intentional_attr(DECL_ORIGIN(current_function_decl)))
+ return;
+
+ if (num == 0) {
+ gcc_assert(gimple_code(stmt) == GIMPLE_RETURN);
-+ lhs = gimple_return_retval(stmt);
++ lhs = gimple_return_retval(as_a_const_greturn(stmt));
+ } else {
-+ gcc_assert(is_gimple_call(stmt));
-+ lhs = gimple_call_arg(stmt, num - 1);
-+ fndecl = gimple_call_fndecl(stmt);
++ const gcall *call = as_a_const_gcall(stmt);
++
++ gcc_assert(is_gimple_call(call));
++ lhs = gimple_call_arg(call, num - 1);
++ fndecl = gimple_call_fndecl(call);
+ }
+
+ if (fndecl != NULL_TREE && is_turn_off_intentional_attr(DECL_ORIGIN(fndecl)))
@@ -119980,9 +123491,9 @@ index 0000000..c43901f
+ asm_data->output = create_new_var(TREE_TYPE(asm_data->output));
+ asm_data->output = make_ssa_name(asm_data->output, stmt);
+ if (gimple_code(stmt) == GIMPLE_RETURN)
-+ gimple_return_set_retval(stmt, asm_data->output);
++ gimple_return_set_retval(as_a_greturn(stmt), asm_data->output);
+ else
-+ gimple_call_set_arg(stmt, argnum - 1, asm_data->output);
++ gimple_call_set_arg(as_a_gcall(stmt), argnum - 1, asm_data->output);
+ update_stmt(stmt);
+}
+
@@ -120062,7 +123573,7 @@ index 0000000..c43901f
+ break;
+ }
+ case GIMPLE_ASM:
-+ if (is_size_overflow_asm(asm_data->def_stmt)) {
++ if (is_size_overflow_asm(as_a_const_gasm(asm_data->def_stmt))) {
+ asm_data->input = NULL_TREE;
+ break;
+ }
@@ -120093,7 +123604,7 @@ index 0000000..c43901f
+ search_missing_size_overflow_attribute_gimple(stmt, argnum);
+
+ asm_data.def_stmt = get_def_stmt(asm_data.output);
-+ if (is_size_overflow_intentional_asm_turn_off(asm_data.def_stmt))
++ if (gimple_code(asm_data.def_stmt) == GIMPLE_ASM && is_size_overflow_intentional_asm_turn_off(as_a_const_gasm(asm_data.def_stmt)))
+ return;
+
+ create_asm_input(stmt, argnum, &asm_data);
@@ -120143,7 +123654,7 @@ index 0000000..c43901f
+ return true;
+}
+
-+static void walk_use_def_ptr(struct pointer_set_t *visited, const_tree lhs)
++static void walk_use_def_ptr(gimple_set *visited, const_tree lhs)
+{
+ gimple def_stmt;
+
@@ -120160,28 +123671,33 @@ index 0000000..c43901f
+ case GIMPLE_CALL:
+ break;
+ case GIMPLE_PHI: {
-+ unsigned int i, n = gimple_phi_num_args(def_stmt);
++ gphi *phi = as_a_gphi(def_stmt);
++ unsigned int i, n = gimple_phi_num_args(phi);
+
+ pointer_set_insert(visited, def_stmt);
+
+ for (i = 0; i < n; i++) {
-+ tree arg = gimple_phi_arg_def(def_stmt, i);
++ tree arg = gimple_phi_arg_def(phi, i);
+
+ walk_use_def_ptr(visited, arg);
+ }
++ break;
+ }
-+ case GIMPLE_ASSIGN:
-+ switch (gimple_num_ops(def_stmt)) {
++ case GIMPLE_ASSIGN: {
++ gassign *assign = as_a_gassign(def_stmt);
++
++ switch (gimple_num_ops(assign)) {
+ case 2:
-+ walk_use_def_ptr(visited, gimple_assign_rhs1(def_stmt));
++ walk_use_def_ptr(visited, gimple_assign_rhs1(assign));
+ return;
+ case 3:
-+ walk_use_def_ptr(visited, gimple_assign_rhs1(def_stmt));
-+ walk_use_def_ptr(visited, gimple_assign_rhs2(def_stmt));
++ walk_use_def_ptr(visited, gimple_assign_rhs1(assign));
++ walk_use_def_ptr(visited, gimple_assign_rhs2(assign));
+ return;
+ default:
+ return;
+ }
++ }
+ default:
+ debug_gimple_stmt((gimple)def_stmt);
+ error("%s: unknown gimple code", __func__);
@@ -120192,7 +123708,7 @@ index 0000000..c43901f
+// Look for a ptr - ptr expression (e.g., cpuset_common_file_read() s - page)
+static void insert_mark_not_intentional_asm_at_ptr(const_tree arg)
+{
-+ struct pointer_set_t *visited;
++ gimple_set *visited;
+
+ visited = pointer_set_create();
+ walk_use_def_ptr(visited, arg);
@@ -120200,7 +123716,7 @@ index 0000000..c43901f
+}
+
+// Determine the return value and insert the asm stmt to mark the return stmt.
-+static void insert_asm_ret(gimple stmt)
++static void insert_asm_ret(greturn *stmt)
+{
+ tree ret;
+
@@ -120209,7 +123725,7 @@ index 0000000..c43901f
+}
+
+// Determine the correct arg index and arg and insert the asm stmt to mark the stmt.
-+static void insert_asm_arg(gimple stmt, unsigned int orig_argnum)
++static void insert_asm_arg(gcall *stmt, unsigned int orig_argnum)
+{
+ tree arg;
+ unsigned int argnum;
@@ -120286,7 +123802,7 @@ index 0000000..c43901f
+ * Look up the intentional_overflow attribute that turns off ipa based duplication
+ * on the callee function.
+ */
-+static bool is_mark_turn_off_attribute(gimple stmt)
++static bool is_mark_turn_off_attribute(gcall *stmt)
+{
+ enum mark mark;
+ const_tree fndecl = gimple_call_fndecl(stmt);
@@ -120298,7 +123814,7 @@ index 0000000..c43901f
+}
+
+// If the argument(s) of the callee function is/are in the hash table or are marked by an attribute then mark the call stmt with an asm stmt
-+static void handle_interesting_function(gimple stmt)
++static void handle_interesting_function(gcall *stmt)
+{
+ unsigned int argnum;
+ tree fndecl;
@@ -120324,7 +123840,7 @@ index 0000000..c43901f
+}
+
+// If the return value of the caller function is in hash table (its index is 0) then mark the return stmt with an asm stmt
-+static void handle_interesting_ret(gimple stmt)
++static void handle_interesting_ret(greturn *stmt)
+{
+ bool orig_argnums[MAX_PARAM + 1] = {false};
+
@@ -120345,13 +123861,13 @@ index 0000000..c43901f
+ for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
+ gimple stmt = gsi_stmt(gsi);
+
-+ if (is_size_overflow_asm(stmt))
++ if (gimple_code(stmt) == GIMPLE_ASM && is_size_overflow_asm(as_a_const_gasm(stmt)))
+ continue;
+
+ if (is_gimple_call(stmt))
-+ handle_interesting_function(stmt);
++ handle_interesting_function(as_a_gcall(stmt));
+ else if (gimple_code(stmt) == GIMPLE_RETURN)
-+ handle_interesting_ret(stmt);
++ handle_interesting_ret(as_a_greturn(stmt));
+ }
+ }
+ return 0;
@@ -120363,6 +123879,7 @@ index 0000000..c43901f
+ * that the ipa pass will detect and insert the size overflow checks for.
+ */
+#if BUILDING_GCC_VERSION >= 4009
++namespace {
+static const struct pass_data insert_size_overflow_asm_pass_data = {
+#else
+static struct gimple_opt_pass insert_size_overflow_asm_pass = {
@@ -120373,7 +123890,8 @@ index 0000000..c43901f
+#if BUILDING_GCC_VERSION >= 4008
+ .optinfo_flags = OPTGROUP_NONE,
+#endif
-+#if BUILDING_GCC_VERSION >= 4009
++#if BUILDING_GCC_VERSION >= 5000
++#elif BUILDING_GCC_VERSION == 4009
+ .has_gate = false,
+ .has_execute = true,
+#else
@@ -120395,34 +123913,39 @@ index 0000000..c43901f
+};
+
+#if BUILDING_GCC_VERSION >= 4009
-+namespace {
+class insert_size_overflow_asm_pass : public gimple_opt_pass {
+public:
+ insert_size_overflow_asm_pass() : gimple_opt_pass(insert_size_overflow_asm_pass_data, g) {}
++#if BUILDING_GCC_VERSION >= 5000
++ virtual unsigned int execute(function *) { return search_interesting_functions(); }
++#else
+ unsigned int execute() { return search_interesting_functions(); }
++#endif
+};
+}
-+#endif
+
-+struct opt_pass *make_insert_size_overflow_asm_pass(void)
++opt_pass *make_insert_size_overflow_asm_pass(void)
+{
-+#if BUILDING_GCC_VERSION >= 4009
+ return new insert_size_overflow_asm_pass();
++}
+#else
++struct opt_pass *make_insert_size_overflow_asm_pass(void)
++{
+ return &insert_size_overflow_asm_pass.pass;
-+#endif
+}
++#endif
diff --git a/tools/gcc/size_overflow_plugin/insert_size_overflow_check_core.c b/tools/gcc/size_overflow_plugin/insert_size_overflow_check_core.c
new file mode 100644
-index 0000000..73f0a12
+index 0000000..0766e39
--- /dev/null
+++ b/tools/gcc/size_overflow_plugin/insert_size_overflow_check_core.c
-@@ -0,0 +1,943 @@
+@@ -0,0 +1,931 @@
+/*
-+ * Copyright 2011-2014 by Emese Revfy <re.emese@gmail.com>
++ * Copyright 2011-2015 by Emese Revfy <re.emese@gmail.com>
+ * Licensed under the GPL v2, or (at your option) v3
+ *
+ * Homepage:
++ * https://github.com/ephox-gcc-plugins
+ * http://www.grsecurity.net/~ephox/overflow_plugin/
+ *
+ * Documentation:
@@ -120486,19 +124009,6 @@ index 0000000..73f0a12
+ return new_type;
+}
+
-+static tree get_lhs(const_gimple stmt)
-+{
-+ switch (gimple_code(stmt)) {
-+ case GIMPLE_ASSIGN:
-+ case GIMPLE_CALL:
-+ return gimple_get_lhs(stmt);
-+ case GIMPLE_PHI:
-+ return gimple_phi_result(stmt);
-+ default:
-+ return NULL_TREE;
-+ }
-+}
-+
+static tree cast_to_new_size_overflow_type(struct visited *visited, gimple stmt, tree rhs, tree size_overflow_type, bool before)
+{
+ gimple_stmt_iterator gsi;
@@ -120572,7 +124082,7 @@ index 0000000..73f0a12
+ return cast_to_new_size_overflow_type(visited, oldstmt, rhs1, dst_type, before);
+}
+
-+tree dup_assign(struct visited *visited, gimple oldstmt, const_tree node, tree rhs1, tree rhs2, tree __unused rhs3)
++tree dup_assign(struct visited *visited, gassign *oldstmt, const_tree node, tree rhs1, tree rhs2, tree __unused rhs3)
+{
+ gimple stmt;
+ gimple_stmt_iterator gsi;
@@ -120641,13 +124151,14 @@ index 0000000..73f0a12
+ assign = build_cast_stmt(visited, size_overflow_type, arg, phi_ssa_name, &gsi, BEFORE_STMT, false);
+ pointer_set_insert(visited->my_stmts, assign);
+
-+ return gimple_assign_lhs(assign);
++ return get_lhs(assign);
+}
+
+static tree use_phi_ssa_name(struct visited *visited, tree ssa_name_var, tree new_arg)
+{
+ gimple_stmt_iterator gsi;
-+ gimple assign, def_stmt = get_def_stmt(new_arg);
++ gimple assign;
++ gimple def_stmt = get_def_stmt(new_arg);
+
+ if (gimple_code(def_stmt) == GIMPLE_PHI) {
+ gsi = gsi_after_labels(gimple_bb(def_stmt));
@@ -120658,7 +124169,7 @@ index 0000000..73f0a12
+ }
+
+ pointer_set_insert(visited->my_stmts, assign);
-+ return gimple_assign_lhs(assign);
++ return get_lhs(assign);
+}
+
+static tree cast_visited_phi_arg(struct visited *visited, tree ssa_name_var, tree arg, tree size_overflow_type)
@@ -120675,13 +124186,12 @@ index 0000000..73f0a12
+
+ assign = build_cast_stmt(visited, size_overflow_type, arg, ssa_name_var, &gsi, BEFORE_STMT, false);
+ pointer_set_insert(visited->my_stmts, assign);
-+ return gimple_assign_lhs(assign);
++ return get_lhs(assign);
+}
+
-+static tree create_new_phi_arg(struct visited *visited, tree ssa_name_var, tree new_arg, gimple oldstmt, unsigned int i)
++static tree create_new_phi_arg(struct visited *visited, tree ssa_name_var, tree new_arg, gphi *oldstmt, unsigned int i)
+{
-+ tree size_overflow_type;
-+ tree arg;
++ tree size_overflow_type, arg;
+ const_gimple def_stmt;
+
+ if (new_arg != NULL_TREE && is_gimple_constant(new_arg))
@@ -120698,7 +124208,7 @@ index 0000000..73f0a12
+ case GIMPLE_NOP: {
+ basic_block bb;
+
-+ bb = gimple_phi_arg_edge(oldstmt, i)->src;
++ bb = gimple_phi_arg_edge(as_a_gphi(oldstmt), i)->src;
+ return cast_parm_decl(visited, ssa_name_var, arg, size_overflow_type, bb);
+ }
+ case GIMPLE_ASM: {
@@ -120708,7 +124218,7 @@ index 0000000..73f0a12
+ gsi = gsi_for_stmt(stmt);
+ assign = build_cast_stmt(visited, size_overflow_type, arg, ssa_name_var, &gsi, AFTER_STMT, false);
+ pointer_set_insert(visited->my_stmts, assign);
-+ return gimple_assign_lhs(assign);
++ return get_lhs(assign);
+ }
+ default:
+ gcc_assert(new_arg != NULL_TREE);
@@ -120717,10 +124227,10 @@ index 0000000..73f0a12
+ }
+}
+
-+static gimple overflow_create_phi_node(struct visited *visited, gimple oldstmt, tree result)
++static gphi *overflow_create_phi_node(struct visited *visited, gphi *oldstmt, tree result)
+{
+ basic_block bb;
-+ gimple phi;
++ gphi *phi;
+ gimple_seq seq;
+ gimple_stmt_iterator gsi = gsi_for_stmt(oldstmt);
+
@@ -120733,7 +124243,7 @@ index 0000000..73f0a12
+ result = create_new_var(size_overflow_type);
+ }
+
-+ phi = create_phi_node(result, bb);
++ phi = as_a_gphi(create_phi_node(result, bb));
+ gimple_phi_set_result(phi, make_ssa_name(result, phi));
+ seq = phi_nodes(bb);
+ gsi = gsi_last(seq);
@@ -120746,12 +124256,12 @@ index 0000000..73f0a12
+}
+
+#if BUILDING_GCC_VERSION <= 4007
-+static tree create_new_phi_node(struct visited *visited, VEC(tree, heap) **args, tree ssa_name_var, gimple oldstmt)
++static tree create_new_phi_node(struct visited *visited, VEC(tree, heap) **args, tree ssa_name_var, gphi *oldstmt)
+#else
-+static tree create_new_phi_node(struct visited *visited, vec<tree, va_heap, vl_embed> *&args, tree ssa_name_var, gimple oldstmt)
++static tree create_new_phi_node(struct visited *visited, vec<tree, va_heap, vl_embed> *&args, tree ssa_name_var, gphi *oldstmt)
+#endif
+{
-+ gimple new_phi;
++ gphi *new_phi;
+ unsigned int i;
+ tree arg, result;
+ location_t loc = gimple_location(oldstmt);
@@ -120793,7 +124303,7 @@ index 0000000..73f0a12
+#else
+ vec<tree, va_heap, vl_embed> *args = NULL;
+#endif
-+ gimple oldstmt = get_def_stmt(orig_result);
++ gphi *oldstmt = as_a_gphi(get_def_stmt(orig_result));
+ unsigned int i, len = gimple_phi_num_args(oldstmt);
+
+ pointer_set_insert(visited->stmts, oldstmt);
@@ -120826,7 +124336,7 @@ index 0000000..73f0a12
+#endif
+}
+
-+static tree create_cast_assign(struct visited *visited, gimple stmt)
++static tree create_cast_assign(struct visited *visited, gassign *stmt)
+{
+ tree rhs1 = gimple_assign_rhs1(stmt);
+ tree lhs = gimple_assign_lhs(stmt);
@@ -120839,7 +124349,7 @@ index 0000000..73f0a12
+ return create_assign(visited, stmt, rhs1, AFTER_STMT);
+}
+
-+static bool skip_lhs_cast_check(const_gimple stmt)
++static bool skip_lhs_cast_check(const gassign *stmt)
+{
+ const_tree rhs = gimple_assign_rhs1(stmt);
+ const_gimple def_stmt = get_def_stmt(rhs);
@@ -120873,7 +124383,7 @@ index 0000000..73f0a12
+
+static void insert_cond(basic_block cond_bb, tree arg, enum tree_code cond_code, tree type_value)
+{
-+ gimple cond_stmt;
++ gcond *cond_stmt;
+ gimple_stmt_iterator gsi = gsi_last_bb(cond_bb);
+
+ cond_stmt = gimple_build_cond(cond_code, arg, type_value, NULL_TREE, NULL_TREE);
@@ -120883,7 +124393,7 @@ index 0000000..73f0a12
+
+static void insert_cond_result(struct cgraph_node *caller_node, basic_block bb_true, const_gimple stmt, const_tree arg, bool min)
+{
-+ gimple func_stmt;
++ gcall *func_stmt;
+ const_gimple def_stmt;
+ const_tree loc_line;
+ tree loc_file, ssa_name, current_func;
@@ -120921,7 +124431,7 @@ index 0000000..73f0a12
+ ssa_name = create_string_param(ssa_name);
+
+ // void report_size_overflow(const char *file, unsigned int line, const char *func, const char *ssa_name)
-+ func_stmt = gimple_build_call(report_size_overflow_decl, 4, loc_file, loc_line, current_func, ssa_name);
++ func_stmt = as_a_gcall(gimple_build_call(report_size_overflow_decl, 4, loc_file, loc_line, current_func, ssa_name));
+ gsi_insert_after(&gsi, func_stmt, GSI_CONTINUE_LINKING);
+
+ callee_node = cgraph_get_create_node(report_size_overflow_decl);
@@ -121005,7 +124515,7 @@ index 0000000..73f0a12
+ insert_check_size_overflow(caller_node, stmt, LT_EXPR, cast_rhs, type_min, before, MIN_CHECK);
+}
+
-+static tree create_cast_overflow_check(struct visited *visited, struct cgraph_node *caller_node, tree new_rhs1, gimple stmt)
++static tree create_cast_overflow_check(struct visited *visited, struct cgraph_node *caller_node, tree new_rhs1, gassign *stmt)
+{
+ bool cast_lhs, cast_rhs;
+ tree lhs = gimple_assign_lhs(stmt);
@@ -121058,7 +124568,7 @@ index 0000000..73f0a12
+ return dup_assign(visited, stmt, lhs, new_rhs1, NULL_TREE, NULL_TREE);
+}
+
-+static tree handle_unary_rhs(struct visited *visited, struct cgraph_node *caller_node, gimple stmt)
++static tree handle_unary_rhs(struct visited *visited, struct cgraph_node *caller_node, gassign *stmt)
+{
+ enum tree_code rhs_code;
+ tree rhs1, new_rhs1, lhs = gimple_assign_lhs(stmt);
@@ -121093,10 +124603,10 @@ index 0000000..73f0a12
+ return create_cast_overflow_check(visited, caller_node, new_rhs1, stmt);
+}
+
-+static tree handle_unary_ops(struct visited *visited, struct cgraph_node *caller_node, gimple stmt)
++static tree handle_unary_ops(struct visited *visited, struct cgraph_node *caller_node, gassign *stmt)
+{
+ tree rhs1, lhs = gimple_assign_lhs(stmt);
-+ gimple def_stmt = get_def_stmt(lhs);
++ gassign *def_stmt = as_a_gassign(get_def_stmt(lhs));
+
+ gcc_assert(gimple_code(def_stmt) != GIMPLE_NOP);
+ rhs1 = gimple_assign_rhs1(def_stmt);
@@ -121155,7 +124665,7 @@ index 0000000..73f0a12
+}
+
+// Skip duplication when there is a minus expr and the type of rhs1 or rhs2 is a pointer_type.
-+static bool is_a_ptr_minus(gimple stmt)
++static bool is_a_ptr_minus(gassign *stmt)
+{
+ const_tree rhs1, rhs2, ptr1_rhs, ptr2_rhs;
+
@@ -121183,7 +124693,7 @@ index 0000000..73f0a12
+{
+ enum intentional_overflow_type res;
+ tree rhs1, rhs2, new_lhs;
-+ gimple def_stmt = get_def_stmt(lhs);
++ gassign *def_stmt = as_a_gassign(get_def_stmt(lhs));
+ tree new_rhs1 = NULL_TREE;
+ tree new_rhs2 = NULL_TREE;
+
@@ -121224,13 +124734,13 @@ index 0000000..73f0a12
+ res = add_mul_intentional_overflow(def_stmt);
+ if (res != NO_INTENTIONAL_OVERFLOW) {
+ new_lhs = dup_assign(visited, def_stmt, lhs, new_rhs1, new_rhs2, NULL_TREE);
-+ insert_cast_expr(visited, get_def_stmt(new_lhs), res);
++ insert_cast_expr(visited, as_a_gassign(get_def_stmt(new_lhs)), res);
+ return new_lhs;
+ }
+
+ if (skip_expr_on_double_type(def_stmt)) {
+ new_lhs = dup_assign(visited, def_stmt, lhs, new_rhs1, new_rhs2, NULL_TREE);
-+ insert_cast_expr(visited, get_def_stmt(new_lhs), NO_INTENTIONAL_OVERFLOW);
++ insert_cast_expr(visited, as_a_gassign(get_def_stmt(new_lhs)), NO_INTENTIONAL_OVERFLOW);
+ return new_lhs;
+ }
+
@@ -121267,7 +124777,7 @@ index 0000000..73f0a12
+static tree handle_ternary_ops(struct visited *visited, struct cgraph_node *caller_node, tree lhs)
+{
+ tree rhs1, rhs2, rhs3, new_rhs1, new_rhs2, new_rhs3, size_overflow_type;
-+ gimple def_stmt = get_def_stmt(lhs);
++ gassign *def_stmt = as_a_gassign(get_def_stmt(lhs));
+
+ size_overflow_type = get_size_overflow_type(visited, def_stmt, lhs);
+
@@ -121346,7 +124856,7 @@ index 0000000..73f0a12
+ case GIMPLE_ASSIGN:
+ switch (gimple_num_ops(def_stmt)) {
+ case 2:
-+ return handle_unary_ops(visited, caller_node, def_stmt);
++ return handle_unary_ops(visited, caller_node, as_a_gassign(def_stmt));
+ case 3:
+ return handle_binary_ops(visited, caller_node, lhs);
+#if BUILDING_GCC_VERSION >= 4006
@@ -121363,16 +124873,17 @@ index 0000000..73f0a12
+
diff --git a/tools/gcc/size_overflow_plugin/insert_size_overflow_check_ipa.c b/tools/gcc/size_overflow_plugin/insert_size_overflow_check_ipa.c
new file mode 100644
-index 0000000..df50164
+index 0000000..e1e6e19
--- /dev/null
+++ b/tools/gcc/size_overflow_plugin/insert_size_overflow_check_ipa.c
-@@ -0,0 +1,1141 @@
+@@ -0,0 +1,1157 @@
+/*
-+ * Copyright 2011-2014 by Emese Revfy <re.emese@gmail.com>
++ * Copyright 2011-2015 by Emese Revfy <re.emese@gmail.com>
+ * Licensed under the GPL v2, or (at your option) v3
+ *
+ * Homepage:
+ * http://www.grsecurity.net/~ephox/overflow_plugin/
++ * https://github.com/ephox-gcc-plugins
+ *
+ * Documentation:
+ * http://forums.grsecurity.net/viewtopic.php?f=7&t=3043
@@ -121396,8 +124907,8 @@ index 0000000..df50164
+
+unsigned int call_count;
+
-+static void set_conditions(struct pointer_set_t *visited, bool *interesting_conditions, const_tree lhs);
-+static void walk_use_def(struct pointer_set_t *visited, struct interesting_node *cur_node, tree lhs);
++static void set_conditions(gimple_set *visited, bool *interesting_conditions, const_tree lhs);
++static void walk_use_def(gimple_set *visited, struct interesting_node *cur_node, tree lhs);
+
+struct visited_fns {
+ struct visited_fns *next;
@@ -121567,9 +125078,9 @@ index 0000000..df50164
+ return cnodes;
+}
+
-+static void walk_phi_set_conditions(struct pointer_set_t *visited, bool *interesting_conditions, const_tree result)
++static void walk_phi_set_conditions(gimple_set *visited, bool *interesting_conditions, const_tree result)
+{
-+ gimple phi = get_def_stmt(result);
++ gphi *phi = as_a_gphi(get_def_stmt(result));
+ unsigned int i, n = gimple_phi_num_args(phi);
+
+ pointer_set_insert(visited, phi);
@@ -121585,7 +125096,7 @@ index 0000000..df50164
+};
+
+// Search for constants, cast assignments and binary/ternary assignments
-+static void set_conditions(struct pointer_set_t *visited, bool *interesting_conditions, const_tree lhs)
++static void set_conditions(gimple_set *visited, bool *interesting_conditions, const_tree lhs)
+{
+ gimple def_stmt = get_def_stmt(lhs);
+
@@ -121602,7 +125113,7 @@ index 0000000..df50164
+
+ switch (gimple_code(def_stmt)) {
+ case GIMPLE_CALL:
-+ if (lhs == gimple_call_lhs(def_stmt))
++ if (lhs == gimple_call_lhs(as_a_const_gcall(def_stmt)))
+ interesting_conditions[RET] = true;
+ return;
+ case GIMPLE_NOP:
@@ -121611,11 +125122,13 @@ index 0000000..df50164
+ case GIMPLE_PHI:
+ interesting_conditions[PHI] = true;
+ return walk_phi_set_conditions(visited, interesting_conditions, lhs);
-+ case GIMPLE_ASSIGN:
-+ if (gimple_num_ops(def_stmt) == 2) {
-+ const_tree rhs = gimple_assign_rhs1(def_stmt);
++ case GIMPLE_ASSIGN: {
++ gassign *assign = as_a_gassign(def_stmt);
++
++ if (gimple_num_ops(assign) == 2) {
++ const_tree rhs = gimple_assign_rhs1(assign);
+
-+ if (gimple_assign_cast_p(def_stmt))
++ if (gimple_assign_cast_p(assign))
+ interesting_conditions[CAST] = true;
+
+ return set_conditions(visited, interesting_conditions, rhs);
@@ -121623,6 +125136,7 @@ index 0000000..df50164
+ interesting_conditions[NOT_UNARY] = true;
+ return;
+ }
++ }
+ default:
+ debug_gimple_stmt(def_stmt);
+ gcc_unreachable();
@@ -121632,7 +125146,7 @@ index 0000000..df50164
+// determine whether duplication will be necessary or not.
+static void search_interesting_conditions(struct interesting_node *cur_node, bool *interesting_conditions)
+{
-+ struct pointer_set_t *visited;
++ gimple_set *visited;
+
+ if (gimple_assign_cast_p(cur_node->first_stmt))
+ interesting_conditions[CAST] = true;
@@ -121645,9 +125159,9 @@ index 0000000..df50164
+}
+
+// Remove the size_overflow asm stmt and create an assignment from the input and output of the asm
-+static void replace_size_overflow_asm_with_assign(gimple asm_stmt, tree lhs, tree rhs)
++static void replace_size_overflow_asm_with_assign(gasm *asm_stmt, tree lhs, tree rhs)
+{
-+ gimple assign;
++ gassign *assign;
+ gimple_stmt_iterator gsi;
+
+ // already removed
@@ -121688,13 +125202,13 @@ index 0000000..df50164
+ if (!def_stmt || !gimple_assign_cast_p(def_stmt))
+ return false;
+
-+ def_stmt = get_def_stmt(gimple_assign_rhs1(def_stmt));
++ def_stmt = get_def_stmt(gimple_assign_rhs1(as_a_gassign(def_stmt)));
+ return def_stmt && gimple_code(def_stmt) == GIMPLE_ASM;
+}
+
-+static void walk_use_def_phi(struct pointer_set_t *visited, struct interesting_node *cur_node, tree result)
++static void walk_use_def_phi(gimple_set *visited, struct interesting_node *cur_node, tree result)
+{
-+ gimple phi = get_def_stmt(result);
++ gphi *phi = as_a_gphi(get_def_stmt(result));
+ unsigned int i, n = gimple_phi_num_args(phi);
+
+ pointer_set_insert(visited, phi);
@@ -121705,9 +125219,9 @@ index 0000000..df50164
+ }
+}
+
-+static void walk_use_def_binary(struct pointer_set_t *visited, struct interesting_node *cur_node, tree lhs)
++static void walk_use_def_binary(gimple_set *visited, struct interesting_node *cur_node, tree lhs)
+{
-+ gimple def_stmt = get_def_stmt(lhs);
++ gassign *def_stmt = as_a_gassign(get_def_stmt(lhs));
+ tree rhs1, rhs2;
+
+ rhs1 = gimple_assign_rhs1(def_stmt);
@@ -121756,16 +125270,16 @@ index 0000000..df50164
+}
+
+// a size_overflow asm stmt in the control flow doesn't stop the recursion
-+static void handle_asm_stmt(struct pointer_set_t *visited, struct interesting_node *cur_node, tree lhs, const_gimple stmt)
++static void handle_asm_stmt(gimple_set *visited, struct interesting_node *cur_node, tree lhs, const gasm *stmt)
+{
-+ if (!is_size_overflow_asm(stmt))
++ if (gimple_code(stmt) != GIMPLE_ASM || !is_size_overflow_asm(stmt))
+ walk_use_def(visited, cur_node, SSA_NAME_VAR(lhs));
+}
+
+/* collect the parm_decls and fndecls (for checking a missing size_overflow attribute (ret or arg) or intentional_overflow)
+ * and component refs (for checking the intentional_overflow attribute).
+ */
-+static void walk_use_def(struct pointer_set_t *visited, struct interesting_node *cur_node, tree lhs)
++static void walk_use_def(gimple_set *visited, struct interesting_node *cur_node, tree lhs)
+{
+ const_gimple def_stmt;
+
@@ -121785,9 +125299,9 @@ index 0000000..df50164
+ case GIMPLE_NOP:
+ return walk_use_def(visited, cur_node, SSA_NAME_VAR(lhs));
+ case GIMPLE_ASM:
-+ return handle_asm_stmt(visited, cur_node, lhs, def_stmt);
++ return handle_asm_stmt(visited, cur_node, lhs, as_a_const_gasm(def_stmt));
+ case GIMPLE_CALL: {
-+ tree fndecl = gimple_call_fndecl(def_stmt);
++ tree fndecl = gimple_call_fndecl(as_a_const_gcall(def_stmt));
+
+ if (fndecl == NULL_TREE)
+ return;
@@ -121799,7 +125313,7 @@ index 0000000..df50164
+ case GIMPLE_ASSIGN:
+ switch (gimple_num_ops(def_stmt)) {
+ case 2:
-+ return walk_use_def(visited, cur_node, gimple_assign_rhs1(def_stmt));
++ return walk_use_def(visited, cur_node, gimple_assign_rhs1(as_a_const_gassign(def_stmt)));
+ case 3:
+ return walk_use_def_binary(visited, cur_node, lhs);
+ }
@@ -121813,7 +125327,7 @@ index 0000000..df50164
+// Collect all the last nodes for checking the intentional_overflow and size_overflow attributes
+static void set_last_nodes(struct interesting_node *cur_node)
+{
-+ struct pointer_set_t *visited;
++ gimple_set *visited;
+
+ visited = pointer_set_create();
+ walk_use_def(visited, cur_node, cur_node->node);
@@ -121866,7 +125380,7 @@ index 0000000..df50164
+ gimple_stmt_iterator gsi = gsi_for_stmt(stmt);
+
+ assign = build_cast_stmt(visited, orig_type, new_node, CREATE_NEW_VAR, &gsi, BEFORE_STMT, false);
-+ return gimple_assign_lhs(assign);
++ return get_lhs(assign);
+}
+
+static void change_orig_node(struct visited *visited, struct interesting_node *cur_node, tree new_node)
@@ -121877,10 +125391,10 @@ index 0000000..df50164
+
+ switch (gimple_code(stmt)) {
+ case GIMPLE_RETURN:
-+ gimple_return_set_retval(stmt, cast_to_orig_type(visited, stmt, orig_node, new_node));
++ gimple_return_set_retval(as_a_greturn(stmt), cast_to_orig_type(visited, stmt, orig_node, new_node));
+ break;
+ case GIMPLE_CALL:
-+ gimple_call_set_arg(stmt, cur_node->num - 1, cast_to_orig_type(visited, stmt, orig_node, new_node));
++ gimple_call_set_arg(as_a_gcall(stmt), cur_node->num - 1, cast_to_orig_type(visited, stmt, orig_node, new_node));
+ break;
+ case GIMPLE_ASSIGN:
+ switch (cur_node->num) {
@@ -121899,7 +125413,7 @@ index 0000000..df50164
+ gcc_unreachable();
+ }
+
-+ set_rhs(stmt, cast_to_orig_type(visited, stmt, orig_node, new_node));
++ set_rhs(as_a_gassign(stmt), cast_to_orig_type(visited, stmt, orig_node, new_node));
+ break;
+ default:
+ debug_gimple_stmt(stmt);
@@ -121986,7 +125500,7 @@ index 0000000..df50164
+ intentional_attr_cur_fndecl: intentional_overflow attribute of the caller function
+ intentional_mark_from_gimple: the intentional overflow type of size_overflow asm stmt from gimple if it exists
+ */
-+static struct interesting_node *create_new_interesting_node(struct interesting_node *head, gimple first_stmt, tree node, unsigned int num, gimple asm_stmt)
++static struct interesting_node *create_new_interesting_node(struct interesting_node *head, gimple first_stmt, tree node, unsigned int num, gasm *asm_stmt)
+{
+ struct interesting_node *new_node;
+ tree fndecl;
@@ -122006,7 +125520,7 @@ index 0000000..df50164
+ return head;
+
+ if (is_gimple_call(first_stmt))
-+ fndecl = gimple_call_fndecl(first_stmt);
++ fndecl = gimple_call_fndecl(as_a_const_gcall(first_stmt));
+ else
+ fndecl = current_function_decl;
+
@@ -122042,7 +125556,7 @@ index 0000000..df50164
+/* Check the ret stmts in the functions on the next cgraph node list (these functions will be in the hash table and they are reachable from ipa).
+ * If the ret stmt is in the next cgraph node list then it's an interesting ret.
+ */
-+static struct interesting_node *handle_stmt_by_cgraph_nodes_ret(struct interesting_node *head, gimple stmt, struct next_cgraph_node *next_node)
++static struct interesting_node *handle_stmt_by_cgraph_nodes_ret(struct interesting_node *head, greturn *stmt, struct next_cgraph_node *next_node)
+{
+ struct next_cgraph_node *cur_node;
+ tree ret = gimple_return_retval(stmt);
@@ -122063,7 +125577,7 @@ index 0000000..df50164
+/* Check the call stmts in the functions on the next cgraph node list (these functions will be in the hash table and they are reachable from ipa).
+ * If the call stmt is in the next cgraph node list then it's an interesting call.
+ */
-+static struct interesting_node *handle_stmt_by_cgraph_nodes_call(struct interesting_node *head, gimple stmt, struct next_cgraph_node *next_node)
++static struct interesting_node *handle_stmt_by_cgraph_nodes_call(struct interesting_node *head, gcall *stmt, struct next_cgraph_node *next_node)
+{
+ unsigned int argnum;
+ tree arg;
@@ -122099,7 +125613,7 @@ index 0000000..df50164
+}
+
+// Get the index of the rhs node in an assignment
-+static unsigned int get_assign_ops_count(const_gimple stmt, tree node)
++static unsigned int get_assign_ops_count(const gassign *stmt, tree node)
+{
+ const_tree rhs1, rhs2;
+ unsigned int ret;
@@ -122127,7 +125641,7 @@ index 0000000..df50164
+}
+
+// Find the correct arg number of a call stmt. It is needed when the interesting function is a cloned function.
-+static unsigned int find_arg_number_gimple(const_tree arg, const_gimple stmt)
++static unsigned int find_arg_number_gimple(const_tree arg, const gcall *stmt)
+{
+ unsigned int i;
+
@@ -122150,7 +125664,7 @@ index 0000000..df50164
+/* starting from the size_overflow asm stmt collect interesting stmts. They can be
+ * any of return, call or assignment stmts (because of inlining).
+ */
-+static struct interesting_node *get_interesting_ret_or_call(struct pointer_set_t *visited, struct interesting_node *head, tree node, gimple intentional_asm)
++static struct interesting_node *get_interesting_ret_or_call(tree_set *visited, struct interesting_node *head, tree node, gasm *intentional_asm)
+{
+ use_operand_p use_p;
+ imm_use_iterator imm_iter;
@@ -122171,28 +125685,31 @@ index 0000000..df50164
+
+ switch (gimple_code(stmt)) {
+ case GIMPLE_CALL:
-+ argnum = find_arg_number_gimple(node, stmt);
++ argnum = find_arg_number_gimple(node, as_a_gcall(stmt));
+ head = create_new_interesting_node(head, stmt, node, argnum, intentional_asm);
+ break;
+ case GIMPLE_RETURN:
+ head = create_new_interesting_node(head, stmt, node, 0, intentional_asm);
+ break;
+ case GIMPLE_ASSIGN:
-+ argnum = get_assign_ops_count(stmt, node);
++ argnum = get_assign_ops_count(as_a_const_gassign(stmt), node);
+ head = create_new_interesting_node(head, stmt, node, argnum, intentional_asm);
+ break;
+ case GIMPLE_PHI: {
-+ tree result = gimple_phi_result(stmt);
++ tree result = gimple_phi_result(as_a_gphi(stmt));
+ head = get_interesting_ret_or_call(visited, head, result, intentional_asm);
+ break;
+ }
-+ case GIMPLE_ASM:
-+ if (gimple_asm_noutputs(stmt) != 0)
++ case GIMPLE_ASM: {
++ gasm *asm_stmt = as_a_gasm(stmt);
++
++ if (gimple_asm_noutputs(asm_stmt) != 0)
+ break;
-+ if (!is_size_overflow_asm(stmt))
++ if (!is_size_overflow_asm(asm_stmt))
+ break;
-+ head = create_new_interesting_node(head, stmt, node, 1, intentional_asm);
++ head = create_new_interesting_node(head, asm_stmt, node, 1, intentional_asm);
+ break;
++ }
+ case GIMPLE_COND:
+ case GIMPLE_SWITCH:
+ break;
@@ -122207,66 +125724,71 @@ index 0000000..df50164
+
+static void remove_size_overflow_asm(gimple stmt)
+{
++ gasm *asm_stmt;
+ gimple_stmt_iterator gsi;
+ tree input, output;
+
-+ if (!is_size_overflow_asm(stmt))
++ if (gimple_code(stmt) != GIMPLE_ASM)
+ return;
+
-+ if (gimple_asm_noutputs(stmt) == 0) {
-+ gsi = gsi_for_stmt(stmt);
-+ ipa_remove_stmt_references(cgraph_get_create_node(current_function_decl), stmt);
++ asm_stmt = as_a_gasm(stmt);
++ if (!is_size_overflow_asm(asm_stmt))
++ return;
++
++ if (gimple_asm_noutputs(asm_stmt) == 0) {
++ gsi = gsi_for_stmt(asm_stmt);
++ ipa_remove_stmt_references(cgraph_get_create_node(current_function_decl), asm_stmt);
+ gsi_remove(&gsi, true);
+ return;
+ }
+
-+ input = gimple_asm_input_op(stmt, 0);
-+ output = gimple_asm_output_op(stmt, 0);
-+ replace_size_overflow_asm_with_assign(stmt, TREE_VALUE(output), TREE_VALUE(input));
++ input = gimple_asm_input_op(asm_stmt, 0);
++ output = gimple_asm_output_op(asm_stmt, 0);
++ replace_size_overflow_asm_with_assign(asm_stmt, TREE_VALUE(output), TREE_VALUE(input));
+}
+
+/* handle the size_overflow asm stmts from the gimple pass and collect the interesting stmts.
+ * If the asm stmt is a parm_decl kind (noutputs == 0) then remove it.
+ * If it is a simple asm stmt then replace it with an assignment from the asm input to the asm output.
+ */
-+static struct interesting_node *handle_stmt_by_size_overflow_asm(gimple stmt, struct interesting_node *head)
++static struct interesting_node *handle_stmt_by_size_overflow_asm(gasm *asm_stmt, struct interesting_node *head)
+{
+ const_tree output;
-+ struct pointer_set_t *visited;
-+ gimple intentional_asm = NOT_INTENTIONAL_ASM;
++ tree_set *visited;
++ gasm *intentional_asm = NOT_INTENTIONAL_ASM;
+
-+ if (!is_size_overflow_asm(stmt))
++ if (!is_size_overflow_asm(asm_stmt))
+ return head;
+
-+ if (is_size_overflow_intentional_asm_yes(stmt) || is_size_overflow_intentional_asm_turn_off(stmt))
-+ intentional_asm = stmt;
++ if (is_size_overflow_intentional_asm_yes(asm_stmt) || is_size_overflow_intentional_asm_turn_off(asm_stmt))
++ intentional_asm = asm_stmt;
+
-+ gcc_assert(gimple_asm_ninputs(stmt) == 1);
++ gcc_assert(gimple_asm_ninputs(asm_stmt) == 1);
+
-+ if (gimple_asm_noutputs(stmt) == 0 && is_size_overflow_intentional_asm_turn_off(stmt))
++ if (gimple_asm_noutputs(asm_stmt) == 0 && is_size_overflow_intentional_asm_turn_off(asm_stmt))
+ return head;
+
-+ if (gimple_asm_noutputs(stmt) == 0) {
++ if (gimple_asm_noutputs(asm_stmt) == 0) {
+ const_tree input;
+
-+ if (!is_size_overflow_intentional_asm_turn_off(stmt))
++ if (!is_size_overflow_intentional_asm_turn_off(asm_stmt))
+ return head;
+
-+ input = gimple_asm_input_op(stmt, 0);
-+ remove_size_overflow_asm(stmt);
++ input = gimple_asm_input_op(asm_stmt, 0);
++ remove_size_overflow_asm(asm_stmt);
+ if (is_gimple_constant(TREE_VALUE(input)))
+ return head;
-+ visited = pointer_set_create();
++ visited = tree_pointer_set_create();
+ head = get_interesting_ret_or_call(visited, head, TREE_VALUE(input), intentional_asm);
+ pointer_set_destroy(visited);
+ return head;
+ }
+
-+ if (!is_size_overflow_intentional_asm_yes(stmt) && !is_size_overflow_intentional_asm_turn_off(stmt))
-+ remove_size_overflow_asm(stmt);
++ if (!is_size_overflow_intentional_asm_yes(asm_stmt) && !is_size_overflow_intentional_asm_turn_off(asm_stmt))
++ remove_size_overflow_asm(asm_stmt);
+
-+ visited = pointer_set_create();
-+ output = gimple_asm_output_op(stmt, 0);
++ visited = tree_pointer_set_create();
++ output = gimple_asm_output_op(asm_stmt, 0);
+ head = get_interesting_ret_or_call(visited, head, TREE_VALUE(output), intentional_asm);
+ pointer_set_destroy(visited);
+ return head;
@@ -122290,14 +125812,14 @@ index 0000000..df50164
+ code = gimple_code(stmt);
+
+ if (code == GIMPLE_ASM)
-+ head = handle_stmt_by_size_overflow_asm(stmt, head);
++ head = handle_stmt_by_size_overflow_asm(as_a_gasm(stmt), head);
+
+ if (!next_node)
+ continue;
+ if (code == GIMPLE_CALL)
-+ head = handle_stmt_by_cgraph_nodes_call(head, stmt, next_node);
++ head = handle_stmt_by_cgraph_nodes_call(head, as_a_gcall(stmt), next_node);
+ if (code == GIMPLE_RETURN)
-+ head = handle_stmt_by_cgraph_nodes_ret(head, stmt, next_node);
++ head = handle_stmt_by_cgraph_nodes_ret(head, as_a_greturn(stmt), next_node);
+ }
+ }
+ return head;
@@ -122434,7 +125956,6 @@ index 0000000..df50164
+ struct visited_fns *visited_fns = NULL;
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(node) {
-+ gcc_assert(cgraph_function_flags_ready);
+#if BUILDING_GCC_VERSION <= 4007
+ gcc_assert(node->reachable);
+#endif
@@ -122447,6 +125968,7 @@ index 0000000..df50164
+}
+
+#if BUILDING_GCC_VERSION >= 4009
++namespace {
+static const struct pass_data insert_size_overflow_check_data = {
+#else
+static struct ipa_opt_pass_d insert_size_overflow_check = {
@@ -122457,7 +125979,8 @@ index 0000000..df50164
+#if BUILDING_GCC_VERSION >= 4008
+ .optinfo_flags = OPTGROUP_NONE,
+#endif
-+#if BUILDING_GCC_VERSION >= 4009
++#if BUILDING_GCC_VERSION >= 5000
++#elif BUILDING_GCC_VERSION == 4009
+ .has_gate = false,
+ .has_execute = true,
+#else
@@ -122490,36 +126013,40 @@ index 0000000..df50164
+};
+
+#if BUILDING_GCC_VERSION >= 4009
-+namespace {
+class insert_size_overflow_check : public ipa_opt_pass_d {
+public:
+ insert_size_overflow_check() : ipa_opt_pass_d(insert_size_overflow_check_data, g, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL) {}
++#if BUILDING_GCC_VERSION >= 5000
++ virtual unsigned int execute(function *) { return search_function(); }
++#else
+ unsigned int execute() { return search_function(); }
++#endif
+};
+}
-+#endif
+
-+struct opt_pass *make_insert_size_overflow_check(void)
++opt_pass *make_insert_size_overflow_check(void)
+{
-+#if BUILDING_GCC_VERSION >= 4009
+ return new insert_size_overflow_check();
++}
+#else
++struct opt_pass *make_insert_size_overflow_check(void)
++{
+ return &insert_size_overflow_check.pass;
-+#endif
+}
-+
++#endif
diff --git a/tools/gcc/size_overflow_plugin/intentional_overflow.c b/tools/gcc/size_overflow_plugin/intentional_overflow.c
new file mode 100644
-index 0000000..d71d72a
+index 0000000..eb62680
--- /dev/null
+++ b/tools/gcc/size_overflow_plugin/intentional_overflow.c
-@@ -0,0 +1,736 @@
+@@ -0,0 +1,748 @@
+/*
-+ * Copyright 2011-2014 by Emese Revfy <re.emese@gmail.com>
++ * Copyright 2011-2015 by Emese Revfy <re.emese@gmail.com>
+ * Licensed under the GPL v2, or (at your option) v3
+ *
+ * Homepage:
+ * http://www.grsecurity.net/~ephox/overflow_plugin/
++ * https://github.com/ephox-gcc-plugins
+ *
+ * Documentation:
+ * http://forums.grsecurity.net/viewtopic.php?f=7&t=3043
@@ -122564,7 +126091,7 @@ index 0000000..d71d72a
+ if (param_head == NULL_TREE)
+ return false;
+
-+ if (TREE_INT_CST_HIGH(TREE_VALUE(param_head)) == -1)
++ if (tree_to_shwi(TREE_VALUE(param_head)) == -1)
+ return true;
+ return false;
+}
@@ -122756,13 +126283,15 @@ index 0000000..d71d72a
+{
+ const_tree rhs1, lhs, rhs1_type, lhs_type;
+ enum machine_mode lhs_mode, rhs_mode;
++ const gassign *assign;
+ gimple def_stmt = get_def_stmt(no_const_rhs);
+
+ if (!def_stmt || !gimple_assign_cast_p(def_stmt))
+ return false;
+
-+ rhs1 = gimple_assign_rhs1(def_stmt);
-+ lhs = gimple_assign_lhs(def_stmt);
++ assign = as_a_const_gassign(def_stmt);
++ rhs1 = gimple_assign_rhs1(assign);
++ lhs = gimple_assign_lhs(assign);
+ rhs1_type = TREE_TYPE(rhs1);
+ lhs_type = TREE_TYPE(lhs);
+ rhs_mode = TYPE_MODE(rhs1_type);
@@ -122786,7 +126315,7 @@ index 0000000..d71d72a
+ return num;
+ if (is_gimple_debug(use_stmt))
+ continue;
-+ if (gimple_assign_cast_p(use_stmt) && is_size_overflow_type(gimple_assign_lhs(use_stmt)))
++ if (gimple_assign_cast_p(use_stmt) && is_size_overflow_type(gimple_assign_lhs(as_a_const_gassign(use_stmt))))
+ continue;
+ num++;
+ }
@@ -122802,12 +126331,14 @@ index 0000000..d71d72a
+bool is_const_plus_unsigned_signed_truncation(const_tree lhs)
+{
+ tree rhs1, lhs_type, rhs_type, rhs2, not_const_rhs;
++ gassign *assign;
+ gimple def_stmt = get_def_stmt(lhs);
+
+ if (!def_stmt || !gimple_assign_cast_p(def_stmt))
+ return false;
+
-+ rhs1 = gimple_assign_rhs1(def_stmt);
++ assign = as_a_gassign(def_stmt);
++ rhs1 = gimple_assign_rhs1(assign);
+ rhs_type = TREE_TYPE(rhs1);
+ lhs_type = TREE_TYPE(lhs);
+ if (TYPE_UNSIGNED(lhs_type) || !TYPE_UNSIGNED(rhs_type))
@@ -122819,11 +126350,12 @@ index 0000000..d71d72a
+ if (!def_stmt || !is_gimple_assign(def_stmt) || gimple_num_ops(def_stmt) != 3)
+ return false;
+
-+ if (gimple_assign_rhs_code(def_stmt) != PLUS_EXPR)
++ assign = as_a_gassign(def_stmt);
++ if (gimple_assign_rhs_code(assign) != PLUS_EXPR)
+ return false;
+
-+ rhs1 = gimple_assign_rhs1(def_stmt);
-+ rhs2 = gimple_assign_rhs2(def_stmt);
++ rhs1 = gimple_assign_rhs1(assign);
++ rhs2 = gimple_assign_rhs2(assign);
+ if (!is_gimple_constant(rhs1) && !is_gimple_constant(rhs2))
+ return false;
+
@@ -122880,7 +126412,7 @@ index 0000000..d71d72a
+ return false;
+}
+
-+bool is_a_constant_overflow(const_gimple stmt, const_tree rhs)
++bool is_a_constant_overflow(const gassign *stmt, const_tree rhs)
+{
+ if (gimple_assign_rhs_code(stmt) == MIN_EXPR)
+ return false;
@@ -122894,7 +126426,7 @@ index 0000000..d71d72a
+ return true;
+}
+
-+static tree change_assign_rhs(struct visited *visited, gimple stmt, const_tree orig_rhs, tree new_rhs)
++static tree change_assign_rhs(struct visited *visited, gassign *stmt, const_tree orig_rhs, tree new_rhs)
+{
+ gimple assign;
+ gimple_stmt_iterator gsi = gsi_for_stmt(stmt);
@@ -122904,10 +126436,10 @@ index 0000000..d71d72a
+
+ assign = build_cast_stmt(visited, origtype, new_rhs, CREATE_NEW_VAR, &gsi, BEFORE_STMT, false);
+ pointer_set_insert(visited->my_stmts, assign);
-+ return gimple_assign_lhs(assign);
++ return get_lhs(assign);
+}
+
-+tree handle_intentional_overflow(struct visited *visited, struct cgraph_node *caller_node, bool check_overflow, gimple stmt, tree change_rhs, tree new_rhs2)
++tree handle_intentional_overflow(struct visited *visited, struct cgraph_node *caller_node, bool check_overflow, gassign *stmt, tree change_rhs, tree new_rhs2)
+{
+ tree new_rhs, orig_rhs;
+ void (*gimple_assign_set_rhs)(gimple, tree);
@@ -122938,9 +126470,10 @@ index 0000000..d71d72a
+ return create_assign(visited, stmt, lhs, AFTER_STMT);
+}
+
-+static bool is_subtraction_special(struct visited *visited, const_gimple stmt)
++static bool is_subtraction_special(struct visited *visited, const gassign *stmt)
+{
-+ gimple rhs1_def_stmt, rhs2_def_stmt;
++ gimple def_stmt_1, def_stmt_2;
++ const gassign *rhs1_def_stmt, *rhs2_def_stmt;
+ const_tree rhs1_def_stmt_rhs1, rhs2_def_stmt_rhs1, rhs1_def_stmt_lhs, rhs2_def_stmt_lhs;
+ enum machine_mode rhs1_def_stmt_rhs1_mode, rhs2_def_stmt_rhs1_mode, rhs1_def_stmt_lhs_mode, rhs2_def_stmt_lhs_mode;
+ const_tree rhs1 = gimple_assign_rhs1(stmt);
@@ -122954,15 +126487,18 @@ index 0000000..d71d72a
+ if (gimple_assign_rhs_code(stmt) != MINUS_EXPR)
+ return false;
+
-+ rhs1_def_stmt = get_def_stmt(rhs1);
-+ rhs2_def_stmt = get_def_stmt(rhs2);
-+ if (!gimple_assign_cast_p(rhs1_def_stmt) || !gimple_assign_cast_p(rhs2_def_stmt))
++ def_stmt_1 = get_def_stmt(rhs1);
++ def_stmt_2 = get_def_stmt(rhs2);
++ if (!gimple_assign_cast_p(def_stmt_1) || !gimple_assign_cast_p(def_stmt_2))
+ return false;
+
++ rhs1_def_stmt = as_a_const_gassign(def_stmt_1);
++ rhs2_def_stmt = as_a_const_gassign(def_stmt_2);
+ rhs1_def_stmt_rhs1 = gimple_assign_rhs1(rhs1_def_stmt);
+ rhs2_def_stmt_rhs1 = gimple_assign_rhs1(rhs2_def_stmt);
+ rhs1_def_stmt_lhs = gimple_assign_lhs(rhs1_def_stmt);
+ rhs2_def_stmt_lhs = gimple_assign_lhs(rhs2_def_stmt);
++
+ rhs1_def_stmt_rhs1_mode = TYPE_MODE(TREE_TYPE(rhs1_def_stmt_rhs1));
+ rhs2_def_stmt_rhs1_mode = TYPE_MODE(TREE_TYPE(rhs2_def_stmt_rhs1));
+ rhs1_def_stmt_lhs_mode = TYPE_MODE(TREE_TYPE(rhs1_def_stmt_lhs));
@@ -122977,15 +126513,15 @@ index 0000000..d71d72a
+ return true;
+}
+
-+static gimple create_binary_assign(struct visited *visited, enum tree_code code, gimple stmt, tree rhs1, tree rhs2)
++static gassign *create_binary_assign(struct visited *visited, enum tree_code code, gassign *stmt, tree rhs1, tree rhs2)
+{
-+ gimple assign;
++ gassign *assign;
+ gimple_stmt_iterator gsi = gsi_for_stmt(stmt);
+ tree type = TREE_TYPE(rhs1);
+ tree lhs = create_new_var(type);
+
+ gcc_assert(types_compatible_p(type, TREE_TYPE(rhs2)));
-+ assign = gimple_build_assign_with_ops(code, lhs, rhs1, rhs2);
++ assign = as_a_gassign(gimple_build_assign_with_ops(code, lhs, rhs1, rhs2));
+ gimple_assign_set_lhs(assign, make_ssa_name(lhs, assign));
+
+ gsi_insert_before(&gsi, assign, GSI_NEW_STMT);
@@ -123005,11 +126541,11 @@ index 0000000..d71d72a
+
+ gsi = gsi_for_stmt(stmt);
+ cast_stmt = build_cast_stmt(visited, intTI_type_node, node, CREATE_NEW_VAR, &gsi, BEFORE_STMT, false);
-+ pointer_set_insert(visited->my_stmts, cast_stmt);
-+ return gimple_assign_lhs(cast_stmt);
++ pointer_set_insert(visited->my_stmts, (gimple)cast_stmt);
++ return get_lhs(cast_stmt);
+}
+
-+static tree get_def_stmt_rhs(struct visited *visited, const_tree var)
++static tree get_def_stmt_rhs(const_tree var)
+{
+ tree rhs1, def_stmt_rhs1;
+ gimple rhs1_def_stmt, def_stmt_rhs1_def_stmt, def_stmt;
@@ -123017,14 +126553,13 @@ index 0000000..d71d72a
+ def_stmt = get_def_stmt(var);
+ if (!gimple_assign_cast_p(def_stmt))
+ return NULL_TREE;
-+ gcc_assert(gimple_code(def_stmt) != GIMPLE_NOP && pointer_set_contains(visited->my_stmts, def_stmt) && gimple_assign_cast_p(def_stmt));
+
-+ rhs1 = gimple_assign_rhs1(def_stmt);
++ rhs1 = gimple_assign_rhs1(as_a_const_gassign(def_stmt));
+ rhs1_def_stmt = get_def_stmt(rhs1);
+ if (!gimple_assign_cast_p(rhs1_def_stmt))
+ return rhs1;
+
-+ def_stmt_rhs1 = gimple_assign_rhs1(rhs1_def_stmt);
++ def_stmt_rhs1 = gimple_assign_rhs1(as_a_const_gassign(rhs1_def_stmt));
+ def_stmt_rhs1_def_stmt = get_def_stmt(def_stmt_rhs1);
+
+ switch (gimple_code(def_stmt_rhs1_def_stmt)) {
@@ -123045,7 +126580,7 @@ index 0000000..d71d72a
+{
+ tree new_rhs1, new_rhs2;
+ tree new_rhs1_def_stmt_rhs1, new_rhs2_def_stmt_rhs1, new_lhs;
-+ gimple assign, stmt = get_def_stmt(lhs);
++ gassign *assign, *stmt = as_a_gassign(get_def_stmt(lhs));
+ tree rhs1 = gimple_assign_rhs1(stmt);
+ tree rhs2 = gimple_assign_rhs2(stmt);
+
@@ -123055,8 +126590,8 @@ index 0000000..d71d72a
+ new_rhs1 = expand(visited, caller_node, rhs1);
+ new_rhs2 = expand(visited, caller_node, rhs2);
+
-+ new_rhs1_def_stmt_rhs1 = get_def_stmt_rhs(visited, new_rhs1);
-+ new_rhs2_def_stmt_rhs1 = get_def_stmt_rhs(visited, new_rhs2);
++ new_rhs1_def_stmt_rhs1 = get_def_stmt_rhs(new_rhs1);
++ new_rhs2_def_stmt_rhs1 = get_def_stmt_rhs(new_rhs2);
+
+ if (new_rhs1_def_stmt_rhs1 == NULL_TREE || new_rhs2_def_stmt_rhs1 == NULL_TREE)
+ return NULL_TREE;
@@ -123099,6 +126634,7 @@ index 0000000..d71d72a
+ const_tree res;
+ tree rhs1, rhs2, def_rhs1, def_rhs2, const_rhs, def_const_rhs;
+ const_gimple def_stmt;
++ const gassign *assign, *def_assign;
+
+ if (!stmt || gimple_code(stmt) == GIMPLE_NOP)
+ return false;
@@ -123107,8 +126643,9 @@ index 0000000..d71d72a
+ if (gimple_assign_rhs_code(stmt) != MULT_EXPR)
+ return false;
+
-+ rhs1 = gimple_assign_rhs1(stmt);
-+ rhs2 = gimple_assign_rhs2(stmt);
++ assign = as_a_const_gassign(stmt);
++ rhs1 = gimple_assign_rhs1(assign);
++ rhs2 = gimple_assign_rhs2(assign);
+ if (is_gimple_constant(rhs1)) {
+ const_rhs = rhs1;
+ def_stmt = get_def_stmt(rhs2);
@@ -123124,8 +126661,9 @@ index 0000000..d71d72a
+ if (gimple_assign_rhs_code(def_stmt) != PLUS_EXPR && gimple_assign_rhs_code(def_stmt) != MINUS_EXPR)
+ return false;
+
-+ def_rhs1 = gimple_assign_rhs1(def_stmt);
-+ def_rhs2 = gimple_assign_rhs2(def_stmt);
++ def_assign = as_a_const_gassign(def_stmt);
++ def_rhs1 = gimple_assign_rhs1(def_assign);
++ def_rhs2 = gimple_assign_rhs2(def_assign);
+ if (is_gimple_constant(def_rhs1))
+ def_const_rhs = def_rhs1;
+ else if (is_gimple_constant(def_rhs2))
@@ -123133,13 +126671,13 @@ index 0000000..d71d72a
+ else
+ return false;
+
-+ res = fold_binary_loc(gimple_location(def_stmt), MULT_EXPR, TREE_TYPE(const_rhs), const_rhs, def_const_rhs);
++ res = fold_binary_loc(gimple_location(def_assign), MULT_EXPR, TREE_TYPE(const_rhs), const_rhs, def_const_rhs);
+ if (is_lt_signed_type_max(res) && is_gt_zero(res))
+ return false;
+ return true;
+}
+
-+enum intentional_overflow_type add_mul_intentional_overflow(const_gimple stmt)
++enum intentional_overflow_type add_mul_intentional_overflow(const gassign *stmt)
+{
+ const_gimple def_stmt_1, def_stmt_2;
+ const_tree rhs1, rhs2;
@@ -123205,17 +126743,17 @@ index 0000000..d71d72a
+
+ if (!is_gimple_assign(def_stmt) || gimple_num_ops(def_stmt) != 2)
+ return false;
-+ rhs = gimple_assign_rhs1(def_stmt);
++ rhs = gimple_assign_rhs1(as_a_const_gassign(def_stmt));
+ def_stmt = get_def_stmt(rhs);
+ if (!def_stmt)
+ return false;
+ return is_call_or_cast(def_stmt);
+}
+
-+void unsigned_signed_cast_intentional_overflow(struct visited *visited, gimple stmt)
++void unsigned_signed_cast_intentional_overflow(struct visited *visited, gassign *stmt)
+{
+ unsigned int use_num;
-+ gimple so_stmt;
++ gassign *so_stmt;
+ const_gimple def_stmt;
+ const_tree rhs1, rhs2;
+ tree rhs = gimple_assign_rhs1(stmt);
@@ -123236,31 +126774,32 @@ index 0000000..d71d72a
+ if (!is_gimple_assign(def_stmt))
+ return;
+
-+ rhs1 = gimple_assign_rhs1(def_stmt);
++ rhs1 = gimple_assign_rhs1(as_a_const_gassign(def_stmt));
+ if (!is_unsigned_cast_or_call_def_stmt(rhs1))
+ return;
+
-+ rhs2 = gimple_assign_rhs2(def_stmt);
++ rhs2 = gimple_assign_rhs2(as_a_const_gassign(def_stmt));
+ if (!is_unsigned_cast_or_call_def_stmt(rhs2))
+ return;
+ if (gimple_num_ops(def_stmt) == 3 && !is_gimple_constant(rhs1) && !is_gimple_constant(rhs2))
+ return;
+
-+ so_stmt = get_dup_stmt(visited, stmt);
++ so_stmt = as_a_gassign(get_dup_stmt(visited, stmt));
+ create_up_and_down_cast(visited, so_stmt, lhs_type, gimple_assign_rhs1(so_stmt));
+}
+
diff --git a/tools/gcc/size_overflow_plugin/misc.c b/tools/gcc/size_overflow_plugin/misc.c
new file mode 100644
-index 0000000..4bddad2
+index 0000000..253b4a8b
--- /dev/null
+++ b/tools/gcc/size_overflow_plugin/misc.c
-@@ -0,0 +1,203 @@
+@@ -0,0 +1,219 @@
+/*
-+ * Copyright 2011-2014 by Emese Revfy <re.emese@gmail.com>
++ * Copyright 2011-2015 by Emese Revfy <re.emese@gmail.com>
+ * Licensed under the GPL v2, or (at your option) v3
+ *
+ * Homepage:
++ * https://github.com/ephox-gcc-plugins
+ * http://www.grsecurity.net/~ephox/overflow_plugin/
+ *
+ * Documentation:
@@ -123294,6 +126833,20 @@ index 0000000..4bddad2
+ current_function_decl = NULL_TREE;
+}
+
++tree get_lhs(const_gimple stmt)
++{
++ switch (gimple_code(stmt)) {
++ case GIMPLE_ASSIGN:
++ case GIMPLE_CALL:
++ return gimple_get_lhs(as_a_const_gassign(stmt));
++ case GIMPLE_PHI:
++ return gimple_phi_result(as_a_const_gphi(stmt));
++ default:
++ debug_gimple_stmt((gimple)stmt);
++ gcc_unreachable();
++ }
++}
++
+static bool is_bool(const_tree node)
+{
+ const_tree type;
@@ -123405,7 +126958,8 @@ index 0000000..4bddad2
+
+gimple build_cast_stmt(struct visited *visited, tree dst_type, tree rhs, tree lhs, gimple_stmt_iterator *gsi, bool before, bool force)
+{
-+ gimple assign, def_stmt;
++ gimple def_stmt;
++ gassign *assign;
+
+ gcc_assert(dst_type != NULL_TREE && rhs != NULL_TREE);
+ gcc_assert(!is_gimple_constant(rhs));
@@ -123461,15 +127015,16 @@ index 0000000..4bddad2
+
diff --git a/tools/gcc/size_overflow_plugin/remove_unnecessary_dup.c b/tools/gcc/size_overflow_plugin/remove_unnecessary_dup.c
new file mode 100644
-index 0000000..7c9e6d1
+index 0000000..de5999d
--- /dev/null
+++ b/tools/gcc/size_overflow_plugin/remove_unnecessary_dup.c
-@@ -0,0 +1,138 @@
+@@ -0,0 +1,139 @@
+/*
-+ * Copyright 2011-2014 by Emese Revfy <re.emese@gmail.com>
++ * Copyright 2011-2015 by Emese Revfy <re.emese@gmail.com>
+ * Licensed under the GPL v2, or (at your option) v3
+ *
+ * Homepage:
++ * https://github.com/ephox-gcc-plugins
+ * http://www.grsecurity.net/~ephox/overflow_plugin/
+ *
+ * Documentation:
@@ -123487,7 +127042,7 @@ index 0000000..7c9e6d1
+#include "gcc-common.h"
+#include "size_overflow.h"
+
-+bool skip_expr_on_double_type(const_gimple stmt)
++bool skip_expr_on_double_type(const gassign *stmt)
+{
+ enum tree_code code = gimple_assign_rhs_code(stmt);
+
@@ -123509,19 +127064,19 @@ index 0000000..7c9e6d1
+ }
+}
+
-+void create_up_and_down_cast(struct visited *visited, gimple use_stmt, tree orig_type, tree rhs)
++void create_up_and_down_cast(struct visited *visited, gassign *use_stmt, tree orig_type, tree rhs)
+{
+ const_tree orig_rhs1;
+ tree down_lhs, new_lhs, dup_type = TREE_TYPE(rhs);
-+ gimple down_cast, up_cast;
++ const_gimple down_cast, up_cast;
+ gimple_stmt_iterator gsi = gsi_for_stmt(use_stmt);
+
+ down_cast = build_cast_stmt(visited, orig_type, rhs, CREATE_NEW_VAR, &gsi, BEFORE_STMT, false);
-+ down_lhs = gimple_assign_lhs(down_cast);
++ down_lhs = get_lhs(down_cast);
+
+ gsi = gsi_for_stmt(use_stmt);
+ up_cast = build_cast_stmt(visited, dup_type, down_lhs, CREATE_NEW_VAR, &gsi, BEFORE_STMT, false);
-+ new_lhs = gimple_assign_lhs(up_cast);
++ new_lhs = get_lhs(up_cast);
+
+ orig_rhs1 = gimple_assign_rhs1(use_stmt);
+ if (operand_equal_p(orig_rhs1, rhs, 0))
@@ -123565,7 +127120,7 @@ index 0000000..7c9e6d1
+ return new_type;
+}
+
-+static void insert_cast_rhs(struct visited *visited, gimple stmt, tree rhs)
++static void insert_cast_rhs(struct visited *visited, gassign *stmt, tree rhs)
+{
+ tree type;
+
@@ -123580,7 +127135,7 @@ index 0000000..7c9e6d1
+ create_up_and_down_cast(visited, stmt, type, rhs);
+}
+
-+static void insert_cast(struct visited *visited, gimple stmt, tree rhs)
++static void insert_cast(struct visited *visited, gassign *stmt, tree rhs)
+{
+ if (LONG_TYPE_SIZE == GET_MODE_BITSIZE(SImode) && !is_size_overflow_type(rhs))
+ return;
@@ -123588,7 +127143,7 @@ index 0000000..7c9e6d1
+ insert_cast_rhs(visited, stmt, rhs);
+}
+
-+void insert_cast_expr(struct visited *visited, gimple stmt, enum intentional_overflow_type type)
++void insert_cast_expr(struct visited *visited, gassign *stmt, enum intentional_overflow_type type)
+{
+ tree rhs1, rhs2;
+
@@ -123605,10 +127160,10 @@ index 0000000..7c9e6d1
+
diff --git a/tools/gcc/size_overflow_plugin/size_overflow.h b/tools/gcc/size_overflow_plugin/size_overflow.h
new file mode 100644
-index 0000000..37f8fc3
+index 0000000..20732b1
--- /dev/null
+++ b/tools/gcc/size_overflow_plugin/size_overflow.h
-@@ -0,0 +1,127 @@
+@@ -0,0 +1,183 @@
+#ifndef SIZE_OVERFLOW_H
+#define SIZE_OVERFLOW_H
+
@@ -123630,11 +127185,66 @@ index 0000000..37f8fc3
+ NO_INTENTIONAL_OVERFLOW, RHS1_INTENTIONAL_OVERFLOW, RHS2_INTENTIONAL_OVERFLOW
+};
+
++
++#if BUILDING_GCC_VERSION >= 5000
++typedef struct hash_set<const_gimple> gimple_set;
++
++static inline bool pointer_set_insert(gimple_set *visited, const_gimple stmt)
++{
++ return visited->add(stmt);
++}
++
++static inline bool pointer_set_contains(gimple_set *visited, const_gimple stmt)
++{
++ return visited->contains(stmt);
++}
++
++static inline gimple_set* pointer_set_create(void)
++{
++ return new hash_set<const_gimple>;
++}
++
++static inline void pointer_set_destroy(gimple_set *visited)
++{
++ delete visited;
++}
++
++typedef struct hash_set<tree> tree_set;
++
++static inline bool pointer_set_insert(tree_set *visited, tree node)
++{
++ return visited->add(node);
++}
++
++static inline bool pointer_set_contains(tree_set *visited, tree node)
++{
++ return visited->contains(node);
++}
++
++static inline tree_set *tree_pointer_set_create(void)
++{
++ return new hash_set<tree>;
++}
++
++static inline void pointer_set_destroy(tree_set *visited)
++{
++ delete visited;
++}
++#else
++typedef struct pointer_set_t gimple_set;
++typedef struct pointer_set_t tree_set;
++
++static inline tree_set *tree_pointer_set_create(void)
++{
++ return pointer_set_create();
++}
++#endif
++
+struct visited {
-+ struct pointer_set_t *stmts;
-+ struct pointer_set_t *my_stmts;
-+ struct pointer_set_t *skip_expr_casts;
-+ struct pointer_set_t *no_cast_check;
++ gimple_set *stmts;
++ gimple_set *my_stmts;
++ gimple_set *skip_expr_casts;
++ gimple_set *no_cast_check;
+};
+
+// size_overflow_plugin.c
@@ -123665,10 +127275,10 @@ index 0000000..37f8fc3
+ unsigned int num;
+ enum mark intentional_attr_decl;
+ enum mark intentional_attr_cur_fndecl;
-+ gimple intentional_mark_from_gimple;
++ gasm *intentional_mark_from_gimple;
+};
+
-+extern bool is_size_overflow_asm(const_gimple stmt);
++extern bool is_size_overflow_asm(const gasm *stmt);
+extern unsigned int get_function_num(const_tree node, const_tree orig_fndecl);
+extern unsigned int get_correct_arg_count(unsigned int argnum, const_tree fndecl);
+extern bool is_missing_function(const_tree orig_fndecl, unsigned int num);
@@ -123683,8 +127293,8 @@ index 0000000..37f8fc3
+
+// intentional_overflow.c
+extern enum mark get_intentional_attr_type(const_tree node);
-+extern bool is_size_overflow_intentional_asm_yes(const_gimple stmt);
-+extern bool is_size_overflow_intentional_asm_turn_off(const_gimple stmt);
++extern bool is_size_overflow_intentional_asm_yes(const gasm *stmt);
++extern bool is_size_overflow_intentional_asm_turn_off(const gasm *stmt);
+extern bool is_end_intentional_intentional_attr(const_tree decl, unsigned int argnum);
+extern bool is_yes_intentional_attr(const_tree decl, unsigned int argnum);
+extern bool is_turn_off_intentional_attr(const_tree decl);
@@ -123692,12 +127302,12 @@ index 0000000..37f8fc3
+extern void check_intentional_attribute_ipa(struct interesting_node *cur_node);
+extern bool is_a_cast_and_const_overflow(const_tree no_const_rhs);
+extern bool is_const_plus_unsigned_signed_truncation(const_tree lhs);
-+extern bool is_a_constant_overflow(const_gimple stmt, const_tree rhs);
-+extern tree handle_intentional_overflow(struct visited *visited, struct cgraph_node *caller_node, bool check_overflow, gimple stmt, tree change_rhs, tree new_rhs2);
++extern bool is_a_constant_overflow(const gassign *stmt, const_tree rhs);
++extern tree handle_intentional_overflow(struct visited *visited, struct cgraph_node *caller_node, bool check_overflow, gassign *stmt, tree change_rhs, tree new_rhs2);
+extern tree handle_integer_truncation(struct visited *visited, struct cgraph_node *caller_node, const_tree lhs);
+extern bool is_a_neg_overflow(const_gimple stmt, const_tree rhs);
-+extern enum intentional_overflow_type add_mul_intentional_overflow(const_gimple def_stmt);
-+extern void unsigned_signed_cast_intentional_overflow(struct visited *visited, gimple stmt);
++extern enum intentional_overflow_type add_mul_intentional_overflow(const gassign *def_stmt);
++extern void unsigned_signed_cast_intentional_overflow(struct visited *visited, gassign *stmt);
+
+
+// insert_size_overflow_check_ipa.c
@@ -123714,6 +127324,7 @@ index 0000000..37f8fc3
+// misc.c
+extern void set_current_function_decl(tree fndecl);
+extern void unset_current_function_decl(void);
++extern tree get_lhs(const_gimple stmt);
+extern gimple get_def_stmt(const_tree node);
+extern tree create_new_var(tree type);
+extern gimple build_cast_stmt(struct visited *visited, tree dst_type, tree rhs, tree lhs, gimple_stmt_iterator *gsi, bool before, bool force);
@@ -123725,28 +127336,29 @@ index 0000000..37f8fc3
+// insert_size_overflow_check_core.c
+extern tree expand(struct visited *visited, struct cgraph_node *caller_node, tree lhs);
+extern void check_size_overflow(struct cgraph_node *caller_node, gimple stmt, tree size_overflow_type, tree cast_rhs, tree rhs, bool before);
-+extern tree dup_assign(struct visited *visited, gimple oldstmt, const_tree node, tree rhs1, tree rhs2, tree __unused rhs3);
++extern tree dup_assign(struct visited *visited, gassign *oldstmt, const_tree node, tree rhs1, tree rhs2, tree __unused rhs3);
+extern tree create_assign(struct visited *visited, gimple oldstmt, tree rhs1, bool before);
+
+
+// remove_unnecessary_dup.c
+extern struct opt_pass *make_remove_unnecessary_dup_pass(void);
-+extern void insert_cast_expr(struct visited *visited, gimple stmt, enum intentional_overflow_type type);
-+extern bool skip_expr_on_double_type(const_gimple stmt);
-+extern void create_up_and_down_cast(struct visited *visited, gimple use_stmt, tree orig_type, tree rhs);
++extern void insert_cast_expr(struct visited *visited, gassign *stmt, enum intentional_overflow_type type);
++extern bool skip_expr_on_double_type(const gassign *stmt);
++extern void create_up_and_down_cast(struct visited *visited, gassign *use_stmt, tree orig_type, tree rhs);
+
+#endif
diff --git a/tools/gcc/size_overflow_plugin/size_overflow_debug.c b/tools/gcc/size_overflow_plugin/size_overflow_debug.c
new file mode 100644
-index 0000000..4378111
+index 0000000..176c32f
--- /dev/null
+++ b/tools/gcc/size_overflow_plugin/size_overflow_debug.c
-@@ -0,0 +1,116 @@
+@@ -0,0 +1,123 @@
+/*
-+ * Copyright 2011-2014 by Emese Revfy <re.emese@gmail.com>
++ * Copyright 2011-2015 by Emese Revfy <re.emese@gmail.com>
+ * Licensed under the GPL v2, or (at your option) v3
+ *
+ * Homepage:
++ * https://github.com/ephox-gcc-plugins
+ * http://www.grsecurity.net/~ephox/overflow_plugin/
+ *
+ * Documentation:
@@ -123763,7 +127375,7 @@ index 0000000..4378111
+
+#include "gcc-common.h"
+
-+static unsigned int dump_functions(void)
++static unsigned int __unused dump_functions(void)
+{
+ struct cgraph_node *node;
+
@@ -123798,6 +127410,7 @@ index 0000000..4378111
+}
+
+#if BUILDING_GCC_VERSION >= 4009
++namespace {
+static const struct pass_data dump_pass_data = {
+#else
+static struct ipa_opt_pass_d dump_pass = {
@@ -123808,7 +127421,8 @@ index 0000000..4378111
+#if BUILDING_GCC_VERSION >= 4008
+ .optinfo_flags = OPTGROUP_NONE,
+#endif
-+#if BUILDING_GCC_VERSION >= 4009
++#if BUILDING_GCC_VERSION >= 5000
++#elif BUILDING_GCC_VERSION == 4009
+ .has_gate = false,
+ .has_execute = true,
+#else
@@ -123841,23 +127455,27 @@ index 0000000..4378111
+};
+
+#if BUILDING_GCC_VERSION >= 4009
-+namespace {
+class dump_pass : public ipa_opt_pass_d {
+public:
+ dump_pass() : ipa_opt_pass_d(dump_pass_data, g, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL) {}
++#if BUILDING_GCC_VERSION >= 5000
++ virtual unsigned int execute(function *) { return dump_functions(); }
++#else
+ unsigned int execute() { return dump_functions(); }
++#endif
+};
+}
-+#endif
+
-+struct opt_pass *make_dump_pass(void)
++opt_pass *make_dump_pass(void)
+{
-+#if BUILDING_GCC_VERSION >= 4009
+ return new dump_pass();
++}
+#else
++struct opt_pass *make_dump_pass(void)
++{
+ return &dump_pass.pass;
-+#endif
+}
++#endif
diff --git a/tools/gcc/size_overflow_plugin/size_overflow_hash.data b/tools/gcc/size_overflow_plugin/size_overflow_hash.data
new file mode 100644
index 0000000..cd3c18f
@@ -129101,15 +132719,16 @@ index 0000000..4ad4525
+zpios_read_64734 zpios_read 3 64734 NULL
diff --git a/tools/gcc/size_overflow_plugin/size_overflow_plugin.c b/tools/gcc/size_overflow_plugin/size_overflow_plugin.c
new file mode 100644
-index 0000000..95f7abd
+index 0000000..7e07890
--- /dev/null
+++ b/tools/gcc/size_overflow_plugin/size_overflow_plugin.c
-@@ -0,0 +1,259 @@
+@@ -0,0 +1,260 @@
+/*
-+ * Copyright 2011-2014 by Emese Revfy <re.emese@gmail.com>
++ * Copyright 2011-2015 by Emese Revfy <re.emese@gmail.com>
+ * Licensed under the GPL v2, or (at your option) v3
+ *
+ * Homepage:
++ * https://github.com/ephox-gcc-plugins
+ * http://www.grsecurity.net/~ephox/overflow_plugin/
+ *
+ * Documentation:
@@ -129137,7 +132756,7 @@ index 0000000..95f7abd
+tree size_overflow_type_TI;
+
+static struct plugin_info size_overflow_plugin_info = {
-+ .version = "20140725",
++ .version = "20140725_01",
+ .help = "no-size-overflow\tturn off size overflow checking\n",
+};
+
@@ -129191,7 +132810,7 @@ index 0000000..95f7abd
+ return NULL_TREE;
+ }
+
-+ if (TREE_INT_CST_HIGH(TREE_VALUE(args)) != 0)
++ if (tree_to_shwi(TREE_VALUE(args)) != 0)
+ return NULL_TREE;
+
+ for (; args; args = TREE_CHAIN(args)) {
@@ -129366,15 +132985,16 @@ index 0000000..95f7abd
+}
diff --git a/tools/gcc/size_overflow_plugin/size_overflow_plugin_hash.c b/tools/gcc/size_overflow_plugin/size_overflow_plugin_hash.c
new file mode 100644
-index 0000000..0888f6c
+index 0000000..2a693fe
--- /dev/null
+++ b/tools/gcc/size_overflow_plugin/size_overflow_plugin_hash.c
-@@ -0,0 +1,364 @@
+@@ -0,0 +1,355 @@
+/*
-+ * Copyright 2011-2014 by Emese Revfy <re.emese@gmail.com>
++ * Copyright 2011-2015 by Emese Revfy <re.emese@gmail.com>
+ * Licensed under the GPL v2, or (at your option) v3
+ *
+ * Homepage:
++ * https://github.com/ephox-gcc-plugins
+ * http://www.grsecurity.net/~ephox/overflow_plugin/
+ *
+ * Documentation:
@@ -129602,43 +133222,33 @@ index 0000000..0888f6c
+ return CANNOT_FIND_ARG;
+}
+
-+static const char *get_asm_string(const_gimple stmt)
-+{
-+ if (!stmt)
-+ return NULL;
-+ if (gimple_code(stmt) != GIMPLE_ASM)
-+ return NULL;
-+
-+ return gimple_asm_string(stmt);
-+}
-+
-+bool is_size_overflow_intentional_asm_turn_off(const_gimple stmt)
++bool is_size_overflow_intentional_asm_turn_off(const gasm *stmt)
+{
+ const char *str;
+
-+ str = get_asm_string(stmt);
-+ if (!str)
++ if (!stmt)
+ return false;
++ str = gimple_asm_string(stmt);
+ return !strncmp(str, TURN_OFF_ASM_STR, sizeof(TURN_OFF_ASM_STR) - 1);
+}
+
-+bool is_size_overflow_intentional_asm_yes(const_gimple stmt)
++bool is_size_overflow_intentional_asm_yes(const gasm *stmt)
+{
+ const char *str;
+
-+ str = get_asm_string(stmt);
-+ if (!str)
++ if (!stmt)
+ return false;
++ str = gimple_asm_string(stmt);
+ return !strncmp(str, YES_ASM_STR, sizeof(YES_ASM_STR) - 1);
+}
+
-+bool is_size_overflow_asm(const_gimple stmt)
++bool is_size_overflow_asm(const gasm *stmt)
+{
+ const char *str;
+
-+ str = get_asm_string(stmt);
-+ if (!str)
++ if (!stmt)
+ return false;
++ str = gimple_asm_string(stmt);
+ return !strncmp(str, OK_ASM_STR, sizeof(OK_ASM_STR) - 1);
+}
+