diff options
Diffstat (limited to '3.2.69')
-rw-r--r-- | 3.2.69/0000_README | 2 | ||||
-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, ¶m); } ++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, ¶m); ++} ++ +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); +} + |