From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) by finch.gentoo.org (Postfix) with ESMTP id 35A7D1381F1 for ; Mon, 30 May 2016 07:59:31 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 0A1AF1420E; Mon, 30 May 2016 07:59:29 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 13B121420E for ; Mon, 30 May 2016 07:59:27 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id EB15233BF11 for ; Mon, 30 May 2016 07:59:25 +0000 (UTC) Received: from localhost.localdomain (localhost [127.0.0.1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id 4403316 for ; Mon, 30 May 2016 07:59:23 +0000 (UTC) From: "Anthony G. Basile" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Anthony G. Basile" Message-ID: <1464595217.91c3b96e63792590118e17193061908a07017497.blueness@gentoo> Subject: [gentoo-commits] proj/hardened-patchset:master commit in: 4.5.5/ X-VCS-Repository: proj/hardened-patchset X-VCS-Files: 4.5.5/0000_README 4.5.5/4420_grsecurity-3.1-4.5.5-201605211442.patch 4.5.5/4420_grsecurity-3.1-4.5.5-201605291201.patch X-VCS-Directories: 4.5.5/ X-VCS-Committer: blueness X-VCS-Committer-Name: Anthony G. Basile X-VCS-Revision: 91c3b96e63792590118e17193061908a07017497 X-VCS-Branch: master Date: Mon, 30 May 2016 07:59:23 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Archives-Salt: aeac8e31-adbc-4a8c-8aa2-47b1ad11919b X-Archives-Hash: ae61d35abfcab2cb7d22e247204a9c21 commit: 91c3b96e63792590118e17193061908a07017497 Author: Anthony G. Basile gentoo org> AuthorDate: Mon May 30 08:00:17 2016 +0000 Commit: Anthony G. Basile gentoo org> CommitDate: Mon May 30 08:00:17 2016 +0000 URL: https://gitweb.gentoo.org/proj/hardened-patchset.git/commit/?id=91c3b96e grsecurity-3.1-4.5.5-201605291201 4.5.5/0000_README | 2 +- ...> 4420_grsecurity-3.1-4.5.5-201605291201.patch} | 18852 ++++++++++--------- 2 files changed, 9793 insertions(+), 9061 deletions(-) diff --git a/4.5.5/0000_README b/4.5.5/0000_README index febdb77..71dba33 100644 --- a/4.5.5/0000_README +++ b/4.5.5/0000_README @@ -2,7 +2,7 @@ README ----------------------------------------------------------------------------- Individual Patch Descriptions: ----------------------------------------------------------------------------- -Patch: 4420_grsecurity-3.1-4.5.5-201605211442.patch +Patch: 4420_grsecurity-3.1-4.5.5-201605291201.patch From: http://www.grsecurity.net Desc: hardened-sources base patch from upstream grsecurity diff --git a/4.5.5/4420_grsecurity-3.1-4.5.5-201605211442.patch b/4.5.5/4420_grsecurity-3.1-4.5.5-201605291201.patch similarity index 99% rename from 4.5.5/4420_grsecurity-3.1-4.5.5-201605211442.patch rename to 4.5.5/4420_grsecurity-3.1-4.5.5-201605291201.patch index 7202c18..1fb08ce 100644 --- a/4.5.5/4420_grsecurity-3.1-4.5.5-201605211442.patch +++ b/4.5.5/4420_grsecurity-3.1-4.5.5-201605291201.patch @@ -408,7 +408,7 @@ index a93b414..f50a50b 100644 A toggle value indicating if modules are allowed to be loaded diff --git a/Makefile b/Makefile -index a23df41..314f8da 100644 +index a23df41..db4f30b 100644 --- a/Makefile +++ b/Makefile @@ -298,7 +298,9 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ @@ -422,27 +422,41 @@ index a23df41..314f8da 100644 ifeq ($(shell $(HOSTCC) -v 2>&1 | grep -c "clang version"), 1) HOSTCFLAGS += -Wno-unused-value -Wno-unused-parameter \ -@@ -434,8 +436,8 @@ export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \ - # Rules shared between *config targets and build targets - - # Basic helpers built in scripts/ --PHONY += scripts_basic --scripts_basic: -+PHONY += scripts_basic gcc-plugins -+scripts_basic: gcc-plugins - $(Q)$(MAKE) $(build)=scripts/basic - $(Q)rm -f .tmp_quiet_recordmcount - -@@ -622,6 +624,8 @@ endif +@@ -417,6 +419,8 @@ export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE + export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL + export KBUILD_ARFLAGS + ++export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS ++ + # When compiling out-of-tree modules, put MODVERDIR in the module + # tree rather than in the kernel tree. The kernel tree might + # even be read-only. +@@ -547,7 +551,7 @@ ifeq ($(KBUILD_EXTMOD),) + # in parallel + PHONY += scripts + scripts: scripts_basic include/config/auto.conf include/config/tristate.conf \ +- asm-generic ++ asm-generic gcc-plugins + $(Q)$(MAKE) $(build)=$(@) + + # Objects we will link into vmlinux / subdirs we need to visit +@@ -622,6 +626,15 @@ endif # Tell gcc to never replace conditional load with a non-conditional one KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0) ++PHONY += gcc-plugins ++gcc-plugins: scripts_basic ++ifdef CONFIG_GCC_PLUGINS ++ $(Q)$(MAKE) $(build)=scripts/gcc-plugins ++endif ++ @: ++ +include scripts/Makefile.gcc-plugins + ifdef CONFIG_READABLE_ASM # Disable optimizations that make assembler listings hard to read. # reorder blocks reorders the control in the function -@@ -714,7 +718,7 @@ KBUILD_CFLAGS += $(call cc-option, -gsplit-dwarf, -g) +@@ -714,7 +727,7 @@ KBUILD_CFLAGS += $(call cc-option, -gsplit-dwarf, -g) else KBUILD_CFLAGS += -g endif @@ -451,7 +465,7 @@ index a23df41..314f8da 100644 endif ifdef CONFIG_DEBUG_INFO_DWARF4 KBUILD_CFLAGS += $(call cc-option, -gdwarf-4,) -@@ -886,7 +890,7 @@ export mod_sign_cmd +@@ -886,7 +899,7 @@ export mod_sign_cmd ifeq ($(KBUILD_EXTMOD),) @@ -460,57 +474,16 @@ index a23df41..314f8da 100644 vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ -@@ -937,6 +941,8 @@ endif - - # The actual objects are generated when descending, - # make sure no implicit rule kicks in -+$(filter-out $(init-y),$(vmlinux-deps)): KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS) -+$(filter-out $(init-y),$(vmlinux-deps)): KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS) - $(sort $(vmlinux-deps)): $(vmlinux-dirs) ; - - # Handle descending into subdirectories listed in $(vmlinux-dirs) -@@ -946,7 +952,7 @@ $(sort $(vmlinux-deps)): $(vmlinux-dirs) ; - # Error messages still appears in the original language - - PHONY += $(vmlinux-dirs) --$(vmlinux-dirs): prepare scripts -+$(vmlinux-dirs): gcc-plugins prepare scripts - $(Q)$(MAKE) $(build)=$@ - - define filechk_kernel.release -@@ -989,10 +995,13 @@ prepare1: prepare2 $(version_h) include/generated/utsrelease.h \ +@@ -989,7 +1002,7 @@ prepare1: prepare2 $(version_h) include/generated/utsrelease.h \ archprepare: archheaders archscripts prepare1 scripts_basic -+prepare0: KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS) -+prepare0: KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS) - prepare0: archprepare FORCE +-prepare0: archprepare FORCE ++prepare0: archprepare gcc-plugins FORCE $(Q)$(MAKE) $(build)=. # All the preparing.. -+prepare: KBUILD_CFLAGS := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS)) - prepare: prepare0 - - # Generate some files -@@ -1103,6 +1112,8 @@ all: modules - # using awk while concatenating to the final file. - - PHONY += modules -+modules: KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS) -+modules: KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS) - modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) modules.builtin - $(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order - @$(kecho) ' Building modules, stage 2.'; -@@ -1118,7 +1129,7 @@ modules.builtin: $(vmlinux-dirs:%=%/modules.builtin) - - # Target to prepare building external modules - PHONY += modules_prepare --modules_prepare: prepare scripts -+modules_prepare: gcc-plugins prepare scripts - - # Target to install modules - PHONY += modules_install -@@ -1184,7 +1195,11 @@ MRPROPER_FILES += .config .config.old .version .old_version \ +@@ -1184,7 +1197,11 @@ MRPROPER_FILES += .config .config.old .version .old_version \ Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \ signing_key.pem signing_key.priv signing_key.x509 \ x509.genkey extra_certificates signing_key.x509.keyid \ @@ -523,7 +496,7 @@ index a23df41..314f8da 100644 # clean - Delete most, but leave enough to build external modules # -@@ -1223,7 +1238,7 @@ distclean: mrproper +@@ -1223,7 +1240,7 @@ distclean: mrproper @find $(srctree) $(RCS_FIND_IGNORE) \ \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ @@ -532,59 +505,31 @@ index a23df41..314f8da 100644 -type f -print | xargs rm -f -@@ -1390,6 +1405,8 @@ PHONY += $(module-dirs) modules - $(module-dirs): crmodverdir $(objtree)/Module.symvers - $(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@) +diff --git a/arch/Kconfig b/arch/Kconfig +index f6b649d..5ba628b 100644 +--- a/arch/Kconfig ++++ b/arch/Kconfig +@@ -353,6 +353,20 @@ config SECCOMP_FILTER -+modules: KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS) -+modules: KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS) - modules: $(module-dirs) - @$(kecho) ' Building modules, stage 2.'; - $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost -@@ -1531,17 +1548,21 @@ else - target-dir = $(if $(KBUILD_EXTMOD),$(dir $<),$(dir $@)) - endif + See Documentation/prctl/seccomp_filter.txt for details. --%.s: %.c prepare scripts FORCE -+%.s: KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS) -+%.s: KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS) -+%.s: %.c gcc-plugins prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) - %.i: %.c prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) --%.o: %.c prepare scripts FORCE -+%.o: KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS) -+%.o: KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS) -+%.o: %.c gcc-plugins prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) - %.lst: %.c prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) --%.s: %.S prepare scripts FORCE -+%.s: %.S gcc-plugins prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) --%.o: %.S prepare scripts FORCE -+%.o: %.S gcc-plugins prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) - %.symtypes: %.c prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) -@@ -1553,11 +1574,15 @@ endif - $(build)=$(build-dir) - # Make sure the latest headers are built for Documentation - Documentation/: headers_install --%/: prepare scripts FORCE -+%/: KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS) -+%/: KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS) -+%/: gcc-plugins prepare scripts FORCE - $(cmd_crmodverdir) - $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ - $(build)=$(build-dir) --%.ko: prepare scripts FORCE -+%.ko: KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS) -+%.ko: KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS) -+%.ko: gcc-plugins prepare scripts FORCE - $(cmd_crmodverdir) - $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ - $(build)=$(build-dir) $(@:.ko=.o) ++config HAVE_GCC_PLUGINS ++ bool ++ help ++ An arch should select this symbol if it supports building with ++ GCC plugins. ++ ++menuconfig GCC_PLUGINS ++ bool "GCC plugins" ++ depends on HAVE_GCC_PLUGINS ++ default y ++ help ++ GCC plugins are loadable modules that provide extra features to the ++ compiler. They are useful for runtime instrumentation and static analysis. ++ + config HAVE_CC_STACKPROTECTOR + bool + help diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h index 572b228..e03acdd 100644 --- a/arch/alpha/include/asm/atomic.h @@ -928,10 +873,18 @@ index 8a188bc..26608f1 100644 Counts number of I and D TLB Misses and exports them via Debugfs The counters can be cleared via Debugfs as well diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index 4f799e5..cc1200e 100644 +index 4f799e5..c1e2b95 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig -@@ -1622,6 +1622,7 @@ config HIGHPTE +@@ -53,6 +53,7 @@ config ARM + select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL) + select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL) + select HAVE_FUNCTION_TRACER if (!XIP_KERNEL) ++ select HAVE_GCC_PLUGINS + select HAVE_GENERIC_DMA_COHERENT + select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7)) + select HAVE_IDE if PCI || ISA || PCMCIA +@@ -1622,6 +1623,7 @@ config HIGHPTE config CPU_SW_DOMAIN_PAN bool "Enable use of CPU domains to implement privileged no-access" depends on MMU && !ARM_LPAE @@ -939,7 +892,7 @@ index 4f799e5..cc1200e 100644 default y help Increase kernel security by ensuring that normal kernel accesses -@@ -1698,7 +1699,7 @@ config ALIGNMENT_TRAP +@@ -1698,7 +1700,7 @@ config ALIGNMENT_TRAP config UACCESS_WITH_MEMCPY bool "Use kernel mem{cpy,set}() for {copy_to,clear}_user()" @@ -948,7 +901,7 @@ index 4f799e5..cc1200e 100644 default y if CPU_FEROCEON help Implement faster copy_to_user and clear_user methods for CPU -@@ -1953,6 +1954,7 @@ config KEXEC +@@ -1953,6 +1955,7 @@ config KEXEC depends on (!SMP || PM_SLEEP_SMP) depends on !CPU_V7M select KEXEC_CORE @@ -956,7 +909,7 @@ index 4f799e5..cc1200e 100644 help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot -@@ -1997,7 +1999,7 @@ config EFI_STUB +@@ -1997,7 +2000,7 @@ config EFI_STUB config EFI bool "UEFI runtime support" @@ -977,6 +930,19 @@ index c6b6175..2884505 100644 ---help--- Say Y here if you want to show the kernel pagetable layout in a debugfs file. This information is only useful for kernel developers +diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile +index 43788b1..2efefcf 100644 +--- a/arch/arm/boot/compressed/Makefile ++++ b/arch/arm/boot/compressed/Makefile +@@ -106,6 +106,8 @@ ORIG_CFLAGS := $(KBUILD_CFLAGS) + KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS)) + endif + ++KBUILD_CFLAGS := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS)) ++ + # -fstack-protector-strong triggers protection checks in this code, + # but it is being used too early to link to meaningful stack_chk logic. + nossp_flags := $(call cc-option, -fno-stack-protector) diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h index 9e10c45..24a14ce 100644 --- a/arch/arm/include/asm/atomic.h @@ -3357,7 +3323,7 @@ index 6bd1089..e999400 100644 { unsigned long ua_flags; diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c -index c169cc3..f290a77 100644 +index c169cc3..b007ec6 100644 --- a/arch/arm/mach-exynos/suspend.c +++ b/arch/arm/mach-exynos/suspend.c @@ -734,8 +734,10 @@ void __init exynos_pm_init(void) @@ -3367,8 +3333,8 @@ index c169cc3..f290a77 100644 - exynos_pm_syscore_ops.suspend = pm_data->pm_suspend; - exynos_pm_syscore_ops.resume = pm_data->pm_resume; + pax_open_kernel(); -+ *(void **)&exynos_pm_syscore_ops.suspend = pm_data->pm_suspend; -+ *(void **)&exynos_pm_syscore_ops.resume = pm_data->pm_resume; ++ const_cast(exynos_pm_syscore_ops.suspend) = pm_data->pm_suspend; ++ const_cast(exynos_pm_syscore_ops.resume) = pm_data->pm_resume; + pax_close_kernel(); register_syscore_ops(&exynos_pm_syscore_ops); @@ -3501,7 +3467,7 @@ index 2af6ff6..1f2959f 100644 /* omap_hwmod_list contains all registered struct omap_hwmods */ static LIST_HEAD(omap_hwmod_list); diff --git a/arch/arm/mach-omap2/powerdomains43xx_data.c b/arch/arm/mach-omap2/powerdomains43xx_data.c -index 95fee54..cfa9cf1 100644 +index 95fee54..b5dd79d 100644 --- a/arch/arm/mach-omap2/powerdomains43xx_data.c +++ b/arch/arm/mach-omap2/powerdomains43xx_data.c @@ -10,6 +10,7 @@ @@ -3518,7 +3484,7 @@ index 95fee54..cfa9cf1 100644 { - omap4_pwrdm_operations.pwrdm_has_voltdm = am43xx_check_vcvp; + pax_open_kernel(); -+ *(void **)&omap4_pwrdm_operations.pwrdm_has_voltdm = am43xx_check_vcvp; ++ const_cast(omap4_pwrdm_operations.pwrdm_has_voltdm) = am43xx_check_vcvp; + pax_close_kernel(); pwrdm_register_platform_funcs(&omap4_pwrdm_operations); pwrdm_register_pwrdms(powerdomains_am43xx); @@ -3548,7 +3514,7 @@ index ff0a68c..b312aa0 100644 sizeof(struct omap_wd_timer_platform_data)); WARN(IS_ERR(pdev), "Can't build omap_device for %s:%s.\n", diff --git a/arch/arm/mach-shmobile/platsmp-apmu.c b/arch/arm/mach-shmobile/platsmp-apmu.c -index aba75c8..b55a9d7 100644 +index aba75c8..b2b340f 100644 --- a/arch/arm/mach-shmobile/platsmp-apmu.c +++ b/arch/arm/mach-shmobile/platsmp-apmu.c @@ -22,6 +22,7 @@ @@ -3565,7 +3531,7 @@ index aba75c8..b55a9d7 100644 { - shmobile_suspend_ops.enter = shmobile_smp_apmu_enter_suspend; + pax_open_kernel(); -+ *(void **)&shmobile_suspend_ops.enter = shmobile_smp_apmu_enter_suspend; ++ const_cast(shmobile_suspend_ops.enter) = shmobile_smp_apmu_enter_suspend; + pax_close_kernel(); } #endif @@ -3727,7 +3693,7 @@ index c8c8b9e..c55cc79 100644 atomic64_set(&mm->context.id, asid); } diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c -index daafcf1..8205ed6 100644 +index daafcf1..a04e1fd 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -25,6 +25,7 @@ @@ -3841,7 +3807,7 @@ index daafcf1..8205ed6 100644 pr_alert("Unhandled fault: %s (0x%03x) at 0x%08lx\n", inf->name, fsr, addr); show_pte(current->mm, addr); -@@ -574,15 +647,104 @@ hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs * +@@ -574,15 +647,118 @@ hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs * ifsr_info[nr].name = name; } @@ -3879,6 +3845,13 @@ index daafcf1..8205ed6 100644 + */ + // dmb(); implied by the exception + regs->ARM_pc = regs->ARM_lr; ++#ifdef CONFIG_ARM_THUMB ++ if (regs->ARM_lr & 1) { ++ regs->ARM_cpsr |= PSR_T_BIT; ++ regs->ARM_pc &= ~0x1U; ++ } else ++ regs->ARM_cpsr &= ~PSR_T_BIT; ++#endif + return; + } + if (pc == 0xffff0fc0UL) { @@ -3901,6 +3874,13 @@ index daafcf1..8205ed6 100644 + */ + regs->ARM_r0 = current_thread_info()->tp_value[0]; + regs->ARM_pc = regs->ARM_lr; ++#ifdef CONFIG_ARM_THUMB ++ if (regs->ARM_lr & 1) { ++ regs->ARM_cpsr |= PSR_T_BIT; ++ regs->ARM_pc &= ~0x1U; ++ } else ++ regs->ARM_cpsr &= ~PSR_T_BIT; ++#endif + return; + } + } @@ -4655,6 +4635,18 @@ index a5bc92d..0bb4730 100644 omap_sram_size - omap_sram_skip); + pax_close_kernel(); } +diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig +index 8cc6228..6d6e4f8 100644 +--- a/arch/arm64/Kconfig ++++ b/arch/arm64/Kconfig +@@ -70,6 +70,7 @@ config ARM64 + select HAVE_FTRACE_MCOUNT_RECORD + select HAVE_FUNCTION_TRACER + select HAVE_FUNCTION_GRAPH_TRACER ++ select HAVE_GCC_PLUGINS + select HAVE_GENERIC_DMA_COHERENT + select HAVE_HW_BREAKPOINT if PERF_EVENTS + select HAVE_IRQ_TIME_ACCOUNTING diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug index e13c4bf..3feaea7 100644 --- a/arch/arm64/Kconfig.debug @@ -5602,10 +5594,18 @@ index 4efe96a..60e8699 100644 #define SMP_CACHE_BYTES L1_CACHE_BYTES diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig -index d3da79d..e607104 100644 +index d3da79d..e317c97 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig -@@ -2656,6 +2656,7 @@ source "kernel/Kconfig.preempt" +@@ -49,6 +49,7 @@ config MIPS + select GENERIC_CMOS_UPDATE + select HAVE_MOD_ARCH_SPECIFIC + select VIRT_TO_BUS ++ select HAVE_GCC_PLUGINS + select MODULES_USE_ELF_REL if MODULES + select MODULES_USE_ELF_RELA if MODULES && 64BIT + select CLONE_BACKWARDS +@@ -2656,6 +2657,7 @@ source "kernel/Kconfig.preempt" config KEXEC bool "Kexec system call" select KEXEC_CORE @@ -7607,10 +7607,18 @@ index f906444..0bb73ae 100644 /* * If for any reason at all we couldn't handle the fault, make diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig -index 9faa18c..6061610 100644 +index 9faa18c..b24277a 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig -@@ -419,6 +419,7 @@ config KEXEC +@@ -143,6 +143,7 @@ config PPC + select ARCH_USE_BUILTIN_BSWAP + select OLD_SIGSUSPEND + select OLD_SIGACTION if PPC32 ++ select HAVE_GCC_PLUGINS + select HAVE_DEBUG_STACKOVERFLOW + select HAVE_IRQ_EXIT_ON_IRQ_STACK + select ARCH_USE_CMPXCHG_LOCKREF if PPC64 +@@ -419,6 +420,7 @@ config KEXEC bool "kexec system call" depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP)) || PPC_BOOK3E select KEXEC_CORE @@ -7619,7 +7627,7 @@ index 9faa18c..6061610 100644 kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h -index 55f106e..70cc82a 100644 +index 55f106e..5968afb 100644 --- a/arch/powerpc/include/asm/atomic.h +++ b/arch/powerpc/include/asm/atomic.h @@ -12,6 +12,11 @@ @@ -7886,19 +7894,7 @@ index 55f106e..70cc82a 100644 PPC_ATOMIC_EXIT_BARRIER " subf %0,%2,%0 \n\ 2:" -@@ -252,6 +299,11 @@ static __inline__ int atomic_dec_if_positive(atomic_t *v) - } - #define atomic_dec_if_positive atomic_dec_if_positive - -+#define smp_mb__before_atomic_dec() smp_mb() -+#define smp_mb__after_atomic_dec() smp_mb() -+#define smp_mb__before_atomic_inc() smp_mb() -+#define smp_mb__after_atomic_inc() smp_mb() -+ - #ifdef __powerpc64__ - - #define ATOMIC64_INIT(i) { (i) } -@@ -265,37 +317,60 @@ static __inline__ long atomic64_read(const atomic64_t *v) +@@ -265,37 +312,60 @@ static __inline__ long atomic64_read(const atomic64_t *v) return t; } @@ -7963,7 +7959,7 @@ index 55f106e..70cc82a 100644 PPC_ATOMIC_EXIT_BARRIER \ : "=&r" (t) \ : "r" (a), "r" (&v->counter) \ -@@ -304,6 +379,9 @@ static __inline__ long atomic64_##op##_return(long a, atomic64_t *v) \ +@@ -304,6 +374,9 @@ static __inline__ long atomic64_##op##_return(long a, atomic64_t *v) \ return t; \ } @@ -7973,7 +7969,7 @@ index 55f106e..70cc82a 100644 #define ATOMIC64_OPS(op, asm_op) ATOMIC64_OP(op, asm_op) ATOMIC64_OP_RETURN(op, asm_op) ATOMIC64_OPS(add, add) -@@ -314,40 +392,33 @@ ATOMIC64_OP(xor, xor) +@@ -314,40 +387,33 @@ ATOMIC64_OP(xor, xor) #undef ATOMIC64_OPS #undef ATOMIC64_OP_RETURN @@ -8033,7 +8029,7 @@ index 55f106e..70cc82a 100644 } /* -@@ -360,36 +431,18 @@ static __inline__ long atomic64_inc_return(atomic64_t *v) +@@ -360,36 +426,18 @@ static __inline__ long atomic64_inc_return(atomic64_t *v) */ #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) @@ -8081,7 +8077,7 @@ index 55f106e..70cc82a 100644 } #define atomic64_sub_and_test(a, v) (atomic64_sub_return((a), (v)) == 0) -@@ -422,6 +475,16 @@ static __inline__ long atomic64_dec_if_positive(atomic64_t *v) +@@ -422,6 +470,16 @@ static __inline__ long atomic64_dec_if_positive(atomic64_t *v) #define atomic64_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) #define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) @@ -8090,7 +8086,7 @@ index 55f106e..70cc82a 100644 + return cmpxchg(&(v->counter), old, new); +} + -+static inline long atomic64_xchg_unchecked(atomic64_unchecked_t *v, long new) ++static inline long atomic64_xchg_unchecked(atomic64_unchecked_t *v, long new) +{ + return xchg(&(v->counter), new); +} @@ -8098,7 +8094,7 @@ index 55f106e..70cc82a 100644 /** * atomic64_add_unless - add unless the number is a given value * @v: pointer of type atomic64_t -@@ -437,13 +500,29 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) +@@ -437,13 +495,29 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) __asm__ __volatile__ ( PPC_ATOMIC_ENTRY_BARRIER @@ -8698,17 +8694,17 @@ index b7c20f0..4adc0f1 100644 static inline unsigned long clear_user(void __user *addr, unsigned long size) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile -index 794f22a..f8de42b 100644 +index 794f22a..9a76447 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -14,6 +14,11 @@ CFLAGS_prom_init.o += -fPIC CFLAGS_btext.o += -fPIC endif -+CFLAGS_REMOVE_cputable.o = $(LATENT_ENTROPY_PLUGIN_CFLAGS) -+CFLAGS_REMOVE_prom_init.o = $(LATENT_ENTROPY_PLUGIN_CFLAGS) -+CFLAGS_REMOVE_btext.o = $(LATENT_ENTROPY_PLUGIN_CFLAGS) -+CFLAGS_REMOVE_prom.o = $(LATENT_ENTROPY_PLUGIN_CFLAGS) ++CFLAGS_cputable.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) ++CFLAGS_prom_init.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) ++CFLAGS_btext.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) ++CFLAGS_prom.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) + ifdef CONFIG_FUNCTION_TRACER # Do not trace early boot code @@ -9678,6 +9674,18 @@ index 6777177..d44b592 100644 info.high_limit = TASK_SIZE; addr = vm_unmapped_area(&info); } +diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig +index 57ffaf2..4d1fe9a 100644 +--- a/arch/sparc/Kconfig ++++ b/arch/sparc/Kconfig +@@ -39,6 +39,7 @@ config SPARC + select GENERIC_STRNCPY_FROM_USER + select GENERIC_STRNLEN_USER + select MODULES_USE_ELF_RELA ++ select HAVE_GCC_PLUGINS + select ODD_RT_SIGACTION + select OLD_SIGSUSPEND + select ARCH_HAS_SG_CHAIN diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index f2fbf9e..fea461e 100644 --- a/arch/sparc/include/asm/atomic_64.h @@ -12221,16 +12229,14 @@ index c034dc3..cf1cc96 100644 /* diff --git a/arch/um/Makefile b/arch/um/Makefile -index e3abe6f..ae224ef 100644 +index e3abe6f..33a363c 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile -@@ -73,6 +73,10 @@ USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -I%,,$(KBUILD_CFLAGS))) \ +@@ -73,6 +73,8 @@ USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -I%,,$(KBUILD_CFLAGS))) \ -D_FILE_OFFSET_BITS=64 -idirafter $(srctree)/include \ -idirafter $(obj)/include -D__KERNEL__ -D__UM_HOST__ -+ifdef CONSTIFY_PLUGIN -+USER_CFLAGS += -fplugin-arg-constify_plugin-no-constify -+endif ++USER_CFLAGS := $(filter-out $(GCC_PLUGINS_CFLAGS),$(USER_CFLAGS)) + #This will adjust *FLAGS accordingly to the platform. include $(ARCH_DIR)/Makefile-os-$(OS) @@ -12338,7 +12344,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 3bf45a0..7b04039 100644 +index 3bf45a0..25ca7da 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -38,14 +38,13 @@ config X86 @@ -12366,7 +12372,15 @@ index 3bf45a0..7b04039 100644 select HAVE_CMPXCHG_DOUBLE select HAVE_CMPXCHG_LOCAL select HAVE_CONTEXT_TRACKING if X86_64 -@@ -290,7 +289,7 @@ config X86_64_SMP +@@ -109,6 +108,7 @@ config X86 + select HAVE_FUNCTION_GRAPH_FP_TEST + select HAVE_FUNCTION_GRAPH_TRACER + select HAVE_FUNCTION_TRACER ++ select HAVE_GCC_PLUGINS + select HAVE_GENERIC_DMA_COHERENT if X86_32 + select HAVE_HW_BREAKPOINT + select HAVE_IDE +@@ -290,7 +290,7 @@ config X86_64_SMP config X86_32_LAZY_GS def_bool y @@ -12375,7 +12389,7 @@ index 3bf45a0..7b04039 100644 config ARCH_HWEIGHT_CFLAGS string -@@ -674,6 +673,7 @@ config SCHED_OMIT_FRAME_POINTER +@@ -674,6 +674,7 @@ config SCHED_OMIT_FRAME_POINTER menuconfig HYPERVISOR_GUEST bool "Linux guest support" @@ -12383,7 +12397,7 @@ index 3bf45a0..7b04039 100644 ---help--- Say Y here to enable options for running Linux under various hyper- visors. This option enables basic hypervisor detection and platform -@@ -1073,6 +1073,7 @@ config VM86 +@@ -1073,6 +1074,7 @@ config VM86 config X86_16BIT bool "Enable support for 16-bit segments" if EXPERT @@ -12391,7 +12405,7 @@ index 3bf45a0..7b04039 100644 default y depends on MODIFY_LDT_SYSCALL ---help--- -@@ -1227,6 +1228,7 @@ choice +@@ -1227,6 +1229,7 @@ choice config NOHIGHMEM bool "off" @@ -12399,7 +12413,7 @@ index 3bf45a0..7b04039 100644 ---help--- Linux can use up to 64 Gigabytes of physical memory on x86 systems. However, the address space of 32-bit x86 processors is only 4 -@@ -1263,6 +1265,7 @@ config NOHIGHMEM +@@ -1263,6 +1266,7 @@ config NOHIGHMEM config HIGHMEM4G bool "4GB" @@ -12407,7 +12421,7 @@ index 3bf45a0..7b04039 100644 ---help--- Select this if you have a 32-bit processor and between 1 and 4 gigabytes of physical RAM. -@@ -1315,7 +1318,7 @@ config PAGE_OFFSET +@@ -1315,7 +1319,7 @@ config PAGE_OFFSET hex default 0xB0000000 if VMSPLIT_3G_OPT default 0x80000000 if VMSPLIT_2G @@ -12416,7 +12430,7 @@ index 3bf45a0..7b04039 100644 default 0x40000000 if VMSPLIT_1G default 0xC0000000 depends on X86_32 -@@ -1336,7 +1339,6 @@ config X86_PAE +@@ -1336,7 +1340,6 @@ config X86_PAE config ARCH_PHYS_ADDR_T_64BIT def_bool y @@ -12424,7 +12438,7 @@ index 3bf45a0..7b04039 100644 config ARCH_DMA_ADDR_T_64BIT def_bool y -@@ -1467,7 +1469,7 @@ config ARCH_PROC_KCORE_TEXT +@@ -1467,7 +1470,7 @@ config ARCH_PROC_KCORE_TEXT config ILLEGAL_POINTER_VALUE hex @@ -12433,7 +12447,7 @@ index 3bf45a0..7b04039 100644 default 0xdead000000000000 if X86_64 source "mm/Kconfig" -@@ -1776,6 +1778,7 @@ source kernel/Kconfig.hz +@@ -1776,6 +1779,7 @@ source kernel/Kconfig.hz config KEXEC bool "kexec system call" select KEXEC_CORE @@ -12441,7 +12455,7 @@ index 3bf45a0..7b04039 100644 ---help--- kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot -@@ -1958,7 +1961,9 @@ config X86_NEED_RELOCS +@@ -1958,7 +1962,9 @@ config X86_NEED_RELOCS config PHYSICAL_ALIGN hex "Alignment value to which kernel should be aligned" @@ -12452,7 +12466,7 @@ index 3bf45a0..7b04039 100644 range 0x2000 0x1000000 if X86_32 range 0x200000 0x1000000 if X86_64 ---help--- -@@ -2041,6 +2046,7 @@ config COMPAT_VDSO +@@ -2041,6 +2047,7 @@ config COMPAT_VDSO def_bool n prompt "Disable the 32-bit vDSO (needed for glibc 2.3.3)" depends on X86_32 || IA32_EMULATION @@ -12460,7 +12474,7 @@ index 3bf45a0..7b04039 100644 ---help--- Certain buggy versions of glibc will crash if they are presented with a 32-bit vDSO that is not mapped at the address -@@ -2081,15 +2087,6 @@ choice +@@ -2081,15 +2088,6 @@ choice If unsure, select "Emulate". @@ -12476,7 +12490,7 @@ index 3bf45a0..7b04039 100644 config LEGACY_VSYSCALL_EMULATE bool "Emulate" help -@@ -2170,6 +2167,22 @@ config MODIFY_LDT_SYSCALL +@@ -2170,6 +2168,22 @@ config MODIFY_LDT_SYSCALL Saying 'N' here may make sense for embedded or server kernels. @@ -12610,20 +12624,6 @@ index 4086abc..52a0a9b 100644 +*** ${VERSION}.${PATCHLEVEL} PaX kernels no longer build correctly with old versions of binutils. +*** Please upgrade your binutils to 2.18 or newer +endef -diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile -index bbe1a62..ec6a3ec 100644 ---- a/arch/x86/boot/Makefile -+++ b/arch/x86/boot/Makefile -@@ -58,6 +58,9 @@ clean-files += cpustr.h - # --------------------------------------------------------------------------- - - KBUILD_CFLAGS := $(USERINCLUDE) $(REALMODE_CFLAGS) -D_SETUP -+ifdef CONSTIFY_PLUGIN -+KBUILD_CFLAGS += -fplugin-arg-constify_plugin-no-constify -+endif - KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ - GCOV_PROFILE := n - UBSAN_SANITIZE := n diff --git a/arch/x86/boot/bitops.h b/arch/x86/boot/bitops.h index 878e4b9..20537ab 100644 --- a/arch/x86/boot/bitops.h @@ -12660,17 +12660,13 @@ index 9011a88..06aa820 100644 } diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile -index f9ce75d..0b1600d 100644 +index f9ce75d..245ea76 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile -@@ -30,6 +30,26 @@ KBUILD_CFLAGS += $(cflags-y) - KBUILD_CFLAGS += -mno-mmx -mno-sse +@@ -31,6 +31,23 @@ KBUILD_CFLAGS += -mno-mmx -mno-sse KBUILD_CFLAGS += $(call cc-option,-ffreestanding) KBUILD_CFLAGS += $(call cc-option,-fno-stack-protector) -+ifdef CONSTIFY_PLUGIN -+KBUILD_CFLAGS += -fplugin-arg-constify_plugin-no-constify -+endif -+ + +ifdef CONFIG_DEBUG_INFO +ifdef CONFIG_DEBUG_INFO_SPLIT +KBUILD_CFLAGS += $(call cc-option, -gsplit-dwarf, -g) @@ -12687,9 +12683,10 @@ index f9ce75d..0b1600d 100644 +KBUILD_CFLAGS += $(call cc-option, -femit-struct-debug-baseonly) \ + $(call cc-option,-fno-var-tracking) +endif - ++ KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ GCOV_PROFILE := n + UBSAN_SANITIZE :=n diff --git a/arch/x86/boot/compressed/efi_stub_32.S b/arch/x86/boot/compressed/efi_stub_32.S index a53440e..c3dbf1e 100644 --- a/arch/x86/boot/compressed/efi_stub_32.S @@ -15756,7 +15753,7 @@ index e32206e0..809adae 100644 .macro REMOVE_PT_GPREGS_FROM_STACK addskip=0 diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c -index 1a4477c..95199ec4 100644 +index 1a4477c..7061819 100644 --- a/arch/x86/entry/common.c +++ b/arch/x86/entry/common.c @@ -32,9 +32,7 @@ @@ -15869,7 +15866,7 @@ index 1a4477c..95199ec4 100644 + [param4] "m" (regs->si), + [param5] "m" (regs->di), + [param6] "m" (regs->bp) -+ : "di", "si", "dx", "cx", "r8", "r9", "memory"); ++ : "ax", "di", "si", "dx", "cx", "r8", "r9", "r10", "r11", "memory"); +#else + asm volatile("pushl %[param6]\n\t" + "pushl %[param5]\n\t" @@ -22879,7 +22876,7 @@ index 82c34ee..940fa40 100644 unsigned, unsigned, unsigned); diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h -index c7b5510..2ab8977 100644 +index c7b5510..f6d5ca4 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -39,7 +39,7 @@ @@ -22961,7 +22958,7 @@ index c7b5510..2ab8977 100644 } static inline unsigned long current_stack_pointer(void) -@@ -179,14 +182,9 @@ static inline unsigned long current_stack_pointer(void) +@@ -179,41 +182,9 @@ static inline unsigned long current_stack_pointer(void) #else /* !__ASSEMBLY__ */ @@ -22973,11 +22970,38 @@ index c7b5510..2ab8977 100644 #define GET_THREAD_INFO(reg) \ - _ASM_MOV PER_CPU_VAR(cpu_current_top_of_stack),reg ; \ - _ASM_SUB $(THREAD_SIZE),reg ; +- +-/* +- * ASM operand which evaluates to a 'thread_info' address of +- * the current task, if it is known that "reg" is exactly "off" +- * bytes below the top of the stack currently. +- * +- * ( The kernel stack's size is known at build time, it is usually +- * 2 or 4 pages, and the bottom of the kernel stack contains +- * the thread_info structure. So to access the thread_info very +- * quickly from assembly code we can calculate down from the +- * top of the kernel stack to the bottom, using constant, +- * build-time calculations only. ) +- * +- * For example, to fetch the current thread_info->flags value into %eax +- * on x86-64 defconfig kernels, in syscall entry code where RSP is +- * currently at exactly SIZEOF_PTREGS bytes away from the top of the +- * stack: +- * +- * mov ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS), %eax +- * +- * will translate to: +- * +- * 8b 84 24 b8 c0 ff ff mov -0x3f48(%rsp), %eax +- * +- * which is below the current RSP by almost 16K. +- */ +-#define ASM_THREAD_INFO(field, reg, off) ((field)+(off)-THREAD_SIZE)(reg) + _ASM_MOV PER_CPU_VAR(current_tinfo),reg ; - /* - * ASM operand which evaluates to a 'thread_info' address of -@@ -279,5 +277,12 @@ static inline bool is_ia32_task(void) + #endif + +@@ -279,5 +250,12 @@ static inline bool is_ia32_task(void) extern void arch_task_cache_init(void); extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); extern void arch_release_task_struct(struct task_struct *tsk); @@ -25722,7 +25746,7 @@ index 2cad71d..5f1baf2 100644 __bts_event_stop(event); diff --git a/arch/x86/kernel/cpu/perf_event_intel_cqm.c b/arch/x86/kernel/cpu/perf_event_intel_cqm.c -index a316ca9..99344f4 100644 +index a316ca9..07e219e 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_cqm.c +++ b/arch/x86/kernel/cpu/perf_event_intel_cqm.c @@ -1364,7 +1364,9 @@ static int __init intel_cqm_init(void) @@ -25731,7 +25755,7 @@ index a316ca9..99344f4 100644 - event_attr_intel_cqm_llc_scale.event_str = str; + pax_open_kernel(); -+ *(const char **)&event_attr_intel_cqm_llc_scale.event_str = str; ++ const_cast(event_attr_intel_cqm_llc_scale.event_str) = str; + pax_close_kernel(); ret = intel_cqm_setup_rmid_cache(); @@ -25798,7 +25822,7 @@ index 653f88d..11b6b78 100644 if (!insn.opcode.got) return X86_BR_ABORT; diff --git a/arch/x86/kernel/cpu/perf_event_intel_pt.c b/arch/x86/kernel/cpu/perf_event_intel_pt.c -index c0bbd10..727ae15e 100644 +index c0bbd10..53a5dc6 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_pt.c +++ b/arch/x86/kernel/cpu/perf_event_intel_pt.c @@ -133,14 +133,10 @@ static const struct attribute_group *pt_attr_groups[] = { @@ -25839,22 +25863,22 @@ index c0bbd10..727ae15e 100644 + struct dev_ext_attribute *de_attr = &de_attrs[i]; - de_attr->attr.attr.name = pt_caps[i].name; -+ *(const char **)&de_attr->attr.attr.name = pt_caps[i].name; ++ const_cast(de_attr->attr.attr.name) = pt_caps[i].name; sysfs_attr_init(&de_attr->attr.attr); - de_attr->attr.attr.mode = S_IRUGO; - de_attr->attr.show = pt_cap_show; - de_attr->var = (void *)i; -+ *(umode_t *)&de_attr->attr.attr.mode = S_IRUGO; -+ *(void **)&de_attr->attr.show = pt_cap_show; -+ *(void **)&de_attr->var = (void *)i; ++ const_cast(de_attr->attr.attr.mode) = S_IRUGO; ++ const_cast(de_attr->attr.show) = pt_cap_show; ++ const_cast(de_attr->var) = (void *)i; attrs[i] = &de_attr->attr.attr; } - pt_cap_group.attrs = attrs; -+ *(struct attribute ***)&pt_cap_group.attrs = attrs; ++ const_cast(pt_cap_group.attrs) = attrs; + pax_close_kernel(); return 0; @@ -27813,7 +27837,7 @@ index 64341aa..b1e6632 100644 +EXPORT_SYMBOL(cpu_pgd); +#endif diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c -index be22f5a..c5d0e1f 100644 +index be22f5a..a04fa14 100644 --- a/arch/x86/kernel/i8259.c +++ b/arch/x86/kernel/i8259.c @@ -110,7 +110,7 @@ static int i8259A_irq_pending(unsigned int irq) @@ -27845,10 +27869,10 @@ index be22f5a..c5d0e1f 100644 * when acking. */ - i8259A_chip.irq_mask_ack = disable_8259A_irq; -+ *(void **)&i8259A_chip.irq_mask_ack = disable_8259A_irq; ++ const_cast(i8259A_chip.irq_mask_ack) = disable_8259A_irq; else - i8259A_chip.irq_mask_ack = mask_and_ack_8259A; -+ *(void **)&i8259A_chip.irq_mask_ack = mask_and_ack_8259A; ++ const_cast(i8259A_chip.irq_mask_ack) = mask_and_ack_8259A; + pax_close_kernel(); udelay(100); /* wait for 8259A to initialize */ @@ -29041,7 +29065,7 @@ index 6d9582e..f746287 100644 return; } diff --git a/arch/x86/kernel/paravirt-spinlocks.c b/arch/x86/kernel/paravirt-spinlocks.c -index 33ee3e0..ca43dee 100644 +index 33ee3e0..6d23e5c 100644 --- a/arch/x86/kernel/paravirt-spinlocks.c +++ b/arch/x86/kernel/paravirt-spinlocks.c @@ -23,16 +23,32 @@ bool pv_is_native_spin_unlock(void) @@ -29058,7 +29082,7 @@ index 33ee3e0..ca43dee 100644 +static void native_kick(int cpu) +{ +} -+//#else /* !CONFIG_QUEUED_SPINLOCKS */ ++#else /* !CONFIG_QUEUED_SPINLOCKS */ +static void native_unlock_kick(struct arch_spinlock *lock, __ticket_t ticket) +{ +} @@ -37439,7 +37463,7 @@ index 4e664bd..2beeaa2 100644 return NULL; diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c -index 1d2e639..d7f0e67 100644 +index 1d2e639..6473b8a 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -23,6 +23,7 @@ @@ -37467,14 +37491,14 @@ index 1d2e639..d7f0e67 100644 - model->num_virt_counters = model->num_counters; + if (!model->num_virt_counters) { + pax_open_kernel(); -+ *(unsigned int *)&model->num_virt_counters = model->num_counters; ++ const_cast(model->num_virt_counters) = model->num_counters; + pax_close_kernel(); + } mux_init(ops); diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c -index 50d86c0..7985318 100644 +index 50d86c0..b0b9ae0 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -519,9 +519,11 @@ static int op_amd_init(struct oprofile_operations *ops) @@ -37485,15 +37509,15 @@ index 50d86c0..7985318 100644 - op_amd_spec.num_controls = num_counters; - op_amd_spec.num_virt_counters = max(num_counters, NUM_VIRT_COUNTERS); + pax_open_kernel(); -+ *(unsigned int *)&op_amd_spec.num_counters = num_counters; -+ *(unsigned int *)&op_amd_spec.num_controls = num_counters; -+ *(unsigned int *)&op_amd_spec.num_virt_counters = max(num_counters, NUM_VIRT_COUNTERS); ++ const_cast(op_amd_spec.num_counters) = num_counters; ++ const_cast(op_amd_spec.num_controls) = num_counters; ++ const_cast(op_amd_spec.num_virt_counters) = max(num_counters, NUM_VIRT_COUNTERS); + pax_close_kernel(); return 0; } diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c -index d90528e..0127e2b 100644 +index d90528e..a44aa09 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -19,6 +19,7 @@ @@ -37511,8 +37535,8 @@ index d90528e..0127e2b 100644 - op_arch_perfmon_spec.num_counters = num_counters; - op_arch_perfmon_spec.num_controls = num_counters; + pax_open_kernel(); -+ *(unsigned int *)&op_arch_perfmon_spec.num_counters = num_counters; -+ *(unsigned int *)&op_arch_perfmon_spec.num_controls = num_counters; ++ const_cast(op_arch_perfmon_spec.num_counters) = num_counters; ++ const_cast(op_arch_perfmon_spec.num_controls) = num_counters; + pax_close_kernel(); } @@ -37808,7 +37832,7 @@ index 9770e55..76067ec 100644 } EXPORT_SYMBOL(pcibios_set_irq_routing); diff --git a/arch/x86/pci/vmd.c b/arch/x86/pci/vmd.c -index d57e480..20eb97a 100644 +index d57e480..fc4db30 100644 --- a/arch/x86/pci/vmd.c +++ b/arch/x86/pci/vmd.c @@ -374,7 +374,7 @@ static void vmd_teardown_dma_ops(struct vmd_dev *vmd) @@ -37816,7 +37840,7 @@ index d57e480..20eb97a 100644 do { \ if (source->fn) \ - dest->fn = vmd_##fn; \ -+ *(void **)&dest->fn = vmd_##fn; \ ++ const_cast(dest->fn) = vmd_##fn; \ } while (0) static void vmd_setup_dma_ops(struct vmd_dev *vmd) @@ -38238,20 +38262,6 @@ index 0b7a63d..dff2199 100644 trampoline_pgd[511] = init_level4_pgt[511].pgd; #endif } -diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile -index 3e75fcf..4cfefb8 100644 ---- a/arch/x86/realmode/rm/Makefile -+++ b/arch/x86/realmode/rm/Makefile -@@ -68,6 +68,9 @@ $(obj)/realmode.relocs: $(obj)/realmode.elf FORCE - - KBUILD_CFLAGS := $(LINUXINCLUDE) $(REALMODE_CFLAGS) -D_SETUP -D_WAKEUP \ - -I$(srctree)/arch/x86/boot -+ifdef CONSTIFY_PLUGIN -+KBUILD_CFLAGS += -fplugin-arg-constify_plugin-no-constify -+endif - KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ - GCOV_PROFILE := n - UBSAN_SANITIZE := n diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S index a28221d..93c40f1 100644 --- a/arch/x86/realmode/rm/header.S @@ -39659,7 +39669,7 @@ index b719ab3..371e2a6 100644 enum acpi_battery_files { info_tag = 0, diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c -index a83e3c6..c3d617f 100644 +index a83e3c6..7f4a90b 100644 --- a/drivers/acpi/bgrt.c +++ b/drivers/acpi/bgrt.c @@ -86,8 +86,10 @@ static int __init bgrt_init(void) @@ -39669,8 +39679,8 @@ index a83e3c6..c3d617f 100644 - bin_attr_image.private = bgrt_image; - bin_attr_image.size = bgrt_image_size; + pax_open_kernel(); -+ *(void **)&bin_attr_image.private = bgrt_image; -+ *(size_t *)&bin_attr_image.size = bgrt_image_size; ++ const_cast(bin_attr_image.private) = bgrt_image; ++ const_cast(bin_attr_image.size) = bgrt_image_size; + pax_close_kernel(); bgrt_kobj = kobject_create_and_add("bgrt", acpi_kobj); @@ -39966,7 +39976,7 @@ index 7d00b7a..d5fd80d 100644 int ret; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c -index 55e257c..28b9a25 100644 +index 55e257c..554c697 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -103,7 +103,7 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev); @@ -40009,7 +40019,7 @@ index 55e257c..28b9a25 100644 *pp = NULL; - ops->inherits = NULL; -+ *(struct ata_port_operations **)&ops->inherits = NULL; ++ const_cast(ops->inherits) = NULL; + pax_close_kernel(); spin_unlock(&lock); @@ -40051,7 +40061,7 @@ index f840ca1..edd6ef3 100644 extern int libata_fua; extern int libata_noacpi; diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c -index 80fe0f6..8c0fa3f 100644 +index 80fe0f6..d95a192 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -864,7 +864,9 @@ static int arasan_cf_probe(struct platform_device *pdev) @@ -40060,7 +40070,7 @@ index 80fe0f6..8c0fa3f 100644 if (quirk & CF_BROKEN_PIO) { - ap->ops->set_piomode = NULL; + pax_open_kernel(); -+ *(void **)&ap->ops->set_piomode = NULL; ++ const_cast(ap->ops->set_piomode) = NULL; + pax_close_kernel(); ap->pio_mask = 0; } @@ -41138,7 +41148,7 @@ index 560751b..3a4847a 100644 static ssize_t show_node_state(struct device *dev, struct device_attribute *attr, char *buf) diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c -index 279e539..b87ed03 100644 +index 279e539..4c9d7fb 100644 --- a/drivers/base/platform-msi.c +++ b/drivers/base/platform-msi.c @@ -24,6 +24,8 @@ @@ -41157,10 +41167,10 @@ index 279e539..b87ed03 100644 + pax_open_kernel(); if (ops->msi_init == NULL) - ops->msi_init = platform_msi_init; -+ *(void **)&ops->msi_init = platform_msi_init; ++ const_cast(ops->msi_init) = platform_msi_init; if (ops->set_desc == NULL) - ops->set_desc = platform_msi_set_desc; -+ *(void **)&ops->set_desc = platform_msi_set_desc; ++ const_cast(ops->set_desc) = platform_msi_set_desc; + pax_close_kernel(); } @@ -41172,25 +41182,25 @@ index 279e539..b87ed03 100644 + pax_open_kernel(); if (!chip->irq_mask) - chip->irq_mask = irq_chip_mask_parent; -+ *(void **)&chip->irq_mask = irq_chip_mask_parent; ++ const_cast(chip->irq_mask) = irq_chip_mask_parent; if (!chip->irq_unmask) - chip->irq_unmask = irq_chip_unmask_parent; -+ *(void **)&chip->irq_unmask = irq_chip_unmask_parent; ++ const_cast(chip->irq_unmask) = irq_chip_unmask_parent; if (!chip->irq_eoi) - chip->irq_eoi = irq_chip_eoi_parent; -+ *(void **)&chip->irq_eoi = irq_chip_eoi_parent; ++ const_cast(chip->irq_eoi) = irq_chip_eoi_parent; if (!chip->irq_set_affinity) - chip->irq_set_affinity = msi_domain_set_affinity; -+ *(void **)&chip->irq_set_affinity = msi_domain_set_affinity; ++ const_cast(chip->irq_set_affinity) = msi_domain_set_affinity; if (!chip->irq_write_msi_msg) - chip->irq_write_msi_msg = platform_msi_write_msg; -+ *(void **)&chip->irq_write_msi_msg = platform_msi_write_msg; ++ const_cast(chip->irq_write_msi_msg) = platform_msi_write_msg; + pax_close_kernel(); } static void platform_msi_free_descs(struct device *dev, int base, int nvec) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c -index 0caf92a..cff4879 100644 +index 0caf92a..62c184c 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1804,8 +1804,10 @@ int genpd_dev_pm_attach(struct device *dev) @@ -41200,8 +41210,8 @@ index 0caf92a..cff4879 100644 - dev->pm_domain->detach = genpd_dev_pm_detach; - dev->pm_domain->sync = genpd_dev_pm_sync; + pax_open_kernel(); -+ *(void **)&dev->pm_domain->detach = genpd_dev_pm_detach; -+ *(void **)&dev->pm_domain->sync = genpd_dev_pm_sync; ++ const_cast(dev->pm_domain->detach) = genpd_dev_pm_detach; ++ const_cast(dev->pm_domain->sync) = genpd_dev_pm_sync; + pax_close_kernel(); mutex_lock(&pd->lock); @@ -42349,7 +42359,7 @@ index 24a652f..2dffae6 100644 int err; diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c -index 577cc4b..bfe0c2d 100644 +index 577cc4b..129a13e 100644 --- a/drivers/bus/arm-cci.c +++ b/drivers/bus/arm-cci.c @@ -1249,16 +1249,22 @@ static int cci_pmu_init_attrs(struct cci_pmu *cci_pmu, struct platform_device *p @@ -42358,7 +42368,7 @@ index 577cc4b..bfe0c2d 100644 return -ENOMEM; - pmu_event_attr_group.attrs = attrs; + pax_open_kernel(); -+ *(struct attribute ***)&pmu_event_attr_group.attrs = attrs; ++ const_cast(pmu_event_attr_group.attrs) = attrs; + pax_close_kernel(); } if (model->nformat_attrs) { @@ -42368,18 +42378,18 @@ index 577cc4b..bfe0c2d 100644 return -ENOMEM; - pmu_format_attr_group.attrs = attrs; + pax_open_kernel(); -+ *(struct attribute ***)&pmu_format_attr_group.attrs = attrs; ++ const_cast(pmu_format_attr_group.attrs) = attrs; + pax_close_kernel(); } - pmu_cpumask_attr.var = cci_pmu; + pax_open_kernel(); -+ *(void **)&pmu_cpumask_attr.var = cci_pmu; ++ const_cast(pmu_cpumask_attr.var) = cci_pmu; + pax_close_kernel(); return 0; } diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c -index 1b257ea..ea76b22 100644 +index 1b257ea..2280898 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -610,7 +610,6 @@ int register_cdrom(struct cdrom_device_info *cdi) @@ -42398,7 +42408,7 @@ index 1b257ea..ea76b22 100644 - cdo->generic_packet = cdrom_dummy_generic_packet; + if (!cdo->generic_packet) { + pax_open_kernel(); -+ *(void **)&cdo->generic_packet = cdrom_dummy_generic_packet; ++ const_cast(cdo->generic_packet) = cdrom_dummy_generic_packet; + pax_close_kernel(); + } @@ -43150,7 +43160,7 @@ index aa872d2..afeae37 100644 /** * struct samsung_clk_reg_dump: register dump of clock controller registers. diff --git a/drivers/clk/socfpga/clk-gate.c b/drivers/clk/socfpga/clk-gate.c -index aa7a6e6..e67210d 100644 +index aa7a6e6..1e9b426 100644 --- a/drivers/clk/socfpga/clk-gate.c +++ b/drivers/clk/socfpga/clk-gate.c @@ -21,6 +21,7 @@ @@ -43177,14 +43187,14 @@ index aa7a6e6..e67210d 100644 - gateclk_ops.enable = clk_gate_ops.enable; - gateclk_ops.disable = clk_gate_ops.disable; + pax_open_kernel(); -+ *(void **)&gateclk_ops.enable = clk_gate_ops.enable; -+ *(void **)&gateclk_ops.disable = clk_gate_ops.disable; ++ const_cast(gateclk_ops.enable) = clk_gate_ops.enable; ++ const_cast(gateclk_ops.disable) = clk_gate_ops.disable; + pax_close_kernel(); } rc = of_property_read_u32(node, "fixed-divider", &fixed_div); diff --git a/drivers/clk/socfpga/clk-pll.c b/drivers/clk/socfpga/clk-pll.c -index c7f4631..463813a 100644 +index c7f4631..8d1b7d0 100644 --- a/drivers/clk/socfpga/clk-pll.c +++ b/drivers/clk/socfpga/clk-pll.c @@ -20,6 +20,7 @@ @@ -43211,14 +43221,14 @@ index c7f4631..463813a 100644 - clk_pll_ops.enable = clk_gate_ops.enable; - clk_pll_ops.disable = clk_gate_ops.disable; + pax_open_kernel(); -+ *(void **)&clk_pll_ops.enable = clk_gate_ops.enable; -+ *(void **)&clk_pll_ops.disable = clk_gate_ops.disable; ++ const_cast(clk_pll_ops.enable) = clk_gate_ops.enable; ++ const_cast(clk_pll_ops.disable) = clk_gate_ops.disable; + pax_close_kernel(); clk = clk_register(NULL, &pll_clk->hw.hw); if (WARN_ON(IS_ERR(clk))) { diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c -index b5bcd77..0f7bd99 100644 +index b5bcd77..fc230cb 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -25,6 +25,8 @@ @@ -43237,14 +43247,14 @@ index b5bcd77..0f7bd99 100644 - ops->clk_readl = clk_memmap_readl; - ops->clk_writel = clk_memmap_writel; + pax_open_kernel(); -+ *(void **)&ops->clk_readl = clk_memmap_readl; -+ *(void **)&ops->clk_writel = clk_memmap_writel; ++ const_cast(ops->clk_readl) = clk_memmap_readl; ++ const_cast(ops->clk_writel) = clk_memmap_writel; + pax_close_kernel(); return 0; } diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c -index 51eef87..d944fa7 100644 +index 51eef87..f530cf9 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -682,8 +682,11 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) @@ -43255,7 +43265,7 @@ index 51eef87..d944fa7 100644 - acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; + if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) { + pax_open_kernel(); -+ *(u8 *)&acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; ++ const_cast(acpi_cpufreq_driver.flags) |= CPUFREQ_CONST_LOOPS; + pax_close_kernel(); + } @@ -43267,7 +43277,7 @@ index 51eef87..d944fa7 100644 case ACPI_ADR_SPACE_FIXED_HARDWARE: - acpi_cpufreq_driver.get = get_cur_freq_on_cpu; + pax_open_kernel(); -+ *(void **)&acpi_cpufreq_driver.get = get_cur_freq_on_cpu; ++ const_cast(acpi_cpufreq_driver.get) = get_cur_freq_on_cpu; + pax_close_kernel(); break; default: @@ -43279,14 +43289,14 @@ index 51eef87..d944fa7 100644 - acpi_cpufreq_driver.set_boost = set_boost; - acpi_cpufreq_driver.boost_enabled = boost_state(0); + pax_open_kernel(); -+ *(void **)&acpi_cpufreq_driver.set_boost = set_boost; -+ *(bool *)&acpi_cpufreq_driver.boost_enabled = boost_state(0); ++ const_cast(acpi_cpufreq_driver.set_boost) = set_boost; ++ const_cast(acpi_cpufreq_driver.boost_enabled) = boost_state(0); + pax_close_kernel(); cpu_notifier_register_begin(); diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c -index 0ca74d0..15705fb 100644 +index 0ca74d0..1a0d302 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -461,7 +461,9 @@ static int dt_cpufreq_probe(struct platform_device *pdev) @@ -43295,13 +43305,13 @@ index 0ca74d0..15705fb 100644 - dt_cpufreq_driver.driver_data = dev_get_platdata(&pdev->dev); + pax_open_kernel(); -+ *(void **)&dt_cpufreq_driver.driver_data = dev_get_platdata(&pdev->dev); ++ const_cast(dt_cpufreq_driver.driver_data) = dev_get_platdata(&pdev->dev); + pax_close_kernel(); ret = cpufreq_register_driver(&dt_cpufreq_driver); if (ret) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c -index e979ec7..a024e16 100644 +index e979ec7..a76375c 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -474,12 +474,12 @@ EXPORT_SYMBOL_GPL(cpufreq_freq_transition_end); @@ -43343,7 +43353,7 @@ index e979ec7..a024e16 100644 write_lock_irqsave(&cpufreq_driver_lock, flags); - cpufreq_driver->boost_enabled = state; + pax_open_kernel(); -+ *(bool *)&cpufreq_driver->boost_enabled = state; ++ const_cast(cpufreq_driver->boost_enabled) = state; + pax_close_kernel(); write_unlock_irqrestore(&cpufreq_driver_lock, flags); @@ -43352,7 +43362,7 @@ index e979ec7..a024e16 100644 write_lock_irqsave(&cpufreq_driver_lock, flags); - cpufreq_driver->boost_enabled = !state; + pax_open_kernel(); -+ *(bool *)&cpufreq_driver->boost_enabled = !state; ++ const_cast(cpufreq_driver->boost_enabled) = !state; + pax_close_kernel(); write_unlock_irqrestore(&cpufreq_driver_lock, flags); @@ -43363,7 +43373,7 @@ index e979ec7..a024e16 100644 - cpufreq_driver->set_boost = cpufreq_boost_set_sw; + pax_open_kernel(); -+ *(void **)&cpufreq_driver->set_boost = cpufreq_boost_set_sw; ++ const_cast(cpufreq_driver->set_boost) = cpufreq_boost_set_sw; + pax_close_kernel(); /* This will get removed on driver unregister */ @@ -43376,7 +43386,7 @@ index e979ec7..a024e16 100644 - driver_data->flags |= CPUFREQ_CONST_LOOPS; + if (driver_data->setpolicy) { + pax_open_kernel(); -+ *(u8 *)&driver_data->flags |= CPUFREQ_CONST_LOOPS; ++ const_cast(driver_data->flags) |= CPUFREQ_CONST_LOOPS; + pax_close_kernel(); + } @@ -43445,7 +43455,7 @@ index 91e767a0..3b40724 100644 struct dbs_data *dbs_data = _gov##_dbs_cdata.gdbs_data; \ return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \ diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c -index eae5107..26e7a39 100644 +index eae5107..3dd6408 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -534,7 +534,7 @@ static void od_exit(struct dbs_data *dbs_data, bool notify) @@ -43463,7 +43473,7 @@ index eae5107..26e7a39 100644 { - od_ops.powersave_bias_target = f; + pax_open_kernel(); -+ *(void **)&od_ops.powersave_bias_target = f; ++ const_cast(od_ops.powersave_bias_target) = f; + pax_close_kernel(); od_set_powersave_bias(powersave_bias); } @@ -43473,7 +43483,7 @@ index eae5107..26e7a39 100644 { - od_ops.powersave_bias_target = generic_powersave_bias_target; + pax_open_kernel(); -+ *(void **)&od_ops.powersave_bias_target = generic_powersave_bias_target; ++ const_cast(od_ops.powersave_bias_target) = generic_powersave_bias_target; + pax_close_kernel(); od_set_powersave_bias(0); } @@ -43634,7 +43644,7 @@ index e895123..05de99b 100644 #if IS_ENABLED(CONFIG_ACPI) diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c -index 5dd95da..abc3837 100644 +index 5dd95da..ac41e5e 100644 --- a/drivers/cpufreq/p4-clockmod.c +++ b/drivers/cpufreq/p4-clockmod.c @@ -134,10 +134,14 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) @@ -43643,13 +43653,13 @@ index 5dd95da..abc3837 100644 case 0x1C: /* Atom */ - p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; + pax_open_kernel(); -+ *(u8 *)&p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; ++ const_cast(p4clockmod_driver.flags) |= CPUFREQ_CONST_LOOPS; + pax_close_kernel(); return speedstep_get_frequency(SPEEDSTEP_CPU_PCORE); case 0x0D: /* Pentium M (Dothan) */ - p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; + pax_open_kernel(); -+ *(u8 *)&p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; ++ const_cast(p4clockmod_driver.flags) |= CPUFREQ_CONST_LOOPS; + pax_close_kernel(); /* fall through */ case 0x09: /* Pentium M (Banias) */ @@ -43660,7 +43670,7 @@ index 5dd95da..abc3837 100644 * throttling is active or not. */ - p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; + pax_open_kernel(); -+ *(u8 *)&p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; ++ const_cast(p4clockmod_driver.flags) |= CPUFREQ_CONST_LOOPS; + pax_close_kernel(); if (speedstep_detect_processor() == SPEEDSTEP_CPU_P4M) { @@ -43776,7 +43786,7 @@ index 9bb42ba..b01b4a2 100644 MODULE_AUTHOR("David S. Miller "); diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c -index 7d4a315..21bb886 100644 +index 7d4a315..ce41fb3 100644 --- a/drivers/cpufreq/speedstep-centrino.c +++ b/drivers/cpufreq/speedstep-centrino.c @@ -351,8 +351,11 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) @@ -43787,7 +43797,7 @@ index 7d4a315..21bb886 100644 - centrino_driver.flags |= CPUFREQ_CONST_LOOPS; + if (cpu_has(cpu, X86_FEATURE_CONSTANT_TSC)) { + pax_open_kernel(); -+ *(u8 *)¢rino_driver.flags |= CPUFREQ_CONST_LOOPS; ++ const_cast(centrino_driver.flags) |= CPUFREQ_CONST_LOOPS; + pax_close_kernel(); + } @@ -44575,7 +44585,7 @@ index 94a58a0..5b8dd03 100644 }; diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c -index 88bebe1..c7b636f 100644 +index 88bebe1..e599fad 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -712,14 +712,18 @@ static int __init dmi_init(void) @@ -44585,8 +44595,8 @@ index 88bebe1..c7b636f 100644 - bin_attr_smbios_entry_point.size = smbios_entry_point_size; - bin_attr_smbios_entry_point.private = smbios_entry_point; + pax_open_kernel(); -+ *(size_t *)&bin_attr_smbios_entry_point.size = smbios_entry_point_size; -+ *(void **)&bin_attr_smbios_entry_point.private = smbios_entry_point; ++ const_cast(bin_attr_smbios_entry_point.size) = smbios_entry_point_size; ++ const_cast(bin_attr_smbios_entry_point.private) = smbios_entry_point; + pax_close_kernel(); ret = sysfs_create_bin_file(tables_kobj, &bin_attr_smbios_entry_point); if (ret) @@ -44595,8 +44605,8 @@ index 88bebe1..c7b636f 100644 - bin_attr_DMI.size = dmi_len; - bin_attr_DMI.private = dmi_table; + pax_open_kernel(); -+ *(size_t *)&bin_attr_DMI.size = dmi_len; -+ *(void **)&bin_attr_DMI.private = dmi_table; ++ const_cast(bin_attr_DMI.size) = dmi_len; ++ const_cast(bin_attr_DMI.private) = dmi_table; + pax_close_kernel(); ret = sysfs_create_bin_file(tables_kobj, &bin_attr_DMI); if (!ret) @@ -44623,7 +44633,7 @@ index d425374..1da1716 100644 EXPORT_SYMBOL_GPL(cper_next_record_id); diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c -index c51f3b2..d1cc54e 100644 +index c51f3b2..54523fd 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -176,15 +176,17 @@ static struct attribute_group efi_subsys_attr_group = { @@ -44641,11 +44651,11 @@ index c51f3b2..d1cc54e 100644 - generic_ops.get_next_variable = efi.get_next_variable; - generic_ops.query_variable_store = efi_query_variable_store; + pax_open_kernel(); -+ *(void **)&generic_ops.get_variable = efi.get_variable; -+ *(void **)&generic_ops.set_variable = efi.set_variable; -+ *(void **)&generic_ops.set_variable_nonblocking = efi.set_variable_nonblocking; -+ *(void **)&generic_ops.get_next_variable = efi.get_next_variable; -+ *(void **)&generic_ops.query_variable_store = efi_query_variable_store; ++ const_cast(generic_ops.get_variable) = efi.get_variable; ++ const_cast(generic_ops.set_variable) = efi.set_variable; ++ const_cast(generic_ops.set_variable_nonblocking) = efi.set_variable_nonblocking; ++ const_cast(generic_ops.get_next_variable) = efi.get_next_variable; ++ const_cast(generic_ops.query_variable_store) = efi_query_variable_store; + pax_close_kernel(); return efivars_register(&generic_efivars, &generic_ops, efi_kobj); @@ -44690,7 +44700,7 @@ index f1ab05e..ab51228 100644 .ident = "Google Board", .matches = { diff --git a/drivers/firmware/google/memconsole.c b/drivers/firmware/google/memconsole.c -index 2f569aa..26e4f39 100644 +index 2f569aa..3af5497 100644 --- a/drivers/firmware/google/memconsole.c +++ b/drivers/firmware/google/memconsole.c @@ -136,7 +136,7 @@ static bool __init found_memconsole(void) @@ -44708,7 +44718,7 @@ index 2f569aa..26e4f39 100644 - memconsole_bin_attr.size = memconsole_length; + pax_open_kernel(); -+ *(size_t *)&memconsole_bin_attr.size = memconsole_length; ++ const_cast(memconsole_bin_attr.size) = memconsole_length; + pax_close_kernel(); + return sysfs_create_bin_file(firmware_kobj, &memconsole_bin_attr); @@ -44840,7 +44850,7 @@ index ac8deb0..f3caa10 100644 return -EINVAL; } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c -index 5c1ba87..ab4a059 100644 +index 5c1ba87..f711915 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -669,8 +669,10 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) @@ -44850,8 +44860,8 @@ index 5c1ba87..ab4a059 100644 - gpiochip->irqchip->irq_request_resources = NULL; - gpiochip->irqchip->irq_release_resources = NULL; + pax_open_kernel(); -+ *(void **)&gpiochip->irqchip->irq_request_resources = NULL; -+ *(void **)&gpiochip->irqchip->irq_release_resources = NULL; ++ const_cast(gpiochip->irqchip->irq_request_resources) = NULL; ++ const_cast(gpiochip->irqchip->irq_release_resources) = NULL; + pax_close_kernel(); gpiochip->irqchip = NULL; } @@ -44863,8 +44873,8 @@ index 5c1ba87..ab4a059 100644 - irqchip->irq_request_resources = gpiochip_irq_reqres; - irqchip->irq_release_resources = gpiochip_irq_relres; + pax_open_kernel(); -+ *(void **)&irqchip->irq_request_resources = gpiochip_irq_reqres; -+ *(void **)&irqchip->irq_release_resources = gpiochip_irq_relres; ++ const_cast(irqchip->irq_request_resources) = gpiochip_irq_reqres; ++ const_cast(irqchip->irq_release_resources) = gpiochip_irq_relres; + pax_close_kernel(); } @@ -45050,7 +45060,7 @@ index 51bfc11..4d4112a 100644 static const struct vga_switcheroo_client_ops amdgpu_switcheroo_ops = { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c -index 9ef1db8..bfd5d78 100644 +index 9ef1db8..5eec19b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -495,7 +495,7 @@ static struct drm_driver kms_driver = { @@ -45082,7 +45092,7 @@ index 9ef1db8..bfd5d78 100644 - driver->num_ioctls = amdgpu_max_kms_ioctl; + + pax_open_kernel(); -+ *(int *)&kms_driver.num_ioctls = amdgpu_max_kms_ioctl; ++ const_cast(kms_driver.num_ioctls) = amdgpu_max_kms_ioctl; + pax_close_kernel(); + amdgpu_register_atpx_handler(); @@ -46288,7 +46298,7 @@ index d918567..6cfd904 100644 /** * Determine if the device really is AGP or not. diff --git a/drivers/gpu/drm/i810/i810_drv.c b/drivers/gpu/drm/i810/i810_drv.c -index 44f4a13..0063c1b 100644 +index 44f4a13..af9f6f5 100644 --- a/drivers/gpu/drm/i810/i810_drv.c +++ b/drivers/gpu/drm/i810/i810_drv.c @@ -87,7 +87,11 @@ static int __init i810_init(void) @@ -46298,7 +46308,7 @@ index 44f4a13..0063c1b 100644 - driver.num_ioctls = i810_max_ioctl; + + pax_open_kernel(); -+ *(int *)&driver.num_ioctls = i810_max_ioctl; ++ const_cast(driver.num_ioctls) = i810_max_ioctl; + pax_close_kernel(); + return drm_pci_init(&driver, &i810_pci_driver); @@ -46547,7 +46557,7 @@ index 97f3a56..32c712e 100644 ret = drm_ioctl(filp, cmd, arg); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c -index fa8afa7..0bac957 100644 +index fa8afa7..7375300 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -4490,14 +4490,15 @@ void intel_irq_init(struct drm_i915_private *dev_priv) @@ -46558,14 +46568,14 @@ index fa8afa7..0bac957 100644 if (IS_GEN2(dev_priv)) { dev->max_vblank_count = 0; - dev->driver->get_vblank_counter = i8xx_get_vblank_counter; -+ *(void **)&dev->driver->get_vblank_counter = i8xx_get_vblank_counter; ++ const_cast(dev->driver->get_vblank_counter) = i8xx_get_vblank_counter; } else if (IS_G4X(dev_priv) || INTEL_INFO(dev_priv)->gen >= 5) { dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */ - dev->driver->get_vblank_counter = g4x_get_vblank_counter; -+ *(void **)&dev->driver->get_vblank_counter = g4x_get_vblank_counter; ++ const_cast(dev->driver->get_vblank_counter) = g4x_get_vblank_counter; } else { - dev->driver->get_vblank_counter = i915_get_vblank_counter; -+ *(void **)&dev->driver->get_vblank_counter = i915_get_vblank_counter; ++ const_cast(dev->driver->get_vblank_counter) = i915_get_vblank_counter; dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ } @@ -46575,8 +46585,8 @@ index fa8afa7..0bac957 100644 - dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp; - dev->driver->get_scanout_position = i915_get_crtc_scanoutpos; -+ *(void **)&dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp; -+ *(void **)&dev->driver->get_scanout_position = i915_get_crtc_scanoutpos; ++ const_cast(dev->driver->get_vblank_timestamp) = i915_get_vblank_timestamp; ++ const_cast(dev->driver->get_scanout_position) = i915_get_crtc_scanoutpos; if (IS_CHERRYVIEW(dev_priv)) { - dev->driver->irq_handler = cherryview_irq_handler; @@ -46585,12 +46595,12 @@ index fa8afa7..0bac957 100644 - dev->driver->irq_uninstall = cherryview_irq_uninstall; - dev->driver->enable_vblank = valleyview_enable_vblank; - dev->driver->disable_vblank = valleyview_disable_vblank; -+ *(void **)&dev->driver->irq_handler = cherryview_irq_handler; -+ *(void **)&dev->driver->irq_preinstall = cherryview_irq_preinstall; -+ *(void **)&dev->driver->irq_postinstall = cherryview_irq_postinstall; -+ *(void **)&dev->driver->irq_uninstall = cherryview_irq_uninstall; -+ *(void **)&dev->driver->enable_vblank = valleyview_enable_vblank; -+ *(void **)&dev->driver->disable_vblank = valleyview_disable_vblank; ++ const_cast(dev->driver->irq_handler) = cherryview_irq_handler; ++ const_cast(dev->driver->irq_preinstall) = cherryview_irq_preinstall; ++ const_cast(dev->driver->irq_postinstall) = cherryview_irq_postinstall; ++ const_cast(dev->driver->irq_uninstall) = cherryview_irq_uninstall; ++ const_cast(dev->driver->enable_vblank) = valleyview_enable_vblank; ++ const_cast(dev->driver->disable_vblank) = valleyview_disable_vblank; dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; } else if (IS_VALLEYVIEW(dev_priv)) { - dev->driver->irq_handler = valleyview_irq_handler; @@ -46599,12 +46609,12 @@ index fa8afa7..0bac957 100644 - dev->driver->irq_uninstall = valleyview_irq_uninstall; - dev->driver->enable_vblank = valleyview_enable_vblank; - dev->driver->disable_vblank = valleyview_disable_vblank; -+ *(void **)&dev->driver->irq_handler = valleyview_irq_handler; -+ *(void **)&dev->driver->irq_preinstall = valleyview_irq_preinstall; -+ *(void **)&dev->driver->irq_postinstall = valleyview_irq_postinstall; -+ *(void **)&dev->driver->irq_uninstall = valleyview_irq_uninstall; -+ *(void **)&dev->driver->enable_vblank = valleyview_enable_vblank; -+ *(void **)&dev->driver->disable_vblank = valleyview_disable_vblank; ++ const_cast(dev->driver->irq_handler) = valleyview_irq_handler; ++ const_cast(dev->driver->irq_preinstall) = valleyview_irq_preinstall; ++ const_cast(dev->driver->irq_postinstall) = valleyview_irq_postinstall; ++ const_cast(dev->driver->irq_uninstall) = valleyview_irq_uninstall; ++ const_cast(dev->driver->enable_vblank) = valleyview_enable_vblank; ++ const_cast(dev->driver->disable_vblank) = valleyview_disable_vblank; dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; } else if (INTEL_INFO(dev_priv)->gen >= 8) { - dev->driver->irq_handler = gen8_irq_handler; @@ -46613,12 +46623,12 @@ index fa8afa7..0bac957 100644 - dev->driver->irq_uninstall = gen8_irq_uninstall; - dev->driver->enable_vblank = gen8_enable_vblank; - dev->driver->disable_vblank = gen8_disable_vblank; -+ *(void **)&dev->driver->irq_handler = gen8_irq_handler; -+ *(void **)&dev->driver->irq_preinstall = gen8_irq_reset; -+ *(void **)&dev->driver->irq_postinstall = gen8_irq_postinstall; -+ *(void **)&dev->driver->irq_uninstall = gen8_irq_uninstall; -+ *(void **)&dev->driver->enable_vblank = gen8_enable_vblank; -+ *(void **)&dev->driver->disable_vblank = gen8_disable_vblank; ++ const_cast(dev->driver->irq_handler) = gen8_irq_handler; ++ const_cast(dev->driver->irq_preinstall) = gen8_irq_reset; ++ const_cast(dev->driver->irq_postinstall) = gen8_irq_postinstall; ++ const_cast(dev->driver->irq_uninstall) = gen8_irq_uninstall; ++ const_cast(dev->driver->enable_vblank) = gen8_enable_vblank; ++ const_cast(dev->driver->disable_vblank) = gen8_disable_vblank; if (IS_BROXTON(dev)) dev_priv->display.hpd_irq_setup = bxt_hpd_irq_setup; else if (HAS_PCH_SPT(dev)) @@ -46632,12 +46642,12 @@ index fa8afa7..0bac957 100644 - dev->driver->irq_uninstall = ironlake_irq_uninstall; - dev->driver->enable_vblank = ironlake_enable_vblank; - dev->driver->disable_vblank = ironlake_disable_vblank; -+ *(void **)&dev->driver->irq_handler = ironlake_irq_handler; -+ *(void **)&dev->driver->irq_preinstall = ironlake_irq_reset; -+ *(void **)&dev->driver->irq_postinstall = ironlake_irq_postinstall; -+ *(void **)&dev->driver->irq_uninstall = ironlake_irq_uninstall; -+ *(void **)&dev->driver->enable_vblank = ironlake_enable_vblank; -+ *(void **)&dev->driver->disable_vblank = ironlake_disable_vblank; ++ const_cast(dev->driver->irq_handler) = ironlake_irq_handler; ++ const_cast(dev->driver->irq_preinstall) = ironlake_irq_reset; ++ const_cast(dev->driver->irq_postinstall) = ironlake_irq_postinstall; ++ const_cast(dev->driver->irq_uninstall) = ironlake_irq_uninstall; ++ const_cast(dev->driver->enable_vblank) = ironlake_enable_vblank; ++ const_cast(dev->driver->disable_vblank) = ironlake_disable_vblank; dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup; } else { if (INTEL_INFO(dev_priv)->gen == 2) { @@ -46645,42 +46655,42 @@ index fa8afa7..0bac957 100644 - dev->driver->irq_postinstall = i8xx_irq_postinstall; - dev->driver->irq_handler = i8xx_irq_handler; - dev->driver->irq_uninstall = i8xx_irq_uninstall; -+ *(void **)&dev->driver->irq_preinstall = i8xx_irq_preinstall; -+ *(void **)&dev->driver->irq_postinstall = i8xx_irq_postinstall; -+ *(void **)&dev->driver->irq_handler = i8xx_irq_handler; -+ *(void **)&dev->driver->irq_uninstall = i8xx_irq_uninstall; ++ const_cast(dev->driver->irq_preinstall) = i8xx_irq_preinstall; ++ const_cast(dev->driver->irq_postinstall) = i8xx_irq_postinstall; ++ const_cast(dev->driver->irq_handler) = i8xx_irq_handler; ++ const_cast(dev->driver->irq_uninstall) = i8xx_irq_uninstall; } else if (INTEL_INFO(dev_priv)->gen == 3) { - dev->driver->irq_preinstall = i915_irq_preinstall; - dev->driver->irq_postinstall = i915_irq_postinstall; - dev->driver->irq_uninstall = i915_irq_uninstall; - dev->driver->irq_handler = i915_irq_handler; -+ *(void **)&dev->driver->irq_preinstall = i915_irq_preinstall; -+ *(void **)&dev->driver->irq_postinstall = i915_irq_postinstall; -+ *(void **)&dev->driver->irq_uninstall = i915_irq_uninstall; -+ *(void **)&dev->driver->irq_handler = i915_irq_handler; ++ const_cast(dev->driver->irq_preinstall) = i915_irq_preinstall; ++ const_cast(dev->driver->irq_postinstall) = i915_irq_postinstall; ++ const_cast(dev->driver->irq_uninstall) = i915_irq_uninstall; ++ const_cast(dev->driver->irq_handler) = i915_irq_handler; } else { - dev->driver->irq_preinstall = i965_irq_preinstall; - dev->driver->irq_postinstall = i965_irq_postinstall; - dev->driver->irq_uninstall = i965_irq_uninstall; - dev->driver->irq_handler = i965_irq_handler; -+ *(void **)&dev->driver->irq_preinstall = i965_irq_preinstall; -+ *(void **)&dev->driver->irq_postinstall = i965_irq_postinstall; -+ *(void **)&dev->driver->irq_uninstall = i965_irq_uninstall; -+ *(void **)&dev->driver->irq_handler = i965_irq_handler; ++ const_cast(dev->driver->irq_preinstall) = i965_irq_preinstall; ++ const_cast(dev->driver->irq_postinstall) = i965_irq_postinstall; ++ const_cast(dev->driver->irq_uninstall) = i965_irq_uninstall; ++ const_cast(dev->driver->irq_handler) = i965_irq_handler; } if (I915_HAS_HOTPLUG(dev_priv)) dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; - dev->driver->enable_vblank = i915_enable_vblank; - dev->driver->disable_vblank = i915_disable_vblank; -+ *(void **)&dev->driver->enable_vblank = i915_enable_vblank; -+ *(void **)&dev->driver->disable_vblank = i915_disable_vblank; ++ const_cast(dev->driver->enable_vblank) = i915_enable_vblank; ++ const_cast(dev->driver->disable_vblank) = i915_disable_vblank; } + pax_close_kernel(); } /** diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c -index 39b00b9..aa9fc8a 100644 +index 39b00b9..244538d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15111,13 +15111,13 @@ struct intel_quirk { @@ -46693,8 +46703,9 @@ index 39b00b9..aa9fc8a 100644 /* For systems that don't have a meaningful PCI subdevice/subvendor ID */ struct intel_dmi_quirk { void (*hook)(struct drm_device *dev); - const struct dmi_system_id (*dmi_id_list)[]; +- const struct dmi_system_id (*dmi_id_list)[]; -}; ++ const struct dmi_system_id *dmi_id_list; +} __do_const; static int intel_dmi_reverse_brightness(const struct dmi_system_id *id) @@ -46726,10 +46737,19 @@ index 39b00b9..aa9fc8a 100644 + +static const struct intel_dmi_quirk intel_dmi_quirks[] = { + { -+ .dmi_id_list = &intel_dmi_quirks_table, ++ .dmi_id_list = intel_dmi_quirks_table, .hook = quirk_invert_brightness, }, }; +@@ -15219,7 +15221,7 @@ static void intel_init_quirks(struct drm_device *dev) + q->hook(dev); + } + for (i = 0; i < ARRAY_SIZE(intel_dmi_quirks); i++) { +- if (dmi_check_system(*intel_dmi_quirks[i].dmi_id_list) != 0) ++ if (dmi_check_system(intel_dmi_quirks[i].dmi_id_list) != 0) + intel_dmi_quirks[i].hook(dev); + } + } diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 2f57d79..7152e6e 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c @@ -46744,7 +46764,7 @@ index 2f57d79..7152e6e 100644 imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL); diff --git a/drivers/gpu/drm/mga/mga_drv.c b/drivers/gpu/drm/mga/mga_drv.c -index 5e2f131..d227dbc 100644 +index 5e2f131..c134c7c 100644 --- a/drivers/gpu/drm/mga/mga_drv.c +++ b/drivers/gpu/drm/mga/mga_drv.c @@ -92,7 +92,10 @@ static struct pci_driver mga_pci_driver = { @@ -46753,7 +46773,7 @@ index 5e2f131..d227dbc 100644 { - driver.num_ioctls = mga_max_ioctl; + pax_open_kernel(); -+ *(int *)&driver.num_ioctls = mga_max_ioctl; ++ const_cast(driver.num_ioctls) = mga_max_ioctl; + pax_close_kernel(); + return drm_pci_init(&driver, &mga_pci_driver); @@ -47140,7 +47160,7 @@ index fe4c222..48b7b75 100644 omap_irq.o \ omap_debugfs.o \ diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c -index ef5b902..47cf7f5 100644 +index ef5b902..2ae011b 100644 --- a/drivers/gpu/drm/omapdrm/dss/display.c +++ b/drivers/gpu/drm/omapdrm/dss/display.c @@ -161,12 +161,14 @@ int omapdss_register_display(struct omap_dss_device *dssdev) @@ -47150,13 +47170,13 @@ index ef5b902..47cf7f5 100644 + pax_open_kernel(); if (drv && drv->get_resolution == NULL) - drv->get_resolution = omapdss_default_get_resolution; -+ *(void **)&drv->get_resolution = omapdss_default_get_resolution; ++ const_cast(drv->get_resolution) = omapdss_default_get_resolution; if (drv && drv->get_recommended_bpp == NULL) - drv->get_recommended_bpp = omapdss_default_get_recommended_bpp; -+ *(void **)&drv->get_recommended_bpp = omapdss_default_get_recommended_bpp; ++ const_cast(drv->get_recommended_bpp) = omapdss_default_get_recommended_bpp; if (drv && drv->get_timings == NULL) - drv->get_timings = omapdss_default_get_timings; -+ *(void **)&drv->get_timings = omapdss_default_get_timings; ++ const_cast(drv->get_timings) = omapdss_default_get_timings; + pax_close_kernel(); mutex_lock(&panel_list_mutex); @@ -47232,7 +47252,7 @@ index 47e5264..3393741 100644 { struct drm_device *ddev = connector->dev; diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c -index 7307b07..8eecdd0 100644 +index 7307b07..3346540 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -37,7 +37,7 @@ @@ -47251,7 +47271,7 @@ index 7307b07..8eecdd0 100644 - qxl_driver.num_ioctls = qxl_max_ioctls; + + pax_open_kernel(); -+ *(int *)&qxl_driver.num_ioctls = qxl_max_ioctls; ++ const_cast(qxl_driver.num_ioctls) = qxl_max_ioctls; + pax_close_kernel(); + return drm_pci_init(&qxl_driver, &qxl_pci_driver); @@ -47362,7 +47382,7 @@ index 0bf1e20..42a7310 100644 ret = drm_irq_install(qdev->ddev, qdev->ddev->pdev->irq); qdev->ram_header->int_mask = QXL_INTERRUPT_MASK; diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c -index 9534127..3fbab8c 100644 +index 9534127..1d17b3f 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c @@ -103,7 +103,7 @@ static void qxl_ttm_global_fini(struct qxl_device *qdev) @@ -47416,8 +47436,8 @@ index 9534127..3fbab8c 100644 - else - qxl_mem_types_list[i].data = qdev->mman.bdev.man[TTM_PL_PRIV0].priv; + pax_open_kernel(); -+ *(void **)&qxl_mem_types_list[0].data = qdev->mman.bdev.man[TTM_PL_VRAM].priv; -+ *(void **)&qxl_mem_types_list[1].data = qdev->mman.bdev.man[TTM_PL_PRIV0].priv; ++ const_cast(qxl_mem_types_list[0].data) = qdev->mman.bdev.man[TTM_PL_VRAM].priv; ++ const_cast(qxl_mem_types_list[1].data) = qdev->mman.bdev.man[TTM_PL_PRIV0].priv; + pax_close_kernel(); - } @@ -47440,7 +47460,7 @@ index 14fd83b5f..b2acbd19 100644 /* We don't support anything other than bus-mastering ring mode, * but the ring can be in either AGP or PCI space for the ring diff --git a/drivers/gpu/drm/r128/r128_drv.c b/drivers/gpu/drm/r128/r128_drv.c -index c57b4de..2614d79 100644 +index c57b4de..1a875fb 100644 --- a/drivers/gpu/drm/r128/r128_drv.c +++ b/drivers/gpu/drm/r128/r128_drv.c @@ -94,7 +94,9 @@ static struct pci_driver r128_pci_driver = { @@ -47449,7 +47469,7 @@ index c57b4de..2614d79 100644 { - driver.num_ioctls = r128_max_ioctl; + pax_open_kernel(); -+ *(int *)&driver.num_ioctls = r128_max_ioctl; ++ const_cast(driver.num_ioctls) = r128_max_ioctl; + pax_close_kernel(); return drm_pci_init(&driver, &r128_pci_driver); @@ -47659,7 +47679,7 @@ index 4197ca1..f07709e 100644 static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = { diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c -index e266ffc..0392d08 100644 +index e266ffc..e510e3f 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -130,7 +130,7 @@ extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, unsigned int crtc, @@ -47688,7 +47708,7 @@ index e266ffc..0392d08 100644 - driver->num_ioctls = radeon_max_kms_ioctl; + + pax_open_kernel(); -+ *(int *)&driver->num_ioctls = radeon_max_kms_ioctl; ++ const_cast(driver->num_ioctls) = radeon_max_kms_ioctl; + pax_close_kernel(); + radeon_register_atpx_handler(); @@ -47808,7 +47828,7 @@ index d47dff9..0752202 100644 -int savage_max_ioctl = ARRAY_SIZE(savage_ioctls); +const int savage_max_ioctl = ARRAY_SIZE(savage_ioctls); diff --git a/drivers/gpu/drm/savage/savage_drv.c b/drivers/gpu/drm/savage/savage_drv.c -index 21aed1f..5db7419 100644 +index 21aed1f..85d23a0 100644 --- a/drivers/gpu/drm/savage/savage_drv.c +++ b/drivers/gpu/drm/savage/savage_drv.c @@ -76,7 +76,10 @@ static struct pci_driver savage_pci_driver = { @@ -47817,7 +47837,7 @@ index 21aed1f..5db7419 100644 { - driver.num_ioctls = savage_max_ioctl; + pax_open_kernel(); -+ *(int *)&driver.num_ioctls = savage_max_ioctl; ++ const_cast(driver.num_ioctls) = savage_max_ioctl; + pax_close_kernel(); + return drm_pci_init(&driver, &savage_pci_driver); @@ -47837,7 +47857,7 @@ index 37b6995..9b31aaf 100644 #define S3_SAVAGE3D_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX)) diff --git a/drivers/gpu/drm/sis/sis_drv.c b/drivers/gpu/drm/sis/sis_drv.c -index 79bce76..4fd9a20 100644 +index 79bce76..6c02219 100644 --- a/drivers/gpu/drm/sis/sis_drv.c +++ b/drivers/gpu/drm/sis/sis_drv.c @@ -128,7 +128,10 @@ static struct pci_driver sis_pci_driver = { @@ -47846,7 +47866,7 @@ index 79bce76..4fd9a20 100644 { - driver.num_ioctls = sis_max_ioctl; + pax_open_kernel(); -+ *(int *)&driver.num_ioctls = sis_max_ioctl; ++ const_cast(driver.num_ioctls) = sis_max_ioctl; + pax_close_kernel(); + return drm_pci_init(&driver, &sis_pci_driver); @@ -47875,7 +47895,7 @@ index 93ad8a5..48f0a57 100644 -int sis_max_ioctl = ARRAY_SIZE(sis_ioctls); +const int sis_max_ioctl = ARRAY_SIZE(sis_ioctls); diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c -index dde6f20..1969ca6 100644 +index dde6f20..a74f8b9 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -1657,7 +1657,7 @@ static int tegra_dc_debugfs_init(struct tegra_dc *dc, struct drm_minor *minor) @@ -47883,7 +47903,7 @@ index dde6f20..1969ca6 100644 for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) - dc->debugfs_files[i].data = dc; -+ *(void **)&dc->debugfs_files[i].data = dc; ++ const_cast(dc->debugfs_files[i].data) = dc; err = drm_debugfs_create_files(dc->debugfs_files, ARRAY_SIZE(debugfs_files), @@ -47914,7 +47934,7 @@ index b7ef492..8968507 100644 struct dentry *debugfs; }; diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c -index 757c6e8..710a6ff 100644 +index 757c6e8..36532d6 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -1003,8 +1003,11 @@ static int tegra_sor_debugfs_init(struct tegra_sor *sor, @@ -47925,7 +47945,7 @@ index 757c6e8..710a6ff 100644 - sor->debugfs_files[i].data = sor; + for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) { + pax_open_kernel(); -+ *(void **)&sor->debugfs_files[i].data = sor; ++ const_cast(sor->debugfs_files[i].data) = sor; + pax_close_kernel(); + } @@ -48205,7 +48225,7 @@ index d17d8f2..67e8e48b 100644 -int via_max_ioctl = ARRAY_SIZE(via_ioctls); +const int via_max_ioctl = ARRAY_SIZE(via_ioctls); diff --git a/drivers/gpu/drm/via/via_drv.c b/drivers/gpu/drm/via/via_drv.c -index ed8aa8f..16c84fc 100644 +index ed8aa8f..114cc8d 100644 --- a/drivers/gpu/drm/via/via_drv.c +++ b/drivers/gpu/drm/via/via_drv.c @@ -107,7 +107,10 @@ static struct pci_driver via_pci_driver = { @@ -48214,7 +48234,7 @@ index ed8aa8f..16c84fc 100644 { - driver.num_ioctls = via_max_ioctl; + pax_open_kernel(); -+ *(int *)&driver.num_ioctls = via_max_ioctl; ++ const_cast(driver.num_ioctls) = via_max_ioctl; + pax_close_kernel(); + via_init_command_verifier(); @@ -49094,7 +49114,7 @@ index d127ace..6ee866f 100644 int i, j = 1; diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c -index 146eed70b..7679efd 100644 +index 146eed70b..7312f08 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -1060,8 +1060,10 @@ static void sklh_idle_state_table_update(void) @@ -49104,8 +49124,8 @@ index 146eed70b..7679efd 100644 - skl_cstates[5].disabled = 1; /* C8-SKL */ - skl_cstates[6].disabled = 1; /* C9-SKL */ + pax_open_kernel(); -+ *(bool *)&skl_cstates[5].disabled = 1; /* C8-SKL */ -+ *(bool *)&skl_cstates[6].disabled = 1; /* C9-SKL */ ++ const_cast(skl_cstates[5].disabled) = 1; /* C8-SKL */ ++ const_cast(skl_cstates[6].disabled) = 1; /* C9-SKL */ + pax_close_kernel(); } /* @@ -50103,18 +50123,6 @@ index 8c4daf7..77a87ab 100644 nesqp->destroyed = 1; /* Blow away the connection if it exists. */ -diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h -index 7df16f7..7e1b21e 100644 ---- a/drivers/infiniband/hw/qib/qib.h -+++ b/drivers/infiniband/hw/qib/qib.h -@@ -52,6 +52,7 @@ - #include - #include - #include -+#include - - #include "qib_common.h" - #include "qib_verbs.h" diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 6c8ff10..73cfbb6 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c @@ -50492,7 +50500,7 @@ index 2087534..c3f6b6c 100644 return -ENOMEM; diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c -index 59ee4b8..6632759 100644 +index 59ee4b8..e4b6234 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -341,7 +341,7 @@ enum arm_smmu_domain_stage { @@ -50528,7 +50536,7 @@ index 59ee4b8..6632759 100644 /* Update our support page sizes to reflect the page table format */ - arm_smmu_ops.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap; + pax_open_kernel(); -+ *(unsigned long *)&arm_smmu_ops.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap; ++ const_cast(arm_smmu_ops.pgsize_bitmap) = pgtbl_cfg.pgsize_bitmap; + pax_close_kernel(); /* Initialise the context bank with our page table cfg */ @@ -50630,7 +50638,7 @@ index 59ee4b8..6632759 100644 - arm_smmu_ops.pgsize_bitmap &= size; + pax_open_kernel(); -+ *(unsigned long *)&arm_smmu_ops.pgsize_bitmap &= size; ++ const_cast(arm_smmu_ops.pgsize_bitmap) &= size; + pax_close_kernel(); dev_notice(smmu->dev, "\tSupported page sizes: 0x%08lx\n", size); @@ -51582,7 +51590,7 @@ index fef6586..22353ff 100644 } else if ((DIDD_Table[x].type > 0) && (DIDD_Table[x].type < 16)) { /* IDI Adapter found */ diff --git a/drivers/isdn/hardware/eicon/mntfunc.c b/drivers/isdn/hardware/eicon/mntfunc.c -index 1cd9aff..1a3e2b6 100644 +index 1cd9aff..3775d52 100644 --- a/drivers/isdn/hardware/eicon/mntfunc.c +++ b/drivers/isdn/hardware/eicon/mntfunc.c @@ -26,8 +26,13 @@ extern void DIVA_DIDD_Read(void *, int); @@ -51592,7 +51600,7 @@ index 1cd9aff..1a3e2b6 100644 + +static void didd_nothing(ENTITY IDI_CALL_ENTITY_T *e) +{ -+ diva_maint_prtComp(e); ++ diva_maint_prtComp((char *)e); +} static DESCRIPTOR MaintDescriptor = -{ IDI_DIMAINT, 0, 0, (IDI_CALL) diva_maint_prtComp }; @@ -52967,10 +52975,50 @@ index 6b420a5..d5acb8f 100644 struct gc_stat { diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c -index 22b9e34..ac456ec 100644 +index 22b9e34..d8406e7 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c -@@ -468,7 +468,7 @@ void __bch_btree_node_write(struct btree *b, struct closure *parent) +@@ -337,15 +337,17 @@ static void btree_complete_write(struct btree *b, struct btree_write *w) + w->journal = NULL; + } + +-static void btree_node_write_unlock(struct closure *cl) ++static void btree_node_write_unlock(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct btree *b = container_of(cl, struct btree, io); + + up(&b->io_mutex); + } + +-static void __btree_node_write_done(struct closure *cl) ++static void __btree_node_write_done(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct btree *b = container_of(cl, struct btree, io); + struct btree_write *w = btree_prev_write(b); + +@@ -359,8 +361,9 @@ static void __btree_node_write_done(struct closure *cl) + closure_return_with_destructor(cl, btree_node_write_unlock); + } + +-static void btree_node_write_done(struct closure *cl) ++static void btree_node_write_done(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct btree *b = container_of(cl, struct btree, io); + struct bio_vec *bv; + int n; +@@ -368,7 +371,7 @@ static void btree_node_write_done(struct closure *cl) + bio_for_each_segment_all(bv, b->bio, n) + __free_page(bv->bv_page); + +- __btree_node_write_done(cl); ++ __btree_node_write_done(&cl->work); + } + + static void btree_node_write_endio(struct bio *bio) +@@ -468,7 +471,7 @@ void __bch_btree_node_write(struct btree *b, struct closure *parent) do_btree_node_write(b); @@ -52979,12 +53027,44 @@ index 22b9e34..ac456ec 100644 &PTR_CACHE(b->c, &b->key, 0)->btree_sectors_written); b->written += set_blocks(i, block_bytes(b->c)); +diff --git a/drivers/md/bcache/closure.c b/drivers/md/bcache/closure.c +index 9eaf1d6..86e6fa1 100644 +--- a/drivers/md/bcache/closure.c ++++ b/drivers/md/bcache/closure.c +@@ -29,12 +29,12 @@ static inline void closure_put_after_sub(struct closure *cl, int flags) + closure_queue(cl); + } else { + struct closure *parent = cl->parent; +- closure_fn *destructor = cl->fn; ++ work_func_t destructor = cl->fn; + + closure_debug_destroy(cl); + + if (destructor) +- destructor(cl); ++ destructor(&cl->work); + + if (parent) + closure_put(parent); diff --git a/drivers/md/bcache/closure.h b/drivers/md/bcache/closure.h -index 782cc2c..4fdd593 100644 +index 782cc2c..34864f4 100644 --- a/drivers/md/bcache/closure.h +++ b/drivers/md/bcache/closure.h -@@ -238,7 +238,7 @@ static inline void closure_set_stopped(struct closure *cl) - static inline void set_closure_fn(struct closure *cl, closure_fn *fn, +@@ -151,7 +151,7 @@ struct closure { + struct workqueue_struct *wq; + struct task_struct *task; + struct llist_node list; +- closure_fn *fn; ++ work_func_t fn; + }; + struct work_struct work; + }; +@@ -235,10 +235,10 @@ static inline void closure_set_stopped(struct closure *cl) + atomic_sub(CLOSURE_RUNNING, &cl->remaining); + } + +-static inline void set_closure_fn(struct closure *cl, closure_fn *fn, ++static inline void set_closure_fn(struct closure *cl, work_func_t fn, struct workqueue_struct *wq) { - BUG_ON(object_is_on_stack(cl)); @@ -52992,6 +53072,24 @@ index 782cc2c..4fdd593 100644 closure_set_ip(cl); cl->fn = fn; cl->wq = wq; +@@ -253,7 +253,7 @@ static inline void closure_queue(struct closure *cl) + INIT_WORK(&cl->work, cl->work.func); + BUG_ON(!queue_work(wq, &cl->work)); + } else +- cl->fn(cl); ++ cl->fn(&cl->work); + } + + /** +@@ -372,7 +372,7 @@ do { \ + * asynchronously out of a new closure - @parent will then wait for @cl to + * finish. + */ +-static inline void closure_call(struct closure *cl, closure_fn fn, ++static inline void closure_call(struct closure *cl, work_func_t fn, + struct workqueue_struct *wq, + struct closure *parent) + { diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c index 86a0bb8..0832b32 100644 --- a/drivers/md/bcache/io.c @@ -53035,10 +53133,46 @@ index 86a0bb8..0832b32 100644 errors >>= IO_ERROR_SHIFT; diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c -index 29eba72..348efc9 100644 +index 29eba72..1d0108a 100644 --- a/drivers/md/bcache/journal.c +++ b/drivers/md/bcache/journal.c -@@ -621,7 +621,7 @@ static void journal_write_unlocked(struct closure *cl) +@@ -555,10 +555,11 @@ static void journal_write_endio(struct bio *bio) + closure_put(&w->c->journal.io); + } + +-static void journal_write(struct closure *); ++static void journal_write(struct work_struct *); + +-static void journal_write_done(struct closure *cl) ++static void journal_write_done(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct journal *j = container_of(cl, struct journal, io); + struct journal_write *w = (j->cur == j->w) + ? &j->w[1] +@@ -568,17 +569,19 @@ static void journal_write_done(struct closure *cl) + continue_at_nobarrier(cl, journal_write, system_wq); + } + +-static void journal_write_unlock(struct closure *cl) ++static void journal_write_unlock(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct cache_set *c = container_of(cl, struct cache_set, journal.io); + + c->journal.io_in_flight = 0; + spin_unlock(&c->journal.lock); + } + +-static void journal_write_unlocked(struct closure *cl) ++static void journal_write_unlocked(struct work_struct *work) + __releases(c->journal.lock) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct cache_set *c = container_of(cl, struct cache_set, journal.io); + struct cache *ca; + struct journal_write *w = c->journal.cur; +@@ -621,7 +624,7 @@ static void journal_write_unlocked(struct closure *cl) ca = PTR_CACHE(c, k, i); bio = &ca->journal.bio; @@ -53047,6 +53181,278 @@ index 29eba72..348efc9 100644 bio_reset(bio); bio->bi_iter.bi_sector = PTR_OFFSET(k, i); +@@ -653,12 +656,13 @@ static void journal_write_unlocked(struct closure *cl) + continue_at(cl, journal_write_done, NULL); + } + +-static void journal_write(struct closure *cl) ++static void journal_write(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct cache_set *c = container_of(cl, struct cache_set, journal.io); + + spin_lock(&c->journal.lock); +- journal_write_unlocked(cl); ++ journal_write_unlocked(&cl->work); + } + + static void journal_try_write(struct cache_set *c) +diff --git a/drivers/md/bcache/movinggc.c b/drivers/md/bcache/movinggc.c +index b929fc9..4557031 100644 +--- a/drivers/md/bcache/movinggc.c ++++ b/drivers/md/bcache/movinggc.c +@@ -34,14 +34,16 @@ static bool moving_pred(struct keybuf *buf, struct bkey *k) + + /* Moving GC - IO loop */ + +-static void moving_io_destructor(struct closure *cl) ++static void moving_io_destructor(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct moving_io *io = container_of(cl, struct moving_io, cl); + kfree(io); + } + +-static void write_moving_finish(struct closure *cl) ++static void write_moving_finish(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct moving_io *io = container_of(cl, struct moving_io, cl); + struct bio *bio = &io->bio.bio; + struct bio_vec *bv; +@@ -92,8 +94,9 @@ static void moving_init(struct moving_io *io) + bch_bio_map(bio, NULL); + } + +-static void write_moving(struct closure *cl) ++static void write_moving(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct moving_io *io = container_of(cl, struct moving_io, cl); + struct data_insert_op *op = &io->op; + +@@ -116,8 +119,9 @@ static void write_moving(struct closure *cl) + continue_at(cl, write_moving_finish, op->wq); + } + +-static void read_moving_submit(struct closure *cl) ++static void read_moving_submit(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct moving_io *io = container_of(cl, struct moving_io, cl); + struct bio *bio = &io->bio.bio; + +diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c +index 25fa844..8181a97 100644 +--- a/drivers/md/bcache/request.c ++++ b/drivers/md/bcache/request.c +@@ -24,7 +24,7 @@ + + struct kmem_cache *bch_search_cache; + +-static void bch_data_insert_start(struct closure *); ++static void bch_data_insert_start(struct work_struct *); + + static unsigned cache_mode(struct cached_dev *dc, struct bio *bio) + { +@@ -53,8 +53,9 @@ static void bio_csum(struct bio *bio, struct bkey *k) + + /* Insert data into cache */ + +-static void bch_data_insert_keys(struct closure *cl) ++static void bch_data_insert_keys(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct data_insert_op *op = container_of(cl, struct data_insert_op, cl); + atomic_t *journal_ref = NULL; + struct bkey *replace_key = op->replace ? &op->replace_key : NULL; +@@ -143,8 +144,9 @@ out: + continue_at(cl, bch_data_insert_keys, op->wq); + } + +-static void bch_data_insert_error(struct closure *cl) ++static void bch_data_insert_error(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct data_insert_op *op = container_of(cl, struct data_insert_op, cl); + + /* +@@ -170,7 +172,7 @@ static void bch_data_insert_error(struct closure *cl) + + op->insert_keys.top = dst; + +- bch_data_insert_keys(cl); ++ bch_data_insert_keys(&cl->work); + } + + static void bch_data_insert_endio(struct bio *bio) +@@ -191,8 +193,9 @@ static void bch_data_insert_endio(struct bio *bio) + bch_bbio_endio(op->c, bio, bio->bi_error, "writing data to cache"); + } + +-static void bch_data_insert_start(struct closure *cl) ++static void bch_data_insert_start(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct data_insert_op *op = container_of(cl, struct data_insert_op, cl); + struct bio *bio = op->bio, *n; + +@@ -313,8 +316,9 @@ err: + * If s->bypass is true, instead of inserting the data it invalidates the + * region of the cache represented by s->cache_bio and op->inode. + */ +-void bch_data_insert(struct closure *cl) ++void bch_data_insert(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct data_insert_op *op = container_of(cl, struct data_insert_op, cl); + + trace_bcache_write(op->c, op->inode, op->bio, +@@ -322,7 +326,7 @@ void bch_data_insert(struct closure *cl) + + bch_keylist_init(&op->insert_keys); + bio_get(op->bio); +- bch_data_insert_start(cl); ++ bch_data_insert_start(&cl->work); + } + + /* Congested? */ +@@ -570,8 +574,9 @@ static int cache_lookup_fn(struct btree_op *op, struct btree *b, struct bkey *k) + return n == bio ? MAP_DONE : MAP_CONTINUE; + } + +-static void cache_lookup(struct closure *cl) ++static void cache_lookup(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct search *s = container_of(cl, struct search, iop.cl); + struct bio *bio = &s->bio.bio; + int ret; +@@ -631,8 +636,9 @@ static void do_bio_hook(struct search *s, struct bio *orig_bio) + bio_cnt_set(bio, 3); + } + +-static void search_free(struct closure *cl) ++static void search_free(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct search *s = container_of(cl, struct search, cl); + bio_complete(s); + +@@ -676,19 +682,21 @@ static inline struct search *search_alloc(struct bio *bio, + + /* Cached devices */ + +-static void cached_dev_bio_complete(struct closure *cl) ++static void cached_dev_bio_complete(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct search *s = container_of(cl, struct search, cl); + struct cached_dev *dc = container_of(s->d, struct cached_dev, disk); + +- search_free(cl); ++ search_free(&cl->work); + cached_dev_put(dc); + } + + /* Process reads */ + +-static void cached_dev_cache_miss_done(struct closure *cl) ++static void cached_dev_cache_miss_done(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct search *s = container_of(cl, struct search, cl); + + if (s->iop.replace_collision) +@@ -702,11 +710,12 @@ static void cached_dev_cache_miss_done(struct closure *cl) + __free_page(bv->bv_page); + } + +- cached_dev_bio_complete(cl); ++ cached_dev_bio_complete(&cl->work); + } + +-static void cached_dev_read_error(struct closure *cl) ++static void cached_dev_read_error(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct search *s = container_of(cl, struct search, cl); + struct bio *bio = &s->bio.bio; + +@@ -725,8 +734,9 @@ static void cached_dev_read_error(struct closure *cl) + continue_at(cl, cached_dev_cache_miss_done, NULL); + } + +-static void cached_dev_read_done(struct closure *cl) ++static void cached_dev_read_done(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct search *s = container_of(cl, struct search, cl); + struct cached_dev *dc = container_of(s->d, struct cached_dev, disk); + +@@ -765,8 +775,9 @@ static void cached_dev_read_done(struct closure *cl) + continue_at(cl, cached_dev_cache_miss_done, NULL); + } + +-static void cached_dev_read_done_bh(struct closure *cl) ++static void cached_dev_read_done_bh(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct search *s = container_of(cl, struct search, cl); + struct cached_dev *dc = container_of(s->d, struct cached_dev, disk); + +@@ -864,13 +875,14 @@ static void cached_dev_read(struct cached_dev *dc, struct search *s) + + /* Process writes */ + +-static void cached_dev_write_complete(struct closure *cl) ++static void cached_dev_write_complete(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct search *s = container_of(cl, struct search, cl); + struct cached_dev *dc = container_of(s->d, struct cached_dev, disk); + + up_read_non_owner(&dc->writeback_lock); +- cached_dev_bio_complete(cl); ++ cached_dev_bio_complete(&cl->work); + } + + static void cached_dev_write(struct cached_dev *dc, struct search *s) +@@ -942,8 +954,9 @@ static void cached_dev_write(struct cached_dev *dc, struct search *s) + continue_at(cl, cached_dev_write_complete, NULL); + } + +-static void cached_dev_nodata(struct closure *cl) ++static void cached_dev_nodata(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct search *s = container_of(cl, struct search, cl); + struct bio *bio = &s->bio.bio; + +@@ -1063,8 +1076,9 @@ static int flash_dev_cache_miss(struct btree *b, struct search *s, + return MAP_CONTINUE; + } + +-static void flash_dev_nodata(struct closure *cl) ++static void flash_dev_nodata(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct search *s = container_of(cl, struct search, cl); + + if (s->iop.flush_journal) +diff --git a/drivers/md/bcache/request.h b/drivers/md/bcache/request.h +index 1ff3687..b8f4a05 100644 +--- a/drivers/md/bcache/request.h ++++ b/drivers/md/bcache/request.h +@@ -33,7 +33,7 @@ struct data_insert_op { + }; + + unsigned bch_get_congested(struct cache_set *); +-void bch_data_insert(struct closure *cl); ++void bch_data_insert(struct work_struct *work); + + void bch_cached_dev_request_init(struct cached_dev *dc); + void bch_flash_dev_request_init(struct bcache_device *d); diff --git a/drivers/md/bcache/stats.c b/drivers/md/bcache/stats.c index 0ca072c..5e6e5c3 100644 --- a/drivers/md/bcache/stats.c @@ -53161,10 +53567,43 @@ index adbff14..018c2d2 100644 struct cache_stat_collector collector; diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c -index a296425..397607e 100644 +index a296425..c5d881c 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c -@@ -530,7 +530,7 @@ void bch_prio_write(struct cache *ca) +@@ -241,8 +241,9 @@ static void __write_super(struct cache_sb *sb, struct bio *bio) + submit_bio(REQ_WRITE, bio); + } + +-static void bch_write_bdev_super_unlock(struct closure *cl) ++static void bch_write_bdev_super_unlock(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct cached_dev *dc = container_of(cl, struct cached_dev, sb_write); + + up(&dc->sb_write_mutex); +@@ -275,8 +276,9 @@ static void write_super_endio(struct bio *bio) + closure_put(&ca->set->sb_write); + } + +-static void bcache_write_super_unlock(struct closure *cl) ++static void bcache_write_super_unlock(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct cache_set *c = container_of(cl, struct cache_set, sb_write); + + up(&c->sb_write_mutex); +@@ -326,8 +328,9 @@ static void uuid_endio(struct bio *bio) + closure_put(cl); + } + +-static void uuid_io_unlock(struct closure *cl) ++static void uuid_io_unlock(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct cache_set *c = container_of(cl, struct cache_set, uuid_write); + + up(&c->uuid_write_mutex); +@@ -530,7 +533,7 @@ void bch_prio_write(struct cache *ca) ca->disk_buckets->seq++; @@ -53173,6 +53612,83 @@ index a296425..397607e 100644 &ca->meta_sectors_written); //pr_debug("free %zu, free_inc %zu, unused %zu", fifo_used(&ca->free), +@@ -1049,8 +1052,9 @@ void bch_cached_dev_release(struct kobject *kobj) + module_put(THIS_MODULE); + } + +-static void cached_dev_free(struct closure *cl) ++static void cached_dev_free(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct cached_dev *dc = container_of(cl, struct cached_dev, disk.cl); + + cancel_delayed_work_sync(&dc->writeback_rate_update); +@@ -1074,8 +1078,9 @@ static void cached_dev_free(struct closure *cl) + kobject_put(&dc->disk.kobj); + } + +-static void cached_dev_flush(struct closure *cl) ++static void cached_dev_flush(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct cached_dev *dc = container_of(cl, struct cached_dev, disk.cl); + struct bcache_device *d = &dc->disk; + +@@ -1191,8 +1196,9 @@ void bch_flash_dev_release(struct kobject *kobj) + kfree(d); + } + +-static void flash_dev_free(struct closure *cl) ++static void flash_dev_free(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct bcache_device *d = container_of(cl, struct bcache_device, cl); + mutex_lock(&bch_register_lock); + bcache_device_free(d); +@@ -1200,8 +1206,9 @@ static void flash_dev_free(struct closure *cl) + kobject_put(&d->kobj); + } + +-static void flash_dev_flush(struct closure *cl) ++static void flash_dev_flush(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct bcache_device *d = container_of(cl, struct bcache_device, cl); + + mutex_lock(&bch_register_lock); +@@ -1320,8 +1327,9 @@ void bch_cache_set_release(struct kobject *kobj) + module_put(THIS_MODULE); + } + +-static void cache_set_free(struct closure *cl) ++static void cache_set_free(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct cache_set *c = container_of(cl, struct cache_set, cl); + struct cache *ca; + unsigned i; +@@ -1366,8 +1374,9 @@ static void cache_set_free(struct closure *cl) + kobject_put(&c->kobj); + } + +-static void cache_set_flush(struct closure *cl) ++static void cache_set_flush(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct cache_set *c = container_of(cl, struct cache_set, caching); + struct cache *ca; + struct btree *b; +@@ -1408,8 +1417,9 @@ static void cache_set_flush(struct closure *cl) + closure_return(cl); + } + +-static void __cache_set_unregister(struct closure *cl) ++static void __cache_set_unregister(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct cache_set *c = container_of(cl, struct cache_set, caching); + struct cached_dev *dc; + size_t i; diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c index b3ff57d..b2e30fb 100644 --- a/drivers/md/bcache/sysfs.c @@ -53215,6 +53731,51 @@ index b3ff57d..b2e30fb 100644 } return size; +diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c +index b9346cd..708ea8f 100644 +--- a/drivers/md/bcache/writeback.c ++++ b/drivers/md/bcache/writeback.c +@@ -118,14 +118,16 @@ static void dirty_init(struct keybuf_key *w) + bch_bio_map(bio, NULL); + } + +-static void dirty_io_destructor(struct closure *cl) ++static void dirty_io_destructor(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct dirty_io *io = container_of(cl, struct dirty_io, cl); + kfree(io); + } + +-static void write_dirty_finish(struct closure *cl) ++static void write_dirty_finish(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct dirty_io *io = container_of(cl, struct dirty_io, cl); + struct keybuf_key *w = io->bio.bi_private; + struct cached_dev *dc = io->dc; +@@ -177,8 +179,9 @@ static void dirty_endio(struct bio *bio) + closure_put(&io->cl); + } + +-static void write_dirty(struct closure *cl) ++static void write_dirty(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct dirty_io *io = container_of(cl, struct dirty_io, cl); + struct keybuf_key *w = io->bio.bi_private; + +@@ -204,8 +207,9 @@ static void read_dirty_endio(struct bio *bio) + dirty_endio(bio); + } + +-static void read_dirty_submit(struct closure *cl) ++static void read_dirty_submit(struct work_struct *work) + { ++ struct closure *cl = container_of(work, struct closure, work); + struct dirty_io *io = container_of(cl, struct dirty_io, cl); + + closure_bio_submit(&io->bio, cl); diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index d80cce4..d7f15c4 100644 --- a/drivers/md/bitmap.c @@ -54725,6 +55286,19 @@ index 80caa70..d076ecf 100644 vma->vm_ops = &zoran_vm_ops; vma->vm_flags |= VM_DONTEXPAND; +diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c +index de32e3a..e6a7bff 100644 +--- a/drivers/media/platform/am437x/am437x-vpfe.c ++++ b/drivers/media/platform/am437x/am437x-vpfe.c +@@ -1706,7 +1706,7 @@ static int vpfe_get_app_input_index(struct vpfe_device *vpfe, + sdinfo = &cfg->sub_devs[i]; + client = v4l2_get_subdevdata(sdinfo->sd); + if (client->addr == curr_client->addr && +- client->adapter->nr == client->adapter->nr) { ++ client->adapter->nr == curr_client->adapter->nr) { + if (vpfe->current_input >= 1) + return -1; + *app_input_index = j + vpfe->current_input; diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index 70c28d1..ff21b13 100644 --- a/drivers/media/platform/omap/omap_vout.c @@ -56578,7 +57152,7 @@ index f7ab115..16b2087 100644 if (!irq) { dev_warn(tps65910->dev, "No interrupt support, no core IRQ\n"); diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c -index 40e51b0..b986312 100644 +index 40e51b0..af35565 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -34,6 +34,7 @@ @@ -56597,16 +57171,16 @@ index 40e51b0..b986312 100644 - twl4030_irq_chip.name = "twl4030"; + pax_open_kernel(); + memcpy((void *)&twl4030_irq_chip, &dummy_irq_chip, sizeof twl4030_irq_chip); -+ *(const char **)&twl4030_irq_chip.name = "twl4030"; ++ const_cast(twl4030_irq_chip.name) = "twl4030"; - twl4030_sih_irq_chip.irq_ack = dummy_irq_chip.irq_ack; -+ *(void **)&twl4030_sih_irq_chip.irq_ack = dummy_irq_chip.irq_ack; ++ const_cast(twl4030_sih_irq_chip.irq_ack) = dummy_irq_chip.irq_ack; + pax_close_kernel(); for (i = irq_base; i < irq_end; i++) { irq_set_chip_and_handler(i, &twl4030_irq_chip, diff --git a/drivers/misc/c2port/core.c b/drivers/misc/c2port/core.c -index cc8645b..7cc15e4 100644 +index cc8645b..ab85ae4 100644 --- a/drivers/misc/c2port/core.c +++ b/drivers/misc/c2port/core.c @@ -922,7 +922,9 @@ struct c2port_device *c2port_device_register(char *name, @@ -56615,7 +57189,7 @@ index cc8645b..7cc15e4 100644 - bin_attr_flash_data.size = ops->blocks_num * ops->block_size; + pax_open_kernel(); -+ *(size_t *)&bin_attr_flash_data.size = ops->blocks_num * ops->block_size; ++ const_cast(bin_attr_flash_data.size) = ops->blocks_num * ops->block_size; + pax_close_kernel(); c2dev->dev = device_create(c2port_class, NULL, 0, c2dev, @@ -56705,7 +57279,7 @@ index c439c82..1f20f57 100644 int mapped_btns[3]; diff --git a/drivers/misc/mic/scif/scif_api.c b/drivers/misc/mic/scif/scif_api.c -index ddc9e4b..7b9c669 100644 +index ddc9e4b..9e27f41 100644 --- a/drivers/misc/mic/scif/scif_api.c +++ b/drivers/misc/mic/scif/scif_api.c @@ -1486,10 +1486,12 @@ int scif_client_register(struct scif_client *client) @@ -56717,10 +57291,10 @@ index ddc9e4b..7b9c669 100644 - si->add_dev = scif_add_client_dev; - si->remove_dev = scif_remove_client_dev; + pax_open_kernel(); -+ *(const char **)&si->name = client->name; -+ *(struct bus_type **)&si->subsys = &scif_peer_bus; -+ *(void **)&si->add_dev = scif_add_client_dev; -+ *(void **)&si->remove_dev = scif_remove_client_dev; ++ const_cast(si->name) = client->name; ++ const_cast(si->subsys) = &scif_peer_bus; ++ const_cast(si->add_dev) = scif_add_client_dev; ++ const_cast(si->remove_dev) = scif_remove_client_dev; + pax_close_kernel(); return subsys_interface_register(&client->si); @@ -57235,7 +57809,7 @@ index f695b58..7b7d017 100644 +} __do_const; #endif /* _DW_MMC_H_ */ diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c -index 0d6ca41..d438654 100644 +index 0d6ca41..bdc6710 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1634,7 +1634,9 @@ static int mmci_probe(struct amba_device *dev, @@ -57244,13 +57818,13 @@ index 0d6ca41..d438654 100644 if (variant->busy_detect) { - mmci_ops.card_busy = mmci_card_busy; + pax_open_kernel(); -+ *(void **)&mmci_ops.card_busy = mmci_card_busy; ++ const_cast(mmci_ops.card_busy) = mmci_card_busy; + pax_close_kernel(); mmci_write_datactrlreg(host, MCI_ST_DPSM_BUSYMODE); mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; mmc->max_busy_timeout = 0; diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c -index f6e4d97..57358ff 100644 +index f6e4d97..8bd8c05 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2088,7 +2088,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev) @@ -57259,13 +57833,13 @@ index f6e4d97..57358ff 100644 dev_info(&pdev->dev, "multiblock reads disabled due to 35xx erratum 2.1.1.128; MMC read performance may suffer\n"); - omap_hsmmc_ops.multi_io_quirk = omap_hsmmc_multi_io_quirk; + pax_open_kernel(); -+ *(void **)&omap_hsmmc_ops.multi_io_quirk = omap_hsmmc_multi_io_quirk; ++ const_cast(omap_hsmmc_ops.multi_io_quirk) = omap_hsmmc_multi_io_quirk; + pax_close_kernel(); } device_init_wakeup(&pdev->dev, true); diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c -index f25f292..a0e1250 100644 +index f25f292..7f4b03f 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -1194,9 +1194,12 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) @@ -57276,7 +57850,7 @@ index f25f292..a0e1250 100644 - sdhci_esdhc_ops.platform_execute_tuning = + if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { + pax_open_kernel(); -+ *(void **)&sdhci_esdhc_ops.platform_execute_tuning = ++ const_cast(sdhci_esdhc_ops.platform_execute_tuning) = esdhc_executing_tuning; + pax_close_kernel(); + } @@ -57284,7 +57858,7 @@ index f25f292..a0e1250 100644 if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) writel(readl(host->ioaddr + ESDHC_TUNING_CTRL) | diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c -index 70c724b..308aafc 100644 +index 70c724b..0c24beb 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -598,9 +598,11 @@ static int sdhci_s3c_probe(struct platform_device *pdev) @@ -57295,9 +57869,9 @@ index 70c724b..308aafc 100644 - sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock; - sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock; + pax_open_kernel(); -+ *(void **)&sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock; -+ *(void **)&sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock; -+ *(void **)&sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock; ++ const_cast(sdhci_s3c_ops.set_clock) = sdhci_cmu_set_clock; ++ const_cast(sdhci_s3c_ops.get_min_clock) = sdhci_cmu_get_min_clock; ++ const_cast(sdhci_s3c_ops.get_max_clock) = sdhci_cmu_get_max_clock; + pax_close_kernel(); } @@ -59971,7 +60545,7 @@ index 245c063..74ed9c9 100644 mdio_cmd->op = op; mdio_cmd->mdio_addr = loc; diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c -index 34d269c..43dcc17 100644 +index 34d269c..69e1ac2 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -475,7 +475,7 @@ static void stop_pci_io(struct octeon_device *oct) @@ -60018,7 +60592,7 @@ index 34d269c..43dcc17 100644 - lionetdevops.ndo_select_queue = select_q; + if (num_iqueues > 1) { + pax_open_kernel(); -+ *(void **)&lionetdevops.ndo_select_queue = select_q; ++ const_cast(lionetdevops.ndo_select_queue) = select_q; + pax_close_kernel(); + } @@ -60316,7 +60890,7 @@ index e51892d..3e645f4 100644 struct hix5hd2_priv *priv = netdev_priv(dev); struct hix5hd2_desc *desc; diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c -index d4f92ed..38fdf5b 100644 +index d4f92ed..d4755e0 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c @@ -857,16 +857,18 @@ int hns_dsaf_ae_init(struct dsaf_device *dsaf_dev) @@ -60327,11 +60901,11 @@ index d4f92ed..38fdf5b 100644 switch (dsaf_dev->dsaf_ver) { case AE_VERSION_1: - hns_dsaf_ops.toggle_ring_irq = hns_ae_toggle_ring_irq; -+ *(void **)&hns_dsaf_ops.toggle_ring_irq = hns_ae_toggle_ring_irq; ++ const_cast(hns_dsaf_ops.toggle_ring_irq) = hns_ae_toggle_ring_irq; break; case AE_VERSION_2: - hns_dsaf_ops.toggle_ring_irq = hns_aev2_toggle_ring_irq; -+ *(void **)&hns_dsaf_ops.toggle_ring_irq = hns_aev2_toggle_ring_irq; ++ const_cast(hns_dsaf_ops.toggle_ring_irq) = hns_aev2_toggle_ring_irq; break; default: break; @@ -60809,7 +61383,7 @@ index 6409a06..e5bd4d6 100644 struct netxen_adapter *adapter = pci_get_drvdata(pdev); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c -index bf89216..4044d8c 100644 +index bf89216..b08442a 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -2324,7 +2324,9 @@ int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter) @@ -60818,13 +61392,13 @@ index bf89216..4044d8c 100644 ahw->nic_mode = QLCNIC_DEFAULT_MODE; - adapter->nic_ops->init_driver = qlcnic_83xx_init_default_driver; + pax_open_kernel(); -+ *(void **)&adapter->nic_ops->init_driver = qlcnic_83xx_init_default_driver; ++ const_cast(adapter->nic_ops->init_driver) = qlcnic_83xx_init_default_driver; + pax_close_kernel(); ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry; max_sds_rings = QLCNIC_MAX_SDS_RINGS; max_tx_rings = QLCNIC_MAX_TX_RINGS; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c -index 3490675..0b9e15a 100644 +index 3490675..cf148ea 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c @@ -207,17 +207,23 @@ int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter) @@ -60833,7 +61407,7 @@ index 3490675..0b9e15a 100644 ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry; - nic_ops->init_driver = qlcnic_83xx_init_non_privileged_vnic; + pax_open_kernel(); -+ *(void **)&nic_ops->init_driver = qlcnic_83xx_init_non_privileged_vnic; ++ const_cast(nic_ops->init_driver) = qlcnic_83xx_init_non_privileged_vnic; + pax_close_kernel(); break; case QLCNIC_PRIV_FUNC: @@ -60841,7 +61415,7 @@ index 3490675..0b9e15a 100644 ahw->idc.state_entry = qlcnic_83xx_idc_vnic_pf_entry; - nic_ops->init_driver = qlcnic_83xx_init_privileged_vnic; + pax_open_kernel(); -+ *(void **)&nic_ops->init_driver = qlcnic_83xx_init_privileged_vnic; ++ const_cast(nic_ops->init_driver) = qlcnic_83xx_init_privileged_vnic; + pax_close_kernel(); break; case QLCNIC_MGMT_FUNC: @@ -60849,7 +61423,7 @@ index 3490675..0b9e15a 100644 ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry; - nic_ops->init_driver = qlcnic_83xx_init_mgmt_vnic; + pax_open_kernel(); -+ *(void **)&nic_ops->init_driver = qlcnic_83xx_init_mgmt_vnic; ++ const_cast(nic_ops->init_driver) = qlcnic_83xx_init_mgmt_vnic; + pax_close_kernel(); break; default: @@ -61604,7 +62178,7 @@ index f9db2ce..6cd460c 100644 } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c -index 94e6888..1d08b6a 100644 +index 94e6888..c5c3f55 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -335,7 +335,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port, @@ -61628,13 +62202,13 @@ index 94e6888..1d08b6a 100644 - ops->get_size = macvlan_get_size; - ops->fill_info = macvlan_fill_info; + pax_open_kernel(); -+ *(size_t *)&ops->priv_size = sizeof(struct macvlan_dev); -+ *(void **)&ops->validate = macvlan_validate; -+ *(int *)&ops->maxtype = IFLA_MACVLAN_MAX; -+ *(const void **)&ops->policy = macvlan_policy; -+ *(void **)&ops->changelink = macvlan_changelink; -+ *(void **)&ops->get_size = macvlan_get_size; -+ *(void **)&ops->fill_info = macvlan_fill_info; ++ const_cast(ops->priv_size) = sizeof(struct macvlan_dev); ++ const_cast(ops->validate) = macvlan_validate; ++ const_cast(ops->maxtype) = IFLA_MACVLAN_MAX; ++ const_cast(ops->policy) = macvlan_policy; ++ const_cast(ops->changelink) = macvlan_changelink; ++ const_cast(ops->get_size) = macvlan_get_size; ++ const_cast(ops->fill_info) = macvlan_fill_info; + pax_close_kernel(); return rtnl_link_register(ops); @@ -62585,7 +63159,7 @@ index 831a544..d846785 100644 struct ath_nf_limits { s16 max; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c -index c1b33fd..9f904b1 100644 +index c1b33fd..d61f3b4 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2589,16 +2589,18 @@ void ath9k_fill_chanctx_ops(void) @@ -62603,16 +63177,16 @@ index c1b33fd..9f904b1 100644 - ath9k_ops.unassign_vif_chanctx = ath9k_unassign_vif_chanctx; - ath9k_ops.mgd_prepare_tx = ath9k_mgd_prepare_tx; + pax_open_kernel(); -+ *(void **)&ath9k_ops.hw_scan = ath9k_hw_scan; -+ *(void **)&ath9k_ops.cancel_hw_scan = ath9k_cancel_hw_scan; -+ *(void **)&ath9k_ops.remain_on_channel = ath9k_remain_on_channel; -+ *(void **)&ath9k_ops.cancel_remain_on_channel = ath9k_cancel_remain_on_channel; -+ *(void **)&ath9k_ops.add_chanctx = ath9k_add_chanctx; -+ *(void **)&ath9k_ops.remove_chanctx = ath9k_remove_chanctx; -+ *(void **)&ath9k_ops.change_chanctx = ath9k_change_chanctx; -+ *(void **)&ath9k_ops.assign_vif_chanctx = ath9k_assign_vif_chanctx; -+ *(void **)&ath9k_ops.unassign_vif_chanctx = ath9k_unassign_vif_chanctx; -+ *(void **)&ath9k_ops.mgd_prepare_tx = ath9k_mgd_prepare_tx; ++ const_cast(ath9k_ops.hw_scan) = ath9k_hw_scan; ++ const_cast(ath9k_ops.cancel_hw_scan) = ath9k_cancel_hw_scan; ++ const_cast(ath9k_ops.remain_on_channel) = ath9k_remain_on_channel; ++ const_cast(ath9k_ops.cancel_remain_on_channel) = ath9k_cancel_remain_on_channel; ++ const_cast(ath9k_ops.add_chanctx) = ath9k_add_chanctx; ++ const_cast(ath9k_ops.remove_chanctx) = ath9k_remove_chanctx; ++ const_cast(ath9k_ops.change_chanctx) = ath9k_change_chanctx; ++ const_cast(ath9k_ops.assign_vif_chanctx) = ath9k_assign_vif_chanctx; ++ const_cast(ath9k_ops.unassign_vif_chanctx) = ath9k_unassign_vif_chanctx; ++ const_cast(ath9k_ops.mgd_prepare_tx) = ath9k_mgd_prepare_tx; + pax_close_kernel(); } @@ -63861,7 +64435,7 @@ index ed0adaf..4bb4f53 100644 return ret; } diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c -index af1b3e6..9bc08d3 100644 +index af1b3e6..c014779 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c @@ -1399,8 +1399,9 @@ il3945_dump_nic_error_log(struct il_priv *il) @@ -63899,7 +64473,7 @@ index af1b3e6..9bc08d3 100644 D_INFO("Disabling hw_scan\n"); - il3945_mac_ops.hw_scan = NULL; + pax_open_kernel(); -+ *(void **)&il3945_mac_ops.hw_scan = NULL; ++ const_cast(il3945_mac_ops.hw_scan) = NULL; + pax_close_kernel(); } @@ -65682,7 +66256,7 @@ index 48e8a97..3499ec8 100644 const struct iw_handler_def prism54_handler_def = { diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c -index a28414c..26c8768 100644 +index a28414c..ad61156 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -3218,20 +3218,20 @@ static int __init init_mac80211_hwsim(void) @@ -65705,17 +66279,17 @@ index a28414c..26c8768 100644 - mac80211_hwsim_unassign_vif_chanctx; + pax_open_kernel(); + memcpy((void *)&mac80211_hwsim_mchan_ops, &mac80211_hwsim_ops, sizeof mac80211_hwsim_mchan_ops); -+ *(void **)&mac80211_hwsim_mchan_ops.hw_scan = mac80211_hwsim_hw_scan; -+ *(void **)&mac80211_hwsim_mchan_ops.cancel_hw_scan = mac80211_hwsim_cancel_hw_scan; -+ *(void **)&mac80211_hwsim_mchan_ops.sw_scan_start = NULL; -+ *(void **)&mac80211_hwsim_mchan_ops.sw_scan_complete = NULL; -+ *(void **)&mac80211_hwsim_mchan_ops.remain_on_channel = mac80211_hwsim_roc; -+ *(void **)&mac80211_hwsim_mchan_ops.cancel_remain_on_channel = mac80211_hwsim_croc; -+ *(void **)&mac80211_hwsim_mchan_ops.add_chanctx = mac80211_hwsim_add_chanctx; -+ *(void **)&mac80211_hwsim_mchan_ops.remove_chanctx = mac80211_hwsim_remove_chanctx; -+ *(void **)&mac80211_hwsim_mchan_ops.change_chanctx = mac80211_hwsim_change_chanctx; -+ *(void **)&mac80211_hwsim_mchan_ops.assign_vif_chanctx = mac80211_hwsim_assign_vif_chanctx; -+ *(void **)&mac80211_hwsim_mchan_ops.unassign_vif_chanctx = mac80211_hwsim_unassign_vif_chanctx; ++ const_cast(mac80211_hwsim_mchan_ops.hw_scan) = mac80211_hwsim_hw_scan; ++ const_cast(mac80211_hwsim_mchan_ops.cancel_hw_scan) = mac80211_hwsim_cancel_hw_scan; ++ const_cast(mac80211_hwsim_mchan_ops.sw_scan_start) = NULL; ++ const_cast(mac80211_hwsim_mchan_ops.sw_scan_complete) = NULL; ++ const_cast(mac80211_hwsim_mchan_ops.remain_on_channel) = mac80211_hwsim_roc; ++ const_cast(mac80211_hwsim_mchan_ops.cancel_remain_on_channel) = mac80211_hwsim_croc; ++ const_cast(mac80211_hwsim_mchan_ops.add_chanctx) = mac80211_hwsim_add_chanctx; ++ const_cast(mac80211_hwsim_mchan_ops.remove_chanctx) = mac80211_hwsim_remove_chanctx; ++ const_cast(mac80211_hwsim_mchan_ops.change_chanctx) = mac80211_hwsim_change_chanctx; ++ const_cast(mac80211_hwsim_mchan_ops.assign_vif_chanctx) = mac80211_hwsim_assign_vif_chanctx; ++ const_cast(mac80211_hwsim_mchan_ops.unassign_vif_chanctx) = mac80211_hwsim_unassign_vif_chanctx; + pax_close_kernel(); spin_lock_init(&hwsim_radio_lock); @@ -66131,7 +66705,7 @@ index 29dfc51..8297755 100644 void rtl_swlps_rf_sleep(struct ieee80211_hw *hw); void rtl_p2p_ps_cmd(struct ieee80211_hw *hw , u8 p2p_ps_state); diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c -index b661f896..ddf7d2b 100644 +index b661f896..ebea675 100644 --- a/drivers/net/wireless/ti/wl1251/sdio.c +++ b/drivers/net/wireless/ti/wl1251/sdio.c @@ -282,13 +282,17 @@ static int wl1251_sdio_probe(struct sdio_func *func, @@ -66141,8 +66715,8 @@ index b661f896..ddf7d2b 100644 - wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq; - wl1251_sdio_ops.disable_irq = wl1251_disable_line_irq; + pax_open_kernel(); -+ *(void **)&wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq; -+ *(void **)&wl1251_sdio_ops.disable_irq = wl1251_disable_line_irq; ++ const_cast(wl1251_sdio_ops.enable_irq) = wl1251_enable_line_irq; ++ const_cast(wl1251_sdio_ops.disable_irq) = wl1251_disable_line_irq; + pax_close_kernel(); wl1251_info("using dedicated interrupt line"); @@ -66150,14 +66724,14 @@ index b661f896..ddf7d2b 100644 - wl1251_sdio_ops.enable_irq = wl1251_sdio_enable_irq; - wl1251_sdio_ops.disable_irq = wl1251_sdio_disable_irq; + pax_open_kernel(); -+ *(void **)&wl1251_sdio_ops.enable_irq = wl1251_sdio_enable_irq; -+ *(void **)&wl1251_sdio_ops.disable_irq = wl1251_sdio_disable_irq; ++ const_cast(wl1251_sdio_ops.enable_irq) = wl1251_sdio_enable_irq; ++ const_cast(wl1251_sdio_ops.disable_irq) = wl1251_sdio_disable_irq; + pax_close_kernel(); wl1251_info("using SDIO interrupt"); } diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c -index a0d6ccc..93d9ac5 100644 +index a0d6ccc..36e1ae3 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -656,7 +656,9 @@ static int wl12xx_identify_chip(struct wl1271 *wl) @@ -66166,7 +66740,7 @@ index a0d6ccc..93d9ac5 100644 /* read data preparation is only needed by wl127x */ - wl->ops->prepare_read = wl127x_prepare_read; + pax_open_kernel(); -+ *(void **)&wl->ops->prepare_read = wl127x_prepare_read; ++ const_cast(wl->ops->prepare_read) = wl127x_prepare_read; + pax_close_kernel(); wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, @@ -66177,13 +66751,13 @@ index a0d6ccc..93d9ac5 100644 /* read data preparation is only needed by wl127x */ - wl->ops->prepare_read = wl127x_prepare_read; + pax_open_kernel(); -+ *(void **)&wl->ops->prepare_read = wl127x_prepare_read; ++ const_cast(wl->ops->prepare_read) = wl127x_prepare_read; + pax_close_kernel(); wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, WL127X_IFTYPE_SR_VER, WL127X_MAJOR_SR_VER, diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c -index 1bf26cc..3b15c02 100644 +index 1bf26cc..7dd1267 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -2018,8 +2018,10 @@ static int wl18xx_setup(struct wl1271 *wl) @@ -66193,8 +66767,8 @@ index 1bf26cc..3b15c02 100644 - wl18xx_ops.set_rx_csum = NULL; - wl18xx_ops.init_vif = NULL; + pax_open_kernel(); -+ *(void **)&wl18xx_ops.set_rx_csum = NULL; -+ *(void **)&wl18xx_ops.init_vif = NULL; ++ const_cast(wl18xx_ops.set_rx_csum) = NULL; ++ const_cast(wl18xx_ops.init_vif) = NULL; + pax_close_kernel(); } @@ -66687,7 +67261,7 @@ index 680f578..cf80097 100644 struct nvme_dev *dev = pci_get_drvdata(pdev); diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c -index 655f79d..509e3cd 100644 +index 655f79d..c684ede 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -1170,7 +1170,9 @@ static int __init of_fdt_raw_init(void) @@ -66696,7 +67270,7 @@ index 655f79d..509e3cd 100644 } - of_fdt_raw_attr.size = fdt_totalsize(initial_boot_params); + pax_open_kernel(); -+ *(size_t *)&of_fdt_raw_attr.size = fdt_totalsize(initial_boot_params); ++ const_cast(of_fdt_raw_attr.size) = fdt_totalsize(initial_boot_params); + pax_close_kernel(); return sysfs_create_bin_file(firmware_kobj, &of_fdt_raw_attr); } @@ -66881,7 +67455,7 @@ index 1652bc7..4f999c4 100644 struct gen_pci_cfg_windows { struct resource res; diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c -index 2f6d3a1..5bc1bf1 100644 +index 2f6d3a1..cb43cfc 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -463,7 +463,9 @@ static int __init ibm_acpiphp_init(void) @@ -66890,7 +67464,7 @@ index 2f6d3a1..5bc1bf1 100644 - ibm_apci_table_attr.size = ibm_get_table_from_acpi(NULL); + pax_open_kernel(); -+ *(size_t *)&ibm_apci_table_attr.size = ibm_get_table_from_acpi(NULL); ++ const_cast(ibm_apci_table_attr.size) = ibm_get_table_from_acpi(NULL); + pax_close_kernel(); retval = sysfs_create_bin_file(sysdir, &ibm_apci_table_attr); @@ -66927,7 +67501,7 @@ index 88a44a7..de358ce 100644 status = cpci_hp_register_controller(&generic_hpc); diff --git a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c -index 5f49c3f..989cd41 100644 +index 5f49c3f..438f019 100644 --- a/drivers/pci/hotplug/cpcihp_zt5550.c +++ b/drivers/pci/hotplug/cpcihp_zt5550.c @@ -59,7 +59,6 @@ @@ -66964,9 +67538,9 @@ index 5f49c3f..989cd41 100644 - zt5550_hpc_ops.disable_irq = zt5550_hc_disable_irq; - zt5550_hpc_ops.check_irq = zt5550_hc_check_irq; + pax_open_kernel(); -+ *(void **)&zt5550_hpc_ops.enable_irq = zt5550_hc_enable_irq; -+ *(void **)&zt5550_hpc_ops.disable_irq = zt5550_hc_disable_irq; -+ *(void **)&zt5550_hpc_ops.check_irq = zt5550_hc_check_irq; ++ const_cast(zt5550_hpc_ops.enable_irq) = zt5550_hc_enable_irq; ++ const_cast(zt5550_hpc_ops.disable_irq) = zt5550_hc_disable_irq; ++ const_cast(zt5550_hpc_ops.check_irq) = zt5550_hc_check_irq; + pax_open_kernel(); } else { info("using ENUM# polling mode"); @@ -66987,7 +67561,7 @@ index c25fc90..b054774 100644 dbg("int15 entry = %p\n", compaq_int15_entry_point); diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c -index 9acd199..0645a09 100644 +index 9acd199..1b19f5b 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -434,8 +434,10 @@ int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, @@ -66997,8 +67571,8 @@ index 9acd199..0645a09 100644 - slot->ops->owner = owner; - slot->ops->mod_name = mod_name; + pax_open_kernel(); -+ *(struct module **)&slot->ops->owner = owner; -+ *(const char **)&slot->ops->mod_name = mod_name; ++ const_cast(slot->ops->owner) = owner; ++ const_cast(slot->ops->mod_name) = mod_name; + pax_close_kernel(); mutex_lock(&pci_hp_mutex); @@ -67017,7 +67591,7 @@ index ac531e6..716d058 100644 int retval = -ENOMEM; diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c -index a080f44..9ff42d9 100644 +index a080f44..24ad26c 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -474,8 +474,8 @@ static int populate_msi_sysfs(struct pci_dev *pdev) @@ -67047,13 +67621,13 @@ index a080f44..9ff42d9 100644 + pax_open_kernel(); if (ops->set_desc == NULL) - ops->set_desc = pci_msi_domain_set_desc; -+ *(void **)&ops->set_desc = pci_msi_domain_set_desc; ++ const_cast(ops->set_desc) = pci_msi_domain_set_desc; if (ops->msi_check == NULL) - ops->msi_check = pci_msi_domain_check_cap; -+ *(void **)&ops->msi_check = pci_msi_domain_check_cap; ++ const_cast(ops->msi_check) = pci_msi_domain_check_cap; if (ops->handle_error == NULL) - ops->handle_error = pci_msi_domain_handle_error; -+ *(void **)&ops->handle_error = pci_msi_domain_handle_error; ++ const_cast(ops->handle_error) = pci_msi_domain_handle_error; + pax_close_kernel(); } } @@ -67065,13 +67639,13 @@ index a080f44..9ff42d9 100644 + pax_open_kernel(); if (!chip->irq_write_msi_msg) - chip->irq_write_msi_msg = pci_msi_domain_write_msg; -+ *(void **)&chip->irq_write_msi_msg = pci_msi_domain_write_msg; ++ const_cast(chip->irq_write_msi_msg) = pci_msi_domain_write_msg; if (!chip->irq_mask) - chip->irq_mask = pci_msi_mask_irq; -+ *(void **)&chip->irq_mask = pci_msi_mask_irq; ++ const_cast(chip->irq_mask) = pci_msi_mask_irq; if (!chip->irq_unmask) - chip->irq_unmask = pci_msi_unmask_irq; -+ *(void **)&chip->irq_unmask = pci_msi_unmask_irq; ++ const_cast(chip->irq_unmask) = pci_msi_unmask_irq; + pax_close_kernel(); } @@ -67238,7 +67812,7 @@ index c8969dd..4764267 100644 bool supports_sleepmode; int irq; diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c -index 523b6b7..e9aa88d 100644 +index 523b6b7..eb4c74d 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -24,6 +24,7 @@ @@ -67255,7 +67829,7 @@ index 523b6b7..e9aa88d 100644 /* Setup proper .irq_set_type function */ - gpio_irqchip.irq_set_type = at91_gpio->ops->irq_type; + pax_open_kernel(); -+ *(void **)&gpio_irqchip.irq_set_type = at91_gpio->ops->irq_type; ++ const_cast(gpio_irqchip.irq_set_type) = at91_gpio->ops->irq_type; + pax_close_kernel(); /* Disable irqs of this PIO controller */ @@ -67398,7 +67972,7 @@ index 6aa33c4..cfb5425 100644 .ident = "OakTrail platform", .matches = { diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c -index 4231770..10a6caf 100644 +index 4231770..cbf93a6 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -605,7 +605,7 @@ static int dmi_check_cb(const struct dmi_system_id *dmi) @@ -67421,12 +67995,12 @@ index 4231770..10a6caf 100644 - dev_attr_wlan.attr.mode |= S_IWUSR; - dev_attr_threeg.attr.mode |= S_IWUSR; + pax_open_kernel(); -+ *(void **)&dev_attr_bluetooth.store = store_bluetooth; -+ *(void **)&dev_attr_wlan.store = store_wlan; -+ *(void **)&dev_attr_threeg.store = store_threeg; -+ *(umode_t *)&dev_attr_bluetooth.attr.mode |= S_IWUSR; -+ *(umode_t *)&dev_attr_wlan.attr.mode |= S_IWUSR; -+ *(umode_t *)&dev_attr_threeg.attr.mode |= S_IWUSR; ++ const_cast(dev_attr_bluetooth.store) = store_bluetooth; ++ const_cast(dev_attr_wlan.store) = store_wlan; ++ const_cast(dev_attr_threeg.store) = store_threeg; ++ const_cast(dev_attr_bluetooth.attr.mode) |= S_IWUSR; ++ const_cast(dev_attr_wlan.attr.mode) |= S_IWUSR; ++ const_cast(dev_attr_threeg.attr.mode) |= S_IWUSR; + pax_close_kernel(); } @@ -67756,7 +68330,7 @@ index ed2d7fd..266b28f 100644 __power_supply_attrs[i] = &power_supply_attrs[i].attr; } diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c -index 1b5d450..3257054 100644 +index 1b5d450..b6042f8 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -17,6 +17,7 @@ @@ -67773,13 +68347,13 @@ index 1b5d450..3257054 100644 match = of_match_node(at91_reset_of_match, pdev->dev.of_node); - at91_restart_nb.notifier_call = match->data; + pax_open_kernel(); -+ *(void **)&at91_restart_nb.notifier_call = match->data; ++ const_cast(at91_restart_nb.notifier_call) = match->data; + pax_close_kernel(); sclk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(sclk)) diff --git a/drivers/powercap/powercap_sys.c b/drivers/powercap/powercap_sys.c -index 14bde0d..89f2669 100644 +index 14bde0d..9391277 100644 --- a/drivers/powercap/powercap_sys.c +++ b/drivers/powercap/powercap_sys.c @@ -154,8 +154,77 @@ struct powercap_constraint_attr { @@ -67887,7 +68461,7 @@ index 14bde0d..89f2669 100644 - dev_attr->store = store; + + pax_open_kernel(); -+ *(const char **)&dev_attr->attr.name = name; ++ const_cast(dev_attr->attr.name) = name; + pax_close_kernel(); return 0; @@ -67959,10 +68533,10 @@ index 14bde0d..89f2669 100644 + pax_open_kernel(); if (power_zone->ops->reset_energy_uj) - dev_attr_energy_uj.attr.mode = S_IWUSR | S_IRUGO; -+ *(umode_t *)&dev_attr_energy_uj.attr.mode = S_IWUSR | S_IRUGO; ++ const_cast(dev_attr_energy_uj.attr.mode) = S_IWUSR | S_IRUGO; else - dev_attr_energy_uj.attr.mode = S_IRUGO; -+ *(umode_t *)&dev_attr_energy_uj.attr.mode = S_IRUGO; ++ const_cast(dev_attr_energy_uj.attr.mode) = S_IRUGO; + pax_close_kernel(); power_zone->zone_dev_attrs[count++] = &dev_attr_energy_uj.attr; @@ -68016,7 +68590,7 @@ index 744c988..a269ffb 100644 if (ret != 0) { put_device(&rdev->dev); diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c -index b87f62d..345b9a1 100644 +index b87f62d..34f1cdf 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -423,8 +423,10 @@ static int max8660_probe(struct i2c_client *client, @@ -68026,14 +68600,14 @@ index b87f62d..345b9a1 100644 - max8660_dcdc_ops.enable = max8660_dcdc_enable; - max8660_dcdc_ops.disable = max8660_dcdc_disable; + pax_open_kernel(); -+ *(void **)&max8660_dcdc_ops.enable = max8660_dcdc_enable; -+ *(void **)&max8660_dcdc_ops.disable = max8660_dcdc_disable; ++ const_cast(max8660_dcdc_ops.enable) = max8660_dcdc_enable; ++ const_cast(max8660_dcdc_ops.disable) = max8660_dcdc_disable; + pax_close_kernel(); } /* diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c -index 5b75b7c..142c226 100644 +index 5b75b7c..8b1bb06 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -658,9 +658,11 @@ static int max8973_probe(struct i2c_client *client, @@ -68044,9 +68618,9 @@ index 5b75b7c..142c226 100644 - max->ops.disable = regulator_disable_regmap; - max->ops.is_enabled = regulator_is_enabled_regmap; + pax_open_kernel(); -+ *(void **)&max->ops.enable = regulator_enable_regmap; -+ *(void **)&max->ops.disable = regulator_disable_regmap; -+ *(void **)&max->ops.is_enabled = regulator_is_enabled_regmap; ++ const_cast(max->ops.enable) = regulator_enable_regmap; ++ const_cast(max->ops.disable) = regulator_disable_regmap; ++ const_cast(max->ops.is_enabled) = regulator_is_enabled_regmap; + pax_close_kernel(); break; } @@ -68059,15 +68633,15 @@ index 5b75b7c..142c226 100644 - max->ops.disable = regulator_disable_regmap; - max->ops.is_enabled = regulator_is_enabled_regmap; + pax_open_kernel(); -+ *(void **)&max->ops.enable = regulator_enable_regmap; -+ *(void **)&max->ops.disable = regulator_disable_regmap; -+ *(void **)&max->ops.is_enabled = regulator_is_enabled_regmap; ++ const_cast(max->ops.enable) = regulator_enable_regmap; ++ const_cast(max->ops.disable) = regulator_disable_regmap; ++ const_cast(max->ops.is_enabled) = regulator_is_enabled_regmap; + pax_close_kernel(); max->ops.set_current_limit = max8973_set_current_limit; max->ops.get_current_limit = max8973_get_current_limit; break; diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c -index 0d17c92..a29f627 100644 +index 0d17c92..ce5897e 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -584,10 +584,12 @@ static int mc13892_regulator_probe(struct platform_device *pdev) @@ -68080,8 +68654,8 @@ index 0d17c92..a29f627 100644 sizeof(struct regulator_ops)); - mc13892_vcam_ops.set_mode = mc13892_vcam_set_mode, - mc13892_vcam_ops.get_mode = mc13892_vcam_get_mode, -+ *(void **)&mc13892_vcam_ops.set_mode = mc13892_vcam_set_mode, -+ *(void **)&mc13892_vcam_ops.get_mode = mc13892_vcam_get_mode, ++ const_cast(mc13892_vcam_ops.set_mode) = mc13892_vcam_set_mode, ++ const_cast(mc13892_vcam_ops.get_mode) = mc13892_vcam_get_mode, + pax_close_kernel(); mc13892_regulators[MC13892_VCAM].desc.ops = &mc13892_vcam_ops; @@ -68177,7 +68751,7 @@ index 9e03d15..36e341c 100644 /* handle firmware resource entries before booting the remote processor */ diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c -index 9a3f2a6..604f463 100644 +index 9a3f2a6..c19b00a 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -18,6 +18,7 @@ @@ -68195,14 +68769,14 @@ index 9a3f2a6..604f463 100644 - armada38x_rtc_ops.set_alarm = NULL; - armada38x_rtc_ops.alarm_irq_enable = NULL; + pax_open_kernel(); -+ *(void **)&armada38x_rtc_ops.set_alarm = NULL; -+ *(void **)&armada38x_rtc_ops.alarm_irq_enable = NULL; ++ const_cast(armada38x_rtc_ops.set_alarm) = NULL; ++ const_cast(armada38x_rtc_ops.alarm_irq_enable) = NULL; + pax_close_kernel(); } platform_set_drvdata(pdev, rtc); if (rtc->irq != -1) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c -index 84fb541..fee0421a 100644 +index 84fb541..a526dd0 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -735,7 +735,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) @@ -68211,7 +68785,7 @@ index 84fb541..fee0421a 100644 /* export at least the first block of NVRAM */ - nvram.size = address_space - NVRAM_OFFSET; + pax_open_kernel(); -+ *(size_t *)&nvram.size = address_space - NVRAM_OFFSET; ++ const_cast(nvram.size) = address_space - NVRAM_OFFSET; + pax_close_kernel(); retval = sysfs_create_bin_file(&dev->kobj, &nvram); if (retval < 0) { @@ -68251,7 +68825,7 @@ index cf685f6..2311b8f 100644 unsigned long flags; #define HAS_NVRAM 0 /* bit 0 == sysfs file active */ diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c -index d99a705..f8ebd79 100644 +index d99a705..99654e7 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -485,7 +485,9 @@ static int m48t59_rtc_probe(struct platform_device *pdev) @@ -68260,7 +68834,7 @@ index d99a705..f8ebd79 100644 - m48t59_nvram_attr.size = pdata->offset; + pax_open_kernel(); -+ *(size_t *)&m48t59_nvram_attr.size = pdata->offset; ++ const_cast(m48t59_nvram_attr.size) = pdata->offset; + pax_close_kernel(); ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); @@ -68303,7 +68877,7 @@ index 7155c08..10ba718 100644 dev_err(&client->dev, "unable to register the class device\n"); return PTR_ERR(rv8803->rtc); diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c -index 772d221..60e31aa 100644 +index 772d221..3a56e42 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -489,9 +489,11 @@ static int rx8010_probe(struct i2c_client *client, @@ -68314,15 +68888,15 @@ index 772d221..60e31aa 100644 - rx8010_rtc_ops.set_alarm = rx8010_set_alarm; - rx8010_rtc_ops.alarm_irq_enable = rx8010_alarm_irq_enable; + pax_open_kernel(); -+ *(void **)&rx8010_rtc_ops.read_alarm = rx8010_read_alarm; -+ *(void **)&rx8010_rtc_ops.set_alarm = rx8010_set_alarm; -+ *(void **)&rx8010_rtc_ops.alarm_irq_enable = rx8010_alarm_irq_enable; ++ const_cast(rx8010_rtc_ops.read_alarm) = rx8010_read_alarm; ++ const_cast(rx8010_rtc_ops.set_alarm) = rx8010_set_alarm; ++ const_cast(rx8010_rtc_ops.alarm_irq_enable) = rx8010_alarm_irq_enable; + pax_close_kernel(); } } diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c -index 3a2da4c..e88493c 100644 +index 3a2da4c..1d1d4b1 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -112,8 +112,10 @@ static int test_probe(struct platform_device *plat_dev) @@ -68332,34 +68906,16 @@ index 3a2da4c..e88493c 100644 - test_rtc_ops.set_mmss64 = test_rtc_set_mmss64; - test_rtc_ops.set_mmss = NULL; + pax_open_kernel(); -+ *(void **)&test_rtc_ops.set_mmss64 = test_rtc_set_mmss64; -+ *(void **)&test_rtc_ops.set_mmss = NULL; ++ const_cast(test_rtc_ops.set_mmss64) = test_rtc_set_mmss64; ++ const_cast(test_rtc_ops.set_mmss) = NULL; + pax_close_kernel(); } rtc = devm_rtc_device_register(&plat_dev->dev, "test", diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c -index e4c2437..2297164 100644 +index e4c2437..3b3cd62 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c -@@ -647,7 +647,7 @@ static void _aac_probe_container2(void * context, struct fib * fibptr) - } - aac_fib_complete(fibptr); - aac_fib_free(fibptr); -- callback = (int (*)(struct scsi_cmnd *))(scsicmd->SCp.ptr); -+ callback = scsicmd->SCp.ptr; - scsicmd->SCp.ptr = NULL; - (*callback)(scsicmd); - return; -@@ -726,7 +726,7 @@ static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(stru - - dinfo->count = cpu_to_le32(scmd_id(scsicmd)); - dinfo->type = cpu_to_le32(FT_FILESYS); -- scsicmd->SCp.ptr = (char *)callback; -+ scsicmd->SCp.ptr = callback; - - status = aac_fib_send(ContainerCommand, - fibptr, @@ -775,6 +775,11 @@ static int aac_probe_container_callback1(struct scsi_cmnd * scsicmd) return 0; } @@ -70641,7 +71197,7 @@ index 25aa9b9..d700a65 100644 snprintf(name, sizeof(name), "discovery_trace"); vport->debug_disc_trc = diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c -index f57d02c..ab7b70c 100644 +index f57d02c..6ba534b 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -11028,7 +11028,7 @@ lpfc_pci_resume_one(struct pci_dev *pdev) @@ -70660,8 +71216,8 @@ index f57d02c..ab7b70c 100644 - lpfc_transport_functions.vport_create = lpfc_vport_create; - lpfc_transport_functions.vport_delete = lpfc_vport_delete; + pax_open_kernel(); -+ *(void **)&lpfc_transport_functions.vport_create = lpfc_vport_create; -+ *(void **)&lpfc_transport_functions.vport_delete = lpfc_vport_delete; ++ const_cast(lpfc_transport_functions.vport_create) = lpfc_vport_create; ++ const_cast(lpfc_transport_functions.vport_delete) = lpfc_vport_delete; + pax_close_kernel(); } lpfc_transport_template = @@ -71004,7 +71560,7 @@ index 0103e46..6220a84 100644 extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *, bool); extern void qla2x00_init_host_attr(scsi_qla_host_t *); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c -index f6c7ce3..2dd675b 100644 +index f6c7ce3..dccd3d4 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -291,12 +291,12 @@ struct scsi_transport_template *qla2xxx_transport_vport_template = NULL; @@ -71029,8 +71585,8 @@ index f6c7ce3..2dd675b 100644 - ha->isp_ops->calc_req_entries = qla2x00_calc_iocbs_64; - ha->isp_ops->build_iocbs = qla2x00_build_scsi_iocbs_64; + pax_open_kernel(); -+ *(void **)&ha->isp_ops->calc_req_entries = qla2x00_calc_iocbs_64; -+ *(void **)&ha->isp_ops->build_iocbs = qla2x00_build_scsi_iocbs_64; ++ const_cast(ha->isp_ops->calc_req_entries) = qla2x00_calc_iocbs_64; ++ const_cast(ha->isp_ops->build_iocbs) = qla2x00_build_scsi_iocbs_64; + pax_close_kernel(); return; } @@ -74424,7 +74980,7 @@ index 9a14074..3d02410 100644 struct rtw_adapter *padapter = netdev_priv(pnetdev); struct xmit_priv *pxmitpriv = &padapter->xmitpriv; diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c -index c78421b..f75c4c4 100644 +index c78421b..e1ba746 100644 --- a/drivers/staging/sm750fb/sm750.c +++ b/drivers/staging/sm750fb/sm750.c @@ -720,6 +720,7 @@ static struct fb_ops lynxfb_ops = { @@ -74449,7 +75005,7 @@ index c78421b..f75c4c4 100644 if (!g_hwcursor) { - lynxfb_ops.fb_cursor = NULL; + pax_open_kernel(); -+ *(void **)&lynxfb_ops.fb_cursor = NULL; ++ const_cast(lynxfb_ops.fb_cursor) = NULL; + pax_close_kernel(); hw_cursor_disable(&crtc->cursor); } @@ -74461,9 +75017,9 @@ index c78421b..f75c4c4 100644 - lynxfb_ops.fb_copyarea = lynxfb_ops_copyarea; - lynxfb_ops.fb_imageblit = lynxfb_ops_imageblit; + pax_open_kernel(); -+ *(void **)&lynxfb_ops.fb_fillrect = lynxfb_ops_fillrect; -+ *(void **)&lynxfb_ops.fb_copyarea = lynxfb_ops_copyarea; -+ *(void **)&lynxfb_ops.fb_imageblit = lynxfb_ops_imageblit; ++ const_cast(lynxfb_ops.fb_fillrect) = lynxfb_ops_fillrect; ++ const_cast(lynxfb_ops.fb_copyarea) = lynxfb_ops_copyarea; ++ const_cast(lynxfb_ops.fb_imageblit) = lynxfb_ops_imageblit; + pax_close_kernel(); } info->fbops = &lynxfb_ops; @@ -74589,7 +75145,7 @@ index 3072f1a..1071742 100644 login->tgt_agt = sbp_target_agent_register(login); if (IS_ERR(login->tgt_agt)) { diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c -index 6ceac4f..b2ed52c 100644 +index 6ceac4f..f8059ccd 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -838,10 +838,11 @@ __cpufreq_cooling_register(struct device_node *np, @@ -74601,9 +75157,9 @@ index 6ceac4f..b2ed52c 100644 - cpufreq_cooling_ops.state2power = cpufreq_state2power; - cpufreq_cooling_ops.power2state = cpufreq_power2state; + pax_open_kernel(); -+ *(void **)&cpufreq_cooling_ops.get_requested_power = cpufreq_get_requested_power; -+ *(void **)&cpufreq_cooling_ops.state2power = cpufreq_state2power; -+ *(void **)&cpufreq_cooling_ops.power2state = cpufreq_power2state; ++ const_cast(cpufreq_cooling_ops.get_requested_power) = cpufreq_get_requested_power; ++ const_cast(cpufreq_cooling_ops.state2power) = cpufreq_state2power; ++ const_cast(cpufreq_cooling_ops.power2state) = cpufreq_power2state; + pax_close_kernel(); cpufreq_dev->plat_get_static_power = plat_static_func; @@ -74655,7 +75211,7 @@ index 01f0015..aa56551 100644 err = PTR_ERR(cdev); dev_err(df->dev.parent, diff --git a/drivers/thermal/int340x_thermal/int3400_thermal.c b/drivers/thermal/int340x_thermal/int3400_thermal.c -index 5836e55..740ab89 100644 +index 5836e55..708bbd6 100644 --- a/drivers/thermal/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/int340x_thermal/int3400_thermal.c @@ -272,8 +272,10 @@ static int int3400_thermal_probe(struct platform_device *pdev) @@ -74665,14 +75221,14 @@ index 5836e55..740ab89 100644 - int3400_thermal_ops.get_mode = int3400_thermal_get_mode; - int3400_thermal_ops.set_mode = int3400_thermal_set_mode; + pax_open_kernel(); -+ *(void **)&int3400_thermal_ops.get_mode = int3400_thermal_get_mode; -+ *(void **)&int3400_thermal_ops.set_mode = int3400_thermal_set_mode; ++ const_cast(int3400_thermal_ops.get_mode) = int3400_thermal_get_mode; ++ const_cast(int3400_thermal_ops.set_mode) = int3400_thermal_set_mode; + pax_close_kernel(); } priv->thermal = thermal_zone_device_register("INT3400 Thermal", 0, 0, priv, &int3400_thermal_ops, diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c -index 9043f8f..ab0f354 100644 +index 9043f8f..1b53349 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -31,6 +31,7 @@ @@ -74691,9 +75247,9 @@ index 9043f8f..ab0f354 100644 - tzd->ops->get_trend = of_thermal_get_trend; - tzd->ops->set_emul_temp = of_thermal_set_emul_temp; + pax_open_kernel(); -+ *(void **)&tzd->ops->get_temp = of_thermal_get_temp; -+ *(void **)&tzd->ops->get_trend = of_thermal_get_trend; -+ *(void **)&tzd->ops->set_emul_temp = of_thermal_set_emul_temp; ++ const_cast(tzd->ops->get_temp) = of_thermal_get_temp; ++ const_cast(tzd->ops->get_trend) = of_thermal_get_trend; ++ const_cast(tzd->ops->set_emul_temp) = of_thermal_set_emul_temp; + pax_close_kernel(); mutex_unlock(&tzd->lock); @@ -74706,9 +75262,9 @@ index 9043f8f..ab0f354 100644 - tzd->ops->get_trend = NULL; - tzd->ops->set_emul_temp = NULL; + pax_open_kernel(); -+ *(void **)&tzd->ops->get_temp = NULL; -+ *(void **)&tzd->ops->get_trend = NULL; -+ *(void **)&tzd->ops->set_emul_temp = NULL; ++ const_cast(tzd->ops->get_temp) = NULL; ++ const_cast(tzd->ops->get_trend) = NULL; ++ const_cast(tzd->ops->set_emul_temp) = NULL; + pax_close_kernel(); tz->ops = NULL; @@ -75289,7 +75845,7 @@ index b280abaa..3ccd7d1 100644 } EXPORT_SYMBOL_GPL(n_tty_inherit_ops); diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c -index 2348fa6..14894f4 100644 +index 2348fa6..490e407 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -879,8 +879,10 @@ static void __init unix98_pty_init(void) @@ -75299,7 +75855,7 @@ index 2348fa6..14894f4 100644 + pax_open_kernel(); tty_default_fops(&ptmx_fops); - ptmx_fops.open = ptmx_open; -+ *(void **)&ptmx_fops.open = ptmx_open; ++ const_cast(ptmx_fops.open) = ptmx_open; + pax_close_kernel(); cdev_init(&ptmx_cdev, &ptmx_fops); @@ -75336,7 +75892,7 @@ index 802eac7..f5dcf07 100644 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); spin_unlock_irqrestore(&info->port.lock, flags); diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c -index c9720a9..f6c9276 100644 +index c9720a9..964f2d9 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -488,9 +488,9 @@ static void univ8250_release_port(struct uart_port *port) @@ -75346,9 +75902,9 @@ index c9720a9..f6c9276 100644 - ops->config_port = univ8250_config_port; - ops->request_port = univ8250_request_port; - ops->release_port = univ8250_release_port; -+ *(void **)&ops->config_port = univ8250_config_port; -+ *(void **)&ops->request_port = univ8250_request_port; -+ *(void **)&ops->release_port = univ8250_release_port; ++ const_cast(ops->config_port) = univ8250_config_port; ++ const_cast(ops->request_port) = univ8250_request_port; ++ const_cast(ops->release_port) = univ8250_release_port; } #else @@ -75435,7 +75991,7 @@ index a119f11..120444e 100644 struct jsm_board *brd = pci_get_drvdata(pdev); diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c -index 117df15..2f7dfcf 100644 +index 117df15..8f7486f 100644 --- a/drivers/tty/serial/kgdb_nmi.c +++ b/drivers/tty/serial/kgdb_nmi.c @@ -53,7 +53,9 @@ static int kgdb_nmi_console_setup(struct console *co, char *options) @@ -75444,7 +76000,7 @@ index 117df15..2f7dfcf 100644 */ - dbg_io_ops->is_console = true; + pax_open_kernel(); -+ *(int *)&dbg_io_ops->is_console = true; ++ const_cast(dbg_io_ops->is_console) = true; + pax_close_kernel(); return 0; @@ -76984,6 +77540,105 @@ index 48672fa..9245081 100644 /* Device for a quirk */ #define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index a85a1c9..0f198bc 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -1861,9 +1861,9 @@ td_cleanup: + * unsigned). Play it safe and say we didn't transfer anything. + */ + if (urb->actual_length > urb->transfer_buffer_length) { +- xhci_warn(xhci, "URB transfer length is wrong, xHC issue? req. len = %u, act. len = %u\n", ++ xhci_warn(xhci, "URB transfer length is wrong, xHC issue? req. len = %u, trans. len = %u\n", + urb->transfer_buffer_length, +- urb->actual_length); ++ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len))); + urb->actual_length = 0; + if (td->urb->transfer_flags & URB_SHORT_NOT_OK) + *status = -EREMOTEIO; +@@ -1942,10 +1942,15 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, + return finish_td(xhci, td, event_trb, event, ep, status, false); + case COMP_STOP: + /* Did we stop at data stage? */ +- if (event_trb != ep_ring->dequeue && event_trb != td->last_trb) +- td->urb->actual_length = +- td->urb->transfer_buffer_length - +- EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); ++ if (event_trb != ep_ring->dequeue && event_trb != td->last_trb) { ++ if (td->urb->transfer_buffer_length >= EVENT_TRB_LEN(le32_to_cpu(event->transfer_len))) ++ td->urb->actual_length = ++ td->urb->transfer_buffer_length - ++ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); ++ else ++ td->urb->actual_length = ++ td->urb->transfer_buffer_length + 1; ++ } + /* fall through */ + case COMP_STOP_INVAL: + return finish_td(xhci, td, event_trb, event, ep, status, false); +@@ -1959,12 +1964,15 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, + /* else fall through */ + case COMP_STALL: + /* Did we transfer part of the data (middle) phase? */ +- if (event_trb != ep_ring->dequeue && +- event_trb != td->last_trb) +- td->urb->actual_length = +- td->urb->transfer_buffer_length - +- EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); +- else if (!td->urb_length_set) ++ if (event_trb != ep_ring->dequeue && event_trb != td->last_trb) { ++ if (td->urb->transfer_buffer_length >= EVENT_TRB_LEN(le32_to_cpu(event->transfer_len))) ++ td->urb->actual_length = ++ td->urb->transfer_buffer_length - ++ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); ++ else ++ td->urb->actual_length = ++ td->urb->transfer_buffer_length + 1; ++ } else if (!td->urb_length_set) + td->urb->actual_length = 0; + + return finish_td(xhci, td, event_trb, event, ep, status, false); +@@ -1997,9 +2005,12 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, + * the last TRB. + */ + td->urb_length_set = true; +- td->urb->actual_length = +- td->urb->transfer_buffer_length - +- EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); ++ if (td->urb->transfer_buffer_length >= EVENT_TRB_LEN(le32_to_cpu(event->transfer_len))) ++ td->urb->actual_length = ++ td->urb->transfer_buffer_length - ++ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); ++ else ++ BUG(); + xhci_dbg(xhci, "Waiting for status " + "stage event\n"); + return 0; +@@ -2194,11 +2205,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, + /* Fast path - was this the last TRB in the TD for this URB? */ + } else if (event_trb == td->last_trb) { + if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { +- td->urb->actual_length = +- td->urb->transfer_buffer_length - +- EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); +- if (td->urb->transfer_buffer_length < +- td->urb->actual_length) { ++ if (td->urb->transfer_buffer_length < EVENT_TRB_LEN(le32_to_cpu(event->transfer_len))) { + xhci_warn(xhci, "HC gave bad length " + "of %d bytes left\n", + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len))); +@@ -2207,7 +2214,10 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, + *status = -EREMOTEIO; + else + *status = 0; +- } ++ } else ++ td->urb->actual_length = ++ td->urb->transfer_buffer_length - ++ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); + /* Don't overwrite a previously set error code */ + if (*status == -EINPROGRESS) { + if (td->urb->transfer_flags & URB_SHORT_NOT_OK) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 8e713cc..8c92a15 100644 --- a/drivers/usb/host/xhci.c @@ -77621,7 +78276,7 @@ index c42ce2f..4c8bc59 100644 "PCI", "PRO AGP", diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c -index f34ed47f..026367f 100644 +index f34ed47f..7283c9f 100644 --- a/drivers/video/fbdev/aty/atyfb_base.c +++ b/drivers/video/fbdev/aty/atyfb_base.c @@ -1335,10 +1335,14 @@ static int atyfb_set_par(struct fb_info *info) @@ -77630,13 +78285,13 @@ index f34ed47f..026367f 100644 if (var->accel_flags) { - info->fbops->fb_sync = atyfb_sync; + pax_open_kernel(); -+ *(void **)&info->fbops->fb_sync = atyfb_sync; ++ const_cast(info->fbops->fb_sync) = atyfb_sync; + pax_close_kernel(); info->flags &= ~FBINFO_HWACCEL_DISABLED; } else { - info->fbops->fb_sync = NULL; + pax_open_kernel(); -+ *(void **)&info->fbops->fb_sync = NULL; ++ const_cast(info->fbops->fb_sync) = NULL; + pax_close_kernel(); info->flags |= FBINFO_HWACCEL_DISABLED; } @@ -77663,7 +78318,7 @@ index 51f29d6..2c15339 100644 const struct aty_pll_ops aty_pll_ct = { diff --git a/drivers/video/fbdev/aty/mach64_cursor.c b/drivers/video/fbdev/aty/mach64_cursor.c -index 2fa0317..4983f2a 100644 +index 2fa0317..d687dab 100644 --- a/drivers/video/fbdev/aty/mach64_cursor.c +++ b/drivers/video/fbdev/aty/mach64_cursor.c @@ -8,6 +8,7 @@ @@ -77680,7 +78335,7 @@ index 2fa0317..4983f2a 100644 - info->fbops->fb_cursor = atyfb_cursor; + pax_open_kernel(); -+ *(void **)&info->fbops->fb_cursor = atyfb_cursor; ++ const_cast(info->fbops->fb_cursor) = atyfb_cursor; + pax_close_kernel(); return 0; @@ -77721,7 +78376,7 @@ index 10c988a..f7d9299 100644 + .set_pll = aty_set_pll, }; diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c -index 57721c7..55142ed 100644 +index 57721c7..332b94b 100644 --- a/drivers/video/fbdev/core/fb_defio.c +++ b/drivers/video/fbdev/core/fb_defio.c @@ -207,7 +207,9 @@ void fb_deferred_io_init(struct fb_info *info) @@ -77730,17 +78385,19 @@ index 57721c7..55142ed 100644 mutex_init(&fbdefio->lock); - info->fbops->fb_mmap = fb_deferred_io_mmap; + pax_open_kernel(); -+ *(void **)&info->fbops->fb_mmap = fb_deferred_io_mmap; ++ const_cast(info->fbops->fb_mmap) = fb_deferred_io_mmap; + pax_close_kernel(); INIT_DELAYED_WORK(&info->deferred_work, fb_deferred_io_work); INIT_LIST_HEAD(&fbdefio->pagelist); if (fbdefio->delay == 0) /* set a default of 1 s */ -@@ -238,7 +240,7 @@ void fb_deferred_io_cleanup(struct fb_info *info) +@@ -238,7 +240,9 @@ void fb_deferred_io_cleanup(struct fb_info *info) page->mapping = NULL; } - info->fbops->fb_mmap = NULL; -+ *(void **)&info->fbops->fb_mmap = NULL; ++ pax_open_kernel(); ++ const_cast(info->fbops->fb_mmap) = NULL; ++ pax_close_kernel(); mutex_destroy(&fbdefio->lock); } EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup); @@ -77872,7 +78529,7 @@ index 11eb094..622ee31 100644 { 640, 480, 48, 16, 33, 10, 96, 2, 60 }, { 800, 600, 144, 24, 28, 8, 112, 6, 60 }, diff --git a/drivers/video/fbdev/mb862xx/mb862xxfb_accel.c b/drivers/video/fbdev/mb862xx/mb862xxfb_accel.c -index fe92eed..106e085 100644 +index fe92eed..239e386 100644 --- a/drivers/video/fbdev/mb862xx/mb862xxfb_accel.c +++ b/drivers/video/fbdev/mb862xx/mb862xxfb_accel.c @@ -312,14 +312,18 @@ void mb862xxfb_init_accel(struct fb_info *info, int xres) @@ -77883,9 +78540,9 @@ index fe92eed..106e085 100644 - info->fbops->fb_copyarea = cfb_copyarea; - info->fbops->fb_imageblit = cfb_imageblit; + pax_open_kernel(); -+ *(void **)&info->fbops->fb_fillrect = cfb_fillrect; -+ *(void **)&info->fbops->fb_copyarea = cfb_copyarea; -+ *(void **)&info->fbops->fb_imageblit = cfb_imageblit; ++ const_cast(info->fbops->fb_fillrect) = cfb_fillrect; ++ const_cast(info->fbops->fb_copyarea) = cfb_copyarea; ++ const_cast(info->fbops->fb_imageblit) = cfb_imageblit; + pax_close_kernel(); } else { outreg(disp, GC_L0EM, 3); @@ -77893,15 +78550,15 @@ index fe92eed..106e085 100644 - info->fbops->fb_copyarea = mb86290fb_copyarea; - info->fbops->fb_imageblit = mb86290fb_imageblit; + pax_open_kernel(); -+ *(void **)&info->fbops->fb_fillrect = mb86290fb_fillrect; -+ *(void **)&info->fbops->fb_copyarea = mb86290fb_copyarea; -+ *(void **)&info->fbops->fb_imageblit = mb86290fb_imageblit; ++ const_cast(info->fbops->fb_fillrect) = mb86290fb_fillrect; ++ const_cast(info->fbops->fb_copyarea) = mb86290fb_copyarea; ++ const_cast(info->fbops->fb_imageblit) = mb86290fb_imageblit; + pax_close_kernel(); } outreg(draw, GDC_REG_DRAW_BASE, 0); outreg(draw, GDC_REG_MODE_MISC, 0x8000); diff --git a/drivers/video/fbdev/nvidia/nvidia.c b/drivers/video/fbdev/nvidia/nvidia.c -index ce7dab7..a87baf8 100644 +index ce7dab7..89d6521 100644 --- a/drivers/video/fbdev/nvidia/nvidia.c +++ b/drivers/video/fbdev/nvidia/nvidia.c @@ -660,19 +660,23 @@ static int nvidiafb_set_par(struct fb_info *info) @@ -77913,10 +78570,10 @@ index ce7dab7..a87baf8 100644 - info->fbops->fb_copyarea = nvidiafb_copyarea; - info->fbops->fb_sync = nvidiafb_sync; + pax_open_kernel(); -+ *(void **)&info->fbops->fb_imageblit = nvidiafb_imageblit; -+ *(void **)&info->fbops->fb_fillrect = nvidiafb_fillrect; -+ *(void **)&info->fbops->fb_copyarea = nvidiafb_copyarea; -+ *(void **)&info->fbops->fb_sync = nvidiafb_sync; ++ const_cast(info->fbops->fb_imageblit) = nvidiafb_imageblit; ++ const_cast(info->fbops->fb_fillrect) = nvidiafb_fillrect; ++ const_cast(info->fbops->fb_copyarea) = nvidiafb_copyarea; ++ const_cast(info->fbops->fb_sync) = nvidiafb_sync; + pax_close_kernel(); info->pixmap.scan_align = 4; info->flags &= ~FBINFO_HWACCEL_DISABLED; @@ -77928,10 +78585,10 @@ index ce7dab7..a87baf8 100644 - info->fbops->fb_copyarea = cfb_copyarea; - info->fbops->fb_sync = NULL; + pax_open_kernel(); -+ *(void **)&info->fbops->fb_imageblit = cfb_imageblit; -+ *(void **)&info->fbops->fb_fillrect = cfb_fillrect; -+ *(void **)&info->fbops->fb_copyarea = cfb_copyarea; -+ *(void **)&info->fbops->fb_sync = NULL; ++ const_cast(info->fbops->fb_imageblit) = cfb_imageblit; ++ const_cast(info->fbops->fb_fillrect) = cfb_fillrect; ++ const_cast(info->fbops->fb_copyarea) = cfb_copyarea; ++ const_cast(info->fbops->fb_sync) = NULL; + pax_close_kernel(); info->pixmap.scan_align = 1; info->flags |= FBINFO_HWACCEL_DISABLED; @@ -77944,14 +78601,14 @@ index ce7dab7..a87baf8 100644 - info->fbops->fb_cursor = NULL; + if (!hwcur) { + pax_open_kernel(); -+ *(void **)&info->fbops->fb_cursor = NULL; ++ const_cast(info->fbops->fb_cursor) = NULL; + pax_close_kernel(); + } info->var.accel_flags = (!noaccel); diff --git a/drivers/video/fbdev/omap2/omapfb/dss/display.c b/drivers/video/fbdev/omap2/omapfb/dss/display.c -index ef5b902..47cf7f5 100644 +index ef5b902..2ae011b 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/display.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/display.c @@ -161,12 +161,14 @@ int omapdss_register_display(struct omap_dss_device *dssdev) @@ -77961,19 +78618,19 @@ index ef5b902..47cf7f5 100644 + pax_open_kernel(); if (drv && drv->get_resolution == NULL) - drv->get_resolution = omapdss_default_get_resolution; -+ *(void **)&drv->get_resolution = omapdss_default_get_resolution; ++ const_cast(drv->get_resolution) = omapdss_default_get_resolution; if (drv && drv->get_recommended_bpp == NULL) - drv->get_recommended_bpp = omapdss_default_get_recommended_bpp; -+ *(void **)&drv->get_recommended_bpp = omapdss_default_get_recommended_bpp; ++ const_cast(drv->get_recommended_bpp) = omapdss_default_get_recommended_bpp; if (drv && drv->get_timings == NULL) - drv->get_timings = omapdss_default_get_timings; -+ *(void **)&drv->get_timings = omapdss_default_get_timings; ++ const_cast(drv->get_timings) = omapdss_default_get_timings; + pax_close_kernel(); mutex_lock(&panel_list_mutex); list_add_tail(&dssdev->panel_list, &panel_list); diff --git a/drivers/video/fbdev/s1d13xxxfb.c b/drivers/video/fbdev/s1d13xxxfb.c -index 96aa46d..c67c213 100644 +index 96aa46d..65e2554 100644 --- a/drivers/video/fbdev/s1d13xxxfb.c +++ b/drivers/video/fbdev/s1d13xxxfb.c @@ -880,8 +880,10 @@ static int s1d13xxxfb_probe(struct platform_device *pdev) @@ -77983,8 +78640,8 @@ index 96aa46d..c67c213 100644 - s1d13xxxfb_fbops.fb_fillrect = s1d13xxxfb_bitblt_solidfill; - s1d13xxxfb_fbops.fb_copyarea = s1d13xxxfb_bitblt_copyarea; + pax_open_kernel(); -+ *(void **)&s1d13xxxfb_fbops.fb_fillrect = s1d13xxxfb_bitblt_solidfill; -+ *(void **)&s1d13xxxfb_fbops.fb_copyarea = s1d13xxxfb_bitblt_copyarea; ++ const_cast(s1d13xxxfb_fbops.fb_fillrect) = s1d13xxxfb_bitblt_solidfill; ++ const_cast(s1d13xxxfb_fbops.fb_copyarea) = s1d13xxxfb_bitblt_copyarea; + pax_close_kernel(); info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN | FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA; @@ -78020,7 +78677,7 @@ index 32e23c2..7b73082 100644 extern void SiS_SetChrontelGPIO(struct SiS_Private *SiS_Pr, unsigned short myvbinfo); extern unsigned short SiS_HandleDDC(struct SiS_Private *SiS_Pr, unsigned int VBFlags, int VGAEngine, diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c -index 9279e5f..d5f5276 100644 +index 9279e5f..d9fb0bd 100644 --- a/drivers/video/fbdev/smscufx.c +++ b/drivers/video/fbdev/smscufx.c @@ -1174,7 +1174,9 @@ static int ufx_ops_release(struct fb_info *info, int user) @@ -78029,13 +78686,13 @@ index 9279e5f..d5f5276 100644 info->fbdefio = NULL; - info->fbops->fb_mmap = ufx_ops_mmap; + pax_open_kernel(); -+ *(void **)&info->fbops->fb_mmap = ufx_ops_mmap; ++ const_cast(info->fbops->fb_mmap) = ufx_ops_mmap; + pax_close_kernel(); } pr_debug("released /dev/fb%d user=%d count=%d", diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c -index e9c2f7b..8df1264 100644 +index e9c2f7b..87506f4 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -623,11 +623,11 @@ static int dlfb_handle_damage(struct dlfb_data *dev, int x, int y, @@ -78076,7 +78733,7 @@ index e9c2f7b..8df1264 100644 info->fbdefio = NULL; - info->fbops->fb_mmap = dlfb_ops_mmap; + pax_open_kernel(); -+ *(void **)&info->fbops->fb_mmap = dlfb_ops_mmap; ++ const_cast(info->fbops->fb_mmap) = dlfb_ops_mmap; + pax_close_kernel(); } @@ -78133,7 +78790,7 @@ index e9c2f7b..8df1264 100644 return count; } diff --git a/drivers/video/fbdev/uvesafb.c b/drivers/video/fbdev/uvesafb.c -index 178ae93..624b2eb 100644 +index 178ae93..043ddca 100644 --- a/drivers/video/fbdev/uvesafb.c +++ b/drivers/video/fbdev/uvesafb.c @@ -19,6 +19,7 @@ @@ -78202,7 +78859,7 @@ index 178ae93..624b2eb 100644 - info->fbops->fb_blank = NULL; + if (!blank) { + pax_open_kernel(); -+ *(void **)&info->fbops->fb_blank = NULL; ++ const_cast(info->fbops->fb_blank) = NULL; + pax_close_kernel(); + } @@ -78216,7 +78873,7 @@ index 178ae93..624b2eb 100644 - info->fbops->fb_pan_display = NULL; + if (!par->ypan) { + pax_open_kernel(); -+ *(void **)&info->fbops->fb_pan_display = NULL; ++ const_cast(info->fbops->fb_pan_display) = NULL; + pax_close_kernel(); + } } @@ -78247,7 +78904,7 @@ index 178ae93..624b2eb 100644 } return 0; diff --git a/drivers/video/fbdev/vesafb.c b/drivers/video/fbdev/vesafb.c -index 528fe91..6fd29fe 100644 +index 528fe91..475d9e6 100644 --- a/drivers/video/fbdev/vesafb.c +++ b/drivers/video/fbdev/vesafb.c @@ -9,6 +9,7 @@ @@ -78348,7 +79005,7 @@ index 528fe91..6fd29fe 100644 - info->fbops->fb_pan_display = NULL; + if (!ypan) { + pax_open_kernel(); -+ *(void **)&info->fbops->fb_pan_display = NULL; ++ const_cast(info->fbops->fb_pan_display) = NULL; + pax_close_kernel(); + } @@ -99826,7 +100483,7 @@ index 7cfa0aa..d5ef97b7 100644 seq_printf(m, "CacheOp: alo=%d luo=%d luc=%d gro=%d\n", atomic_read(&fscache_n_cop_alloc_object), diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c -index c5b6b71..3949af6 100644 +index c5b6b71..527e347 100644 --- a/fs/fuse/cuse.c +++ b/fs/fuse/cuse.c @@ -611,10 +611,12 @@ static int __init cuse_init(void) @@ -99839,9 +100496,9 @@ index c5b6b71..3949af6 100644 - cuse_channel_fops.release = cuse_channel_release; + pax_open_kernel(); + memcpy((void *)&cuse_channel_fops, &fuse_dev_operations, sizeof(fuse_dev_operations)); -+ *(void **)&cuse_channel_fops.owner = THIS_MODULE; -+ *(void **)&cuse_channel_fops.open = cuse_channel_open; -+ *(void **)&cuse_channel_fops.release = cuse_channel_release; ++ const_cast(cuse_channel_fops.owner) = THIS_MODULE; ++ const_cast(cuse_channel_fops.open) = cuse_channel_open; ++ const_cast(cuse_channel_fops.release) = cuse_channel_release; + pax_close_kernel(); cuse_class = class_create(THIS_MODULE, "cuse"); @@ -100191,7 +100848,7 @@ index 4a6cf28..d3a29d3 100644 jffs2_prealloc_raw_node_refs(c, jeb, 1); diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c -index cad86ba..a0bfc33 100644 +index cad86ba..7de4d99 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -111,8 +111,9 @@ static int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg) @@ -100205,6 +100862,15 @@ index cad86ba..a0bfc33 100644 int ret = jffs2_do_readpage_nolock(inode, pg); unlock_page(pg); return ret; +@@ -125,7 +126,7 @@ static int jffs2_readpage (struct file *filp, struct page *pg) + int ret; + + mutex_lock(&f->sem); +- ret = jffs2_do_readpage_unlock(pg->mapping->host, pg); ++ ret = jffs2_do_readpage_unlock((struct file *)pg->mapping->host, pg); + mutex_unlock(&f->sem); + return ret; + } diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index bead25a..5186b1c 100644 --- a/fs/jffs2/fs.c @@ -110271,7 +110937,7 @@ index d955481..a985dc41 100644 #endif diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c -index 52ccd34..7a6b202 100644 +index 52ccd34..a166501 100644 --- a/fs/nls/nls_base.c +++ b/fs/nls/nls_base.c @@ -234,21 +234,25 @@ EXPORT_SYMBOL(utf16s_to_utf8s); @@ -110286,7 +110952,7 @@ index 52ccd34..7a6b202 100644 - nls->owner = owner; + pax_open_kernel(); -+ *(void **)&nls->owner = owner; ++ const_cast(nls->owner) = owner; + pax_close_kernel(); spin_lock(&nls_lock); - while (*tmp) { @@ -110301,7 +110967,7 @@ index 52ccd34..7a6b202 100644 } - nls->next = tables; + pax_open_kernel(); -+ *(struct nls_table **)&nls->next = tables; ++ const_cast(nls->next) = tables; + pax_close_kernel(); tables = nls; spin_unlock(&nls_lock); @@ -110394,7 +111060,7 @@ index 8e14187..d9cec2f 100644 { const unsigned char *uni2charset; diff --git a/fs/nls/nls_euc-jp.c b/fs/nls/nls_euc-jp.c -index 162b3f1..2cb932a 100644 +index 162b3f1..b9121f8 100644 --- a/fs/nls/nls_euc-jp.c +++ b/fs/nls/nls_euc-jp.c @@ -406,7 +406,7 @@ static inline int sjisnec2sjisibm(unsigned char *sjisibm, @@ -110413,14 +111079,14 @@ index 162b3f1..2cb932a 100644 - table.charset2upper = p_nls->charset2upper; - table.charset2lower = p_nls->charset2lower; + pax_open_kernel(); -+ *(const unsigned char **)&table.charset2upper = p_nls->charset2upper; -+ *(const unsigned char **)&table.charset2lower = p_nls->charset2lower; ++ const_cast(table.charset2upper) = p_nls->charset2upper; ++ const_cast(table.charset2lower) = p_nls->charset2lower; + pax_close_kernel(); return register_nls(&table); } diff --git a/fs/nls/nls_koi8-ru.c b/fs/nls/nls_koi8-ru.c -index a80a741..13030f7 100644 +index a80a741..f28c9c9 100644 --- a/fs/nls/nls_koi8-ru.c +++ b/fs/nls/nls_koi8-ru.c @@ -13,7 +13,7 @@ @@ -110439,8 +111105,8 @@ index a80a741..13030f7 100644 - table.charset2upper = p_nls->charset2upper; - table.charset2lower = p_nls->charset2lower; + pax_open_kernel(); -+ *(const unsigned char **)&table.charset2upper = p_nls->charset2upper; -+ *(const unsigned char **)&table.charset2lower = p_nls->charset2lower; ++ const_cast(table.charset2upper) = p_nls->charset2upper; ++ const_cast(table.charset2lower) = p_nls->charset2lower; + pax_close_kernel(); return register_nls(&table); } @@ -112482,7 +113148,7 @@ index 350984a..0fb02a9 100644 net = get_proc_net(inode); if (net == NULL) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c -index fe5b6e6..e5f3883 100644 +index fe5b6e6..cd2913c 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -11,13 +11,21 @@ @@ -112515,7 +113181,7 @@ index fe5b6e6..e5f3883 100644 { - dir->header.ctl_table[0].child = sysctl_mount_point; + pax_open_kernel(); -+ *(const void **)&dir->header.ctl_table[0].child = sysctl_mount_point; ++ const_cast(dir->header.ctl_table[0].child) = sysctl_mount_point; + pax_close_kernel(); } @@ -112524,7 +113190,7 @@ index fe5b6e6..e5f3883 100644 { - dir->header.ctl_table[0].child = NULL; + pax_open_kernel(); -+ *(void **)&dir->header.ctl_table[0].child = NULL; ++ const_cast(dir->header.ctl_table[0].child) = NULL; + pax_close_kernel(); } @@ -112565,7 +113231,7 @@ index fe5b6e6..e5f3883 100644 + if (gr_handle_chroot_sysctl(op)) + goto out; + dget(filp->f_path.dentry); -+ if (gr_handle_sysctl_mod(filp->f_path.dentry->d_parent->d_name.name, table->procname, op)) { ++ if (gr_handle_sysctl_mod((const char *)filp->f_path.dentry->d_parent->d_name.name, table->procname, op)) { + dput(filp->f_path.dentry); + goto out; + } @@ -113941,7 +114607,7 @@ index 6c21228..9afd5fe 100644 if (sbi->s_bytesex == BYTESEX_PDP) return PDP_swab((__force __u32)n); diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c -index 4a0e48f..ca5b016 100644 +index 4a0e48f..d3e1fbf 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c @@ -53,7 +53,7 @@ static const struct file_operations tracefs_file_operations = { @@ -113960,8 +114626,8 @@ index 4a0e48f..ca5b016 100644 - tracefs_ops.mkdir = mkdir; - tracefs_ops.rmdir = rmdir; + pax_open_kernel(); -+ *(void **)&tracefs_ops.mkdir = mkdir; -+ *(void **)&tracefs_ops.rmdir = rmdir; ++ const_cast(tracefs_ops.mkdir) = mkdir; ++ const_cast(tracefs_ops.rmdir) = rmdir; + pax_close_kernel(); return dentry; @@ -115665,7 +116331,7 @@ index 0000000..e136e5f +endif diff --git a/grsecurity/gracl.c b/grsecurity/gracl.c new file mode 100644 -index 0000000..7ad630a +index 0000000..3c66319 --- /dev/null +++ b/grsecurity/gracl.c @@ -0,0 +1,2757 @@ @@ -115867,7 +116533,7 @@ index 0000000..7ad630a + +static int prepend_name(char **buffer, int *buflen, struct qstr *name) +{ -+ return prepend(buffer, buflen, name->name, name->len); ++ return prepend(buffer, buflen, (const char *)name->name, name->len); +} + +static int prepend_path(const struct path *path, struct path *root, @@ -116231,7 +116897,7 @@ index 0000000..7ad630a +__lookup_name_entry(const struct gr_policy_state *state, const char *name) +{ + unsigned int len = strlen(name); -+ unsigned int key = full_name_hash(name, len); ++ unsigned int key = full_name_hash((const unsigned char *)name, len); + unsigned int index = key % state->name_set.n_size; + struct name_entry *match; + @@ -116253,7 +116919,7 @@ index 0000000..7ad630a +lookup_name_entry_create(const char *name) +{ + unsigned int len = strlen(name); -+ unsigned int key = full_name_hash(name, len); ++ unsigned int key = full_name_hash((const unsigned char *)name, len); + unsigned int index = key % running_polstate.name_set.n_size; + struct name_entry *match; + @@ -120006,7 +120672,7 @@ index 0000000..25f54ef +}; diff --git a/grsecurity/gracl_policy.c b/grsecurity/gracl_policy.c new file mode 100644 -index 0000000..302bda8 +index 0000000..2fc92ec --- /dev/null +++ b/grsecurity/gracl_policy.c @@ -0,0 +1,1784 @@ @@ -120362,7 +121028,7 @@ index 0000000..302bda8 + struct name_entry **curr, *nentry; + struct inodev_entry *ientry; + unsigned int len = strlen(name); -+ unsigned int key = full_name_hash(name, len); ++ unsigned int key = full_name_hash((const unsigned char *)name, len); + unsigned int index = key % polstate->name_set.n_size; + + curr = &polstate->name_set.n_hash[index]; @@ -121387,7 +122053,7 @@ index 0000000..302bda8 + FOR_EACH_ROLE_END(r) + + for (i = 0; i < polstate->num_sprole_pws; i++) { -+ if (!strcmp(rolename, polstate->acl_special_roles[i]->rolename)) { ++ if (!strcmp(rolename, (const char *)polstate->acl_special_roles[i]->rolename)) { + *salt = polstate->acl_special_roles[i]->salt; + *sum = polstate->acl_special_roles[i]->sum; + return 1; @@ -121674,11 +122340,11 @@ index 0000000..302bda8 + } + + if (lookup_special_role_auth -+ (gr_usermode->mode, gr_usermode->sp_role, &sprole_salt, &sprole_sum) ++ (gr_usermode->mode, (const char *)gr_usermode->sp_role, &sprole_salt, &sprole_sum) + && ((!sprole_salt && !sprole_sum) + || !(chkpw(gr_usermode, sprole_salt, sprole_sum)))) { + char *p = ""; -+ assign_special_role(gr_usermode->sp_role); ++ assign_special_role((const char *)gr_usermode->sp_role); + read_lock(&tasklist_lock); + if (current->real_parent) + p = current->real_parent->role->rolename; @@ -125636,7 +126302,7 @@ index 0000000..ae02d8e +EXPORT_SYMBOL_GPL(gr_handle_new_usb); diff --git a/grsecurity/grsum.c b/grsecurity/grsum.c new file mode 100644 -index 0000000..4fb2ce6 +index 0000000..aef6b92 --- /dev/null +++ b/grsecurity/grsum.c @@ -0,0 +1,54 @@ @@ -125674,12 +126340,12 @@ index 0000000..4fb2ce6 + + sg_init_table(sg, 2); + sg_set_buf(&sg[0], salt, GR_SALT_LEN); -+ sg_set_buf(&sg[1], entry->pw, strlen(entry->pw)); ++ sg_set_buf(&sg[1], entry->pw, strlen((const char *)entry->pw)); + + desc.tfm = tfm; + desc.flags = 0; + -+ cryptres = crypto_hash_digest(&desc, sg, GR_SALT_LEN + strlen(entry->pw), ++ cryptres = crypto_hash_digest(&desc, sg, GR_SALT_LEN + strlen((const char *)entry->pw), + temp_sum); + + memset(entry->pw, 0, GR_PW_LEN); @@ -127062,7 +127728,7 @@ index a76c917..75d6aeb 100644 asmlinkage long compat_sys_lookup_dcookie(u32, u32, char __user *, compat_size_t); /* diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h -index eeae401..a2a9f48 100644 +index eeae401..c108d27 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -116,9 +116,9 @@ @@ -127078,7 +127744,7 @@ index eeae401..a2a9f48 100644 #define __maybe_unused __attribute__((unused)) #define __always_unused __attribute__((unused)) -@@ -184,9 +184,38 @@ +@@ -184,9 +184,39 @@ # define __compiletime_warning(message) __attribute__((warning(message))) # define __compiletime_error(message) __attribute__((error(message))) #endif /* __CHECKER__ */ @@ -127099,6 +127765,7 @@ index eeae401..a2a9f48 100644 +#ifdef CONSTIFY_PLUGIN +#define __no_const __attribute__((no_const)) +#define __do_const __attribute__((do_const)) ++#define const_cast(x) (*(typeof((typeof(x))0) *)&(x)) +#endif + +#ifdef SIZE_OVERFLOW_PLUGIN @@ -127118,7 +127785,7 @@ index eeae401..a2a9f48 100644 * Mark a position in code as unreachable. This can be used to * suppress control flow warnings after asm blocks that transfer diff --git a/include/linux/compiler.h b/include/linux/compiler.h -index 48f5aab..2d1c52f 100644 +index 48f5aab..4206700 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -5,11 +5,14 @@ @@ -127340,7 +128007,7 @@ index 48f5aab..2d1c52f 100644 }) /** -@@ -416,6 +432,38 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s +@@ -416,6 +432,42 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s # define __attribute_const__ /* unimplemented */ #endif @@ -127376,10 +128043,14 @@ index 48f5aab..2d1c52f 100644 +# define __nocapture(...) +#endif + ++#ifndef const_cast ++# define const_cast(x) (x) ++#endif ++ /* * Tell gcc if a function is cold. The compiler will assume any path * directly leading to the call is unlikely. -@@ -425,6 +473,22 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s +@@ -425,6 +477,22 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s #define __cold #endif @@ -127402,7 +128073,7 @@ index 48f5aab..2d1c52f 100644 /* Simple shorthand for a section definition */ #ifndef __section # define __section(S) __attribute__ ((__section__(#S))) -@@ -447,6 +511,8 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s +@@ -447,6 +515,8 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s # define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) #endif @@ -127411,7 +128082,7 @@ index 48f5aab..2d1c52f 100644 /* Is this type a native word size -- useful for atomic operations */ #ifndef __native_word # define __native_word(t) (sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long)) -@@ -526,8 +592,9 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s +@@ -526,8 +596,9 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s */ #define __ACCESS_ONCE(x) ({ \ __maybe_unused typeof(x) __var = (__force typeof(x)) 0; \ @@ -131980,7 +132651,7 @@ index 556ec1e..38c19c9 100644 /* diff --git a/include/linux/sched.h b/include/linux/sched.h -index a10494a..2facd6d 100644 +index a10494a..9f25fd6 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -7,7 +7,7 @@ @@ -132253,7 +132924,7 @@ index a10494a..2facd6d 100644 { return tsk->pid; } -@@ -2289,6 +2397,25 @@ extern u64 sched_clock_cpu(int cpu); +@@ -2289,6 +2397,26 @@ extern u64 sched_clock_cpu(int cpu); extern void sched_clock_init(void); @@ -132267,6 +132938,7 @@ index a10494a..2facd6d 100644 + + while (ptr < end) { + c = *(volatile int *)ptr; ++ (void)c; + ptr += PAGE_SIZE/sizeof(int); + } +} @@ -132279,7 +132951,7 @@ index a10494a..2facd6d 100644 #ifndef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK static inline void sched_clock_tick(void) { -@@ -2417,7 +2544,9 @@ extern void set_curr_task(int cpu, struct task_struct *p); +@@ -2417,7 +2545,9 @@ extern void set_curr_task(int cpu, struct task_struct *p); void yield(void); union thread_union { @@ -132289,7 +132961,7 @@ index a10494a..2facd6d 100644 unsigned long stack[THREAD_SIZE/sizeof(long)]; }; -@@ -2450,6 +2579,7 @@ extern struct pid_namespace init_pid_ns; +@@ -2450,6 +2580,7 @@ extern struct pid_namespace init_pid_ns; */ extern struct task_struct *find_task_by_vpid(pid_t nr); @@ -132297,7 +132969,7 @@ index a10494a..2facd6d 100644 extern struct task_struct *find_task_by_pid_ns(pid_t nr, struct pid_namespace *ns); -@@ -2481,7 +2611,7 @@ extern void proc_caches_init(void); +@@ -2481,7 +2612,7 @@ extern void proc_caches_init(void); extern void flush_signals(struct task_struct *); extern void ignore_signals(struct task_struct *); extern void flush_signal_handlers(struct task_struct *, int force_default); @@ -132306,7 +132978,7 @@ index a10494a..2facd6d 100644 static inline int kernel_dequeue_signal(siginfo_t *info) { -@@ -2635,7 +2765,7 @@ extern void __cleanup_sighand(struct sighand_struct *); +@@ -2635,7 +2766,7 @@ extern void __cleanup_sighand(struct sighand_struct *); extern void exit_itimers(struct signal_struct *); extern void flush_itimer_signals(void); @@ -132315,7 +132987,7 @@ index a10494a..2facd6d 100644 extern int do_execve(struct filename *, const char __user * const __user *, -@@ -2750,11 +2880,13 @@ static inline int thread_group_empty(struct task_struct *p) +@@ -2750,11 +2881,13 @@ static inline int thread_group_empty(struct task_struct *p) * It must not be nested with write_lock_irq(&tasklist_lock), * neither inside nor outside. */ @@ -132329,7 +133001,7 @@ index a10494a..2facd6d 100644 static inline void task_unlock(struct task_struct *p) { spin_unlock(&p->alloc_lock); -@@ -2840,9 +2972,9 @@ static inline unsigned long *end_of_stack(struct task_struct *p) +@@ -2840,9 +2973,9 @@ static inline unsigned long *end_of_stack(struct task_struct *p) #define task_stack_end_corrupted(task) \ (*(end_of_stack(task)) != STACK_END_MAGIC) @@ -132404,6 +133076,19 @@ index dc368b8..e895209 100644 extern int __must_check down_killable(struct semaphore *sem); extern int __must_check down_trylock(struct semaphore *sem); extern int __must_check down_timeout(struct semaphore *sem, long jiffies); +diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h +index fb7eb9c..1b493dc 100644 +--- a/include/linux/seq_buf.h ++++ b/include/linux/seq_buf.h +@@ -16,7 +16,7 @@ + * @readpos: The next position to read in the buffer. + */ + struct seq_buf { +- char *buffer; ++ unsigned char *buffer; + size_t size; + size_t len; + loff_t readpos; diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index dde00de..202bfd3 100644 --- a/include/linux/seq_file.h @@ -133368,7 +134053,7 @@ index fa7bc29..0d96561 100644 struct ctl_node { struct rb_node node; diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h -index c6f0f0d..a34ab2d 100644 +index c6f0f0d..e663567 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -34,7 +34,8 @@ struct attribute { @@ -133401,6 +134086,15 @@ index c6f0f0d..a34ab2d 100644 /** * sysfs_bin_attr_init - initialize a dynamically allocated bin_attribute +@@ -512,7 +515,7 @@ static inline void sysfs_notify_dirent(struct kernfs_node *kn) + } + + static inline struct kernfs_node *sysfs_get_dirent(struct kernfs_node *parent, +- const unsigned char *name) ++ const char *name) + { + return kernfs_find_and_get(parent, name); + } diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h index 387fa7d..3fcde6b 100644 --- a/include/linux/sysrq.h @@ -136761,7 +137455,7 @@ index 45432b5..988f1e4 100644 +} +EXPORT_SYMBOL(capable_wrt_inode_uidgid_nolog); diff --git a/kernel/cgroup.c b/kernel/cgroup.c -index 355cd5f..6273802 100644 +index 355cd5f..93e1510 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -3333,7 +3333,7 @@ static int cgroup_add_file(struct cgroup_subsys_state *css, struct cgroup *cgrp, @@ -136781,12 +137475,12 @@ index 355cd5f..6273802 100644 - cft->ss = NULL; + + pax_open_kernel(); -+ *(void **)&cft->kf_ops = NULL; -+ *(void **)&cft->ss = NULL; ++ const_cast(cft->kf_ops) = NULL; ++ const_cast(cft->ss) = NULL; /* revert flags set by cgroup core while adding @cfts */ - cft->flags &= ~(__CFTYPE_ONLY_ON_DFL | __CFTYPE_NOT_ON_DFL); -+ *(unsigned int *)&cft->flags &= ~(__CFTYPE_ONLY_ON_DFL | __CFTYPE_NOT_ON_DFL); ++ const_cast(cft->flags) &= ~(__CFTYPE_ONLY_ON_DFL | __CFTYPE_NOT_ON_DFL); + pax_close_kernel(); } } @@ -136798,8 +137492,8 @@ index 355cd5f..6273802 100644 - cft->kf_ops = kf_ops; - cft->ss = ss; + pax_open_kernel(); -+ *(void **)&cft->kf_ops = kf_ops; -+ *(void **)&cft->ss = ss; ++ const_cast(cft->kf_ops) = kf_ops; ++ const_cast(cft->ss) = ss; + pax_close_kernel(); } @@ -136829,7 +137523,7 @@ index 355cd5f..6273802 100644 + pax_open_kernel(); for (cft = cfts; cft && cft->name[0] != '\0'; cft++) - cft->flags |= __CFTYPE_ONLY_ON_DFL; -+ *(unsigned int *)&cft->flags |= __CFTYPE_ONLY_ON_DFL; ++ const_cast(cft->flags) |= __CFTYPE_ONLY_ON_DFL; + pax_close_kernel(); return cgroup_add_cftypes(ss, cfts); } @@ -136841,7 +137535,7 @@ index 355cd5f..6273802 100644 + pax_open_kernel(); for (cft = cfts; cft && cft->name[0] != '\0'; cft++) - cft->flags |= __CFTYPE_NOT_ON_DFL; -+ *(unsigned int *)&cft->flags |= __CFTYPE_NOT_ON_DFL; ++ const_cast(cft->flags) |= __CFTYPE_NOT_ON_DFL; + pax_close_kernel(); return cgroup_add_cftypes(ss, cfts); } @@ -138224,7 +138918,7 @@ index 84118723..317f7a5 100644 irq_wake_secondary(desc, action); diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c -index 38e89ce..58960ac 100644 +index 38e89ce..8b7a537 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -214,16 +214,18 @@ static void msi_domain_update_dom_ops(struct msi_domain_info *info) @@ -138234,19 +138928,19 @@ index 38e89ce..58960ac 100644 + pax_open_kernel(); if (ops->get_hwirq == NULL) - ops->get_hwirq = msi_domain_ops_default.get_hwirq; -+ *(void **)&ops->get_hwirq = msi_domain_ops_default.get_hwirq; ++ const_cast(ops->get_hwirq) = msi_domain_ops_default.get_hwirq; if (ops->msi_init == NULL) - ops->msi_init = msi_domain_ops_default.msi_init; -+ *(void **)&ops->msi_init = msi_domain_ops_default.msi_init; ++ const_cast(ops->msi_init) = msi_domain_ops_default.msi_init; if (ops->msi_check == NULL) - ops->msi_check = msi_domain_ops_default.msi_check; -+ *(void **)&ops->msi_check = msi_domain_ops_default.msi_check; ++ const_cast(ops->msi_check) = msi_domain_ops_default.msi_check; if (ops->msi_prepare == NULL) - ops->msi_prepare = msi_domain_ops_default.msi_prepare; -+ *(void **)&ops->msi_prepare = msi_domain_ops_default.msi_prepare; ++ const_cast(ops->msi_prepare) = msi_domain_ops_default.msi_prepare; if (ops->set_desc == NULL) - ops->set_desc = msi_domain_ops_default.set_desc; -+ *(void **)&ops->set_desc = msi_domain_ops_default.set_desc; ++ const_cast(ops->set_desc) = msi_domain_ops_default.set_desc; + pax_close_kernel(); } @@ -138259,7 +138953,7 @@ index 38e89ce..58960ac 100644 - chip->irq_set_affinity = msi_domain_set_affinity; + if (!chip->irq_set_affinity) { + pax_open_kernel(); -+ *(void **)&chip->irq_set_affinity = msi_domain_set_affinity; ++ const_cast(chip->irq_set_affinity) = msi_domain_set_affinity; + pax_close_kernel(); + } } @@ -139888,7 +140582,7 @@ index 794ebe8..f81f123 100644 } return mod; diff --git a/kernel/notifier.c b/kernel/notifier.c -index fd2c9ac..95e58f6 100644 +index fd2c9ac..6263e05 100644 --- a/kernel/notifier.c +++ b/kernel/notifier.c @@ -5,6 +5,7 @@ @@ -139908,7 +140602,7 @@ index fd2c9ac..95e58f6 100644 } - n->next = *nl; + pax_open_kernel(); -+ *(const void **)&n->next = *nl; ++ const_cast(n->next) = *nl; rcu_assign_pointer(*nl, n); + pax_close_kernel(); return 0; @@ -139923,7 +140617,7 @@ index fd2c9ac..95e58f6 100644 } - n->next = *nl; + pax_open_kernel(); -+ *(const void **)&n->next = *nl; ++ const_cast(n->next) = *nl; rcu_assign_pointer(*nl, n); + pax_close_kernel(); return 0; @@ -140025,7 +140719,7 @@ index d96469d..81d6d28 100644 } EXPORT_SYMBOL(__stack_chk_fail); diff --git a/kernel/pid.c b/kernel/pid.c -index 4d73a83..4712357 100644 +index 4d73a83..9df1950 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -33,6 +33,7 @@ @@ -140078,15 +140772,18 @@ index 4d73a83..4712357 100644 struct pid *get_task_pid(struct task_struct *task, enum pid_type type) { struct pid *pid; -@@ -497,7 +513,7 @@ struct pid *find_get_pid(pid_t nr) +@@ -497,9 +513,9 @@ struct pid *find_get_pid(pid_t nr) } EXPORT_SYMBOL_GPL(find_get_pid); -pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns) +pid_t pid_nr_ns(const struct pid *pid, const struct pid_namespace *ns) { - struct upid *upid; +- struct upid *upid; ++ const struct upid *upid; pid_t nr = 0; + + if (pid && ns->level <= pid->level) { @@ -511,7 +527,7 @@ pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns) } EXPORT_SYMBOL_GPL(pid_nr_ns); @@ -143248,7 +143945,7 @@ index 2be8c4f..444ecfb 100644 } entry = ring_buffer_event_data(event); diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c -index 2829821..a290dc89 100644 +index 2829821..cd4ea77 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c @@ -713,14 +713,16 @@ int register_trace_event(struct trace_event *event) @@ -143258,16 +143955,16 @@ index 2829821..a290dc89 100644 + pax_open_kernel(); if (event->funcs->trace == NULL) - event->funcs->trace = trace_nop_print; -+ *(void **)&event->funcs->trace = trace_nop_print; ++ const_cast(event->funcs->trace) = trace_nop_print; if (event->funcs->raw == NULL) - event->funcs->raw = trace_nop_print; -+ *(void **)&event->funcs->raw = trace_nop_print; ++ const_cast(event->funcs->raw) = trace_nop_print; if (event->funcs->hex == NULL) - event->funcs->hex = trace_nop_print; -+ *(void **)&event->funcs->hex = trace_nop_print; ++ const_cast(event->funcs->hex) = trace_nop_print; if (event->funcs->binary == NULL) - event->funcs->binary = trace_nop_print; -+ *(void **)&event->funcs->binary = trace_nop_print; ++ const_cast(event->funcs->binary) = trace_nop_print; + pax_close_kernel(); key = event->type & (EVENT_HASHSIZE - 1); @@ -151655,7 +152352,7 @@ index 1474cfd..961bc9f 100644 pr_warn("cannot create /proc/net/%s\n", PG_PROC_DIR); return -ENODEV; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c -index 482c371..b02a761 100644 +index 482c371..150e1ee 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -61,7 +61,7 @@ struct rtnl_link { @@ -151675,7 +152372,7 @@ index 482c371..b02a761 100644 - ops->dellink = unregister_netdevice_queue; + if (ops->setup && !ops->dellink) { + pax_open_kernel(); -+ *(void **)&ops->dellink = unregister_netdevice_queue; ++ const_cast(ops->dellink) = unregister_netdevice_queue; + pax_close_kernel(); + } @@ -160008,7 +160705,7 @@ index b5e665b..3030b1d 100644 } diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c -index 9895a8c..705c302 100644 +index 9895a8c..e7c5936 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -166,12 +166,14 @@ int xfrm_register_type(const struct xfrm_type *type, unsigned short family) @@ -160082,7 +160779,7 @@ index 9895a8c..705c302 100644 - mode->afinfo = afinfo; + pax_open_kernel(); -+ *(const void **)&mode->afinfo = afinfo; ++ const_cast(mode->afinfo) = afinfo; modemap[mode->encap] = mode; + pax_close_kernel(); err = 0; @@ -160172,6 +160869,18 @@ index 1db6d73..0819042 100644 # ld-option # Usage: LDFLAGS += $(call ld-option, -X) +diff --git a/scripts/Makefile b/scripts/Makefile +index fd0d53d..1471190 100644 +--- a/scripts/Makefile ++++ b/scripts/Makefile +@@ -44,6 +44,7 @@ subdir-y += mod + subdir-$(CONFIG_SECURITY_SELINUX) += selinux + subdir-$(CONFIG_DTC) += dtc + subdir-$(CONFIG_GDB_SCRIPTS) += gdb ++subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins + + # Let clean descend into subdirs + subdir- += basic kconfig package diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 2c47f9c..9d46008 100644 --- a/scripts/Makefile.build @@ -160216,81 +160925,83 @@ index f9e47a7..b72022a 100644 warning-2 += -Wdisabled-optimization diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins new file mode 100644 -index 0000000..02fd848 +index 0000000..08d4e22 --- /dev/null +++ b/scripts/Makefile.gcc-plugins -@@ -0,0 +1,69 @@ -+__PLUGINCC := $(call cc-ifversion, -ge, 0408, $(HOSTCXX), $(HOSTCC)) -+PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(__PLUGINCC)" "$(HOSTCXX)" "$(CC)") -+ifneq ($(PLUGINCC),) -+ifdef CONFIG_PAX_CONSTIFY_PLUGIN -+CONSTIFY_PLUGIN_CFLAGS := -fplugin=$(objtree)/tools/gcc/constify_plugin.so -DCONSTIFY_PLUGIN -+endif -+ifdef CONFIG_PAX_MEMORY_STACKLEAK -+STACKLEAK_PLUGIN_CFLAGS := -fplugin=$(objtree)/tools/gcc/stackleak_plugin.so -DSTACKLEAK_PLUGIN -+STACKLEAK_PLUGIN_CFLAGS += -fplugin-arg-stackleak_plugin-track-lowest-sp=100 -+endif -+ifdef CONFIG_KALLOCSTAT_PLUGIN -+KALLOCSTAT_PLUGIN_CFLAGS := -fplugin=$(objtree)/tools/gcc/kallocstat_plugin.so -+endif -+ifdef CONFIG_PAX_KERNEXEC_PLUGIN -+KERNEXEC_PLUGIN_CFLAGS := -fplugin=$(objtree)/tools/gcc/kernexec_plugin.so -+KERNEXEC_PLUGIN_CFLAGS += -fplugin-arg-kernexec_plugin-method=$(CONFIG_PAX_KERNEXEC_PLUGIN_METHOD) -DKERNEXEC_PLUGIN -+KERNEXEC_PLUGIN_AFLAGS := -DKERNEXEC_PLUGIN -+endif -+ifdef CONFIG_CHECKER_PLUGIN -+ifeq ($(call cc-ifversion, -ge, 0406, y), y) -+CHECKER_PLUGIN_CFLAGS := -fplugin=$(objtree)/tools/gcc/checker_plugin.so -DCHECKER_PLUGIN -+ifdef CONFIG_CHECKER_PLUGIN_USER -+CHECKER_PLUGIN_CFLAGS += -fplugin-arg-checker_plugin-user -DCHECKER_PLUGIN_USER -+endif -+ifdef CONFIG_CHECKER_PLUGIN_CONTEXT -+CHECKER_PLUGIN_CFLAGS += -fplugin-arg-checker_plugin-context -DCHECKER_PLUGIN_CONTEXT -+endif -+endif -+endif -+COLORIZE_PLUGIN_CFLAGS := -fplugin=$(objtree)/tools/gcc/colorize_plugin.so -+ifdef CONFIG_PAX_SIZE_OVERFLOW -+SIZE_OVERFLOW_PLUGIN_CFLAGS := -fplugin=$(objtree)/tools/gcc/size_overflow_plugin/size_overflow_plugin.so -DSIZE_OVERFLOW_PLUGIN -+endif -+ifdef CONFIG_PAX_LATENT_ENTROPY -+LATENT_ENTROPY_PLUGIN_CFLAGS := -fplugin=$(objtree)/tools/gcc/latent_entropy_plugin.so -DLATENT_ENTROPY_PLUGIN -+endif -+ifdef CONFIG_PAX_MEMORY_STRUCTLEAK -+STRUCTLEAK_PLUGIN_CFLAGS := -fplugin=$(objtree)/tools/gcc/structleak_plugin.so -DSTRUCTLEAK_PLUGIN -+endif -+INITIFY_PLUGIN_CFLAGS := -fplugin=$(objtree)/tools/gcc/initify_plugin.so -DINITIFY_PLUGIN -+ifdef CONFIG_PAX_RAP -+RAP_PLUGIN_CFLAGS := -fplugin=$(objtree)/tools/gcc/rap_plugin/rap_plugin.so -fplugin-arg-rap_plugin-check=call -DRAP_PLUGIN -+#RAP_PLUGIN_CFLAGS += -fplugin-arg-rap_plugin-report=func,fptr,abs -+RAP_PLUGIN_ABS_CFLAGS := -fplugin-arg-rap_plugin-hash=abs-finish -+RAP_PLUGIN_AFLAGS := -DRAP_PLUGIN -+endif -+GCC_PLUGINS_CFLAGS := $(CONSTIFY_PLUGIN_CFLAGS) $(STACKLEAK_PLUGIN_CFLAGS) $(KALLOCSTAT_PLUGIN_CFLAGS) -+GCC_PLUGINS_CFLAGS += $(KERNEXEC_PLUGIN_CFLAGS) $(CHECKER_PLUGIN_CFLAGS) $(COLORIZE_PLUGIN_CFLAGS) -+GCC_PLUGINS_CFLAGS += $(SIZE_OVERFLOW_PLUGIN_CFLAGS) $(LATENT_ENTROPY_PLUGIN_CFLAGS) $(STRUCTLEAK_PLUGIN_CFLAGS) -+GCC_PLUGINS_CFLAGS += $(INITIFY_PLUGIN_CFLAGS) -+GCC_PLUGINS_CFLAGS += $(RAP_PLUGIN_CFLAGS) $(RAP_PLUGIN_ABS_CFLAGS) -+GCC_PLUGINS_AFLAGS := $(KERNEXEC_PLUGIN_AFLAGS) $(RAP_PLUGIN_AFLAGS) -+export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS CONSTIFY_PLUGIN LATENT_ENTROPY_PLUGIN_CFLAGS RAP_PLUGIN_CFLAGS RAP_PLUGIN_ABS_CFLAGS -+ifeq ($(KBUILD_EXTMOD),) -+gcc-plugins: -+ $(Q)$(MAKE) $(build)=tools/gcc -+else -+gcc-plugins: ; -+endif -+else -+gcc-plugins: -+ifeq ($(call cc-ifversion, -ge, 0405, y), y) -+ $(warning warning, your gcc installation does not support plugins, perhaps the necessary headers are missing?) -+ $(CONFIG_SHELL) -x $(srctree)/scripts/gcc-plugin.sh "$(__PLUGINCC)" "$(HOSTCXX)" "$(CC)" -+else -+ $(warning warning, your gcc version does not support plugins, you should upgrade it to gcc 4.5 at least) -+endif -+ $(warning PAX_MEMORY_STACKLEAK and other features will be less secure) +@@ -0,0 +1,71 @@ ++ifdef CONFIG_GCC_PLUGINS ++ __PLUGINCC := $(call cc-ifversion, -ge, 0408, $(HOSTCXX), $(HOSTCC)) ++ PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(__PLUGINCC)" "$(HOSTCXX)" "$(CC)") ++ ++ gcc-plugin-$(CONFIG_PAX_CONSTIFY_PLUGIN) += constify_plugin.so ++ gcc-plugin-cflags-$(CONFIG_PAX_CONSTIFY_PLUGIN) += -DCONSTIFY_PLUGIN ++ ++ gcc-plugin-$(CONFIG_PAX_MEMORY_STACKLEAK) += stackleak_plugin.so ++ gcc-plugin-cflags-$(CONFIG_PAX_MEMORY_STACKLEAK) += -DSTACKLEAK_PLUGIN -fplugin-arg-stackleak_plugin-track-lowest-sp=100 ++ ++ gcc-plugin-$(CONFIG_KALLOCSTAT_PLUGIN) += kallocstat_plugin.so ++ ++ gcc-plugin-$(CONFIG_PAX_KERNEXEC_PLUGIN) += kernexec_plugin.so ++ gcc-plugin-cflags-$(CONFIG_PAX_KERNEXEC_PLUGIN) += -DKERNEXEC_PLUGIN -fplugin-arg-kernexec_plugin-method=$(CONFIG_PAX_KERNEXEC_PLUGIN_METHOD) ++ gcc-plugin-aflags-$(CONFIG_PAX_KERNEXEC_PLUGIN) += -DKERNEXEC_PLUGIN ++ ++ ifdef CONFIG_CHECKER_PLUGIN ++ ifeq ($(call cc-ifversion, -ge, 0406, y), y) ++ gcc-plugin-$(CONFIG_CHECKER_PLUGIN) += checker_plugin.so ++ gcc-plugin-cflags-$(CONFIG_CHECKER_PLUGIN) += -DCHECKER_PLUGIN ++ gcc-plugin-cflags-$(CONFIG_CHECKER_PLUGIN_USER) += -DCHECKER_PLUGIN_USER -fplugin-arg-checker_plugin-user ++ gcc-plugin-cflags-$(CONFIG_CHECKER_PLUGIN_CONTEXT)+= -DCHECKER_PLUGIN_CONTEXT -fplugin-arg-checker_plugin-context ++ endif ++ endif ++ ++ gcc-plugin-y += colorize_plugin.so ++ ++ gcc-plugin-$(CONFIG_PAX_SIZE_OVERFLOW) += size_overflow_plugin/size_overflow_plugin.so ++ gcc-plugin-cflags-$(CONFIG_PAX_SIZE_OVERFLOW) += -DSIZE_OVERFLOW_PLUGIN ++ ++ gcc-plugin-$(CONFIG_PAX_LATENT_ENTROPY) += latent_entropy_plugin.so ++ gcc-plugin-cflags-$(CONFIG_PAX_LATENT_ENTROPY) += -DLATENT_ENTROPY_PLUGIN ++ ifdef CONFIG_PAX_LATENT_ENTROPY ++ DISABLE_LATENT_ENTROPY_PLUGIN += -fplugin-arg-latent_entropy_plugin-disable ++ endif ++ ++ gcc-plugin-$(CONFIG_PAX_MEMORY_STRUCTLEAK) += structleak_plugin.so ++ gcc-plugin-cflags-$(CONFIG_PAX_MEMORY_STRUCTLEAK) += -DSTRUCTLEAK_PLUGIN ++ ++ gcc-plugin-y += initify_plugin.so ++ gcc-plugin-cflags-y += -DINITIFY_PLUGIN ++ ++ gcc-plugin-$(CONFIG_PAX_RAP) += rap_plugin/rap_plugin.so ++ gcc-plugin-cflags-$(CONFIG_PAX_RAP) += -DRAP_PLUGIN -fplugin-arg-rap_plugin-check=call ++# gcc-plugin-cflags-$(CONFIG_PAX_RAP) += -fplugin-arg-rap_plugin-report=func,fptr,abs ++ gcc-plugin-aflags-$(CONFIG_PAX_RAP) += -DRAP_PLUGIN ++ ifdef CONFIG_PAX_RAP ++ RAP_PLUGIN_ABS_CFLAGS := -fplugin-arg-rap_plugin-hash=abs-finish ++ endif ++ gcc-plugin-cflags-$(CONFIG_PAX_RAP) += $(RAP_PLUGIN_ABS_CFLAGS) ++ ++ GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) ++ GCC_PLUGINS_AFLAGS := $(gcc-plugin-aflags-y) ++ ++ export DISABLE_LATENT_ENTROPY_PLUGIN RAP_PLUGIN_ABS_CFLAGS ++ ++ ifeq ($(PLUGINCC),) ++ ifneq ($(GCC_PLUGINS_CFLAGS),) ++ ifeq ($(call cc-ifversion, -ge, 0405, y), y) ++ PLUGINCC := $(shell $(CONFIG_SHELL) -x $(srctree)/scripts/gcc-plugin.sh "$(__PLUGINCC)" "$(HOSTCXX)" "$(CC)") ++ $(warning warning, your gcc installation does not support plugins, perhaps the necessary headers are missing?) ++ else ++ $(warning warning, your gcc version does not support plugins, you should upgrade it to gcc 4.5 at least) ++ endif ++ $(warning PAX_MEMORY_STACKLEAK and other features will be less secure) ++ endif ++ endif ++ ++ KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS) ++ KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS) +endif diff --git a/scripts/Makefile.host b/scripts/Makefile.host -index 133edfa..3cc6af2 100644 +index 133edfa..3439bd8 100644 --- a/scripts/Makefile.host +++ b/scripts/Makefile.host @@ -20,7 +20,25 @@ @@ -160349,7 +161060,7 @@ index 133edfa..3cc6af2 100644 host-objdirs := $(addprefix $(obj)/,$(host-objdirs)) obj-dirs += $(host-objdirs) -@@ -124,5 +158,37 @@ quiet_cmd_host-cxxobjs = HOSTCXX $@ +@@ -124,5 +158,39 @@ quiet_cmd_host-cxxobjs = HOSTCXX $@ $(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE $(call if_changed_dep,host-cxxobjs) @@ -160373,8 +161084,9 @@ index 133edfa..3cc6af2 100644 + cmd_host-cshlib = $(HOSTCC) $(HOSTLDFLAGS) -shared -o $@ \ + $(addprefix $(obj)/,$($(@F:.so=-objs))) \ + $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) -+$(host-cshlib): $(obj)/%: $(host-cshobjs) FORCE ++$(host-cshlib): FORCE + $(call if_changed,host-cshlib) ++$(call multi_depend, $(host-cshlib), .so, -objs -cshobjs) + +# Link a shared library, based on position independent .o files +# *.o -> .so shared library (host-cxxshlib) @@ -160382,8 +161094,9 @@ index 133edfa..3cc6af2 100644 + cmd_host-cxxshlib = $(HOSTCXX) $(HOSTLDFLAGS) -shared -o $@ \ + $(addprefix $(obj)/,$($(@F:.so=-objs))) \ + $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) -+$(host-cxxshlib): $(obj)/%: $(host-cxxshobjs) FORCE ++$(host-cxxshlib): FORCE + $(call if_changed,host-cxxshlib) ++$(call multi_depend, $(host-cxxshlib), .so, -objs -cxxshobjs) + targets += $(host-csingle) $(host-cmulti) $(host-cobjs)\ - $(host-cxxmulti) $(host-cxxobjs) @@ -160592,14 +161305,14 @@ index e229b84..7141e8e 100644 while (get_node_by_phandle(root, phandle)) diff --git a/scripts/gcc-plugin.sh b/scripts/gcc-plugin.sh new file mode 100644 -index 0000000..eaa4fce +index 0000000..fb92075 --- /dev/null +++ b/scripts/gcc-plugin.sh @@ -0,0 +1,51 @@ +#!/bin/sh +srctree=$(dirname "$0") +gccplugins_dir=$($3 -print-file-name=plugin) -+plugincc=$($1 -E -x c++ - -o /dev/null -I"${srctree}"/../tools/gcc -I"${gccplugins_dir}"/include 2>&1 <&1 <= 4008 || defined(ENABLE_BUILD_WITH_CXX) +#warning $2 CXX @@ -160630,7 +161343,7 @@ index 0000000..eaa4fce +esac + +# we need a c++ compiler that supports the designated initializer GNU extension -+plugincc=$($2 -c -x c++ -std=gnu++98 - -fsyntax-only -I"${srctree}"/../tools/gcc -I"${gccplugins_dir}"/include 2>&1 <&1 <@@' \ - -e 's/(^|[^a-zA-Z0-9])__packed([^a-zA-Z0-9_]|$)/\1__attribute__((packed))\2/g' \ -diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c -index 8fa81e8..a9ac144 100644 ---- a/scripts/kallsyms.c -+++ b/scripts/kallsyms.c -@@ -89,7 +89,7 @@ static inline int is_arm_mapping_symbol(const char *str) - } - - static int check_symbol_range(const char *sym, unsigned long long addr, -- struct addr_range *ranges, int entries) -+ struct addr_range *ranges, size_t entries) - { - size_t i; - struct addr_range *ar; -@@ -178,7 +178,7 @@ static int read_symbol(FILE *in, struct sym_entry *s) - } - - static int symbol_in_range(struct sym_entry *s, struct addr_range *ranges, -- int entries) -+ size_t entries) - { - size_t i; - struct addr_range *ar; -diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h -index 91ca126..5f7cad6 100644 ---- a/scripts/kconfig/lkc.h -+++ b/scripts/kconfig/lkc.h -@@ -108,7 +108,8 @@ void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); - void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); - void menu_add_option(int token, char *arg); - void menu_finalize(struct menu *parent); --void menu_set_type(int type); -+enum symbol_type; -+void menu_set_type(enum symbol_type type); - - /* util.c */ - struct file *file_lookup(const char *name); -@@ -123,7 +124,7 @@ struct gstr { - * when max_width is not zero long lines in string s (if any) get - * wrapped not to exceed the max_width value - */ -- int max_width; -+ size_t max_width; - }; - struct gstr str_new(void); - void str_free(struct gstr *gs); -diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c -index aed678e..1a703de 100644 ---- a/scripts/kconfig/menu.c -+++ b/scripts/kconfig/menu.c -@@ -109,7 +109,7 @@ void menu_add_dep(struct expr *dep) - current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep)); - } - --void menu_set_type(int type) -+void menu_set_type(enum symbol_type type) - { - struct symbol *sym = current_entry->sym; - -diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c -index 25cf0c2..eb178ce 100644 ---- a/scripts/kconfig/symbol.c -+++ b/scripts/kconfig/symbol.c -@@ -956,7 +956,7 @@ const char *sym_escape_string_value(const char *in) - - struct sym_match { - struct symbol *sym; -- off_t so, eo; -+ regoff_t so, eo; - }; - - /* Compare matched symbols as thus: -@@ -978,8 +978,8 @@ static int sym_rel_comp(const void *sym1, const void *sym2) - * exactly; if this is the case, we can't decide which comes first, - * and we fallback to sorting alphabetically. - */ -- exact1 = (s1->eo - s1->so) == strlen(s1->sym->name); -- exact2 = (s2->eo - s2->so) == strlen(s2->sym->name); -+ exact1 = (s1->eo - s1->so) == (long)strlen(s1->sym->name); -+ exact2 = (s2->eo - s2->so) == (long)strlen(s2->sym->name); - if (exact1 && !exact2) - return -1; - if (!exact1 && exact2) -diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh -index ba6c34e..ea10bce 100755 ---- a/scripts/link-vmlinux.sh -+++ b/scripts/link-vmlinux.sh -@@ -179,7 +179,7 @@ else - fi; - - # final build of init/ --${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init -+${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init GCC_PLUGINS_CFLAGS="${GCC_PLUGINS_CFLAGS}" GCC_PLUGINS_AFLAGS="${GCC_PLUGINS_AFLAGS}" - - kallsymso="" - kallsyms_vmlinux="" -diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c -index a915507..27c1b41 100644 ---- a/scripts/mod/file2alias.c -+++ b/scripts/mod/file2alias.c -@@ -156,7 +156,7 @@ static void device_id_check(const char *modname, const char *device_id, - unsigned long size, unsigned long id_size, - void *symval) - { -- int i; -+ unsigned int i; - - if (size % id_size || size < id_size) { - fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo " -@@ -185,7 +185,7 @@ static void device_id_check(const char *modname, const char *device_id, - /* USB is special because the bcdDevice can be matched against a numeric range */ - /* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipNinN" */ - static void do_usb_entry(void *symval, -- unsigned int bcdDevice_initial, int bcdDevice_initial_digits, -+ unsigned int bcdDevice_initial, unsigned int bcdDevice_initial_digits, - unsigned char range_lo, unsigned char range_hi, - unsigned char max, struct module *mod) - { -@@ -295,7 +295,7 @@ static void do_usb_entry_multi(void *symval, struct module *mod) - { - unsigned int devlo, devhi; - unsigned char chi, clo, max; -- int ndigits; -+ unsigned int ndigits; - - DEF_FIELD(symval, usb_device_id, match_flags); - DEF_FIELD(symval, usb_device_id, idVendor); -@@ -619,7 +619,7 @@ static void do_pnp_device_entry(void *symval, unsigned long size, - for (i = 0; i < count; i++) { - DEF_FIELD_ADDR(symval + i*id_size, pnp_device_id, id); - char acpi_id[sizeof(*id)]; -- int j; -+ unsigned int j; - - buf_printf(&mod->dev_table_buf, - "MODULE_ALIAS(\"pnp:d%s*\");\n", *id); -@@ -648,7 +648,7 @@ static void do_pnp_card_entries(void *symval, unsigned long size, - - for (j = 0; j < PNP_MAX_DEVICES; j++) { - const char *id = (char *)(*devs)[j].id; -- int i2, j2; -+ unsigned int i2, j2; - int dup = 0; - - if (!id[0]) -@@ -674,7 +674,7 @@ static void do_pnp_card_entries(void *symval, unsigned long size, - /* add an individual alias for every device entry */ - if (!dup) { - char acpi_id[PNP_ID_LEN]; -- int k; -+ unsigned int k; - - buf_printf(&mod->dev_table_buf, - "MODULE_ALIAS(\"pnp:d%s*\");\n", id); -@@ -999,7 +999,7 @@ static void dmi_ascii_filter(char *d, const char *s) - static int do_dmi_entry(const char *filename, void *symval, - char *alias) - { -- int i, j; -+ unsigned int i, j; - DEF_FIELD_ADDR(symval, dmi_system_id, matches); - sprintf(alias, "dmi*"); - -diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c -index 48958d3..d5ccb52 100644 ---- a/scripts/mod/modpost.c -+++ b/scripts/mod/modpost.c -@@ -37,6 +37,7 @@ static int vmlinux_section_warnings = 1; - static int warn_unresolved = 0; - /* How a symbol is exported */ - static int sec_mismatch_count = 0; -+static int writable_fptr_count = 0; - static int sec_mismatch_verbose = 1; - static int sec_mismatch_fatal = 0; - /* ignore missing files */ -@@ -947,6 +948,7 @@ enum mismatch { - ANY_EXIT_TO_ANY_INIT, - EXPORT_TO_INIT_EXIT, - EXTABLE_TO_NON_TEXT, -+ DATA_TO_TEXT - }; - - /** -@@ -1073,6 +1075,12 @@ static const struct sectioncheck sectioncheck[] = { - .good_tosec = {ALL_TEXT_SECTIONS , NULL}, - .mismatch = EXTABLE_TO_NON_TEXT, - .handler = extable_mismatch_handler, -+}, -+/* Do not reference code from writable data */ -+{ -+ .fromsec = { DATA_SECTIONS, NULL }, -+ .bad_tosec = { ALL_TEXT_SECTIONS, NULL }, -+ .mismatch = DATA_TO_TEXT - } - }; - -@@ -1222,10 +1230,10 @@ static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr, - continue; - if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) - continue; -- if (sym->st_value == addr) -- return sym; - /* Find a symbol nearby - addr are maybe negative */ - d = sym->st_value - addr; -+ if (d == 0) -+ return sym; - if (d < 0) - d = addr - sym->st_value; - if (d < distance) { -@@ -1384,7 +1392,11 @@ static void report_sec_mismatch(const char *modname, - char *prl_from; - char *prl_to; - -- sec_mismatch_count++; -+ if (mismatch->mismatch == DATA_TO_TEXT) -+ writable_fptr_count++; -+ else -+ sec_mismatch_count++; -+ - if (!sec_mismatch_verbose) - return; - -@@ -1508,6 +1520,14 @@ static void report_sec_mismatch(const char *modname, - fatal("There's a special handler for this mismatch type, " - "we should never get here."); - break; -+ case DATA_TO_TEXT: -+#if 0 -+ fprintf(stderr, -+ "The %s %s:%s references\n" -+ "the %s %s:%s%s\n", -+ from, fromsec, fromsym, to, tosec, tosym, to_p); -+#endif -+ break; - } - fprintf(stderr, "\n"); - } -@@ -1897,7 +1917,7 @@ static void section_rel(const char *modname, struct elf_info *elf, - static void check_sec_ref(struct module *mod, const char *modname, - struct elf_info *elf) - { -- int i; -+ unsigned int i; - Elf_Shdr *sechdrs = elf->sechdrs; - - /* Walk through all sections */ -@@ -2028,7 +2048,7 @@ void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf, - va_end(ap); - } - --void buf_write(struct buffer *buf, const char *s, int len) -+void buf_write(struct buffer *buf, const char *s, unsigned int len) - { - if (buf->size - buf->pos < len) { - buf->size += len + SZ; -@@ -2258,7 +2278,7 @@ static void write_if_changed(struct buffer *b, const char *fname) - if (fstat(fileno(file), &st) < 0) - goto close_write; - -- if (st.st_size != b->pos) -+ if (st.st_size != (off_t)b->pos) - goto close_write; - - tmp = NOFAIL(malloc(b->pos)); -@@ -2496,6 +2516,14 @@ int main(int argc, char **argv) - "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n"); - } - } -+ if (writable_fptr_count) { -+ if (!sec_mismatch_verbose) { -+ warn("modpost: Found %d writable function pointer(s).\n" -+ "To see full details build your kernel with:\n" -+ "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n", -+ writable_fptr_count); -+ } -+ } - - return err; - } -diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h -index 6a5e151..f2fbaf5 100644 ---- a/scripts/mod/modpost.h -+++ b/scripts/mod/modpost.h -@@ -98,15 +98,15 @@ void *do_nofail(void *ptr, const char *expr); - - struct buffer { - char *p; -- int pos; -- int size; -+ unsigned int pos; -+ unsigned int size; - }; - - void __attribute__((format(printf, 2, 3))) - buf_printf(struct buffer *buf, const char *fmt, ...); - - void --buf_write(struct buffer *buf, const char *s, int len); -+buf_write(struct buffer *buf, const char *s, unsigned int len); - - struct module { - struct module *next; -diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c -index 944418d..15291e4 100644 ---- a/scripts/mod/sumversion.c -+++ b/scripts/mod/sumversion.c -@@ -470,7 +470,7 @@ static void write_version(const char *filename, const char *sum, - goto out; - } - -- if (write(fd, sum, strlen(sum)+1) != strlen(sum)+1) { -+ if (write(fd, sum, strlen(sum)+1) != (ssize_t)strlen(sum)+1) { - warn("writing sum in %s failed: %s\n", - filename, strerror(errno)); - goto out; -diff --git a/scripts/module-common.lds b/scripts/module-common.lds -index 73a2c7d..df11b31 100644 ---- a/scripts/module-common.lds -+++ b/scripts/module-common.lds -@@ -6,6 +6,10 @@ - SECTIONS { - /DISCARD/ : { *(.discard) } - -+ .rodata 0: { -+ *(.rodata) *(.rodata.*) -+ *(.data..read_only) -+ } - __ksymtab 0 : { *(SORT(___ksymtab+*)) } - __ksymtab_gpl 0 : { *(SORT(___ksymtab_gpl+*)) } - __ksymtab_unused 0 : { *(SORT(___ksymtab_unused+*)) } -diff --git a/scripts/package/Makefile b/scripts/package/Makefile -index c2c7389..81b8117 100644 ---- a/scripts/package/Makefile -+++ b/scripts/package/Makefile -@@ -40,7 +40,7 @@ if test "$(objtree)" != "$(srctree)"; then \ - fi ; \ - $(srctree)/scripts/setlocalversion --save-scmversion; \ - ln -sf $(srctree) $(2); \ --tar -cz $(RCS_TAR_IGNORE) -f $(2).tar.gz \ -+tar --owner=root --group=root -cz $(RCS_TAR_IGNORE) -f $(2).tar.gz \ - $(addprefix $(2)/,$(TAR_CONTENT) $(3)); \ - rm -f $(2) $(objtree)/.scmversion - -diff --git a/scripts/package/builddeb b/scripts/package/builddeb -index 6c3b038..54e0b5e 100755 ---- a/scripts/package/builddeb -+++ b/scripts/package/builddeb -@@ -326,6 +326,7 @@ fi - (cd $srctree; find arch/$SRCARCH -name module.lds -o -name Kbuild.platforms -o -name Platform) >> "$objtree/debian/hdrsrcfiles" - (cd $srctree; find $(find arch/$SRCARCH -name include -o -name scripts -type d) -type f) >> "$objtree/debian/hdrsrcfiles" - (cd $objtree; find arch/$SRCARCH/include Module.symvers include scripts -type f) >> "$objtree/debian/hdrobjfiles" -+(cd $objtree; find tools/gcc -name \*.so -o -name gcc-common.h) >> "$objtree/debian/hdrobjfiles" - destdir=$kernel_headers_dir/usr/src/linux-headers-$version - mkdir -p "$destdir" - (cd $srctree; tar -c -f - -T -) < "$objtree/debian/hdrsrcfiles" | (cd $destdir; tar -xf -) -diff --git a/scripts/package/mkspec b/scripts/package/mkspec -index fe44d68..3874acb 100755 ---- a/scripts/package/mkspec -+++ b/scripts/package/mkspec -@@ -120,29 +120,40 @@ echo 'rm -f $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE/{build,source}" - echo "mkdir -p "'$RPM_BUILD_ROOT'"/usr/src/kernels/$KERNELRELEASE" - echo "EXCLUDES=\"$RCS_TAR_IGNORE --exclude .tmp_versions --exclude=*vmlinux* --exclude=*.o --exclude=*.ko --exclude=*.cmd --exclude=Documentation --exclude=firmware --exclude .config.old --exclude .missing-syscalls.d\"" - echo "tar "'$EXCLUDES'" -cf- . | (cd "'$RPM_BUILD_ROOT'"/usr/src/kernels/$KERNELRELEASE;tar xvf -)" --echo 'cd $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE" --echo "ln -sf /usr/src/kernels/$KERNELRELEASE build" --echo "ln -sf /usr/src/kernels/$KERNELRELEASE source" - fi - - echo "" - echo "%clean" - echo 'rm -rf $RPM_BUILD_ROOT' - echo "" -+echo "%pre" -+echo 'chmod -f 0500 /boot' -+echo 'if [ -d /lib/modules ]; then' -+echo 'chmod -f 0500 /lib/modules' -+echo 'fi' -+echo 'if [ -d /lib32/modules ]; then' -+echo 'chmod -f 0500 /lib32/modules' -+echo 'fi' -+echo 'if [ -d /lib64/modules ]; then' -+echo 'chmod -f 0500 /lib64/modules' -+echo 'fi' -+echo "" -+echo "%post devel" -+echo "ln -sf /usr/src/kernels/$KERNELRELEASE /lib/modules/$KERNELRELEASE/build" -+echo "ln -sf /usr/src/kernels/$KERNELRELEASE /lib/modules/$KERNELRELEASE/source" -+echo "" - echo "%post" --echo "if [ -x /sbin/installkernel -a -r /boot/vmlinuz-$KERNELRELEASE -a -r /boot/System.map-$KERNELRELEASE ]; then" --echo "cp /boot/vmlinuz-$KERNELRELEASE /boot/.vmlinuz-$KERNELRELEASE-rpm" --echo "cp /boot/System.map-$KERNELRELEASE /boot/.System.map-$KERNELRELEASE-rpm" --echo "rm -f /boot/vmlinuz-$KERNELRELEASE /boot/System.map-$KERNELRELEASE" --echo "/sbin/installkernel $KERNELRELEASE /boot/.vmlinuz-$KERNELRELEASE-rpm /boot/.System.map-$KERNELRELEASE-rpm" --echo "rm -f /boot/.vmlinuz-$KERNELRELEASE-rpm /boot/.System.map-$KERNELRELEASE-rpm" -+echo "if [ -x /sbin/dracut ]; then" -+echo '/sbin/new-kernel-pkg --dracut --mkinitrd --depmod --install --make-default '"$KERNELRELEASE"' || exit $?' -+echo "else" -+echo '/sbin/new-kernel-pkg --mkinitrd --depmod --install --make-default '"$KERNELRELEASE"' || exit $?' - echo "fi" - echo "" - echo "%files" --echo '%defattr (-, root, root)' --echo "/lib/modules/$KERNELRELEASE" -+echo '%defattr (400, root, root, 500)' - echo "%exclude /lib/modules/$KERNELRELEASE/build" - echo "%exclude /lib/modules/$KERNELRELEASE/source" -+echo "/lib/modules/$KERNELRELEASE" - echo "/lib/firmware/$KERNELRELEASE" - echo "/boot/*" - echo "" -@@ -152,9 +163,11 @@ echo "/usr/include" - echo "" - if ! $PREBUILT; then - echo "%files devel" --echo '%defattr (-, root, root)' -+echo '%defattr (400, root, root, 500)' -+echo "%dir /lib/modules/$KERNELRELEASE" - echo "/usr/src/kernels/$KERNELRELEASE" --echo "/lib/modules/$KERNELRELEASE/build" --echo "/lib/modules/$KERNELRELEASE/source" -+echo "%attr (500, root, root) /usr/src/kernels/$KERNELRELEASE/scripts/recordmcount" -+echo "%attr (500, root, root) /usr/src/kernels/$KERNELRELEASE/scripts/basic/fixdep" -+echo "%attr (500, root, root) /usr/src/kernels/$KERNELRELEASE/scripts/mod/modpost" - echo "" - fi -diff --git a/scripts/pnmtologo.c b/scripts/pnmtologo.c -index 4718d78..9220d58 100644 ---- a/scripts/pnmtologo.c -+++ b/scripts/pnmtologo.c -@@ -244,14 +244,14 @@ static void write_header(void) - fprintf(out, " * Linux logo %s\n", logoname); - fputs(" */\n\n", out); - fputs("#include \n\n", out); -- fprintf(out, "static unsigned char %s_data[] __initdata = {\n", -+ fprintf(out, "static unsigned char %s_data[] = {\n", - logoname); - } - - static void write_footer(void) - { - fputs("\n};\n\n", out); -- fprintf(out, "const struct linux_logo %s __initconst = {\n", logoname); -+ fprintf(out, "const struct linux_logo %s = {\n", logoname); - fprintf(out, "\t.type\t\t= %s,\n", logo_types[logo_type]); - fprintf(out, "\t.width\t\t= %d,\n", logo_width); - fprintf(out, "\t.height\t\t= %d,\n", logo_height); -@@ -381,7 +381,7 @@ static void write_logo_clut224(void) - fputs("\n};\n\n", out); - - /* write logo clut */ -- fprintf(out, "static unsigned char %s_clut[] __initdata = {\n", -+ fprintf(out, "static unsigned char %s_clut[] = {\n", - logoname); - write_hex_cnt = 0; - for (i = 0; i < logo_clutsize; i++) { -diff --git a/scripts/sortextable.h b/scripts/sortextable.h -index ba87004..3f4852c 100644 ---- a/scripts/sortextable.h -+++ b/scripts/sortextable.h -@@ -108,9 +108,9 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) - const char *secstrtab; - const char *strtab; - char *extab_image; -- int extab_index = 0; -- int i; -- int idx; -+ unsigned int extab_index = 0; -+ unsigned int i; -+ unsigned int idx; - unsigned int num_sections; - unsigned int secindex_strings; - -diff --git a/scripts/tags.sh b/scripts/tags.sh -index 23ba1c6..cad2484 100755 ---- a/scripts/tags.sh -+++ b/scripts/tags.sh -@@ -26,7 +26,7 @@ else - fi - - # ignore userspace tools --ignore="$ignore ( -path ${tree}tools ) -prune -o" -+ignore="$ignore ( -path \"${tree}tools/[^g]*\" ) -prune -o" - - # Find all available archs - find_all_archs() -diff --git a/security/Kconfig b/security/Kconfig -index e452378..4388a35 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -4,6 +4,989 @@ - - menu "Security options" - -+menu "Grsecurity" +diff --git a/scripts/gcc-plugins/.gitignore b/scripts/gcc-plugins/.gitignore +new file mode 100644 +index 0000000..de92ed9 +--- /dev/null ++++ b/scripts/gcc-plugins/.gitignore +@@ -0,0 +1 @@ ++randomize_layout_seed.h +diff --git a/scripts/gcc-plugins/Makefile b/scripts/gcc-plugins/Makefile +new file mode 100644 +index 0000000..ad7ca02 +--- /dev/null ++++ b/scripts/gcc-plugins/Makefile +@@ -0,0 +1,57 @@ ++#CC := gcc ++#PLUGIN_SOURCE_FILES := pax_plugin.c ++#PLUGIN_OBJECT_FILES := $(patsubst %.c,%.o,$(PLUGIN_SOURCE_FILES)) ++GCCPLUGINS_DIR := $(shell $(CC) -print-file-name=plugin) ++#CFLAGS += -I$(GCCPLUGINS_DIR)/include -fPIC -O2 -Wall -W -std=gnu99 + -+ config ARCH_TRACK_EXEC_LIMIT -+ bool ++ifeq ($(PLUGINCC),$(HOSTCC)) ++HOSTLIBS := hostlibs ++HOST_EXTRACFLAGS += -I$(GCCPLUGINS_DIR)/include -I$(src) -std=gnu99 -ggdb -Wall -W ++export HOST_EXTRACFLAGS ++else ++HOSTLIBS := hostcxxlibs ++HOST_EXTRACXXFLAGS += -I$(GCCPLUGINS_DIR)/include -I$(src) -std=gnu++98 -fno-rtti -fno-exceptions -fasynchronous-unwind-tables -ggdb -Wall -W -Wno-unused-parameter -Wno-narrowing -Wno-unused-variable ++export HOST_EXTRACXXFLAGS ++endif + -+ config PAX_KERNEXEC_PLUGIN -+ bool ++export GCCPLUGINS_DIR HOSTLIBS + -+ config PAX_PER_CPU_PGD -+ bool ++$(HOSTLIBS)-$(CONFIG_PAX_CONSTIFY_PLUGIN) := constify_plugin.so ++$(HOSTLIBS)-$(CONFIG_PAX_MEMORY_STACKLEAK) += stackleak_plugin.so ++$(HOSTLIBS)-$(CONFIG_KALLOCSTAT_PLUGIN) += kallocstat_plugin.so ++$(HOSTLIBS)-$(CONFIG_PAX_KERNEXEC_PLUGIN) += kernexec_plugin.so ++$(HOSTLIBS)-$(CONFIG_CHECKER_PLUGIN) += checker_plugin.so ++$(HOSTLIBS)-y += colorize_plugin.so ++$(HOSTLIBS)-$(CONFIG_PAX_LATENT_ENTROPY) += latent_entropy_plugin.so ++$(HOSTLIBS)-$(CONFIG_PAX_MEMORY_STRUCTLEAK) += structleak_plugin.so ++$(HOSTLIBS)-y += initify_plugin.so ++$(HOSTLIBS)-$(CONFIG_GRKERNSEC_RANDSTRUCT) += randomize_layout_plugin.so + -+ config TASK_SIZE_MAX_SHIFT -+ int -+ depends on X86_64 -+ default 47 if !PAX_PER_CPU_PGD -+ default 42 if PAX_PER_CPU_PGD ++subdir-$(CONFIG_PAX_SIZE_OVERFLOW) := size_overflow_plugin ++subdir- += size_overflow_plugin + -+ config PAX_ENABLE_PAE -+ bool -+ default y if (X86_32 && (MPENTIUM4 || MK8 || MPSC || MCORE2 || MATOM)) -+ -+ config PAX_USERCOPY_SLABS -+ bool ++subdir-$(CONFIG_PAX_RAP) += rap_plugin ++subdir- += rap_plugin + -+config GRKERNSEC -+ bool "Grsecurity" -+ select CRYPTO -+ select CRYPTO_SHA256 -+ select PROC_FS -+ select STOP_MACHINE -+ select TTY -+ select DEBUG_KERNEL -+ select DEBUG_LIST -+ select MULTIUSER -+ help -+ If you say Y here, you will be able to configure many features -+ that will enhance the security of your system. It is highly -+ recommended that you say Y here and read through the help -+ for each option so that you fully understand the features and -+ can evaluate their usefulness for your machine. ++always := $($(HOSTLIBS)-y) + -+choice -+ prompt "Configuration Method" -+ depends on GRKERNSEC -+ default GRKERNSEC_CONFIG_CUSTOM -+ help ++constify_plugin-objs := constify_plugin.o ++stackleak_plugin-objs := stackleak_plugin.o ++kallocstat_plugin-objs := kallocstat_plugin.o ++kernexec_plugin-objs := kernexec_plugin.o ++checker_plugin-objs := checker_plugin.o ++colorize_plugin-objs := colorize_plugin.o ++latent_entropy_plugin-objs := latent_entropy_plugin.o ++structleak_plugin-objs := structleak_plugin.o ++initify_plugin-objs := initify_plugin.o ++randomize_layout_plugin-objs := randomize_layout_plugin.o + -+config GRKERNSEC_CONFIG_AUTO -+ bool "Automatic" -+ help -+ If you choose this configuration method, you'll be able to answer a small -+ number of simple questions about how you plan to use this kernel. -+ The settings of grsecurity and PaX will be automatically configured for -+ the highest commonly-used settings within the provided constraints. ++$(obj)/randomize_layout_plugin.o: $(objtree)/$(obj)/randomize_layout_seed.h + -+ If you require additional configuration, custom changes can still be made -+ from the "custom configuration" menu. ++quiet_cmd_create_randomize_layout_seed = GENSEED $@ ++ cmd_create_randomize_layout_seed = \ ++ $(CONFIG_SHELL) $(srctree)/$(src)/gen-random-seed.sh $@ $(objtree)/include/generated/randomize_layout_hash.h ++$(objtree)/$(obj)/randomize_layout_seed.h: FORCE ++ $(call if_changed,create_randomize_layout_seed) + -+config GRKERNSEC_CONFIG_CUSTOM -+ bool "Custom" -+ help -+ If you choose this configuration method, you'll be able to configure all -+ grsecurity and PaX settings manually. Via this method, no options are -+ automatically enabled. ++targets += randomize_layout_seed.h randomize_layout_hash.h +diff --git a/scripts/gcc-plugins/checker_plugin.c b/scripts/gcc-plugins/checker_plugin.c +new file mode 100644 +index 0000000..efaf576 +--- /dev/null ++++ b/scripts/gcc-plugins/checker_plugin.c +@@ -0,0 +1,496 @@ ++/* ++ * Copyright 2011-2016 by the PaX Team ++ * Licensed under the GPL v2 ++ * ++ * Note: the choice of the license means that the compilation process is ++ * NOT 'eligible' as defined by gcc's library exception to the GPL v3, ++ * but for the kernel it doesn't matter since it doesn't link against ++ * any of the gcc libraries ++ * ++ * gcc plugin to implement various sparse (source code checker) features ++ * ++ * TODO: ++ * - define separate __iomem, __percpu and __rcu address spaces (lots of code to patch) ++ * ++ * BUGS: ++ * - none known ++ */ + -+ Take note that if menuconfig is exited with this configuration method -+ chosen, you will not be able to use the automatic configuration methods -+ without starting again with a kernel configuration with no grsecurity -+ or PaX options specified inside. ++#include "gcc-common.h" + -+endchoice ++extern void c_register_addr_space (const char *str, addr_space_t as); ++extern enum machine_mode default_addr_space_pointer_mode (addr_space_t); ++extern enum machine_mode default_addr_space_address_mode (addr_space_t); ++extern bool default_addr_space_valid_pointer_mode(enum machine_mode mode, addr_space_t as); ++extern bool default_addr_space_legitimate_address_p(enum machine_mode mode, rtx mem, bool strict, addr_space_t as); ++extern rtx default_addr_space_legitimize_address(rtx x, rtx oldx, enum machine_mode mode, addr_space_t as); + -+choice -+ prompt "Usage Type" -+ depends on (GRKERNSEC && GRKERNSEC_CONFIG_AUTO) -+ default GRKERNSEC_CONFIG_SERVER -+ help ++int plugin_is_GPL_compatible; + -+config GRKERNSEC_CONFIG_SERVER -+ bool "Server" -+ help -+ Choose this option if you plan to use this kernel on a server. ++static struct plugin_info checker_plugin_info = { ++ .version = "201602181345", ++ .help = "user\tturn on user/kernel address space checking\n" ++ "context\tturn on locking context checking\n" ++}; + -+config GRKERNSEC_CONFIG_DESKTOP -+ bool "Desktop" -+ help -+ Choose this option if you plan to use this kernel on a desktop. ++#define ADDR_SPACE_KERNEL 0 ++#define ADDR_SPACE_FORCE_KERNEL 1 ++#define ADDR_SPACE_USER 2 ++#define ADDR_SPACE_FORCE_USER 3 ++#define ADDR_SPACE_IOMEM 0 ++#define ADDR_SPACE_FORCE_IOMEM 0 ++#define ADDR_SPACE_PERCPU 0 ++#define ADDR_SPACE_FORCE_PERCPU 0 ++#define ADDR_SPACE_RCU 0 ++#define ADDR_SPACE_FORCE_RCU 0 + -+endchoice ++static enum machine_mode checker_addr_space_pointer_mode(addr_space_t addrspace) ++{ ++ return default_addr_space_pointer_mode(ADDR_SPACE_GENERIC); ++} + -+choice -+ prompt "Virtualization Type" -+ depends on (GRKERNSEC && X86 && GRKERNSEC_CONFIG_AUTO) -+ default GRKERNSEC_CONFIG_VIRT_NONE -+ help ++static enum machine_mode checker_addr_space_address_mode(addr_space_t addrspace) ++{ ++ return default_addr_space_address_mode(ADDR_SPACE_GENERIC); ++} + -+config GRKERNSEC_CONFIG_VIRT_NONE -+ bool "None" -+ help -+ Choose this option if this kernel will be run on bare metal. ++static bool checker_addr_space_valid_pointer_mode(enum machine_mode mode, addr_space_t as) ++{ ++ return default_addr_space_valid_pointer_mode(mode, as); ++} + -+config GRKERNSEC_CONFIG_VIRT_GUEST -+ bool "Guest" -+ help -+ Choose this option if this kernel will be run as a VM guest. ++static bool checker_addr_space_legitimate_address_p(enum machine_mode mode, rtx mem, bool strict, addr_space_t as) ++{ ++ return default_addr_space_legitimate_address_p(mode, mem, strict, ADDR_SPACE_GENERIC); ++} + -+config GRKERNSEC_CONFIG_VIRT_HOST -+ bool "Host" -+ help -+ Choose this option if this kernel will be run as a VM host. ++static rtx checker_addr_space_legitimize_address(rtx x, rtx oldx, enum machine_mode mode, addr_space_t as) ++{ ++ return default_addr_space_legitimize_address(x, oldx, mode, as); ++} + -+endchoice ++static bool checker_addr_space_subset_p(addr_space_t subset, addr_space_t superset) ++{ ++ if (subset == ADDR_SPACE_FORCE_KERNEL && superset == ADDR_SPACE_KERNEL) ++ return true; + -+choice -+ prompt "Virtualization Hardware" -+ depends on (GRKERNSEC && X86 && GRKERNSEC_CONFIG_AUTO && (GRKERNSEC_CONFIG_VIRT_GUEST || GRKERNSEC_CONFIG_VIRT_HOST)) -+ help ++ if (subset == ADDR_SPACE_FORCE_USER && superset == ADDR_SPACE_USER) ++ return true; + -+config GRKERNSEC_CONFIG_VIRT_EPT -+ bool "EPT/RVI Processor Support" -+ depends on X86 -+ help -+ Choose this option if your CPU supports the EPT or RVI features of 2nd-gen -+ hardware virtualization. This allows for additional kernel hardening protections -+ to operate without additional performance impact. ++ if (subset == ADDR_SPACE_FORCE_IOMEM && superset == ADDR_SPACE_IOMEM) ++ return true; + -+ To see if your Intel processor supports EPT, see: -+ http://ark.intel.com/Products/VirtualizationTechnology -+ (Most Core i3/5/7 support EPT) ++ if (subset == ADDR_SPACE_KERNEL && superset == ADDR_SPACE_FORCE_USER) ++ return true; + -+ To see if your AMD processor supports RVI, see: -+ http://support.amd.com/us/kbarticles/Pages/GPU120AMDRVICPUsHyperVWin8.aspx ++ if (subset == ADDR_SPACE_KERNEL && superset == ADDR_SPACE_FORCE_IOMEM) ++ return true; + -+config GRKERNSEC_CONFIG_VIRT_SOFT -+ bool "First-gen/No Hardware Virtualization" -+ help -+ Choose this option if you use an Atom/Pentium/Core 2 processor that either doesn't -+ support hardware virtualization or doesn't support the EPT/RVI extensions. ++ if (subset == ADDR_SPACE_USER && superset == ADDR_SPACE_FORCE_KERNEL) ++ return true; + -+endchoice ++ if (subset == ADDR_SPACE_IOMEM && superset == ADDR_SPACE_FORCE_KERNEL) ++ return true; + -+choice -+ prompt "Virtualization Software" -+ depends on (GRKERNSEC && GRKERNSEC_CONFIG_AUTO && (GRKERNSEC_CONFIG_VIRT_GUEST || GRKERNSEC_CONFIG_VIRT_HOST)) -+ help ++ return subset == superset; ++} + -+config GRKERNSEC_CONFIG_VIRT_XEN -+ bool "Xen" -+ help -+ Choose this option if this kernel is running as a Xen guest or host. ++static rtx checker_addr_space_convert(rtx op, tree from_type, tree to_type) ++{ ++// addr_space_t from_as = TYPE_ADDR_SPACE(TREE_TYPE(from_type)); ++// addr_space_t to_as = TYPE_ADDR_SPACE(TREE_TYPE(to_type)); + -+config GRKERNSEC_CONFIG_VIRT_VMWARE -+ bool "VMWare" -+ help -+ Choose this option if this kernel is running as a VMWare guest or host. ++ return op; ++} + -+config GRKERNSEC_CONFIG_VIRT_KVM -+ bool "KVM" -+ help -+ Choose this option if this kernel is running as a KVM guest or host. ++static void register_checker_address_spaces(void *event_data, void *data) ++{ ++ c_register_addr_space("__kernel", ADDR_SPACE_KERNEL); ++ c_register_addr_space("__force_kernel", ADDR_SPACE_FORCE_KERNEL); ++ c_register_addr_space("__user", ADDR_SPACE_USER); ++ c_register_addr_space("__force_user", ADDR_SPACE_FORCE_USER); ++// c_register_addr_space("__iomem", ADDR_SPACE_IOMEM); ++// c_register_addr_space("__force_iomem", ADDR_SPACE_FORCE_IOMEM); ++// c_register_addr_space("__percpu", ADDR_SPACE_PERCPU); ++// c_register_addr_space("__force_percpu", ADDR_SPACE_FORCE_PERCPU); ++// c_register_addr_space("__rcu", ADDR_SPACE_RCU); ++// c_register_addr_space("__force_rcu", ADDR_SPACE_FORCE_RCU); + -+config GRKERNSEC_CONFIG_VIRT_VIRTUALBOX -+ bool "VirtualBox" -+ help -+ Choose this option if this kernel is running as a VirtualBox guest or host. ++ targetm.addr_space.pointer_mode = checker_addr_space_pointer_mode; ++ targetm.addr_space.address_mode = checker_addr_space_address_mode; ++ targetm.addr_space.valid_pointer_mode = checker_addr_space_valid_pointer_mode; ++ targetm.addr_space.legitimate_address_p = checker_addr_space_legitimate_address_p; ++// targetm.addr_space.legitimize_address = checker_addr_space_legitimize_address; ++ targetm.addr_space.subset_p = checker_addr_space_subset_p; ++ targetm.addr_space.convert = checker_addr_space_convert; ++} + -+config GRKERNSEC_CONFIG_VIRT_HYPERV -+ bool "Hyper-V" -+ help -+ Choose this option if this kernel is running as a Hyper-V guest. ++static bool split_context_attribute(tree args, tree *lock, tree *in, tree *out) ++{ ++ *in = TREE_VALUE(args); + -+endchoice ++ if (TREE_CODE(*in) != INTEGER_CST) { ++ *lock = *in; ++ args = TREE_CHAIN(args); ++ *in = TREE_VALUE(args); ++ } else ++ *lock = NULL_TREE; + -+choice -+ prompt "Required Priorities" -+ depends on (GRKERNSEC && GRKERNSEC_CONFIG_AUTO) -+ default GRKERNSEC_CONFIG_PRIORITY_PERF -+ help ++ args = TREE_CHAIN(args); ++ if (*lock && !args) ++ return false; + -+config GRKERNSEC_CONFIG_PRIORITY_PERF -+ bool "Performance" -+ help -+ Choose this option if performance is of highest priority for this deployment -+ of grsecurity. Features like UDEREF on a 64bit kernel, kernel stack clearing, -+ clearing of structures intended for userland, and freed memory sanitizing will -+ be disabled. ++ *out = TREE_VALUE(args); ++ return true; ++} + -+config GRKERNSEC_CONFIG_PRIORITY_SECURITY -+ bool "Security" -+ help -+ Choose this option if security is of highest priority for this deployment of -+ grsecurity. UDEREF, kernel stack clearing, clearing of structures intended -+ for userland, and freed memory sanitizing will be enabled for this kernel. -+ In a worst-case scenario, these features can introduce a 20% performance hit -+ (UDEREF on x64 contributing half of this hit). ++static tree handle_context_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs) ++{ ++ *no_add_attrs = true; ++ tree lock, in, out; + -+endchoice ++ if (TREE_CODE(*node) != FUNCTION_DECL) { ++ error("%qE attribute applies to functions only (%qD)", name, *node); ++ return NULL_TREE; ++ } + -+menu "Default Special Groups" -+depends on (GRKERNSEC && GRKERNSEC_CONFIG_AUTO) ++ if (!split_context_attribute(args, &lock, &in, &out)) { ++ error("%qE attribute needs two integers after the lock expression", name); ++ return NULL_TREE; ++ } + -+config GRKERNSEC_PROC_GID -+ int "GID exempted from /proc restrictions" -+ default 1001 -+ help -+ Setting this GID determines which group will be exempted from -+ grsecurity's /proc restrictions, allowing users of the specified -+ group to view network statistics and the existence of other users' -+ processes on the system. This GID may also be chosen at boot time -+ via "grsec_proc_gid=" on the kernel commandline. ++ if (TREE_CODE(in) != INTEGER_CST) { ++ error("the 'in' argument of the %qE attribute must be an integer (%qE)", name, in); ++ return NULL_TREE; ++ } + -+config GRKERNSEC_TPE_UNTRUSTED_GID -+ int "GID for TPE-untrusted users" -+ depends on GRKERNSEC_CONFIG_SERVER && GRKERNSEC_TPE && !GRKERNSEC_TPE_INVERT -+ default 1005 -+ help -+ Setting this GID determines which group untrusted users should -+ be added to. These users will be placed under grsecurity's Trusted Path -+ Execution mechanism, preventing them from executing their own binaries. -+ The users will only be able to execute binaries in directories owned and -+ writable only by the root user. If the sysctl option is enabled, a sysctl -+ option with name "tpe_gid" is created. ++ if (TREE_CODE(out) != INTEGER_CST) { ++ error("the 'out' argument of the %qE attribute must be an integer (%qE)", name, out); ++ return NULL_TREE; ++ } + -+config GRKERNSEC_TPE_TRUSTED_GID -+ int "GID for TPE-trusted users" -+ depends on GRKERNSEC_CONFIG_SERVER && GRKERNSEC_TPE && GRKERNSEC_TPE_INVERT -+ default 1005 -+ help -+ Setting this GID determines what group TPE restrictions will be -+ *disabled* for. If the sysctl option is enabled, a sysctl option -+ with name "tpe_gid" is created. ++ *no_add_attrs = false; ++ return NULL_TREE; ++} + -+config GRKERNSEC_SYMLINKOWN_GID -+ int "GID for users with kernel-enforced SymlinksIfOwnerMatch" -+ depends on GRKERNSEC_CONFIG_SERVER -+ default 1006 -+ help -+ Setting this GID determines what group kernel-enforced -+ SymlinksIfOwnerMatch will be enabled for. If the sysctl option -+ is enabled, a sysctl option with name "symlinkown_gid" is created. ++static struct attribute_spec context_attr = { ++ .name = "context", ++ .min_length = 2, ++ .max_length = 3, ++ .decl_required = true, ++ .type_required = false, ++ .function_type_required = false, ++ .handler = handle_context_attribute, ++#if BUILDING_GCC_VERSION >= 4007 ++ .affects_type_identity = true ++#endif ++}; + ++static void register_attributes(void *event_data, void *data) ++{ ++ register_attribute(&context_attr); ++} + -+endmenu ++static const char context_function[] = "__context__"; ++static GTY(()) tree context_function_decl; + -+menu "Customize Configuration" -+depends on GRKERNSEC ++static const char context_error[] = "__context_error__"; ++static GTY(()) tree context_error_decl; + -+menu "PaX" ++static void context_start_unit(void __unused *gcc_data, void __unused *user_data) ++{ ++ tree fntype, attr; + -+config PAX -+ bool "Enable various PaX features" -+ default y if GRKERNSEC_CONFIG_AUTO -+ depends on GRKERNSEC && (ALPHA || ARM || AVR32 || IA64 || MIPS || PARISC || PPC || SPARC || X86) -+ help -+ This allows you to enable various PaX features. PaX adds -+ intrusion prevention mechanisms to the kernel that reduce -+ the risks posed by exploitable memory corruption bugs. ++ // void __context__(void *, int); ++ fntype = build_function_type_list(void_type_node, ptr_type_node, integer_type_node, NULL_TREE); ++ context_function_decl = build_fn_decl(context_function, fntype); + -+menu "PaX Control" -+ depends on PAX ++ TREE_PUBLIC(context_function_decl) = 1; ++ TREE_USED(context_function_decl) = 1; ++ DECL_EXTERNAL(context_function_decl) = 1; ++ DECL_ARTIFICIAL(context_function_decl) = 1; ++ DECL_PRESERVE_P(context_function_decl) = 1; ++// TREE_NOTHROW(context_function_decl) = 1; ++// DECL_UNINLINABLE(context_function_decl) = 1; ++ DECL_ASSEMBLER_NAME(context_function_decl); // for LTO ++ lang_hooks.decls.pushdecl(context_function_decl); + -+config PAX_SOFTMODE -+ bool 'Support soft mode' -+ help -+ Enabling this option will allow you to run PaX in soft mode, that -+ is, PaX features will not be enforced by default, only on executables -+ marked explicitly. You must also enable PT_PAX_FLAGS or XATTR_PAX_FLAGS -+ support as they are the only way to mark executables for soft mode use. ++ // void __context_error__(const void *, int) __attribute__((error("context error"))); ++ fntype = build_function_type_list(void_type_node, const_ptr_type_node, integer_type_node, NULL_TREE); ++ context_error_decl = build_fn_decl(context_error, fntype); + -+ Soft mode can be activated by using the "pax_softmode=1" kernel command -+ line option on boot. Furthermore you can control various PaX features -+ at runtime via the entries in /proc/sys/kernel/pax. ++ TREE_PUBLIC(context_error_decl) = 1; ++ TREE_USED(context_error_decl) = 1; ++ DECL_EXTERNAL(context_error_decl) = 1; ++ DECL_ARTIFICIAL(context_error_decl) = 1; ++ DECL_PRESERVE_P(context_error_decl) = 1; ++// TREE_NOTHROW(context_error_decl) = 1; ++// DECL_UNINLINABLE(context_error_decl) = 1; ++ TREE_THIS_VOLATILE(context_error_decl) = 1; ++ DECL_ASSEMBLER_NAME(context_error_decl); + -+config PAX_EI_PAX -+ bool 'Use legacy ELF header marking' -+ default y if GRKERNSEC_CONFIG_AUTO -+ help -+ Enabling this option will allow you to control PaX features on -+ a per executable basis via the 'chpax' utility available at -+ http://pax.grsecurity.net/. The control flags will be read from -+ an otherwise reserved part of the ELF header. This marking has -+ numerous drawbacks (no support for soft-mode, toolchain does not -+ know about the non-standard use of the ELF header) therefore it -+ has been deprecated in favour of PT_PAX_FLAGS and XATTR_PAX_FLAGS -+ support. ++ attr = tree_cons(NULL, build_string(14, "context error"), NULL); ++ attr = tree_cons(get_identifier("error"), attr, NULL); ++ decl_attributes(&context_error_decl, attr, 0); ++} + -+ Note that if you enable PT_PAX_FLAGS or XATTR_PAX_FLAGS marking -+ support as well, they will override the legacy EI_PAX marks. ++static bool context_gate(void) ++{ ++ tree context_attr; + -+ If you enable none of the marking options then all applications -+ will run with PaX enabled on them by default. ++return true; + -+config PAX_PT_PAX_FLAGS -+ bool 'Use ELF program header marking' -+ default y if GRKERNSEC_CONFIG_AUTO -+ help -+ Enabling this option will allow you to control PaX features on -+ a per executable basis via the 'paxctl' utility available at -+ http://pax.grsecurity.net/. The control flags will be read from -+ a PaX specific ELF program header (PT_PAX_FLAGS). This marking -+ has the benefits of supporting both soft mode and being fully -+ integrated into the toolchain (the binutils patch is available -+ from http://pax.grsecurity.net). -+ -+ Note that if you enable the legacy EI_PAX marking support as well, -+ the EI_PAX marks will be overridden by the PT_PAX_FLAGS marks. -+ -+ If you enable both PT_PAX_FLAGS and XATTR_PAX_FLAGS support then you -+ must make sure that the marks are the same if a binary has both marks. ++ context_attr = lookup_attribute("context", DECL_ATTRIBUTES(current_function_decl)); ++ return context_attr != NULL_TREE; ++} + -+ If you enable none of the marking options then all applications -+ will run with PaX enabled on them by default. ++static basic_block verify_context_before(gimple_stmt_iterator *gsi, tree context, tree inout, tree error) ++{ ++ gimple stmt; ++ basic_block cond_bb, join_bb, true_bb; ++ edge e; ++ location_t loc; ++ const char *file; ++ int line; ++ size_t len; ++ tree filename; + -+config PAX_XATTR_PAX_FLAGS -+ bool 'Use filesystem extended attributes marking' -+ default y if GRKERNSEC_CONFIG_AUTO -+ select CIFS_XATTR if CIFS -+ select EXT2_FS_XATTR if EXT2_FS -+ select EXT3_FS_XATTR if EXT3_FS -+ select F2FS_FS_XATTR if F2FS_FS -+ select JFFS2_FS_XATTR if JFFS2_FS -+ select REISERFS_FS_XATTR if REISERFS_FS -+ select SQUASHFS_XATTR if SQUASHFS -+ select TMPFS_XATTR if TMPFS -+ help -+ Enabling this option will allow you to control PaX features on -+ a per executable basis via the 'setfattr' utility. The control -+ flags will be read from the user.pax.flags extended attribute of -+ the file. This marking has the benefit of supporting binary-only -+ applications that self-check themselves (e.g., skype) and would -+ not tolerate chpax/paxctl changes. The main drawback is that -+ extended attributes are not supported by some filesystems (e.g., -+ isofs, udf, vfat) so copying files through such filesystems will -+ lose the extended attributes and these PaX markings. ++ stmt = gsi_stmt(*gsi); ++ if (gimple_has_location(stmt)) { ++ loc = gimple_location(stmt); ++ file = gimple_filename(stmt); ++ line = gimple_lineno(stmt); ++ } else { ++ loc = DECL_SOURCE_LOCATION(current_function_decl); ++ file = DECL_SOURCE_FILE(current_function_decl); ++ line = DECL_SOURCE_LINE(current_function_decl); ++ } ++ gcc_assert(file); + -+ Note that if you enable the legacy EI_PAX marking support as well, -+ the EI_PAX marks will be overridden by the XATTR_PAX_FLAGS marks. ++ // if (context != count) __context_error__(__FILE__, __LINE__); ++ stmt = gimple_build_cond(NE_EXPR, context, inout, NULL_TREE, NULL_TREE); ++ gimple_set_location(stmt, loc); ++ gsi_insert_before(gsi, stmt, GSI_NEW_STMT); + -+ If you enable both PT_PAX_FLAGS and XATTR_PAX_FLAGS support then you -+ must make sure that the marks are the same if a binary has both marks. ++ cond_bb = gsi_bb(*gsi); ++ gcc_assert(!gsi_end_p(*gsi)); ++ gcc_assert(stmt == gsi_stmt(*gsi)); + -+ If you enable none of the marking options then all applications -+ will run with PaX enabled on them by default. ++ e = split_block(cond_bb, gsi_stmt(*gsi)); ++ cond_bb = e->src; ++ join_bb = e->dest; ++ e->flags = EDGE_FALSE_VALUE; ++ e->probability = REG_BR_PROB_BASE; + -+choice -+ prompt 'MAC system integration' -+ default PAX_HAVE_ACL_FLAGS -+ help -+ Mandatory Access Control systems have the option of controlling -+ PaX flags on a per executable basis, choose the method supported -+ by your particular system. ++ true_bb = create_empty_bb(EXIT_BLOCK_PTR_FOR_FN(cfun)->prev_bb); ++ make_edge(cond_bb, true_bb, EDGE_TRUE_VALUE); ++ make_edge(true_bb, join_bb, EDGE_FALLTHRU); + -+ - "none": if your MAC system does not interact with PaX, -+ - "direct": if your MAC system defines pax_set_initial_flags() itself, -+ - "hook": if your MAC system uses the pax_set_initial_flags_func callback. ++ set_immediate_dominator(CDI_DOMINATORS, true_bb, cond_bb); ++ set_immediate_dominator(CDI_DOMINATORS, join_bb, cond_bb); + -+ NOTE: this option is for developers/integrators only. ++ gcc_assert(cond_bb->loop_father == join_bb->loop_father); ++ add_bb_to_loop(true_bb, cond_bb->loop_father); + -+ config PAX_NO_ACL_FLAGS -+ bool 'none' ++ // insert call to builtin_trap or __context_error__ ++ *gsi = gsi_start_bb(true_bb); + -+ config PAX_HAVE_ACL_FLAGS -+ bool 'direct' ++// stmt = gimple_build_call(builtin_decl_implicit(BUILT_IN_TRAP), 0); ++ len = strlen(file) + 1; ++ filename = build_string(len, file); ++ TREE_TYPE(filename) = build_array_type(unsigned_char_type_node, build_index_type(size_int(len))); ++ filename = build1(ADDR_EXPR, const_ptr_type_node, filename); ++ stmt = gimple_build_call(error, 2, filename, build_int_cst(NULL_TREE, line)); ++ gimple_set_location(stmt, loc); ++ gsi_insert_after(gsi, stmt, GSI_CONTINUE_LINKING); + -+ config PAX_HOOK_ACL_FLAGS -+ bool 'hook' -+endchoice ++ *gsi = gsi_start_nondebug_bb(join_bb); ++ return join_bb; ++} + -+endmenu ++static void update_context(gimple_stmt_iterator *gsi, tree context, int diff) ++{ ++ gimple assign; ++ tree op; + -+menu "Non-executable pages" -+ depends on PAX ++ op = fold_build2_loc(UNKNOWN_LOCATION, PLUS_EXPR, integer_type_node, context, build_int_cst(integer_type_node, diff)); ++ assign = gimple_build_assign(context, op); ++ gsi_insert_after(gsi, assign, GSI_NEW_STMT); ++ update_stmt(assign); ++} + -+config PAX_NOEXEC -+ bool "Enforce non-executable pages" -+ default y if GRKERNSEC_CONFIG_AUTO -+ depends on ALPHA || (ARM && (CPU_V6 || CPU_V6K || CPU_V7)) || IA64 || MIPS || PARISC || PPC || S390 || SPARC || X86 -+ help -+ By design some architectures do not allow for protecting memory -+ pages against execution or even if they do, Linux does not make -+ use of this feature. In practice this means that if a page is -+ readable (such as the stack or heap) it is also executable. ++static basic_block track_context(basic_block bb, tree context) ++{ ++ gimple_stmt_iterator gsi; ++ gimple assign; + -+ There is a well known exploit technique that makes use of this -+ fact and a common programming mistake where an attacker can -+ introduce code of his choice somewhere in the attacked program's -+ memory (typically the stack or the heap) and then execute it. ++ // adjust context according to the context information on any call stmt ++ for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { ++ gimple stmt = gsi_stmt(gsi); ++ tree fndecl, context_attr; ++ tree lock, in, out; ++ int incount, outcount; + -+ If the attacked program was running with different (typically -+ higher) privileges than that of the attacker, then he can elevate -+ his own privilege level (e.g. get a root shell, write to files for -+ which he does not have write access to, etc). ++ if (!is_gimple_call(stmt)) ++ continue; + -+ Enabling this option will let you choose from various features -+ that prevent the injection and execution of 'foreign' code in -+ a program. ++ fndecl = gimple_call_fndecl(stmt); ++ if (!fndecl) ++ continue; + -+ This will also break programs that rely on the old behaviour and -+ expect that dynamically allocated memory via the malloc() family -+ of functions is executable (which it is not). Notable examples -+ are the XFree86 4.x server, the java runtime and wine. ++ if (fndecl == context_function_decl) { ++ unsigned int num_ops = gimple_num_ops(stmt); ++ int diff = tree_to_shwi(gimple_op(stmt, num_ops - 1)); + -+config PAX_PAGEEXEC -+ bool "Paging based non-executable pages" -+ default y if GRKERNSEC_CONFIG_AUTO -+ depends on PAX_NOEXEC && (!X86_32 || M586 || M586TSC || M586MMX || M686 || MPENTIUMII || MPENTIUMIII || MPENTIUMM || MCORE2 || MATOM || MPENTIUM4 || MPSC || MK7 || MK8 || MWINCHIPC6 || MWINCHIP2 || MWINCHIP3D || MVIAC3_2 || MVIAC7) -+ select ARCH_TRACK_EXEC_LIMIT if X86_32 -+ help -+ This implementation is based on the paging feature of the CPU. -+ On i386 without hardware non-executable bit support there is a -+ variable but usually low performance impact, however on Intel's -+ P4 core based CPUs it is very high so you should not enable this -+ for kernels meant to be used on such CPUs. ++ gcc_assert(diff); ++ update_context(&gsi, context, diff); ++ continue; ++ } + -+ On alpha, avr32, ia64, parisc, sparc, sparc64, x86_64 and i386 -+ with hardware non-executable bit support there is no performance -+ impact, on ppc the impact is negligible. ++ context_attr = lookup_attribute("context", DECL_ATTRIBUTES(fndecl)); ++ if (!context_attr) ++ continue; + -+ Note that several architectures require various emulations due to -+ badly designed userland ABIs, this will cause a performance impact -+ but will disappear as soon as userland is fixed. For example, ppc -+ userland MUST have been built with secure-plt by a recent toolchain. ++ gcc_assert(split_context_attribute(TREE_VALUE(context_attr), &lock, &in, &out)); ++ incount = tree_to_shwi(in); ++ outcount = tree_to_shwi(out); ++ bb = verify_context_before(&gsi, context, in, context_error_decl); ++ update_context(&gsi, context, outcount - incount); ++ } + -+config PAX_SEGMEXEC -+ bool "Segmentation based non-executable pages" -+ default y if GRKERNSEC_CONFIG_AUTO -+ depends on PAX_NOEXEC && X86_32 -+ help -+ This implementation is based on the segmentation feature of the -+ CPU and has a very small performance impact, however applications -+ will be limited to a 1.5 GB address space instead of the normal -+ 3 GB. ++ return bb; ++} + -+config PAX_EMUTRAMP -+ bool "Emulate trampolines" -+ default y if PARISC || GRKERNSEC_CONFIG_AUTO -+ depends on (PAX_PAGEEXEC || PAX_SEGMEXEC) && (PARISC || X86) -+ help -+ There are some programs and libraries that for one reason or -+ another attempt to execute special small code snippets from -+ non-executable memory pages. Most notable examples are the -+ signal handler return code generated by the kernel itself and -+ the GCC trampolines. ++static bool bb_any_loop(basic_block bb) ++{ ++ return bb_loop_depth(bb) || (bb->flags & BB_IRREDUCIBLE_LOOP); ++} + -+ If you enabled CONFIG_PAX_PAGEEXEC or CONFIG_PAX_SEGMEXEC then -+ such programs will no longer work under your kernel. ++static unsigned int context_execute(void) ++{ ++ basic_block bb; ++ gimple assign; ++ gimple_stmt_iterator gsi; ++ tree context_attr, context; ++ tree lock, in, out; + -+ As a remedy you can say Y here and use the 'chpax' or 'paxctl' -+ utilities to enable trampoline emulation for the affected programs -+ yet still have the protection provided by the non-executable pages. ++ loop_optimizer_init(LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS); ++ gcc_assert(current_loops); + -+ On parisc you MUST enable this option and EMUSIGRT as well, otherwise -+ your system will not even boot. ++ calculate_dominance_info(CDI_DOMINATORS); ++ calculate_dominance_info(CDI_POST_DOMINATORS); + -+ Alternatively you can say N here and use the 'chpax' or 'paxctl' -+ utilities to disable CONFIG_PAX_PAGEEXEC and CONFIG_PAX_SEGMEXEC -+ for the affected files. ++ context_attr = lookup_attribute("context", DECL_ATTRIBUTES(current_function_decl)); ++ if (context_attr) { ++ gcc_assert(split_context_attribute(TREE_VALUE(context_attr), &lock, &in, &out)); ++ } else { ++ in = out = integer_zero_node; ++ } + -+ NOTE: enabling this feature *may* open up a loophole in the -+ protection provided by non-executable pages that an attacker -+ could abuse. Therefore the best solution is to not have any -+ files on your system that would require this option. This can -+ be achieved by not using libc5 (which relies on the kernel -+ signal handler return code) and not using or rewriting programs -+ that make use of the nested function implementation of GCC. -+ Skilled users can just fix GCC itself so that it implements -+ nested function calls in a way that does not interfere with PaX. ++ // 1. create local context variable ++ context = create_tmp_var(integer_type_node, "context"); ++ add_referenced_var(context); ++ mark_sym_for_renaming(context); + -+config PAX_EMUSIGRT -+ bool "Automatically emulate sigreturn trampolines" -+ depends on PAX_EMUTRAMP && PARISC -+ default y -+ help -+ Enabling this option will have the kernel automatically detect -+ and emulate signal return trampolines executing on the stack -+ that would otherwise lead to task termination. ++ // 2. initialize local context variable ++ gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); ++ bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); ++ if (!single_pred_p(bb)) { ++ gcc_assert(bb_any_loop(bb)); ++ split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun))); ++ bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); ++ } ++ gsi = gsi_start_bb(bb); ++ assign = gimple_build_assign(context, in); ++ gsi_insert_before(&gsi, assign, GSI_NEW_STMT); ++ update_stmt(assign); + -+ This solution is intended as a temporary one for users with -+ legacy versions of libc (libc5, glibc 2.0, uClibc before 0.9.17, -+ Modula-3 runtime, etc) or executables linked to such, basically -+ everything that does not specify its own SA_RESTORER function in -+ normal executable memory like glibc 2.1+ does. ++ // 3. instrument each BB to track the local context variable ++ FOR_EACH_BB_FN(bb, cfun) { ++ bb = track_context(bb, context); ++ } + -+ On parisc you MUST enable this option, otherwise your system will -+ not even boot. ++ // 4. verify the local context variable against the expected state ++ if (EDGE_COUNT(EXIT_BLOCK_PTR_FOR_FN(cfun)->preds)) { ++ gcc_assert(single_pred_p(EXIT_BLOCK_PTR_FOR_FN(cfun))); ++ gsi = gsi_last_nondebug_bb(single_pred(EXIT_BLOCK_PTR_FOR_FN(cfun))); ++ verify_context_before(&gsi, context, out, context_error_decl); ++ } + -+ NOTE: this feature cannot be disabled on a per executable basis -+ and since it *does* open up a loophole in the protection provided -+ by non-executable pages, the best solution is to not have any -+ files on your system that would require this option. ++ free_dominance_info(CDI_DOMINATORS); ++ free_dominance_info(CDI_POST_DOMINATORS); ++ loop_optimizer_finalize(); ++ return 0; ++} + -+config PAX_MPROTECT -+ bool "Restrict mprotect()" -+ default y if GRKERNSEC_CONFIG_AUTO -+ depends on (PAX_PAGEEXEC || PAX_SEGMEXEC) -+ help -+ Enabling this option will prevent programs from -+ - changing the executable status of memory pages that were -+ not originally created as executable, -+ - making read-only executable pages writable again, -+ - creating executable pages from anonymous memory, -+ - making read-only-after-relocations (RELRO) data pages writable again. ++#define PASS_NAME context ++#define PROPERTIES_REQUIRED PROP_gimple_leh | PROP_cfg ++//#define TODO_FLAGS_START TODO_verify_ssa | TODO_verify_flow | TODO_verify_stmts ++#define TODO_FLAGS_FINISH TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func | TODO_verify_flow | TODO_update_ssa ++#include "gcc-generate-gimple-pass.h" + -+ You should say Y here to complete the protection provided by -+ the enforcement of non-executable pages. ++int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) ++{ ++ const char * const plugin_name = plugin_info->base_name; ++ const int argc = plugin_info->argc; ++ const struct plugin_argument * const argv = plugin_info->argv; ++ int i; ++ bool enable_user, enable_context; ++ struct register_pass_info context_pass_info; + -+ NOTE: you can use the 'chpax' or 'paxctl' utilities to control -+ this feature on a per file basis. ++ static const struct ggc_root_tab gt_ggc_r_gt_checker[] = { ++ { ++ .base = &context_function_decl, ++ .nelt = 1, ++ .stride = sizeof(context_function_decl), ++ .cb = >_ggc_mx_tree_node, ++ .pchw = >_pch_nx_tree_node ++ }, ++ { ++ .base = &context_error_decl, ++ .nelt = 1, ++ .stride = sizeof(context_error_decl), ++ .cb = >_ggc_mx_tree_node, ++ .pchw = >_pch_nx_tree_node ++ }, ++ LAST_GGC_ROOT_TAB ++ }; + -+config PAX_MPROTECT_COMPAT -+ bool "Use legacy/compat protection demoting (read help)" -+ depends on PAX_MPROTECT -+ default n -+ help -+ The current implementation of PAX_MPROTECT denies RWX allocations/mprotects -+ by sending the proper error code to the application. For some older -+ userland, this can cause problems with applications that assume such -+ allocations will not be prevented by PaX or SELinux and other access -+ control systems and have no fallback mechanisms. For modern distros, -+ this option should generally be set to 'N'. -+ -+config PAX_ELFRELOCS -+ bool "Allow ELF text relocations (read help)" -+ depends on PAX_MPROTECT -+ default n -+ help -+ Non-executable pages and mprotect() restrictions are effective -+ in preventing the introduction of new executable code into an -+ attacked task's address space. There remain only two venues -+ for this kind of attack: if the attacker can execute already -+ existing code in the attacked task then he can either have it -+ create and mmap() a file containing his code or have it mmap() -+ an already existing ELF library that does not have position -+ independent code in it and use mprotect() on it to make it -+ writable and copy his code there. While protecting against -+ the former approach is beyond PaX, the latter can be prevented -+ by having only PIC ELF libraries on one's system (which do not -+ need to relocate their code). If you are sure this is your case, -+ as is the case with all modern Linux distributions, then leave -+ this option disabled. You should say 'n' here. ++ context_pass_info.pass = make_context_pass(); ++// context_pass_info.reference_pass_name = "ssa"; ++ context_pass_info.reference_pass_name = "phiprop"; ++ context_pass_info.ref_pass_instance_number = 1; ++ context_pass_info.pos_op = PASS_POS_INSERT_AFTER; + -+config PAX_ETEXECRELOCS -+ bool "Allow ELF ET_EXEC text relocations" -+ depends on PAX_MPROTECT && (ALPHA || IA64 || PARISC) -+ select PAX_ELFRELOCS -+ default y -+ help -+ On some architectures there are incorrectly created applications -+ that require text relocations and would not work without enabling -+ this option. If you are an alpha, ia64 or parisc user, you should -+ enable this option and disable it once you have made sure that -+ none of your applications need it. ++ if (!plugin_default_version_check(version, &gcc_version)) { ++ error(G_("incompatible gcc/plugin versions")); ++ return 1; ++ } + -+config PAX_EMUPLT -+ bool "Automatically emulate ELF PLT" -+ depends on PAX_MPROTECT && (ALPHA || PARISC || SPARC) -+ default y -+ help -+ Enabling this option will have the kernel automatically detect -+ and emulate the Procedure Linkage Table entries in ELF files. -+ On some architectures such entries are in writable memory, and -+ become non-executable leading to task termination. Therefore -+ it is mandatory that you enable this option on alpha, parisc, -+ sparc and sparc64, otherwise your system would not even boot. ++ register_callback(plugin_name, PLUGIN_INFO, NULL, &checker_plugin_info); + -+ NOTE: this feature *does* open up a loophole in the protection -+ provided by the non-executable pages, therefore the proper -+ solution is to modify the toolchain to produce a PLT that does -+ not need to be writable. ++ enable_user = false; ++ enable_context = false; ++ for (i = 0; i < argc; ++i) { ++ if (!strcmp(argv[i].key, "user")) { ++ enable_user = true; ++ continue; ++ } ++ if (!strcmp(argv[i].key, "context")) { ++ enable_context = true; ++ continue; ++ } ++ error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); ++ } + -+config PAX_DLRESOLVE -+ bool 'Emulate old glibc resolver stub' -+ depends on PAX_EMUPLT && SPARC -+ default n -+ help -+ This option is needed if userland has an old glibc (before 2.4) -+ that puts a 'save' instruction into the runtime generated resolver -+ stub that needs special emulation. ++ if (enable_user) ++ register_callback(plugin_name, PLUGIN_PRAGMAS, register_checker_address_spaces, NULL); ++ if (enable_context) { ++ register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); ++ register_callback(plugin_name, PLUGIN_START_UNIT, context_start_unit, NULL); ++ register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, NULL, (void *)>_ggc_r_gt_checker); ++ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &context_pass_info); ++ } + -+config PAX_KERNEXEC -+ bool "Enforce non-executable kernel pages" -+ default y if GRKERNSEC_CONFIG_AUTO && (!X86 || GRKERNSEC_CONFIG_VIRT_NONE || (GRKERNSEC_CONFIG_VIRT_EPT && GRKERNSEC_CONFIG_VIRT_GUEST) || (GRKERNSEC_CONFIG_VIRT_EPT && GRKERNSEC_CONFIG_VIRT_KVM)) -+ depends on (X86 || (ARM && (CPU_V6 || CPU_V6K || CPU_V7) && !(ARM_LPAE && MODULES))) && !XEN -+ select PAX_PER_CPU_PGD if X86_64 || (X86_32 && X86_PAE) -+ select PAX_KERNEXEC_PLUGIN if X86_64 -+ select ARM_KERNMEM_PERMS if ARM -+ help -+ This is the kernel land equivalent of PAGEEXEC and MPROTECT, -+ that is, enabling this option will make it harder to inject -+ and execute 'foreign' code in kernel memory itself. ++ return 0; ++} +diff --git a/scripts/gcc-plugins/colorize_plugin.c b/scripts/gcc-plugins/colorize_plugin.c +new file mode 100644 +index 0000000..ffe60f6 +--- /dev/null ++++ b/scripts/gcc-plugins/colorize_plugin.c +@@ -0,0 +1,162 @@ ++/* ++ * Copyright 2012-2016 by PaX Team ++ * Licensed under the GPL v2 ++ * ++ * Note: the choice of the license means that the compilation process is ++ * NOT 'eligible' as defined by gcc's library exception to the GPL v3, ++ * but for the kernel it doesn't matter since it doesn't link against ++ * any of the gcc libraries ++ * ++ * gcc plugin to colorize diagnostic output ++ * ++ */ + -+ Note that on amd64, CONFIG_EFI enabled with "efi=old_map" on -+ the kernel command-line will result in an RWX physical map. ++#include "gcc-common.h" + -+ Likewise, the EFI runtime services are necessarily mapped as -+ RWX. If CONFIG_EFI is enabled on an EFI-capable system, it -+ is recommended that you boot with "noefi" on the kernel -+ command-line if possible to eliminate the mapping. ++int plugin_is_GPL_compatible; + -+choice -+ prompt "Return Address Instrumentation Method" -+ default PAX_KERNEXEC_PLUGIN_METHOD_BTS -+ depends on PAX_KERNEXEC_PLUGIN -+ help -+ Select the method used to instrument function pointer dereferences. -+ Note that binary modules cannot be instrumented by this approach. ++static struct plugin_info colorize_plugin_info = { ++ .version = "201602181345", ++ .help = "color=[never|always|auto]\tdetermine when to colorize\n", ++}; + -+ Note that the implementation requires a gcc with plugin support, -+ i.e., gcc 4.5 or newer. You may need to install the supporting -+ headers explicitly in addition to the normal gcc package. ++#define GREEN "\033[32m\033[K" ++#define LIGHTGREEN "\033[1;32m\033[K" ++#define YELLOW "\033[33m\033[K" ++#define LIGHTYELLOW "\033[1;33m\033[K" ++#define RED "\033[31m\033[K" ++#define LIGHTRED "\033[1;31m\033[K" ++#define BLUE "\033[34m\033[K" ++#define LIGHTBLUE "\033[1;34m\033[K" ++#define BRIGHT "\033[1;m\033[K" ++#define NORMAL "\033[m\033[K" + -+ config PAX_KERNEXEC_PLUGIN_METHOD_BTS -+ bool "bts" -+ help -+ This method is compatible with binary only modules but has -+ a higher runtime overhead. ++static diagnostic_starter_fn old_starter; ++static diagnostic_finalizer_fn old_finalizer; + -+ config PAX_KERNEXEC_PLUGIN_METHOD_OR -+ bool "or" -+ depends on !PARAVIRT -+ help -+ This method is incompatible with binary only modules but has -+ a lower runtime overhead. -+endchoice ++static void start_colorize(diagnostic_context *context, diagnostic_info *diagnostic) ++{ ++ const char *color; ++ char *newprefix; + -+config PAX_KERNEXEC_PLUGIN_METHOD -+ string -+ default "bts" if PAX_KERNEXEC_PLUGIN_METHOD_BTS -+ default "or" if PAX_KERNEXEC_PLUGIN_METHOD_OR -+ default "" ++ switch (diagnostic->kind) { ++ case DK_NOTE: ++ color = LIGHTBLUE; ++ break; + -+config PAX_KERNEXEC_MODULE_TEXT -+ int "Minimum amount of memory reserved for module code" -+ default "8" if (!GRKERNSEC_CONFIG_AUTO || GRKERNSEC_CONFIG_SERVER) -+ default "12" if (GRKERNSEC_CONFIG_AUTO && GRKERNSEC_CONFIG_DESKTOP) -+ depends on PAX_KERNEXEC && X86_32 -+ help -+ Due to implementation details the kernel must reserve a fixed -+ amount of memory for runtime allocated code (such as modules) -+ at compile time that cannot be changed at runtime. Here you -+ can specify the minimum amount in MB that will be reserved. -+ Due to the same implementation details this size will always -+ be rounded up to the next 2/4 MB boundary (depends on PAE) so -+ the actually available memory for runtime allocated code will -+ usually be more than this minimum. ++ case DK_PEDWARN: ++ case DK_WARNING: ++ color = LIGHTYELLOW; ++ break; + -+ The default 4 MB should be enough for most users but if you have -+ an excessive number of modules (e.g., most distribution configs -+ compile many drivers as modules) or use huge modules such as -+ nvidia's kernel driver, you will need to adjust this amount. -+ A good rule of thumb is to look at your currently loaded kernel -+ modules and add up their sizes. ++ case DK_ERROR: ++ case DK_FATAL: ++ case DK_ICE: ++ case DK_PERMERROR: ++ case DK_SORRY: ++ color = LIGHTRED; ++ break; + -+endmenu ++ default: ++ color = NORMAL; ++ } + -+menu "Address Space Layout Randomization" -+ depends on PAX ++ old_starter(context, diagnostic); ++ if (-1 == asprintf(&newprefix, "%s%s" NORMAL, color, context->printer->prefix)) ++ return; ++ pp_destroy_prefix(context->printer); ++ pp_set_prefix(context->printer, newprefix); ++} + -+config PAX_ASLR -+ bool "Address Space Layout Randomization" -+ default y if GRKERNSEC_CONFIG_AUTO -+ help -+ Many if not most exploit techniques rely on the knowledge of -+ certain addresses in the attacked program. The following options -+ will allow the kernel to apply a certain amount of randomization -+ to specific parts of the program thereby forcing an attacker to -+ guess them in most cases. Any failed guess will most likely crash -+ the attacked program which allows the kernel to detect such attempts -+ and react on them. PaX itself provides no reaction mechanisms, -+ instead it is strongly encouraged that you make use of grsecurity's -+ (http://www.grsecurity.net/) built-in crash detection features or -+ develop one yourself. ++static void finalize_colorize(diagnostic_context *context, diagnostic_info *diagnostic) ++{ ++ old_finalizer(context, diagnostic); ++} + -+ By saying Y here you can choose to randomize the following areas: -+ - top of the task's kernel stack -+ - top of the task's userland stack -+ - base address for mmap() requests that do not specify one -+ (this includes all libraries) -+ - base address of the main executable ++static void colorize_arm(void) ++{ ++ old_starter = diagnostic_starter(global_dc); ++ old_finalizer = diagnostic_finalizer(global_dc); + -+ It is strongly recommended to say Y here as address space layout -+ randomization has negligible impact on performance yet it provides -+ a very effective protection. ++ diagnostic_starter(global_dc) = start_colorize; ++ diagnostic_finalizer(global_dc) = finalize_colorize; ++} + -+ NOTE: you can use the 'chpax' or 'paxctl' utilities to control -+ this feature on a per file basis. ++static unsigned int colorize_rearm_execute(void) ++{ ++ if (diagnostic_starter(global_dc) == start_colorize) ++ return 0; + -+config PAX_RANDKSTACK -+ bool "Randomize kernel stack base" -+ default y if GRKERNSEC_CONFIG_AUTO && !(GRKERNSEC_CONFIG_VIRT_HOST && GRKERNSEC_CONFIG_VIRT_VIRTUALBOX) -+ depends on X86_TSC && X86 -+ help -+ By saying Y here the kernel will randomize every task's kernel -+ stack on every system call. This will not only force an attacker -+ to guess it but also prevent him from making use of possible -+ leaked information about it. ++ colorize_arm(); ++ return 0; ++} + -+ Since the kernel stack is a rather scarce resource, randomization -+ may cause unexpected stack overflows, therefore you should very -+ carefully test your system. Note that once enabled in the kernel -+ configuration, this feature cannot be disabled on a per file basis. ++#define PASS_NAME colorize_rearm ++#define NO_GATE ++#include "gcc-generate-simple_ipa-pass.h" + -+config PAX_RANDUSTACK -+ bool ++static void colorize_start_unit(void *gcc_data, void *user_data) ++{ ++ colorize_arm(); ++} + -+config PAX_RANDMMAP -+ bool "Randomize user stack and mmap() bases" -+ default y if GRKERNSEC_CONFIG_AUTO -+ depends on PAX_ASLR -+ select PAX_RANDUSTACK -+ help -+ By saying Y here the kernel will randomize every task's userland -+ stack and use a randomized base address for mmap() requests that -+ do not specify one themselves. ++static bool should_colorize(void) ++{ ++#if BUILDING_GCC_VERSION >= 4009 ++ return false; ++#else ++ char const *t = getenv("TERM"); + -+ The stack randomization is done in two steps where the second -+ one may apply a big amount of shift to the top of the stack and -+ cause problems for programs that want to use lots of memory (more -+ than 2.5 GB if SEGMEXEC is not active, or 1.25 GB when it is). ++ return t && strcmp(t, "dumb") && isatty(STDERR_FILENO); ++#endif ++} + -+ As a result of mmap randomization all dynamically loaded libraries -+ will appear at random addresses and therefore be harder to exploit -+ by a technique where an attacker attempts to execute library code -+ for his purposes (e.g. spawn a shell from an exploited program that -+ is running at an elevated privilege level). ++int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) ++{ ++ const char * const plugin_name = plugin_info->base_name; ++ const int argc = plugin_info->argc; ++ const struct plugin_argument * const argv = plugin_info->argv; ++ int i; ++ struct register_pass_info colorize_rearm_pass_info; ++ bool colorize; + -+ Furthermore, if a program is relinked as a dynamic ELF file, its -+ base address will be randomized as well, completing the full -+ randomization of the address space layout. Attacking such programs -+ becomes a guess game. You can find an example of doing this at -+ http://pax.grsecurity.net/et_dyn.tar.gz and practical samples at -+ http://www.grsecurity.net/grsec-gcc-specs.tar.gz . ++ colorize_rearm_pass_info.pass = make_colorize_rearm_pass(); ++ colorize_rearm_pass_info.reference_pass_name = "*free_lang_data"; ++ colorize_rearm_pass_info.ref_pass_instance_number = 1; ++ colorize_rearm_pass_info.pos_op = PASS_POS_INSERT_AFTER; + -+ NOTE: you can use the 'chpax' or 'paxctl' utilities to control this -+ feature on a per file basis. ++ if (!plugin_default_version_check(version, &gcc_version)) { ++ error(G_("incompatible gcc/plugin versions")); ++ return 1; ++ } + -+endmenu ++ register_callback(plugin_name, PLUGIN_INFO, NULL, &colorize_plugin_info); + -+menu "Miscellaneous hardening features" ++ colorize = getenv("GCC_COLORS") ? should_colorize() : false; + -+config PAX_MEMORY_SANITIZE -+ bool "Sanitize all freed memory" -+ default y if (GRKERNSEC_CONFIG_AUTO && GRKERNSEC_CONFIG_PRIORITY_SECURITY) -+ help -+ By saying Y here the kernel will erase memory pages and slab objects -+ as soon as they are freed. This in turn reduces the lifetime of data -+ stored in them, making it less likely that sensitive information such -+ as passwords, cryptographic secrets, etc stay in memory for too long. ++ for (i = 0; i < argc; ++i) { ++ if (!strcmp(argv[i].key, "color")) { ++ if (!argv[i].value) { ++ error(G_("no value supplied for option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); ++ continue; ++ } ++ if (!strcmp(argv[i].value, "always")) ++ colorize = true; ++ else if (!strcmp(argv[i].value, "never")) ++ colorize = false; ++ else if (!strcmp(argv[i].value, "auto")) ++ colorize = should_colorize(); ++ else ++ error(G_("invalid option argument '-fplugin-arg-%s-%s=%s'"), plugin_name, argv[i].key, argv[i].value); ++ continue; ++ } ++ error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); ++ } + -+ This is especially useful for programs whose runtime is short, long -+ lived processes and the kernel itself benefit from this as long as -+ they ensure timely freeing of memory that may hold sensitive -+ information. ++ if (colorize) { ++ // TODO: parse GCC_COLORS as used by gcc 4.9+ ++ register_callback(plugin_name, PLUGIN_START_UNIT, &colorize_start_unit, NULL); ++ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &colorize_rearm_pass_info); ++ } ++ return 0; ++} +diff --git a/scripts/gcc-plugins/constify_plugin.c b/scripts/gcc-plugins/constify_plugin.c +new file mode 100644 +index 0000000..7142f36 +--- /dev/null ++++ b/scripts/gcc-plugins/constify_plugin.c +@@ -0,0 +1,521 @@ ++/* ++ * Copyright 2011 by Emese Revfy ++ * Copyright 2011-2016 by PaX Team ++ * Licensed under the GPL v2, or (at your option) v3 ++ * ++ * This gcc plugin constifies all structures which contain only function pointers or are explicitly marked for constification. ++ * ++ * Homepage: ++ * http://www.grsecurity.net/~ephox/const_plugin/ ++ * ++ * Usage: ++ * $ gcc -I`gcc -print-file-name=plugin`/include -fPIC -shared -O2 -o constify_plugin.so constify_plugin.c ++ * $ gcc -fplugin=constify_plugin.so test.c -O2 ++ */ + -+ A nice side effect of the sanitization of slab objects is the -+ reduction of possible info leaks caused by padding bytes within the -+ leaky structures. Use-after-free bugs for structures containing -+ pointers can also be detected as dereferencing the sanitized pointer -+ will generate an access violation. ++#include "gcc-common.h" + -+ The tradeoff is performance impact, on a single CPU system kernel -+ compilation sees a 3% slowdown, other systems and workloads may vary -+ and you are advised to test this feature on your expected workload -+ before deploying it. ++// unused C type flag in all versions 4.5-6 ++#define TYPE_CONSTIFY_VISITED(TYPE) TYPE_LANG_FLAG_4(TYPE) + -+ The slab sanitization feature excludes a few slab caches per default -+ for performance reasons. To extend the feature to cover those as -+ well, pass "pax_sanitize_slab=full" as kernel command line parameter. ++int plugin_is_GPL_compatible; + -+ To reduce the performance penalty by sanitizing pages only, albeit -+ limiting the effectiveness of this feature at the same time, slab -+ sanitization can be disabled with the kernel command line parameter -+ "pax_sanitize_slab=off". ++static bool enabled = true; + -+ Note that this feature does not protect data stored in live pages, -+ e.g., process memory swapped to disk may stay there for a long time. ++static struct plugin_info const_plugin_info = { ++ .version = "201605212045", ++ .help = "disable\tturn off constification\n", ++}; + -+config PAX_MEMORY_STACKLEAK -+ bool "Sanitize kernel stack" -+ default y if (GRKERNSEC_CONFIG_AUTO && GRKERNSEC_CONFIG_PRIORITY_SECURITY) -+ depends on X86 -+ help -+ By saying Y here the kernel will erase the kernel stack before it -+ returns from a system call. This in turn reduces the information -+ that a kernel stack leak bug can reveal. ++typedef struct { ++ bool has_fptr_field; ++ bool has_writable_field; ++ bool has_do_const_field; ++ bool has_no_const_field; ++} constify_info; + -+ Note that such a bug can still leak information that was put on -+ the stack by the current system call (the one eventually triggering -+ the bug) but traces of earlier system calls on the kernel stack -+ cannot leak anymore. ++static const_tree get_field_type(const_tree field) ++{ ++ return strip_array_types(TREE_TYPE(field)); ++} + -+ The tradeoff is performance impact: on a single CPU system kernel -+ compilation sees a 1% slowdown, other systems and workloads may vary -+ and you are advised to test this feature on your expected workload -+ before deploying it. ++static bool is_fptr(const_tree field) ++{ ++ const_tree ptr = get_field_type(field); + -+ Note that the full feature requires a gcc with plugin support, -+ i.e., gcc 4.5 or newer. You may need to install the supporting -+ headers explicitly in addition to the normal gcc package. Using -+ older gcc versions means that functions with large enough stack -+ frames may leave uninitialized memory behind that may be exposed -+ to a later syscall leaking the stack. ++ if (TREE_CODE(ptr) != POINTER_TYPE) ++ return false; + -+config PAX_MEMORY_STRUCTLEAK -+ bool "Forcibly initialize local variables copied to userland" -+ default y if (GRKERNSEC_CONFIG_AUTO && GRKERNSEC_CONFIG_PRIORITY_SECURITY) -+ help -+ By saying Y here the kernel will zero initialize some local -+ variables that are going to be copied to userland. This in -+ turn prevents unintended information leakage from the kernel -+ stack should later code forget to explicitly set all parts of -+ the copied variable. ++ return TREE_CODE(TREE_TYPE(ptr)) == FUNCTION_TYPE; ++} + -+ The tradeoff is less performance impact than PAX_MEMORY_STACKLEAK -+ at a much smaller coverage. ++/* ++ * determine whether the given structure type meets the requirements for automatic constification, ++ * including the constification attributes on nested structure types ++ */ ++static void constifiable(const_tree node, constify_info *cinfo) ++{ ++ const_tree field; + -+ Note that the implementation requires a gcc with plugin support, -+ i.e., gcc 4.5 or newer. You may need to install the supporting -+ headers explicitly in addition to the normal gcc package. ++ gcc_assert(TREE_CODE(node) == RECORD_TYPE || TREE_CODE(node) == UNION_TYPE); + -+config PAX_MEMORY_UDEREF -+ bool "Prevent invalid userland pointer dereference" -+ default y if GRKERNSEC_CONFIG_AUTO && !(X86_64 && GRKERNSEC_CONFIG_PRIORITY_PERF) && !(X86_64 && GRKERNSEC_CONFIG_VIRT_HOST && GRKERNSEC_CONFIG_VIRT_VIRTUALBOX) && (!X86 || GRKERNSEC_CONFIG_VIRT_NONE || GRKERNSEC_CONFIG_VIRT_EPT) -+ depends on (X86 || (ARM && (CPU_V6 || CPU_V6K || CPU_V7) && !ARM_LPAE)) && !UML_X86 && !XEN -+ select PAX_PER_CPU_PGD if X86_64 -+ help -+ By saying Y here the kernel will be prevented from dereferencing -+ userland pointers in contexts where the kernel expects only kernel -+ pointers. This is both a useful runtime debugging feature and a -+ security measure that prevents exploiting a class of kernel bugs. ++ // e.g., pointer to structure fields while still constructing the structure type ++ if (TYPE_FIELDS(node) == NULL_TREE) ++ return; + -+ The tradeoff is that some virtualization solutions may experience -+ a huge slowdown and therefore you should not enable this feature -+ for kernels meant to run in such environments. Whether a given VM -+ solution is affected or not is best determined by simply trying it -+ out, the performance impact will be obvious right on boot as this -+ mechanism engages from very early on. A good rule of thumb is that -+ VMs running on CPUs without hardware virtualization support (i.e., -+ the majority of IA-32 CPUs) will likely experience the slowdown. ++ for (field = TYPE_FIELDS(node); field; field = TREE_CHAIN(field)) { ++ const_tree type = get_field_type(field); ++ enum tree_code code = TREE_CODE(type); + -+ On X86_64 the kernel will make use of PCID support when available -+ (Intel's Westmere, Sandy Bridge, etc) for better security (default) -+ or performance impact. Pass pax_weakuderef on the kernel command -+ line to choose the latter. ++ if (node == type) ++ continue; + -+config PAX_REFCOUNT -+ bool "Prevent various kernel object reference counter overflows" -+ default y if GRKERNSEC_CONFIG_AUTO -+ depends on GRKERNSEC && ((ARM && (CPU_V6 || CPU_V6K || CPU_V7)) || MIPS || PPC || SPARC64 || X86) -+ help -+ By saying Y here the kernel will detect and prevent overflowing -+ various (but not all) kinds of object reference counters. Such -+ overflows can normally occur due to bugs only and are often, if -+ not always, exploitable. ++ if (is_fptr(field)) ++ cinfo->has_fptr_field = true; ++ else if (code == RECORD_TYPE || code == UNION_TYPE) { ++ if (lookup_attribute("do_const", TYPE_ATTRIBUTES(type))) ++ cinfo->has_do_const_field = true; ++ else if (lookup_attribute("no_const", TYPE_ATTRIBUTES(type))) ++ cinfo->has_no_const_field = true; ++ else ++ constifiable(type, cinfo); ++ } else if (!TREE_READONLY(field)) ++ cinfo->has_writable_field = true; ++ } ++} + -+ The tradeoff is that data structures protected by an overflowed -+ refcount will never be freed and therefore will leak memory. Note -+ that this leak also happens even without this protection but in -+ that case the overflow can eventually trigger the freeing of the -+ data structure while it is still being used elsewhere, resulting -+ in the exploitable situation that this feature prevents. ++static bool constified(const_tree node) ++{ ++ constify_info cinfo = { ++ .has_fptr_field = false, ++ .has_writable_field = false, ++ .has_do_const_field = false, ++ .has_no_const_field = false ++ }; + -+ Since this has a negligible performance impact, you should enable -+ this feature. ++ gcc_assert(TREE_CODE(node) == RECORD_TYPE || TREE_CODE(node) == UNION_TYPE); + -+config PAX_CONSTIFY_PLUGIN -+ bool "Automatically constify eligible structures" -+ default y -+ depends on !UML && PAX_KERNEXEC -+ help -+ By saying Y here the compiler will automatically constify a class -+ of types that contain only function pointers. This reduces the -+ kernel's attack surface and also produces a better memory layout. ++ if (lookup_attribute("no_const", TYPE_ATTRIBUTES(node))) { ++// gcc_assert(!TYPE_READONLY(node)); ++ return false; ++ } + -+ Note that the implementation requires a gcc with plugin support, -+ i.e., gcc 4.5 or newer. You may need to install the supporting -+ headers explicitly in addition to the normal gcc package. -+ -+ Note that if some code really has to modify constified variables -+ then the source code will have to be patched to allow it. Examples -+ can be found in PaX itself (the no_const attribute) and for some -+ out-of-tree modules at http://www.grsecurity.net/~paxguy1/ . ++ if (lookup_attribute("do_const", TYPE_ATTRIBUTES(node))) { ++ gcc_assert(TYPE_READONLY(node)); ++ return true; ++ } + -+config PAX_USERCOPY -+ bool "Harden heap object copies between kernel and userland" -+ default y if GRKERNSEC_CONFIG_AUTO -+ depends on ARM || IA64 || PPC || SPARC || X86 -+ depends on GRKERNSEC && (SLAB || SLUB || SLOB) -+ select PAX_USERCOPY_SLABS -+ help -+ By saying Y here the kernel will enforce the size of heap objects -+ when they are copied in either direction between the kernel and -+ userland, even if only a part of the heap object is copied. ++ constifiable(node, &cinfo); ++ if ((!cinfo.has_fptr_field || cinfo.has_writable_field || cinfo.has_no_const_field) && !cinfo.has_do_const_field) ++ return false; + -+ Specifically, this checking prevents information leaking from the -+ kernel heap during kernel to userland copies (if the kernel heap -+ object is otherwise fully initialized) and prevents kernel heap -+ overflows during userland to kernel copies. ++ return TYPE_READONLY(node); ++} + -+ Note that the current implementation provides the strictest bounds -+ checks for the SLUB allocator. ++static void deconstify_tree(tree node); + -+ Enabling this option also enables per-slab cache protection against -+ data in a given cache being copied into/out of via userland -+ accessors. Though the whitelist of regions will be reduced over -+ time, it notably protects important data structures like task structs. ++static void deconstify_type(tree type) ++{ ++ tree field; + -+ If frame pointers are enabled on x86, this option will also restrict -+ copies into and out of the kernel stack to local variables within a -+ single frame. ++ gcc_assert(TREE_CODE(type) == RECORD_TYPE || TREE_CODE(type) == UNION_TYPE); + -+ Since this has a negligible performance impact, you should enable -+ this feature. ++ for (field = TYPE_FIELDS(type); field; field = TREE_CHAIN(field)) { ++ const_tree fieldtype = get_field_type(field); + -+config PAX_USERCOPY_DEBUG -+ bool -+ depends on X86 && PAX_USERCOPY -+ default n ++ // special case handling of simple ptr-to-same-array-type members ++ if (TREE_CODE(TREE_TYPE(field)) == POINTER_TYPE) { ++ tree ptrtype = TREE_TYPE(TREE_TYPE(field)); + -+config PAX_SIZE_OVERFLOW -+ bool "Prevent various integer overflows in function size parameters" -+ default y if GRKERNSEC_CONFIG_AUTO -+ help -+ By saying Y here the kernel recomputes expressions of function -+ arguments marked by a size_overflow attribute with double integer -+ precision (DImode/TImode for 32/64 bit integer types). ++ if (TREE_TYPE(TREE_TYPE(field)) == type) ++ continue; ++ if (TREE_CODE(ptrtype) != RECORD_TYPE && TREE_CODE(ptrtype) != UNION_TYPE) ++ continue; ++ if (!constified(ptrtype)) ++ continue; ++ if (TYPE_MAIN_VARIANT(ptrtype) == TYPE_MAIN_VARIANT(type)) { ++ TREE_TYPE(field) = copy_node(TREE_TYPE(field)); ++ TREE_TYPE(TREE_TYPE(field)) = build_qualified_type(type, TYPE_QUALS(ptrtype) & ~TYPE_QUAL_CONST); ++ } ++ continue; ++ } ++ if (TREE_CODE(fieldtype) != RECORD_TYPE && TREE_CODE(fieldtype) != UNION_TYPE) ++ continue; ++ if (!constified(fieldtype)) ++ continue; + -+ The recomputed argument is checked against TYPE_MAX and an event -+ is logged on overflow and the triggering process is killed. ++ deconstify_tree(field); ++ TREE_READONLY(field) = 0; ++ } ++ TYPE_READONLY(type) = 0; ++ C_TYPE_FIELDS_READONLY(type) = 0; ++ if (lookup_attribute("do_const", TYPE_ATTRIBUTES(type))) { ++ TYPE_ATTRIBUTES(type) = copy_list(TYPE_ATTRIBUTES(type)); ++ TYPE_ATTRIBUTES(type) = remove_attribute("do_const", TYPE_ATTRIBUTES(type)); ++ } ++} + -+ Homepage: https://github.com/ephox-gcc-plugins ++static void deconstify_tree(tree node) ++{ ++ tree old_type, new_type, field; + -+ Note that the implementation requires a gcc with plugin support, -+ i.e., gcc 4.5 or newer. You may need to install the supporting -+ headers explicitly in addition to the normal gcc package. ++ old_type = TREE_TYPE(node); ++ while (TREE_CODE(old_type) == ARRAY_TYPE && TREE_CODE(TREE_TYPE(old_type)) != ARRAY_TYPE) { ++ node = TREE_TYPE(node) = copy_node(old_type); ++ old_type = TREE_TYPE(old_type); ++ } + -+config PAX_LATENT_ENTROPY -+ bool "Generate some entropy during boot and runtime" -+ default y if GRKERNSEC_CONFIG_AUTO -+ help -+ By saying Y here the kernel will instrument some kernel code to -+ extract some entropy from both original and artificially created -+ program state. This will help especially embedded systems where -+ there is little 'natural' source of entropy normally. The cost -+ is some slowdown of the boot process and fork and irq processing. ++ gcc_assert(TREE_CODE(old_type) == RECORD_TYPE || TREE_CODE(old_type) == UNION_TYPE); ++ gcc_assert(TYPE_READONLY(old_type) && (TYPE_QUALS(old_type) & TYPE_QUAL_CONST)); + -+ When pax_extra_latent_entropy is passed on the kernel command line, -+ entropy will be extracted from up to the first 4GB of RAM while the -+ runtime memory allocator is being initialized. This costs even more -+ slowdown of the boot process. ++ new_type = build_qualified_type(old_type, TYPE_QUALS(old_type) & ~TYPE_QUAL_CONST); ++ TYPE_FIELDS(new_type) = copy_list(TYPE_FIELDS(new_type)); ++ for (field = TYPE_FIELDS(new_type); field; field = TREE_CHAIN(field)) ++ DECL_FIELD_CONTEXT(field) = new_type; + -+ Note that the implementation requires a gcc with plugin support, -+ i.e., gcc 4.5 or newer. You may need to install the supporting -+ headers explicitly in addition to the normal gcc package. ++ deconstify_type(new_type); + -+ Note that entropy extracted this way is not cryptographically -+ secure! ++ TREE_TYPE(node) = new_type; ++} + -+config PAX_RAP -+ bool "Prevent code reuse attacks" -+ depends on X86_64 -+ default y if GRKERNSEC_CONFIG_AUTO -+ help -+ By saying Y here the kernel will check indirect control transfers -+ in order to detect and prevent attacks that try to hijack control -+ flow by overwriting code pointers. ++static tree handle_no_const_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs) ++{ ++ tree type; ++ constify_info cinfo = { ++ .has_fptr_field = false, ++ .has_writable_field = false, ++ .has_do_const_field = false, ++ .has_no_const_field = false ++ }; + -+ Note that binary modules cannot be instrumented by this approach. ++ *no_add_attrs = true; ++ if (TREE_CODE(*node) == FUNCTION_DECL) { ++ error("%qE attribute does not apply to functions (%qF)", name, *node); ++ return NULL_TREE; ++ } + -+ Note that the implementation requires a gcc with plugin support, -+ i.e., gcc 4.5 or newer. You may need to install the supporting -+ headers explicitly in addition to the normal gcc package. ++ if (TREE_CODE(*node) == PARM_DECL) { ++ error("%qE attribute does not apply to function parameters (%qD)", name, *node); ++ return NULL_TREE; ++ } + -+endmenu ++ if (TREE_CODE(*node) == VAR_DECL) { ++ error("%qE attribute does not apply to variables (%qD)", name, *node); ++ return NULL_TREE; ++ } + -+endmenu ++ if (TYPE_P(*node)) { ++ type = *node; ++ } else { ++ if (TREE_CODE(*node) != TYPE_DECL) { ++ error("%qE attribute does not apply to %qD (%qT)", name, *node, TREE_TYPE(*node)); ++ return NULL_TREE; ++ } ++ type = TREE_TYPE(*node); ++ } + -+source grsecurity/Kconfig ++ if (TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE) { ++ error("%qE attribute used on %qT applies to struct and union types only", name, type); ++ return NULL_TREE; ++ } + -+endmenu ++ if (lookup_attribute(IDENTIFIER_POINTER(name), TYPE_ATTRIBUTES(type))) { ++ error("%qE attribute is already applied to the type %qT", name, type); ++ return NULL_TREE; ++ } + -+endmenu ++ if (TYPE_P(*node)) { ++ if (lookup_attribute("do_const", TYPE_ATTRIBUTES(type))) ++ error("%qE attribute used on type %qT is incompatible with 'do_const'", name, type); ++ else ++ *no_add_attrs = false; ++ return NULL_TREE; ++ } + - source security/keys/Kconfig - - config SECURITY_DMESG_RESTRICT -@@ -104,7 +1087,7 @@ config INTEL_TXT - config LSM_MMAP_MIN_ADDR - int "Low address space for LSM to protect from user allocation" - depends on SECURITY && SECURITY_SELINUX -- default 32768 if ARM || (ARM64 && COMPAT) -+ default 32768 if ALPHA || ARM || (ARM64 && COMPAT) || PARISC || SPARC32 - default 65536 - help - This is the portion of low virtual memory which should be protected -diff --git a/security/apparmor/file.c b/security/apparmor/file.c -index 913f377..6e392d5 100644 ---- a/security/apparmor/file.c -+++ b/security/apparmor/file.c -@@ -348,8 +348,8 @@ static inline bool xindex_is_subset(u32 link, u32 target) - int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry, - struct path *new_dir, struct dentry *new_dentry) - { -- struct path link = { new_dir->mnt, new_dentry }; -- struct path target = { new_dir->mnt, old_dentry }; -+ struct path link = { .mnt = new_dir->mnt, .dentry = new_dentry }; -+ struct path target = { .mnt = new_dir->mnt, .dentry = old_dentry }; - struct path_cond cond = { - d_backing_inode(old_dentry)->i_uid, - d_backing_inode(old_dentry)->i_mode -diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h -index c28b0f2..3b9fee0 100644 ---- a/security/apparmor/include/policy.h -+++ b/security/apparmor/include/policy.h -@@ -134,7 +134,7 @@ struct aa_namespace { - struct aa_ns_acct acct; - struct aa_profile *unconfined; - struct list_head sub_ns; -- atomic_t uniq_null; -+ atomic_unchecked_t uniq_null; - long uniq_id; - - struct dentry *dents[AAFS_NS_SIZEOF]; -diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c -index dec607c..37fe357 100644 ---- a/security/apparmor/lsm.c -+++ b/security/apparmor/lsm.c -@@ -176,7 +176,7 @@ static int common_perm_dir_dentry(int op, struct path *dir, - struct dentry *dentry, u32 mask, - struct path_cond *cond) - { -- struct path path = { dir->mnt, dentry }; -+ struct path path = { .mnt = dir->mnt, .dentry = dentry }; - - return common_perm(op, &path, mask, cond); - } -@@ -193,7 +193,7 @@ static int common_perm_dir_dentry(int op, struct path *dir, - static int common_perm_mnt_dentry(int op, struct vfsmount *mnt, - struct dentry *dentry, u32 mask) - { -- struct path path = { mnt, dentry }; -+ struct path path = { .mnt = mnt, .dentry = dentry }; - struct path_cond cond = { d_backing_inode(dentry)->i_uid, - d_backing_inode(dentry)->i_mode - }; -@@ -315,8 +315,8 @@ static int apparmor_path_rename(struct path *old_dir, struct dentry *old_dentry, - - profile = aa_current_profile(); - if (!unconfined(profile)) { -- struct path old_path = { old_dir->mnt, old_dentry }; -- struct path new_path = { new_dir->mnt, new_dentry }; -+ struct path old_path = { .mnt = old_dir->mnt, .dentry = old_dentry }; -+ struct path new_path = { .mnt = new_dir->mnt, .dentry = new_dentry }; - struct path_cond cond = { d_backing_inode(old_dentry)->i_uid, - d_backing_inode(old_dentry)->i_mode - }; -@@ -677,11 +677,11 @@ static const struct kernel_param_ops param_ops_aalockpolicy = { - .get = param_get_aalockpolicy - }; - --static int param_set_audit(const char *val, struct kernel_param *kp); --static int param_get_audit(char *buffer, struct kernel_param *kp); -+static int param_set_audit(const char *val, const struct kernel_param *kp); -+static int param_get_audit(char *buffer, const struct kernel_param *kp); - --static int param_set_mode(const char *val, struct kernel_param *kp); --static int param_get_mode(char *buffer, struct kernel_param *kp); -+static int param_set_mode(const char *val, const struct kernel_param *kp); -+static int param_get_mode(char *buffer, const struct kernel_param *kp); - - /* Flag values, also controllable via /sys/module/apparmor/parameters - * We define special types as we want to do additional mediation. -@@ -791,7 +791,7 @@ static int param_get_aauint(char *buffer, const struct kernel_param *kp) - return param_get_uint(buffer, kp); - } - --static int param_get_audit(char *buffer, struct kernel_param *kp) -+static int param_get_audit(char *buffer, const struct kernel_param *kp) - { - if (!capable(CAP_MAC_ADMIN)) - return -EPERM; -@@ -802,7 +802,7 @@ static int param_get_audit(char *buffer, struct kernel_param *kp) - return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]); - } - --static int param_set_audit(const char *val, struct kernel_param *kp) -+static int param_set_audit(const char *val, const struct kernel_param *kp) - { - int i; - if (!capable(CAP_MAC_ADMIN)) -@@ -824,7 +824,7 @@ static int param_set_audit(const char *val, struct kernel_param *kp) - return -EINVAL; - } - --static int param_get_mode(char *buffer, struct kernel_param *kp) -+static int param_get_mode(char *buffer, const struct kernel_param *kp) - { - if (!capable(CAP_MAC_ADMIN)) - return -EPERM; -@@ -835,7 +835,7 @@ static int param_get_mode(char *buffer, struct kernel_param *kp) - return sprintf(buffer, "%s", aa_profile_mode_names[aa_g_profile_mode]); - } - --static int param_set_mode(const char *val, struct kernel_param *kp) -+static int param_set_mode(const char *val, const struct kernel_param *kp) - { - int i; - if (!capable(CAP_MAC_ADMIN)) -diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c -index 705c287..81257f1 100644 ---- a/security/apparmor/policy.c -+++ b/security/apparmor/policy.c -@@ -298,7 +298,7 @@ static struct aa_namespace *alloc_namespace(const char *prefix, - /* ns and ns->unconfined share ns->unconfined refcount */ - ns->unconfined->ns = ns; - -- atomic_set(&ns->uniq_null, 0); -+ atomic_set_unchecked(&ns->uniq_null, 0); - - return ns; - -@@ -689,7 +689,7 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat) - { - struct aa_profile *profile = NULL; - char *name; -- int uniq = atomic_inc_return(&parent->ns->uniq_null); -+ int uniq = atomic_inc_return_unchecked(&parent->ns->uniq_null); - - /* freed below */ - name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, GFP_KERNEL); -diff --git a/security/commoncap.c b/security/commoncap.c -index 48071ed..b805e0f 100644 ---- a/security/commoncap.c -+++ b/security/commoncap.c -@@ -438,6 +438,32 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data - return 0; - } - -+/* returns: -+ 1 for suid privilege -+ 2 for sgid privilege -+ 3 for fscap privilege -+*/ -+int is_privileged_binary(const struct dentry *dentry) ++ constifiable(type, &cinfo); ++ if ((cinfo.has_fptr_field && !cinfo.has_writable_field && !cinfo.has_no_const_field) || lookup_attribute("do_const", TYPE_ATTRIBUTES(type))) { ++ if (enabled) { ++ if TYPE_P(*node) ++ deconstify_type(*node); ++ else ++ deconstify_tree(*node); ++ } ++ if (TYPE_P(*node)) ++ TYPE_CONSTIFY_VISITED(*node) = 1; ++ else ++ TYPE_CONSTIFY_VISITED(TREE_TYPE(*node)) = 1; ++ return NULL_TREE; ++ } ++ ++ if (enabled && TYPE_FIELDS(type)) ++ error("%qE attribute used on type %qT that is not constified", name, type); ++ return NULL_TREE; ++} ++ ++static void constify_type(tree type) +{ -+ struct cpu_vfs_cap_data capdata; -+ struct inode *inode = dentry->d_inode; ++ TYPE_READONLY(type) = 1; ++ C_TYPE_FIELDS_READONLY(type) = 1; ++ TYPE_CONSTIFY_VISITED(type) = 1; ++// TYPE_ATTRIBUTES(type) = copy_list(TYPE_ATTRIBUTES(type)); ++// TYPE_ATTRIBUTES(type) = tree_cons(get_identifier("do_const"), NULL_TREE, TYPE_ATTRIBUTES(type)); ++} + -+ if (!inode || S_ISDIR(inode->i_mode)) -+ return 0; ++static tree handle_do_const_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs) ++{ ++ *no_add_attrs = true; ++ if (!TYPE_P(*node)) { ++ error("%qE attribute applies to types only (%qD)", name, *node); ++ return NULL_TREE; ++ } + -+ if (inode->i_mode & S_ISUID) ++ if (TREE_CODE(*node) != RECORD_TYPE && TREE_CODE(*node) != UNION_TYPE) { ++ error("%qE attribute used on %qT applies to struct and union types only", name, *node); ++ return NULL_TREE; ++ } ++ ++ if (lookup_attribute(IDENTIFIER_POINTER(name), TYPE_ATTRIBUTES(*node))) { ++ error("%qE attribute used on %qT is already applied to the type", name, *node); ++ return NULL_TREE; ++ } ++ ++ if (lookup_attribute("no_const", TYPE_ATTRIBUTES(*node))) { ++ error("%qE attribute used on %qT is incompatible with 'no_const'", name, *node); ++ return NULL_TREE; ++ } ++ ++ *no_add_attrs = false; ++ return NULL_TREE; ++} ++ ++static struct attribute_spec no_const_attr = { ++ .name = "no_const", ++ .min_length = 0, ++ .max_length = 0, ++ .decl_required = false, ++ .type_required = false, ++ .function_type_required = false, ++ .handler = handle_no_const_attribute, ++#if BUILDING_GCC_VERSION >= 4007 ++ .affects_type_identity = true ++#endif ++}; ++ ++static struct attribute_spec do_const_attr = { ++ .name = "do_const", ++ .min_length = 0, ++ .max_length = 0, ++ .decl_required = false, ++ .type_required = false, ++ .function_type_required = false, ++ .handler = handle_do_const_attribute, ++#if BUILDING_GCC_VERSION >= 4007 ++ .affects_type_identity = true ++#endif ++}; ++ ++static void register_attributes(void *event_data, void *data) ++{ ++ register_attribute(&no_const_attr); ++ register_attribute(&do_const_attr); ++} ++ ++static void finish_type(void *event_data, void *data) ++{ ++ tree type = (tree)event_data; ++ constify_info cinfo = { ++ .has_fptr_field = false, ++ .has_writable_field = false, ++ .has_do_const_field = false, ++ .has_no_const_field = false ++ }; ++ ++ if (type == NULL_TREE || type == error_mark_node) ++ return; ++ ++#if BUILDING_GCC_VERSION >= 5000 ++ if (TREE_CODE(type) == ENUMERAL_TYPE) ++ return; ++#endif ++ ++ if (TYPE_FIELDS(type) == NULL_TREE || TYPE_CONSTIFY_VISITED(type)) ++ return; ++ ++ constifiable(type, &cinfo); ++ ++ if (lookup_attribute("no_const", TYPE_ATTRIBUTES(type))) { ++ if ((cinfo.has_fptr_field && !cinfo.has_writable_field && !cinfo.has_no_const_field) || cinfo.has_do_const_field) { ++ deconstify_type(type); ++ TYPE_CONSTIFY_VISITED(type) = 1; ++ } else ++ error("'no_const' attribute used on type %qT that is not constified", type); ++ return; ++ } ++ ++ if (lookup_attribute("do_const", TYPE_ATTRIBUTES(type))) { ++ if (!cinfo.has_writable_field && !cinfo.has_no_const_field) { ++ error("'do_const' attribute used on type %qT that is%sconstified", type, cinfo.has_fptr_field ? " " : " not "); ++ return; ++ } ++ constify_type(type); ++ return; ++ } ++ ++ if (cinfo.has_fptr_field && !cinfo.has_writable_field && !cinfo.has_no_const_field) { ++ if (lookup_attribute("do_const", TYPE_ATTRIBUTES(type))) { ++ error("'do_const' attribute used on type %qT that is constified", type); ++ return; ++ } ++ constify_type(type); ++ return; ++ } ++ ++ deconstify_type(type); ++ TYPE_CONSTIFY_VISITED(type) = 1; ++} ++ ++static void check_global_variables(void *event_data, void *data) ++{ ++ varpool_node_ptr node; ++ ++ FOR_EACH_VARIABLE(node) { ++ tree var = NODE_DECL(node); ++ tree type = TREE_TYPE(var); ++ ++ if (TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE) ++ continue; ++ ++ if (!TYPE_READONLY(type) || !C_TYPE_FIELDS_READONLY(type)) ++ continue; ++ ++ if (!TYPE_CONSTIFY_VISITED(type)) ++ continue; ++ ++ if (DECL_EXTERNAL(var)) ++ continue; ++ ++ if (DECL_INITIAL(var)) ++ continue; ++ ++ // this works around a gcc bug/feature where uninitialized globals ++ // are moved into the .bss section regardless of any constification ++ DECL_INITIAL(var) = build_constructor(type, NULL); ++// inform(DECL_SOURCE_LOCATION(var), "constified variable %qE moved into .rodata", var); ++ } ++} ++ ++static unsigned int check_local_variables_execute(void) ++{ ++ unsigned int ret = 0; ++ tree var; ++ ++ unsigned int i; ++ ++ FOR_EACH_LOCAL_DECL(cfun, i, var) { ++ tree type = TREE_TYPE(var); ++ ++ gcc_assert(DECL_P(var)); ++ if (is_global_var(var)) ++ continue; ++ ++ if (TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE) ++ continue; ++ ++ if (!TYPE_READONLY(type) || !C_TYPE_FIELDS_READONLY(type)) ++ continue; ++ ++ if (!TYPE_CONSTIFY_VISITED(type)) ++ continue; ++ ++ error_at(DECL_SOURCE_LOCATION(var), "constified variable %qE cannot be local", var); ++ ret = 1; ++ } ++ return ret; ++} ++ ++#define PASS_NAME check_local_variables ++#define NO_GATE ++#include "gcc-generate-gimple-pass.h" ++ ++static struct { ++ const char *name; ++ const char *asm_op; ++} sections[] = { ++ {".init.rodata", "\t.section\t.init.rodata,\"a\""}, ++ {".ref.rodata", "\t.section\t.ref.rodata,\"a\""}, ++ {".devinit.rodata", "\t.section\t.devinit.rodata,\"a\""}, ++ {".devexit.rodata", "\t.section\t.devexit.rodata,\"a\""}, ++ {".cpuinit.rodata", "\t.section\t.cpuinit.rodata,\"a\""}, ++ {".cpuexit.rodata", "\t.section\t.cpuexit.rodata,\"a\""}, ++ {".meminit.rodata", "\t.section\t.meminit.rodata,\"a\""}, ++ {".memexit.rodata", "\t.section\t.memexit.rodata,\"a\""}, ++ {".data..read_only", "\t.section\t.data..read_only,\"a\""}, ++}; ++ ++static unsigned int (*old_section_type_flags)(tree decl, const char *name, int reloc); ++ ++static unsigned int constify_section_type_flags(tree decl, const char *name, int reloc) ++{ ++ size_t i; ++ ++ for (i = 0; i < ARRAY_SIZE(sections); i++) ++ if (!strcmp(sections[i].name, name)) ++ return 0; ++ return old_section_type_flags(decl, name, reloc); ++} ++ ++static void constify_start_unit(void *gcc_data, void *user_data) ++{ ++// size_t i; ++ ++// for (i = 0; i < ARRAY_SIZE(sections); i++) ++// sections[i].section = get_unnamed_section(0, output_section_asm_op, sections[i].asm_op); ++// sections[i].section = get_section(sections[i].name, 0, NULL); ++ ++ old_section_type_flags = targetm.section_type_flags; ++ targetm.section_type_flags = constify_section_type_flags; ++} ++ ++int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) ++{ ++ const char * const plugin_name = plugin_info->base_name; ++ const int argc = plugin_info->argc; ++ const struct plugin_argument * const argv = plugin_info->argv; ++ int i; ++ ++ struct register_pass_info check_local_variables_pass_info; ++ ++ check_local_variables_pass_info.pass = make_check_local_variables_pass(); ++ check_local_variables_pass_info.reference_pass_name = "ssa"; ++ check_local_variables_pass_info.ref_pass_instance_number = 1; ++ check_local_variables_pass_info.pos_op = PASS_POS_INSERT_BEFORE; ++ ++ if (!plugin_default_version_check(version, &gcc_version)) { ++ error(G_("incompatible gcc/plugin versions")); + return 1; -+ if ((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) -+ return 2; ++ } + -+ if (!get_vfs_caps_from_disk(dentry, &capdata)) { -+ if (!cap_isclear(capdata.inheritable) || !cap_isclear(capdata.permitted)) -+ return 3; ++ for (i = 0; i < argc; ++i) { ++ if (!(strcmp(argv[i].key, "disable"))) { ++ enabled = false; ++ continue; ++ } ++ error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); ++ } ++ ++ if (strncmp(lang_hooks.name, "GNU C", 5) && !strncmp(lang_hooks.name, "GNU C+", 6)) { ++ inform(UNKNOWN_LOCATION, G_("%s supports C only, not %s"), plugin_name, lang_hooks.name); ++ enabled = false; ++ } ++ ++ register_callback(plugin_name, PLUGIN_INFO, NULL, &const_plugin_info); ++ if (enabled) { ++ register_callback(plugin_name, PLUGIN_ALL_IPA_PASSES_START, check_global_variables, NULL); ++ register_callback(plugin_name, PLUGIN_FINISH_TYPE, finish_type, NULL); ++ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &check_local_variables_pass_info); ++ register_callback(plugin_name, PLUGIN_START_UNIT, constify_start_unit, NULL); + } ++ register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); + + return 0; +} +diff --git a/scripts/gcc-plugins/gcc-common.h b/scripts/gcc-plugins/gcc-common.h +new file mode 100644 +index 0000000..0c0b842 +--- /dev/null ++++ b/scripts/gcc-plugins/gcc-common.h +@@ -0,0 +1,879 @@ ++#ifndef GCC_COMMON_H_INCLUDED ++#define GCC_COMMON_H_INCLUDED + - /* - * Attempt to get the on-exec apply capability sets for an executable file from - * its xattrs and, if present, apply them to the proposed credentials being -@@ -628,6 +654,9 @@ int cap_bprm_secureexec(struct linux_binprm *bprm) - const struct cred *cred = current_cred(); - kuid_t root_uid = make_kuid(cred->user_ns, 0); - -+ if (gr_acl_enable_at_secure()) -+ return 1; ++#include "bversion.h" ++#if BUILDING_GCC_VERSION >= 6000 ++#include "gcc-plugin.h" ++#else ++#include "plugin.h" ++#endif ++#include "plugin-version.h" ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "line-map.h" ++#include "input.h" ++#include "tree.h" + - if (!uid_eq(cred->uid, root_uid)) { - if (bprm->cap_effective) - return 1; -diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h -index 585af61..b7d35ff 100644 ---- a/security/integrity/ima/ima.h -+++ b/security/integrity/ima/ima.h -@@ -125,8 +125,8 @@ int ima_init_template(void); - extern spinlock_t ima_queue_lock; - - struct ima_h_table { -- atomic_long_t len; /* number of stored measurements in the list */ -- atomic_long_t violations; -+ atomic_long_unchecked_t len; /* number of stored measurements in the list */ -+ atomic_long_unchecked_t violations; - struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE]; - }; - extern struct ima_h_table ima_htable; -diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c -index 1d950fb..a8f4eab 100644 ---- a/security/integrity/ima/ima_api.c -+++ b/security/integrity/ima/ima_api.c -@@ -137,7 +137,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename, - int result; - - /* can overflow, only indicator */ -- atomic_long_inc(&ima_htable.violations); -+ atomic_long_inc_unchecked(&ima_htable.violations); - - result = ima_alloc_init_template(&event_data, &entry); - if (result < 0) { -diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c -index f355231..c71f640 100644 ---- a/security/integrity/ima/ima_fs.c -+++ b/security/integrity/ima/ima_fs.c -@@ -30,12 +30,12 @@ static DEFINE_MUTEX(ima_write_mutex); - static int valid_policy = 1; - #define TMPBUFLEN 12 - static ssize_t ima_show_htable_value(char __user *buf, size_t count, -- loff_t *ppos, atomic_long_t *val) -+ loff_t *ppos, atomic_long_unchecked_t *val) - { - char tmpbuf[TMPBUFLEN]; - ssize_t len; - -- len = scnprintf(tmpbuf, TMPBUFLEN, "%li\n", atomic_long_read(val)); -+ len = scnprintf(tmpbuf, TMPBUFLEN, "%li\n", atomic_long_read_unchecked(val)); - return simple_read_from_buffer(buf, count, ppos, tmpbuf, len); - } - -diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c -index 552705d..9920f4fb 100644 ---- a/security/integrity/ima/ima_queue.c -+++ b/security/integrity/ima/ima_queue.c -@@ -83,7 +83,7 @@ static int ima_add_digest_entry(struct ima_template_entry *entry) - INIT_LIST_HEAD(&qe->later); - list_add_tail_rcu(&qe->later, &ima_measurements); - -- atomic_long_inc(&ima_htable.len); -+ atomic_long_inc_unchecked(&ima_htable.len); - key = ima_hash_key(entry->digest); - hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]); - return 0; -diff --git a/security/keys/internal.h b/security/keys/internal.h -index 5105c2c..a5010e6 100644 ---- a/security/keys/internal.h -+++ b/security/keys/internal.h -@@ -90,12 +90,16 @@ extern void key_type_put(struct key_type *ktype); - - extern int __key_link_begin(struct key *keyring, - const struct keyring_index_key *index_key, -- struct assoc_array_edit **_edit); -+ struct assoc_array_edit **_edit) -+ __acquires(&keyring->sem) -+ __acquires(&keyring_serialise_link_sem); - extern int __key_link_check_live_key(struct key *keyring, struct key *key); - extern void __key_link(struct key *key, struct assoc_array_edit **_edit); - extern void __key_link_end(struct key *keyring, - const struct keyring_index_key *index_key, -- struct assoc_array_edit *edit); -+ struct assoc_array_edit *edit) -+ __releases(&keyring->sem) -+ __releases(&keyring_serialise_link_sem); - - extern key_ref_t find_key_to_update(key_ref_t keyring_ref, - const struct keyring_index_key *index_key); -@@ -191,7 +195,7 @@ struct request_key_auth { - void *callout_info; - size_t callout_len; - pid_t pid; --}; -+} __randomize_layout; - - extern struct key_type key_type_request_key_auth; - extern struct key *request_key_auth_new(struct key *target, -diff --git a/security/keys/key.c b/security/keys/key.c -index 09ef276..ab2894f 100644 ---- a/security/keys/key.c -+++ b/security/keys/key.c -@@ -283,7 +283,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, - - atomic_set(&key->usage, 1); - init_rwsem(&key->sem); -- lockdep_set_class(&key->sem, &type->lock_class); -+ lockdep_set_class(&key->sem, (struct lock_class_key *)&type->lock_class); - key->index_key.type = type; - key->user = user; - key->quotalen = quotalen; -@@ -1077,7 +1077,9 @@ int register_key_type(struct key_type *ktype) - struct key_type *p; - int ret; - -- memset(&ktype->lock_class, 0, sizeof(ktype->lock_class)); -+ pax_open_kernel(); -+ memset((void *)&ktype->lock_class, 0, sizeof(ktype->lock_class)); -+ pax_close_kernel(); - - ret = -EEXIST; - down_write(&key_types_sem); -@@ -1089,7 +1091,7 @@ int register_key_type(struct key_type *ktype) - } - - /* store the type */ -- list_add(&ktype->link, &key_types_list); -+ pax_list_add((struct list_head *)&ktype->link, &key_types_list); - - pr_notice("Key type %s registered\n", ktype->name); - ret = 0; -@@ -1111,7 +1113,7 @@ EXPORT_SYMBOL(register_key_type); - void unregister_key_type(struct key_type *ktype) - { - down_write(&key_types_sem); -- list_del_init(&ktype->link); -+ pax_list_del_init((struct list_head *)&ktype->link); - downgrade_write(&key_types_sem); - key_gc_keytype(ktype); - pr_notice("Key type %s unregistered\n", ktype->name); -@@ -1129,10 +1131,10 @@ void __init key_init(void) - 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); - - /* add the special key types */ -- list_add_tail(&key_type_keyring.link, &key_types_list); -- list_add_tail(&key_type_dead.link, &key_types_list); -- list_add_tail(&key_type_user.link, &key_types_list); -- list_add_tail(&key_type_logon.link, &key_types_list); -+ pax_list_add_tail((struct list_head *)&key_type_keyring.link, &key_types_list); -+ pax_list_add_tail((struct list_head *)&key_type_dead.link, &key_types_list); -+ pax_list_add_tail((struct list_head *)&key_type_user.link, &key_types_list); -+ pax_list_add_tail((struct list_head *)&key_type_logon.link, &key_types_list); - - /* record the root user tracking */ - rb_link_node(&root_key_user.node, -diff --git a/security/keys/keyring.c b/security/keys/keyring.c -index f931ccf..ed9cd36 100644 ---- a/security/keys/keyring.c -+++ b/security/keys/keyring.c -@@ -1071,8 +1071,6 @@ static int keyring_detect_cycle(struct key *A, struct key *B) - int __key_link_begin(struct key *keyring, - const struct keyring_index_key *index_key, - struct assoc_array_edit **_edit) -- __acquires(&keyring->sem) -- __acquires(&keyring_serialise_link_sem) - { - struct assoc_array_edit *edit; - int ret; -@@ -1172,8 +1170,6 @@ void __key_link(struct key *key, struct assoc_array_edit **_edit) - void __key_link_end(struct key *keyring, - const struct keyring_index_key *index_key, - struct assoc_array_edit *edit) -- __releases(&keyring->sem) -- __releases(&keyring_serialise_link_sem) - { - BUG_ON(index_key->type == NULL); - kenter("%d,%s,", keyring->serial, index_key->type->name); -diff --git a/security/min_addr.c b/security/min_addr.c -index f728728..6457a0c 100644 ---- a/security/min_addr.c -+++ b/security/min_addr.c -@@ -14,6 +14,7 @@ unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR; - */ - static void update_mmap_min_addr(void) - { -+#ifndef SPARC - #ifdef CONFIG_LSM_MMAP_MIN_ADDR - if (dac_mmap_min_addr > CONFIG_LSM_MMAP_MIN_ADDR) - mmap_min_addr = dac_mmap_min_addr; -@@ -22,6 +23,7 @@ static void update_mmap_min_addr(void) - #else - mmap_min_addr = dac_mmap_min_addr; - #endif -+#endif - } - - /* -diff --git a/security/selinux/avc.c b/security/selinux/avc.c -index e60c79d..41fb721 100644 ---- a/security/selinux/avc.c -+++ b/security/selinux/avc.c -@@ -71,7 +71,7 @@ struct avc_xperms_node { - struct avc_cache { - struct hlist_head slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */ - spinlock_t slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */ -- atomic_t lru_hint; /* LRU hint for reclaim scan */ -+ atomic_unchecked_t lru_hint; /* LRU hint for reclaim scan */ - atomic_t active_nodes; - u32 latest_notif; /* latest revocation notification */ - }; -@@ -183,7 +183,7 @@ void __init avc_init(void) - spin_lock_init(&avc_cache.slots_lock[i]); - } - atomic_set(&avc_cache.active_nodes, 0); -- atomic_set(&avc_cache.lru_hint, 0); -+ atomic_set_unchecked(&avc_cache.lru_hint, 0); - - avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), - 0, SLAB_PANIC, NULL); -@@ -521,7 +521,7 @@ static inline int avc_reclaim_node(void) - spinlock_t *lock; - - for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++) { -- hvalue = atomic_inc_return(&avc_cache.lru_hint) & (AVC_CACHE_SLOTS - 1); -+ hvalue = atomic_inc_return_unchecked(&avc_cache.lru_hint) & (AVC_CACHE_SLOTS - 1); - head = &avc_cache.slots[hvalue]; - lock = &avc_cache.slots_lock[hvalue]; - -diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h -index 1450f85..a91e0bc 100644 ---- a/security/selinux/include/xfrm.h -+++ b/security/selinux/include/xfrm.h -@@ -48,7 +48,7 @@ static inline void selinux_xfrm_notify_policyload(void) - - rtnl_lock(); - for_each_net(net) { -- atomic_inc(&net->xfrm.flow_cache_genid); -+ atomic_inc_unchecked(&net->xfrm.flow_cache_genid); - rt_genid_bump_all(net); - } - rtnl_unlock(); -diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c -index 2367b10..a0c3c51 100644 ---- a/security/tomoyo/file.c -+++ b/security/tomoyo/file.c -@@ -692,7 +692,7 @@ int tomoyo_path_number_perm(const u8 type, struct path *path, - { - struct tomoyo_request_info r; - struct tomoyo_obj_info obj = { -- .path1 = *path, -+ .path1 = { .mnt = path->mnt, .dentry = path->dentry }, - }; - int error = -ENOMEM; - struct tomoyo_path_info buf; -@@ -740,7 +740,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, - struct tomoyo_path_info buf; - struct tomoyo_request_info r; - struct tomoyo_obj_info obj = { -- .path1 = *path, -+ .path1 = { .mnt = path->mnt, .dentry = path->dentry }, - }; - int idx; - -@@ -786,7 +786,7 @@ int tomoyo_path_perm(const u8 operation, const struct path *path, const char *ta - { - struct tomoyo_request_info r; - struct tomoyo_obj_info obj = { -- .path1 = *path, -+ .path1 = { .mnt = path->mnt, .dentry = path->dentry }, - }; - int error; - struct tomoyo_path_info buf; -@@ -843,7 +843,7 @@ int tomoyo_mkdev_perm(const u8 operation, struct path *path, - { - struct tomoyo_request_info r; - struct tomoyo_obj_info obj = { -- .path1 = *path, -+ .path1 = { .mnt = path->mnt, .dentry = path->dentry }, - }; - int error = -ENOMEM; - struct tomoyo_path_info buf; -@@ -890,8 +890,8 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, - struct tomoyo_path_info buf2; - struct tomoyo_request_info r; - struct tomoyo_obj_info obj = { -- .path1 = *path1, -- .path2 = *path2, -+ .path1 = { .mnt = path1->mnt, .dentry = path1->dentry }, -+ .path2 = { .mnt = path2->mnt, .dentry = path2->dentry } - }; - int idx; - -diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c -index 390c646..f2f8db3 100644 ---- a/security/tomoyo/mount.c -+++ b/security/tomoyo/mount.c -@@ -118,6 +118,10 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, - type == tomoyo_mounts[TOMOYO_MOUNT_MOVE]) { - need_dev = -1; /* dev_name is a directory */ - } else { -+ if (!capable(CAP_SYS_ADMIN)) { -+ error = -EPERM; -+ goto out; -+ } - fstype = get_fs_type(type); - if (!fstype) { - error = -ENODEV; -diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c -index cbf3df4..22b11df 100644 ---- a/security/tomoyo/tomoyo.c -+++ b/security/tomoyo/tomoyo.c -@@ -165,7 +165,7 @@ static int tomoyo_path_truncate(struct path *path) - */ - static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) - { -- struct path path = { parent->mnt, dentry }; -+ struct path path = { .mnt = parent->mnt, .dentry = dentry }; - return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL); - } - -@@ -181,7 +181,7 @@ static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) - static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, - umode_t mode) - { -- struct path path = { parent->mnt, dentry }; -+ struct path path = { .mnt = parent->mnt, .dentry = dentry }; - return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path, - mode & S_IALLUGO); - } -@@ -196,7 +196,7 @@ static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, - */ - static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) - { -- struct path path = { parent->mnt, dentry }; -+ struct path path = { .mnt = parent->mnt, .dentry = dentry }; - return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL); - } - -@@ -212,7 +212,7 @@ static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) - static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, - const char *old_name) - { -- struct path path = { parent->mnt, dentry }; -+ struct path path = { .mnt = parent->mnt, .dentry = dentry }; - return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name); - } - -@@ -229,7 +229,7 @@ static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, - static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, - umode_t mode, unsigned int dev) - { -- struct path path = { parent->mnt, dentry }; -+ struct path path = { .mnt = parent->mnt, .dentry = dentry }; - int type = TOMOYO_TYPE_CREATE; - const unsigned int perm = mode & S_IALLUGO; - -@@ -268,8 +268,8 @@ static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, - static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, - struct dentry *new_dentry) - { -- struct path path1 = { new_dir->mnt, old_dentry }; -- struct path path2 = { new_dir->mnt, new_dentry }; -+ struct path path1 = { .mnt = new_dir->mnt, .dentry = old_dentry }; -+ struct path path2 = { .mnt = new_dir->mnt, .dentry = new_dentry }; - return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2); - } - -@@ -288,8 +288,8 @@ static int tomoyo_path_rename(struct path *old_parent, - struct path *new_parent, - struct dentry *new_dentry) - { -- struct path path1 = { old_parent->mnt, old_dentry }; -- struct path path2 = { new_parent->mnt, new_dentry }; -+ struct path path1 = { .mnt = old_parent->mnt, .dentry = old_dentry }; -+ struct path path2 = { .mnt = new_parent->mnt, .dentry = new_dentry }; - return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2); - } - -@@ -417,7 +417,7 @@ static int tomoyo_sb_mount(const char *dev_name, struct path *path, - */ - static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) - { -- struct path path = { mnt, mnt->mnt_root }; -+ struct path path = { .mnt = mnt, .dentry = mnt->mnt_root }; - return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path, NULL); - } - -diff --git a/security/yama/Kconfig b/security/yama/Kconfig -index 90c605e..bf3a29a 100644 ---- a/security/yama/Kconfig -+++ b/security/yama/Kconfig -@@ -1,6 +1,6 @@ - config SECURITY_YAMA - bool "Yama support" -- depends on SECURITY -+ depends on SECURITY && !GRKERNSEC - default n - help - This selects Yama, which extends DAC support with additional -diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c -index cb6ed10..fb00554 100644 ---- a/security/yama/yama_lsm.c -+++ b/security/yama/yama_lsm.c -@@ -357,7 +357,7 @@ static struct security_hook_list yama_hooks[] = { - static int yama_dointvec_minmax(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) - { -- struct ctl_table table_copy; -+ ctl_table_no_const table_copy; - - if (write && !capable(CAP_SYS_PTRACE)) - return -EPERM; -diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c -index a04edff..6811b91 100644 ---- a/sound/aoa/codecs/onyx.c -+++ b/sound/aoa/codecs/onyx.c -@@ -54,7 +54,7 @@ struct onyx { - spdif_locked:1, - analog_locked:1, - original_mute:2; -- int open_count; -+ local_t open_count; - struct codec_info *codec_info; - - /* mutex serializes concurrent access to the device -@@ -747,7 +747,7 @@ static int onyx_open(struct codec_info_item *cii, - struct onyx *onyx = cii->codec_data; - - mutex_lock(&onyx->mutex); -- onyx->open_count++; -+ local_inc(&onyx->open_count); - mutex_unlock(&onyx->mutex); - - return 0; -@@ -759,8 +759,7 @@ static int onyx_close(struct codec_info_item *cii, - struct onyx *onyx = cii->codec_data; - - mutex_lock(&onyx->mutex); -- onyx->open_count--; -- if (!onyx->open_count) -+ if (local_dec_and_test(&onyx->open_count)) - onyx->spdif_locked = onyx->analog_locked = 0; - mutex_unlock(&onyx->mutex); - -diff --git a/sound/aoa/codecs/onyx.h b/sound/aoa/codecs/onyx.h -index ffd2025..df062c9 100644 ---- a/sound/aoa/codecs/onyx.h -+++ b/sound/aoa/codecs/onyx.h -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - - /* PCM3052 register definitions */ - -diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c -index ebc9fdf..61f491e 100644 ---- a/sound/core/oss/pcm_oss.c -+++ b/sound/core/oss/pcm_oss.c -@@ -1193,10 +1193,10 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const - if (in_kernel) { - mm_segment_t fs; - fs = snd_enter_user(); -- ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames); -+ ret = snd_pcm_lib_write(substream, (void __force_user *)ptr, frames); - snd_leave_user(fs); - } else { -- ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames); -+ ret = snd_pcm_lib_write(substream, (void __force_user *)ptr, frames); - } - if (ret != -EPIPE && ret != -ESTRPIPE) - break; -@@ -1236,10 +1236,10 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p - if (in_kernel) { - mm_segment_t fs; - fs = snd_enter_user(); -- ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames); -+ ret = snd_pcm_lib_read(substream, (void __force_user *)ptr, frames); - snd_leave_user(fs); - } else { -- ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames); -+ ret = snd_pcm_lib_read(substream, (void __force_user *)ptr, frames); - } - if (ret == -EPIPE) { - if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { -@@ -1335,7 +1335,7 @@ static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const cha - struct snd_pcm_plugin_channel *channels; - size_t oss_frame_bytes = (runtime->oss.plugin_first->src_width * runtime->oss.plugin_first->src_format.channels) / 8; - if (!in_kernel) { -- if (copy_from_user(runtime->oss.buffer, (const char __force __user *)buf, bytes)) -+ if (copy_from_user(runtime->oss.buffer, (const char __force_user *)buf, bytes)) - return -EFAULT; - buf = runtime->oss.buffer; - } -@@ -1405,7 +1405,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha - } - } else { - tmp = snd_pcm_oss_write2(substream, -- (const char __force *)buf, -+ (const char __force_kernel *)buf, - runtime->oss.period_bytes, 0); - if (tmp <= 0) - goto err; -@@ -1431,7 +1431,7 @@ static ssize_t snd_pcm_oss_read2(struct snd_pcm_substream *substream, char *buf, - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_sframes_t frames, frames1; - #ifdef CONFIG_SND_PCM_OSS_PLUGINS -- char __user *final_dst = (char __force __user *)buf; -+ char __user *final_dst = (char __force_user *)buf; - if (runtime->oss.plugin_first) { - struct snd_pcm_plugin_channel *channels; - size_t oss_frame_bytes = (runtime->oss.plugin_last->dst_width * runtime->oss.plugin_last->dst_format.channels) / 8; -@@ -1493,7 +1493,7 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use - xfer += tmp; - runtime->oss.buffer_used -= tmp; - } else { -- tmp = snd_pcm_oss_read2(substream, (char __force *)buf, -+ tmp = snd_pcm_oss_read2(substream, (char __force_kernel *)buf, - runtime->oss.period_bytes, 0); - if (tmp <= 0) - goto err; -@@ -1662,7 +1662,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) - size1); - size1 /= runtime->channels; /* frames */ - fs = snd_enter_user(); -- snd_pcm_lib_write(substream, (void __force __user *)runtime->oss.buffer, size1); -+ snd_pcm_lib_write(substream, (void __force_user *)runtime->oss.buffer, size1); - snd_leave_user(fs); - } - } else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) { -diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c -index 1f64ab0..26a7233 100644 ---- a/sound/core/pcm_compat.c -+++ b/sound/core/pcm_compat.c -@@ -31,7 +31,7 @@ static int snd_pcm_ioctl_delay_compat(struct snd_pcm_substream *substream, - int err; - - fs = snd_enter_user(); -- err = snd_pcm_delay(substream, &delay); -+ err = snd_pcm_delay(substream, (snd_pcm_sframes_t __force_user *)&delay); - snd_leave_user(fs); - if (err < 0) - return err; -diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c -index 3a9b66c..2b38b21 100644 ---- a/sound/core/pcm_lib.c -+++ b/sound/core/pcm_lib.c -@@ -1867,8 +1867,9 @@ EXPORT_SYMBOL(snd_pcm_lib_ioctl); - * Even if more than one periods have elapsed since the last call, you - * have to call this only once. - */ --void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) -+void snd_pcm_period_elapsed(void *_substream) - { -+ struct snd_pcm_substream *substream = _substream; - struct snd_pcm_runtime *runtime; - unsigned long flags; - -diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c -index 9106d8e..e7e2e3c 100644 ---- a/sound/core/pcm_native.c -+++ b/sound/core/pcm_native.c -@@ -3014,11 +3014,11 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, - switch (substream->stream) { - case SNDRV_PCM_STREAM_PLAYBACK: - result = snd_pcm_playback_ioctl1(NULL, substream, cmd, -- (void __user *)arg); -+ (void __force_user *)arg); - break; - case SNDRV_PCM_STREAM_CAPTURE: - result = snd_pcm_capture_ioctl1(NULL, substream, cmd, -- (void __user *)arg); -+ (void __force_user *)arg); - break; - default: - result = -EINVAL; -diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c -index 795437b..3650746 100644 ---- a/sound/core/rawmidi.c -+++ b/sound/core/rawmidi.c -@@ -871,9 +871,10 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card, - * - * Return: The size of read data, or a negative error code on failure. - */ --int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, -- const unsigned char *buffer, int count) -+int snd_rawmidi_receive(void *_substream, const void *_buffer, int count) - { -+ struct snd_rawmidi_substream *substream = _substream; -+ const unsigned char *buffer = _buffer; - unsigned long flags; - int result = 0, count1; - struct snd_rawmidi_runtime *runtime = substream->runtime; -diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c -index b16dbef04..8eb05a4 100644 ---- a/sound/core/seq/oss/seq_oss_synth.c -+++ b/sound/core/seq/oss/seq_oss_synth.c -@@ -653,8 +653,8 @@ snd_seq_oss_synth_info_read(struct snd_info_buffer *buf) - rec->synth_type, rec->synth_subtype, - rec->nr_voices); - snd_iprintf(buf, " capabilities : ioctl %s / load_patch %s\n", -- enabled_str((long)rec->oper.ioctl), -- enabled_str((long)rec->oper.load_patch)); -+ enabled_str(!!rec->oper.ioctl), -+ enabled_str(!!rec->oper.load_patch)); - snd_use_lock_free(&rec->use_lock); - } - } -diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c -index 58e79e0..19751d1 100644 ---- a/sound/core/seq/seq_clientmgr.c -+++ b/sound/core/seq/seq_clientmgr.c -@@ -416,7 +416,7 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, - if (!client->accept_input || (fifo = client->data.user.fifo) == NULL) - return -ENXIO; - -- if (atomic_read(&fifo->overflow) > 0) { -+ if (atomic_read_unchecked(&fifo->overflow) > 0) { - /* buffer overflow is detected */ - snd_seq_fifo_clear(fifo); - /* return error code */ -@@ -446,7 +446,7 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, - count -= sizeof(struct snd_seq_event); - buf += sizeof(struct snd_seq_event); - err = snd_seq_expand_var_event(&cell->event, count, -- (char __force *)buf, 0, -+ (char __force_kernel *)buf, 0, - sizeof(struct snd_seq_event)); - if (err < 0) - break; -@@ -1062,13 +1062,13 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, - } - /* set user space pointer */ - event.data.ext.len = extlen | SNDRV_SEQ_EXT_USRPTR; -- event.data.ext.ptr = (char __force *)buf -+ event.data.ext.ptr = (char __force_kernel *)buf - + sizeof(struct snd_seq_event); - len += extlen; /* increment data length */ - } else { - #ifdef CONFIG_COMPAT - if (client->convert32 && snd_seq_ev_is_varusr(&event)) { -- void *ptr = (void __force *)compat_ptr(event.data.raw32.d[1]); -+ void *ptr = (void __force_kernel *)compat_ptr(event.data.raw32.d[1]); - event.data.ext.ptr = ptr; - } - #endif -@@ -2423,7 +2423,7 @@ int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg) - if (client == NULL) - return -ENXIO; - fs = snd_enter_user(); -- result = snd_seq_do_ioctl(client, cmd, (void __force __user *)arg); -+ result = snd_seq_do_ioctl(client, cmd, (void __force_user *)arg); - snd_leave_user(fs); - return result; - } -diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c -index 6517590..9905cee 100644 ---- a/sound/core/seq/seq_compat.c -+++ b/sound/core/seq/seq_compat.c -@@ -60,7 +60,7 @@ static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned - data->kernel = NULL; - - fs = snd_enter_user(); -- err = snd_seq_do_ioctl(client, cmd, data); -+ err = snd_seq_do_ioctl(client, cmd, (void __force_user *)data); - snd_leave_user(fs); - if (err < 0) - goto error; -diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c -index 1d5acbe..5f55223 100644 ---- a/sound/core/seq/seq_fifo.c -+++ b/sound/core/seq/seq_fifo.c -@@ -50,7 +50,7 @@ struct snd_seq_fifo *snd_seq_fifo_new(int poolsize) - spin_lock_init(&f->lock); - snd_use_lock_init(&f->use_lock); - init_waitqueue_head(&f->input_sleep); -- atomic_set(&f->overflow, 0); -+ atomic_set_unchecked(&f->overflow, 0); - - f->head = NULL; - f->tail = NULL; -@@ -96,7 +96,7 @@ void snd_seq_fifo_clear(struct snd_seq_fifo *f) - unsigned long flags; - - /* clear overflow flag */ -- atomic_set(&f->overflow, 0); -+ atomic_set_unchecked(&f->overflow, 0); - - snd_use_lock_sync(&f->use_lock); - spin_lock_irqsave(&f->lock, flags); -@@ -123,7 +123,7 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f, - err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL); /* always non-blocking */ - if (err < 0) { - if ((err == -ENOMEM) || (err == -EAGAIN)) -- atomic_inc(&f->overflow); -+ atomic_inc_unchecked(&f->overflow); - snd_use_lock_free(&f->use_lock); - return err; - } -diff --git a/sound/core/seq/seq_fifo.h b/sound/core/seq/seq_fifo.h -index 062c446..a4b6f4c 100644 ---- a/sound/core/seq/seq_fifo.h -+++ b/sound/core/seq/seq_fifo.h -@@ -35,7 +35,7 @@ struct snd_seq_fifo { - spinlock_t lock; - snd_use_lock_t use_lock; - wait_queue_head_t input_sleep; -- atomic_t overflow; -+ atomic_unchecked_t overflow; - - }; - -diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c -index c850345..ec0a853 100644 ---- a/sound/core/seq/seq_memory.c -+++ b/sound/core/seq/seq_memory.c -@@ -87,7 +87,7 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event, - - if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) { - char buf[32]; -- char __user *curptr = (char __force __user *)event->data.ext.ptr; -+ char __user *curptr = (char __force_user *)event->data.ext.ptr; - while (len > 0) { - int size = sizeof(buf); - if (len < size) -@@ -126,15 +126,19 @@ EXPORT_SYMBOL(snd_seq_dump_var_event); - * expand the variable length event to linear buffer space. - */ - --static int seq_copy_in_kernel(char **bufptr, const void *src, int size) -+static int seq_copy_in_kernel(void *_bufptr, const void *src, int size) - { -+ char **bufptr = (char **)_bufptr; -+ - memcpy(*bufptr, src, size); - *bufptr += size; - return 0; - } - --static int seq_copy_in_user(char __user **bufptr, const void *src, int size) -+static int seq_copy_in_user(void *_bufptr, const void *src, int size) - { -+ char __user **bufptr = (char __user **)_bufptr; -+ - if (copy_to_user(*bufptr, src, size)) - return -EFAULT; - *bufptr += size; -@@ -158,13 +162,13 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char - if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) { - if (! in_kernel) - return -EINVAL; -- if (copy_from_user(buf, (void __force __user *)event->data.ext.ptr, len)) -+ if (copy_from_user(buf, (void __force_user *)event->data.ext.ptr, len)) - return -EFAULT; - return newlen; - } - err = snd_seq_dump_var_event(event, -- in_kernel ? (snd_seq_dump_func_t)seq_copy_in_kernel : -- (snd_seq_dump_func_t)seq_copy_in_user, -+ in_kernel ? seq_copy_in_kernel : -+ seq_copy_in_user, - &buf); - return err < 0 ? err : newlen; - } -@@ -344,7 +348,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, - tmp->event = src->event; - src = src->next; - } else if (is_usrptr) { -- if (copy_from_user(&tmp->event, (char __force __user *)buf, size)) { -+ if (copy_from_user(&tmp->event, (char __force_user *)buf, size)) { - err = -EFAULT; - goto __error; - } -diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c -index 5dd0ee2..0208e35 100644 ---- a/sound/core/seq/seq_midi.c -+++ b/sound/core/seq/seq_midi.c -@@ -111,8 +111,9 @@ static void snd_midi_input_event(struct snd_rawmidi_substream *substream) - } - } - --static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, int count) -+static int dump_midi(void *_substream, const void *buf, int count) - { -+ struct snd_rawmidi_substream *substream = _substream; - struct snd_rawmidi_runtime *runtime; - int tmp; - -@@ -148,7 +149,7 @@ static int event_process_midi(struct snd_seq_event *ev, int direct, - pr_debug("ALSA: seq_midi: invalid sysex event flags = 0x%x\n", ev->flags); - return 0; - } -- snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream); -+ snd_seq_dump_var_event(ev, dump_midi, substream); - snd_midi_event_reset_decode(msynth->parser); - } else { - if (msynth->parser == NULL) -diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c -index c82ed3e..e11d039 100644 ---- a/sound/core/seq/seq_virmidi.c -+++ b/sound/core/seq/seq_virmidi.c -@@ -90,7 +90,7 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, - if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { - if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) - continue; -- snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)snd_rawmidi_receive, vmidi->substream); -+ snd_seq_dump_var_event(ev, snd_rawmidi_receive, vmidi->substream); - } else { - len = snd_midi_event_decode(vmidi->parser, msg, sizeof(msg), ev); - if (len > 0) -diff --git a/sound/core/sound.c b/sound/core/sound.c -index 175f9e4..3518d31 100644 ---- a/sound/core/sound.c -+++ b/sound/core/sound.c -@@ -86,7 +86,7 @@ static void snd_request_other(int minor) - case SNDRV_MINOR_TIMER: str = "snd-timer"; break; - default: return; - } -- request_module(str); -+ request_module("%s", str); - } - - #endif /* modular kernel */ -diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c -index 2a008a9..a1efb3f 100644 ---- a/sound/drivers/mts64.c -+++ b/sound/drivers/mts64.c -@@ -29,6 +29,7 @@ - #include - #include - #include -+#include - - #define CARD_NAME "Miditerminal 4140" - #define DRIVER_NAME "MTS64" -@@ -67,7 +68,7 @@ struct mts64 { - struct pardevice *pardev; - int pardev_claimed; - -- int open_count; -+ local_t open_count; - int current_midi_output_port; - int current_midi_input_port; - u8 mode[MTS64_NUM_INPUT_PORTS]; -@@ -687,7 +688,7 @@ static int snd_mts64_rawmidi_open(struct snd_rawmidi_substream *substream) - { - struct mts64 *mts = substream->rmidi->private_data; - -- if (mts->open_count == 0) { -+ if (local_read(&mts->open_count) == 0) { - /* We don't need a spinlock here, because this is just called - if the device has not been opened before. - So there aren't any IRQs from the device */ -@@ -695,7 +696,7 @@ static int snd_mts64_rawmidi_open(struct snd_rawmidi_substream *substream) - - msleep(50); - } -- ++(mts->open_count); -+ local_inc(&mts->open_count); - - return 0; - } -@@ -705,8 +706,7 @@ static int snd_mts64_rawmidi_close(struct snd_rawmidi_substream *substream) - struct mts64 *mts = substream->rmidi->private_data; - unsigned long flags; - -- --(mts->open_count); -- if (mts->open_count == 0) { -+ if (local_dec_return(&mts->open_count) == 0) { - /* We need the spinlock_irqsave here because we can still - have IRQs at this point */ - spin_lock_irqsave(&mts->lock, flags); -@@ -715,8 +715,8 @@ static int snd_mts64_rawmidi_close(struct snd_rawmidi_substream *substream) - - msleep(500); - -- } else if (mts->open_count < 0) -- mts->open_count = 0; -+ } else if (local_read(&mts->open_count) < 0) -+ local_set(&mts->open_count, 0); - - return 0; - } -diff --git a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c -index 89c7aa0..6d75e49 100644 ---- a/sound/drivers/opl4/opl4_lib.c -+++ b/sound/drivers/opl4/opl4_lib.c -@@ -29,7 +29,7 @@ MODULE_AUTHOR("Clemens Ladisch "); - MODULE_DESCRIPTION("OPL4 driver"); - MODULE_LICENSE("GPL"); - --static void inline snd_opl4_wait(struct snd_opl4 *opl4) -+static inline void snd_opl4_wait(struct snd_opl4 *opl4) - { - int timeout = 10; - while ((inb(opl4->fm_port) & OPL4_STATUS_BUSY) && --timeout > 0) -diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c -index 464385a..46ab3f6 100644 ---- a/sound/drivers/portman2x4.c -+++ b/sound/drivers/portman2x4.c -@@ -48,6 +48,7 @@ - #include - #include - #include -+#include - - #define CARD_NAME "Portman 2x4" - #define DRIVER_NAME "portman" -@@ -85,7 +86,7 @@ struct portman { - struct pardevice *pardev; - int pardev_claimed; - -- int open_count; -+ local_t open_count; - int mode[PORTMAN_NUM_INPUT_PORTS]; - struct snd_rawmidi_substream *midi_input[PORTMAN_NUM_INPUT_PORTS]; - }; -diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c -index bebddc6..f5976be 100644 ---- a/sound/firewire/amdtp-am824.c -+++ b/sound/firewire/amdtp-am824.c -@@ -314,7 +314,7 @@ void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port, - struct amdtp_am824 *p = s->protocol; - - if (port < p->midi_ports) -- ACCESS_ONCE(p->midi[port]) = midi; -+ ACCESS_ONCE_RW(p->midi[port]) = midi; - } - EXPORT_SYMBOL_GPL(amdtp_am824_midi_trigger); - -diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c -index ed29026..933d2ae 100644 ---- a/sound/firewire/amdtp-stream.c -+++ b/sound/firewire/amdtp-stream.c -@@ -344,7 +344,7 @@ static void update_pcm_pointers(struct amdtp_stream *s, - ptr = s->pcm_buffer_pointer + frames; - if (ptr >= pcm->runtime->buffer_size) - ptr -= pcm->runtime->buffer_size; -- ACCESS_ONCE(s->pcm_buffer_pointer) = ptr; -+ ACCESS_ONCE_RW(s->pcm_buffer_pointer) = ptr; - - s->pcm_period_pointer += frames; - if (s->pcm_period_pointer >= pcm->runtime->period_size) { -@@ -811,7 +811,7 @@ EXPORT_SYMBOL(amdtp_stream_pcm_pointer); - void amdtp_stream_update(struct amdtp_stream *s) - { - /* Precomputing. */ -- ACCESS_ONCE(s->source_node_id_field) = -+ ACCESS_ONCE_RW(s->source_node_id_field) = - (fw_parent_device(s->unit)->card->node_id << CIP_SID_SHIFT) & - CIP_SID_MASK; - } -diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h -index 8775704..8fea566 100644 ---- a/sound/firewire/amdtp-stream.h -+++ b/sound/firewire/amdtp-stream.h -@@ -215,7 +215,7 @@ static inline bool amdtp_stream_pcm_running(struct amdtp_stream *s) - static inline void amdtp_stream_pcm_trigger(struct amdtp_stream *s, - struct snd_pcm_substream *pcm) - { -- ACCESS_ONCE(s->pcm) = pcm; -+ ACCESS_ONCE_RW(s->pcm) = pcm; - } - - static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc) -diff --git a/sound/firewire/digi00x/amdtp-dot.c b/sound/firewire/digi00x/amdtp-dot.c -index 0ac92ab..a2081aa 100644 ---- a/sound/firewire/digi00x/amdtp-dot.c -+++ b/sound/firewire/digi00x/amdtp-dot.c -@@ -365,7 +365,7 @@ void amdtp_dot_midi_trigger(struct amdtp_stream *s, unsigned int port, - struct amdtp_dot *p = s->protocol; - - if (port < p->midi_ports) -- ACCESS_ONCE(p->midi[port]) = midi; -+ ACCESS_ONCE_RW(p->midi[port]) = midi; - } - - static unsigned int process_tx_data_blocks(struct amdtp_stream *s, -diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c -index 48d6dca..a0266c23 100644 ---- a/sound/firewire/isight.c -+++ b/sound/firewire/isight.c -@@ -96,7 +96,7 @@ static void isight_update_pointers(struct isight *isight, unsigned int count) - ptr += count; - if (ptr >= runtime->buffer_size) - ptr -= runtime->buffer_size; -- ACCESS_ONCE(isight->buffer_pointer) = ptr; -+ ACCESS_ONCE_RW(isight->buffer_pointer) = ptr; - - isight->period_counter += count; - if (isight->period_counter >= runtime->period_size) { -@@ -293,7 +293,7 @@ static int isight_hw_params(struct snd_pcm_substream *substream, - if (err < 0) - return err; - -- ACCESS_ONCE(isight->pcm_active) = true; -+ ACCESS_ONCE_RW(isight->pcm_active) = true; - - return 0; - } -@@ -331,7 +331,7 @@ static int isight_hw_free(struct snd_pcm_substream *substream) - { - struct isight *isight = substream->private_data; - -- ACCESS_ONCE(isight->pcm_active) = false; -+ ACCESS_ONCE_RW(isight->pcm_active) = false; - - mutex_lock(&isight->mutex); - isight_stop_streaming(isight); -@@ -424,10 +424,10 @@ static int isight_trigger(struct snd_pcm_substream *substream, int cmd) - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: -- ACCESS_ONCE(isight->pcm_running) = true; -+ ACCESS_ONCE_RW(isight->pcm_running) = true; - break; - case SNDRV_PCM_TRIGGER_STOP: -- ACCESS_ONCE(isight->pcm_running) = false; -+ ACCESS_ONCE_RW(isight->pcm_running) = false; - break; - default: - return -EINVAL; -diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c -index bb53eb3..670cd89 100644 ---- a/sound/firewire/oxfw/oxfw-scs1x.c -+++ b/sound/firewire/oxfw/oxfw-scs1x.c -@@ -278,9 +278,9 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *stream, int up) - - if (up) { - scs->input_escape_count = 0; -- ACCESS_ONCE(scs->input) = stream; -+ ACCESS_ONCE_RW(scs->input) = stream; - } else { -- ACCESS_ONCE(scs->input) = NULL; -+ ACCESS_ONCE_RW(scs->input) = NULL; - } - } - -@@ -310,10 +310,10 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *stream, int up) - scs->output_escaped = false; - scs->output_idle = false; - -- ACCESS_ONCE(scs->output) = stream; -+ ACCESS_ONCE_RW(scs->output) = stream; - tasklet_schedule(&scs->tasklet); - } else { -- ACCESS_ONCE(scs->output) = NULL; -+ ACCESS_ONCE_RW(scs->output) = NULL; - } - } - static void midi_playback_drain(struct snd_rawmidi_substream *stream) -diff --git a/sound/oss/sb_audio.c b/sound/oss/sb_audio.c -index dc91072..d85a10a 100644 ---- a/sound/oss/sb_audio.c -+++ b/sound/oss/sb_audio.c -@@ -900,7 +900,7 @@ sb16_copy_from_user(int dev, - buf16 = (signed short *)(localbuf + localoffs); - while (c) - { -- locallen = (c >= LBUFCOPYSIZE ? LBUFCOPYSIZE : c); -+ locallen = ((unsigned)c >= LBUFCOPYSIZE ? LBUFCOPYSIZE : c); - if (copy_from_user(lbuf8, - userbuf+useroffs + p, - locallen)) -diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c -index 213a416..aeab5c9 100644 ---- a/sound/oss/swarm_cs4297a.c -+++ b/sound/oss/swarm_cs4297a.c -@@ -2623,7 +2623,6 @@ static int __init cs4297a_init(void) - { - struct cs4297a_state *s; - u32 pwr, id; -- mm_segment_t fs; - int rval; - u64 cfg; - int mdio_val; -@@ -2709,22 +2708,23 @@ static int __init cs4297a_init(void) - if (!rval) { - char *sb1250_duart_present; - -+#if 0 -+ mm_segment_t fs; - fs = get_fs(); - set_fs(KERNEL_DS); --#if 0 - val = SOUND_MASK_LINE; - mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long) &val); - for (i = 0; i < ARRAY_SIZE(initvol); i++) { - val = initvol[i].vol; - mixer_ioctl(s, initvol[i].mixch, (unsigned long) &val); - } -+ set_fs(fs); - // cs4297a_write_ac97(s, 0x18, 0x0808); - #else - // cs4297a_write_ac97(s, 0x5e, 0x180); - cs4297a_write_ac97(s, 0x02, 0x0808); - cs4297a_write_ac97(s, 0x18, 0x0808); - #endif -- set_fs(fs); - - list_add(&s->list, &cs4297a_devs); - -diff --git a/sound/pci/als300.c b/sound/pci/als300.c -index add3176..c9394d9 100644 ---- a/sound/pci/als300.c -+++ b/sound/pci/als300.c -@@ -647,7 +647,7 @@ static int snd_als300_create(struct snd_card *card, - struct snd_als300 **rchip) - { - struct snd_als300 *chip; -- void *irq_handler; -+ irq_handler_t irq_handler; - int err; - - static struct snd_device_ops ops = { -diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c -index 1677143..85aca1d 100644 ---- a/sound/pci/aw2/aw2-alsa.c -+++ b/sound/pci/aw2/aw2-alsa.c -@@ -458,7 +458,6 @@ static int snd_aw2_pcm_prepare_playback(struct snd_pcm_substream *substream) - - /* Define Interrupt callback */ - snd_aw2_saa7146_define_it_playback_callback(pcm_device->stream_number, -- (snd_aw2_saa7146_it_cb) - snd_pcm_period_elapsed, - (void *)substream); - -@@ -487,7 +486,6 @@ static int snd_aw2_pcm_prepare_capture(struct snd_pcm_substream *substream) - - /* Define Interrupt callback */ - snd_aw2_saa7146_define_it_capture_callback(pcm_device->stream_number, -- (snd_aw2_saa7146_it_cb) - snd_pcm_period_elapsed, - (void *)substream); - -diff --git a/sound/pci/aw2/aw2-saa7146.c b/sound/pci/aw2/aw2-saa7146.c -index 1d78904..d9c1056 100644 ---- a/sound/pci/aw2/aw2-saa7146.c -+++ b/sound/pci/aw2/aw2-saa7146.c -@@ -262,7 +262,7 @@ void snd_aw2_saa7146_define_it_playback_callback(unsigned int stream_number, - { - if (stream_number < NB_STREAM_PLAYBACK) { - arr_substream_it_playback_cb[stream_number].p_it_callback = -- (snd_aw2_saa7146_it_cb) p_it_callback; -+ p_it_callback; - arr_substream_it_playback_cb[stream_number].p_callback_param = - (void *)p_callback_param; - } -@@ -275,7 +275,7 @@ void snd_aw2_saa7146_define_it_capture_callback(unsigned int stream_number, - { - if (stream_number < NB_STREAM_CAPTURE) { - arr_substream_it_capture_cb[stream_number].p_it_callback = -- (snd_aw2_saa7146_it_cb) p_it_callback; -+ p_it_callback; - arr_substream_it_capture_cb[stream_number].p_callback_param = - (void *)p_callback_param; - } -diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c -index 5fcbb06..f4b85df 100644 ---- a/sound/pci/ctxfi/ctamixer.c -+++ b/sound/pci/ctxfi/ctamixer.c -@@ -297,8 +297,9 @@ static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer) - return 0; - } - --int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr) -+int amixer_mgr_create(struct hw *hw, void **_ramixer_mgr) - { -+ struct amixer_mgr **ramixer_mgr = (struct amixer_mgr **)_ramixer_mgr; - int err; - struct amixer_mgr *amixer_mgr; - -@@ -326,8 +327,10 @@ error: - return err; - } - --int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr) -+int amixer_mgr_destroy(void *_amixer_mgr) - { -+ struct amixer_mgr *amixer_mgr = _amixer_mgr; -+ - rsc_mgr_uninit(&amixer_mgr->mgr); - kfree(amixer_mgr); - return 0; -@@ -452,8 +455,9 @@ static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum) - return 0; - } - --int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr) -+int sum_mgr_create(struct hw *hw, void **_rsum_mgr) - { -+ struct sum_mgr **rsum_mgr = (struct sum_mgr **)_rsum_mgr; - int err; - struct sum_mgr *sum_mgr; - -@@ -481,8 +485,10 @@ error: - return err; - } - --int sum_mgr_destroy(struct sum_mgr *sum_mgr) -+int sum_mgr_destroy(void *_sum_mgr) - { -+ struct sum_mgr *sum_mgr = _sum_mgr; -+ - rsc_mgr_uninit(&sum_mgr->mgr); - kfree(sum_mgr); - return 0; -diff --git a/sound/pci/ctxfi/ctamixer.h b/sound/pci/ctxfi/ctamixer.h -index 2de18aa..2fbd01b 100644 ---- a/sound/pci/ctxfi/ctamixer.h -+++ b/sound/pci/ctxfi/ctamixer.h -@@ -47,8 +47,8 @@ struct sum_mgr { - }; - - /* Constructor and destructor of daio resource manager */ --int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr); --int sum_mgr_destroy(struct sum_mgr *sum_mgr); -+int sum_mgr_create(struct hw *hw, void **rsum_mgr); -+int sum_mgr_destroy(void *sum_mgr); - - /* Define the descriptor of a amixer resource */ - struct amixer_rsc_ops; -@@ -93,7 +93,7 @@ struct amixer_mgr { - }; - - /* Constructor and destructor of amixer resource manager */ --int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr); --int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr); -+int amixer_mgr_create(struct hw *hw, void **ramixer_mgr); -+int amixer_mgr_destroy(void *amixer_mgr); - - #endif /* CTAMIXER_H */ -diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c -index 977a598..a787004 100644 ---- a/sound/pci/ctxfi/ctatc.c -+++ b/sound/pci/ctxfi/ctatc.c -@@ -113,16 +113,16 @@ static struct { - int (*create)(struct hw *hw, void **rmgr); - int (*destroy)(void *mgr); - } rsc_mgr_funcs[NUM_RSCTYP] = { -- [SRC] = { .create = (create_t)src_mgr_create, -- .destroy = (destroy_t)src_mgr_destroy }, -- [SRCIMP] = { .create = (create_t)srcimp_mgr_create, -- .destroy = (destroy_t)srcimp_mgr_destroy }, -- [AMIXER] = { .create = (create_t)amixer_mgr_create, -- .destroy = (destroy_t)amixer_mgr_destroy }, -- [SUM] = { .create = (create_t)sum_mgr_create, -- .destroy = (destroy_t)sum_mgr_destroy }, -- [DAIO] = { .create = (create_t)daio_mgr_create, -- .destroy = (destroy_t)daio_mgr_destroy } -+ [SRC] = { .create = src_mgr_create, -+ .destroy = src_mgr_destroy }, -+ [SRCIMP] = { .create = srcimp_mgr_create, -+ .destroy = srcimp_mgr_destroy }, -+ [AMIXER] = { .create = amixer_mgr_create, -+ .destroy = amixer_mgr_destroy }, -+ [SUM] = { .create = sum_mgr_create, -+ .destroy = sum_mgr_destroy }, -+ [DAIO] = { .create = daio_mgr_create, -+ .destroy = daio_mgr_destroy } - }; - - static int -diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c -index 7f089cb..6bea28e 100644 ---- a/sound/pci/ctxfi/ctdaio.c -+++ b/sound/pci/ctxfi/ctdaio.c -@@ -687,8 +687,9 @@ static int daio_mgr_commit_write(struct daio_mgr *mgr) - return 0; - } - --int daio_mgr_create(struct hw *hw, struct daio_mgr **rdaio_mgr) -+int daio_mgr_create(struct hw *hw, void **_rdaio_mgr) - { -+ struct daio_mgr **rdaio_mgr = (struct daio_mgr **)_rdaio_mgr; - int err, i; - struct daio_mgr *daio_mgr; - struct imapper *entry; -@@ -741,8 +742,9 @@ error1: - return err; - } - --int daio_mgr_destroy(struct daio_mgr *daio_mgr) -+int daio_mgr_destroy(void *_daio_mgr) - { -+ struct daio_mgr *daio_mgr = _daio_mgr; - unsigned long flags; - - /* free daio input mapper list */ -diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h -index a30be73..91b8dbd 100644 ---- a/sound/pci/ctxfi/ctdaio.h -+++ b/sound/pci/ctxfi/ctdaio.h -@@ -119,7 +119,7 @@ struct daio_mgr { - }; - - /* Constructor and destructor of daio resource manager */ --int daio_mgr_create(struct hw *hw, struct daio_mgr **rdaio_mgr); --int daio_mgr_destroy(struct daio_mgr *daio_mgr); -+int daio_mgr_create(struct hw *hw, void **rdaio_mgr); -+int daio_mgr_destroy(void *daio_mgr); - - #endif /* CTDAIO_H */ -diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c -index a5a72df..f86edb8 100644 ---- a/sound/pci/ctxfi/ctsrc.c -+++ b/sound/pci/ctxfi/ctsrc.c -@@ -544,8 +544,9 @@ static int src_mgr_commit_write(struct src_mgr *mgr) - return 0; - } - --int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr) -+int src_mgr_create(struct hw *hw, void **_rsrc_mgr) - { -+ struct src_mgr **rsrc_mgr = (struct src_mgr **)_rsrc_mgr; - int err, i; - struct src_mgr *src_mgr; - -@@ -584,8 +585,10 @@ error1: - return err; - } - --int src_mgr_destroy(struct src_mgr *src_mgr) -+int src_mgr_destroy(void *_src_mgr) - { -+ struct src_mgr *src_mgr = _src_mgr; -+ - rsc_mgr_uninit(&src_mgr->mgr); - kfree(src_mgr); - -@@ -828,8 +831,9 @@ static int srcimp_imap_delete(struct srcimp_mgr *mgr, struct imapper *entry) - return err; - } - --int srcimp_mgr_create(struct hw *hw, struct srcimp_mgr **rsrcimp_mgr) -+int srcimp_mgr_create(struct hw *hw, void **_rsrcimp_mgr) - { -+ struct srcimp_mgr **rsrcimp_mgr = (struct srcimp_mgr **)_rsrcimp_mgr; - int err; - struct srcimp_mgr *srcimp_mgr; - struct imapper *entry; -@@ -873,8 +877,9 @@ error1: - return err; - } - --int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr) -+int srcimp_mgr_destroy(void *_srcimp_mgr) - { -+ struct srcimp_mgr *srcimp_mgr = _srcimp_mgr; - unsigned long flags; - - /* free src input mapper list */ -diff --git a/sound/pci/ctxfi/ctsrc.h b/sound/pci/ctxfi/ctsrc.h -index 92944a0..fc78ed4 100644 ---- a/sound/pci/ctxfi/ctsrc.h -+++ b/sound/pci/ctxfi/ctsrc.h -@@ -143,10 +143,10 @@ struct srcimp_mgr { - }; - - /* Constructor and destructor of SRC resource manager */ --int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr); --int src_mgr_destroy(struct src_mgr *src_mgr); -+int src_mgr_create(struct hw *hw, void **rsrc_mgr); -+int src_mgr_destroy(void *src_mgr); - /* Constructor and destructor of SRCIMP resource manager */ --int srcimp_mgr_create(struct hw *hw, struct srcimp_mgr **rsrc_mgr); --int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr); -+int srcimp_mgr_create(struct hw *hw, void **rsrc_mgr); -+int srcimp_mgr_destroy(void *srcimp_mgr); - - #endif /* CTSRC_H */ -diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c -index 8374188..f073778 100644 ---- a/sound/pci/hda/hda_codec.c -+++ b/sound/pci/hda/hda_codec.c -@@ -1743,7 +1743,7 @@ static int get_kctl_0dB_offset(struct hda_codec *codec, - /* FIXME: set_fs() hack for obtaining user-space TLV data */ - mm_segment_t fs = get_fs(); - set_fs(get_ds()); -- if (!kctl->tlv.c(kctl, 0, sizeof(_tlv), _tlv)) -+ if (!kctl->tlv.c(kctl, 0, sizeof(_tlv), (unsigned int __force_user *)_tlv)) - tlv = _tlv; - set_fs(fs); - } else if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) -diff --git a/sound/pci/ymfpci/ymfpci.h b/sound/pci/ymfpci/ymfpci.h -index 149d4cb..7784769 100644 ---- a/sound/pci/ymfpci/ymfpci.h -+++ b/sound/pci/ymfpci/ymfpci.h -@@ -358,7 +358,7 @@ struct snd_ymfpci { - spinlock_t reg_lock; - spinlock_t voice_lock; - wait_queue_head_t interrupt_sleep; -- atomic_t interrupt_sleep_count; -+ atomic_unchecked_t interrupt_sleep_count; - struct snd_info_entry *proc_entry; - const struct firmware *dsp_microcode; - const struct firmware *controller_microcode; -diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c -index 4c26076..a13f370 100644 ---- a/sound/pci/ymfpci/ymfpci_main.c -+++ b/sound/pci/ymfpci/ymfpci_main.c -@@ -204,8 +204,8 @@ static void snd_ymfpci_hw_stop(struct snd_ymfpci *chip) - if ((snd_ymfpci_readl(chip, YDSXGR_STATUS) & 2) == 0) - break; - } -- if (atomic_read(&chip->interrupt_sleep_count)) { -- atomic_set(&chip->interrupt_sleep_count, 0); -+ if (atomic_read_unchecked(&chip->interrupt_sleep_count)) { -+ atomic_set_unchecked(&chip->interrupt_sleep_count, 0); - wake_up(&chip->interrupt_sleep); - } - __end: -@@ -789,7 +789,7 @@ static void snd_ymfpci_irq_wait(struct snd_ymfpci *chip) - continue; - init_waitqueue_entry(&wait, current); - add_wait_queue(&chip->interrupt_sleep, &wait); -- atomic_inc(&chip->interrupt_sleep_count); -+ atomic_inc_unchecked(&chip->interrupt_sleep_count); - schedule_timeout_uninterruptible(msecs_to_jiffies(50)); - remove_wait_queue(&chip->interrupt_sleep, &wait); - } -@@ -827,8 +827,8 @@ static irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id) - snd_ymfpci_writel(chip, YDSXGR_MODE, mode); - spin_unlock(&chip->reg_lock); - -- if (atomic_read(&chip->interrupt_sleep_count)) { -- atomic_set(&chip->interrupt_sleep_count, 0); -+ if (atomic_read_unchecked(&chip->interrupt_sleep_count)) { -+ atomic_set_unchecked(&chip->interrupt_sleep_count, 0); - wake_up(&chip->interrupt_sleep); - } - } -@@ -2384,7 +2384,7 @@ int snd_ymfpci_create(struct snd_card *card, - spin_lock_init(&chip->reg_lock); - spin_lock_init(&chip->voice_lock); - init_waitqueue_head(&chip->interrupt_sleep); -- atomic_set(&chip->interrupt_sleep_count, 0); -+ atomic_set_unchecked(&chip->interrupt_sleep_count, 0); - chip->card = card; - chip->pci = pci; - chip->irq = -1; -diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c -index d6f4abb..5d59f0c 100644 ---- a/sound/soc/codecs/cx20442.c -+++ b/sound/soc/codecs/cx20442.c -@@ -263,6 +263,12 @@ static int v253_hangup(struct tty_struct *tty) - return 0; - } - -+static int v253_hw_write(void *client, const char *buf, int count) -+{ -+ struct tty_struct *tty = client; -+ return tty->ops->write(client, buf, count); -+} -+ - /* Line discipline .receive_buf() */ - static void v253_receive(struct tty_struct *tty, - const unsigned char *cp, char *fp, int count) -@@ -280,7 +286,7 @@ static void v253_receive(struct tty_struct *tty, - - /* Set up codec driver access to modem controls */ - cx20442->control_data = tty; -- codec->hw_write = (hw_write_t)tty->ops->write; -+ codec->hw_write = v253_hw_write; - codec->component.card->pop_time = 1; - } - } -diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c -index 160d61a..10bfd63 100644 ---- a/sound/soc/codecs/sti-sas.c -+++ b/sound/soc/codecs/sti-sas.c -@@ -591,11 +591,13 @@ static int sti_sas_driver_probe(struct platform_device *pdev) - sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops; - - /* Set dapms*/ -- sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets; -- sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets; -+ pax_open_kernel(); -+ *(const void **)&sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets; -+ *(int *)&sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets; - -- sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes; -- sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes; -+ *(const void **)&sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes; -+ *(int *)&sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes; -+ pax_close_kernel(); - - /* Store context */ - dev_set_drvdata(&pdev->dev, drvdata); -diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c -index f7a6ce7..82310c8 100644 ---- a/sound/soc/codecs/tlv320dac33.c -+++ b/sound/soc/codecs/tlv320dac33.c -@@ -1375,13 +1375,18 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai, - return 0; - } - -+static int dac33_hw_write(void *client, const char *buf, int count) -+{ -+ return i2c_master_send(client, buf, count); -+} -+ - static int dac33_soc_probe(struct snd_soc_codec *codec) - { - struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); - int ret = 0; - - codec->control_data = dac33->control_data; -- codec->hw_write = (hw_write_t) i2c_master_send; -+ codec->hw_write = dac33_hw_write; - dac33->codec = codec; - - /* Read the tlv320dac33 ID registers */ -diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c -index 35f0469..7c25cd5 100644 ---- a/sound/soc/codecs/uda1380.c -+++ b/sound/soc/codecs/uda1380.c -@@ -687,6 +687,11 @@ static struct snd_soc_dai_driver uda1380_dai[] = { - }, - }; - -+static int uda1380_hw_write(void *client, const char *buf, int count) -+{ -+ return i2c_master_send(client, buf, count); -+} -+ - static int uda1380_probe(struct snd_soc_codec *codec) - { - struct uda1380_platform_data *pdata =codec->dev->platform_data; -@@ -695,7 +700,7 @@ static int uda1380_probe(struct snd_soc_codec *codec) - - uda1380->codec = codec; - -- codec->hw_write = (hw_write_t)i2c_master_send; -+ codec->hw_write = uda1380_hw_write; - codec->control_data = uda1380->control_data; - - if (!pdata) -diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h -index cbb4075..edda3dd 100644 ---- a/sound/soc/intel/skylake/skl-sst-dsp.h -+++ b/sound/soc/intel/skylake/skl-sst-dsp.h -@@ -117,14 +117,14 @@ struct skl_dsp_fw_ops { - int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, char *mod_name); - int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id); - --}; -+} __no_const; - - struct skl_dsp_loader_ops { - int (*alloc_dma_buf)(struct device *dev, - struct snd_dma_buffer *dmab, size_t size); - int (*free_dma_buf)(struct device *dev, - struct snd_dma_buffer *dmab); --}; -+} __no_const; - - struct skl_load_module_info { - u16 mod_id; -diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c -index 7e0acd8..7fe0f65 100644 ---- a/sound/soc/soc-ac97.c -+++ b/sound/soc/soc-ac97.c -@@ -416,8 +416,10 @@ int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops, - if (ret) - return ret; - -- ops->warm_reset = snd_soc_ac97_warm_reset; -- ops->reset = snd_soc_ac97_reset; -+ pax_open_kernel(); -+ *(void **)&ops->warm_reset = snd_soc_ac97_warm_reset; -+ *(void **)&ops->reset = snd_soc_ac97_reset; -+ pax_close_kernel(); - - snd_ac97_rst_cfg = cfg; - return 0; -diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c -index 8382ffa..86af7d0 100644 ---- a/sound/soc/xtensa/xtfpga-i2s.c -+++ b/sound/soc/xtensa/xtfpga-i2s.c -@@ -437,7 +437,7 @@ static int xtfpga_pcm_trigger(struct snd_pcm_substream *substream, int cmd) - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -- ACCESS_ONCE(i2s->tx_ptr) = 0; -+ ACCESS_ONCE_RW(i2s->tx_ptr) = 0; - rcu_assign_pointer(i2s->tx_substream, substream); - xtfpga_pcm_refill_fifo(i2s); - break; -diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c -index a020920..55579f6 100644 ---- a/sound/synth/emux/emux_seq.c -+++ b/sound/synth/emux/emux_seq.c -@@ -33,13 +33,13 @@ static int snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *inf - * MIDI emulation operators - */ - static struct snd_midi_op emux_ops = { -- snd_emux_note_on, -- snd_emux_note_off, -- snd_emux_key_press, -- snd_emux_terminate_note, -- snd_emux_control, -- snd_emux_nrpn, -- snd_emux_sysex, -+ .note_on = snd_emux_note_on, -+ .note_off = snd_emux_note_off, -+ .key_press = snd_emux_key_press, -+ .note_terminate = snd_emux_terminate_note, -+ .control = snd_emux_control, -+ .nrpn = snd_emux_nrpn, -+ .sysex = snd_emux_sysex, - }; - - -diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c -index 81b7da8..bb2676f 100644 ---- a/sound/usb/line6/driver.c -+++ b/sound/usb/line6/driver.c -@@ -307,7 +307,7 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data, - { - struct usb_device *usbdev = line6->usbdev; - int ret; -- unsigned char len; -+ unsigned char *plen; - unsigned count; - - if (address > 0xffff || datalen > 0xff) -@@ -324,6 +324,10 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data, - return ret; - } - -+ plen = kmalloc(1, GFP_KERNEL); -+ if (plen == NULL) -+ return -ENOMEM; -+ - /* Wait for data length. We'll get 0xff until length arrives. */ - for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) { - mdelay(LINE6_READ_WRITE_STATUS_DELAY); -@@ -331,30 +335,35 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data, - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_IN, -- 0x0012, 0x0000, &len, 1, -+ 0x0012, 0x0000, plen, 1, - LINE6_TIMEOUT * HZ); - if (ret < 0) { - dev_err(line6->ifcdev, - "receive length failed (error %d)\n", ret); -+ kfree(plen); - return ret; - } - -- if (len != 0xff) -+ if (*plen != 0xff) - break; - } - -- if (len == 0xff) { -+ if (*plen == 0xff) { - dev_err(line6->ifcdev, "read failed after %d retries\n", - count); -+ kfree(plen); - return -EIO; -- } else if (len != datalen) { -+ } else if (*plen != datalen) { - /* should be equal or something went wrong */ - dev_err(line6->ifcdev, - "length mismatch (expected %d, got %d)\n", -- (int)datalen, (int)len); -+ (int)datalen, (int)*plen); -+ kfree(plen); - return -EIO; - } - -+ kfree(plen); -+ - /* receive the result: */ - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, -@@ -378,7 +387,7 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, - { - struct usb_device *usbdev = line6->usbdev; - int ret; -- unsigned char status; -+ unsigned char *status; - int count; - - if (address > 0xffff || datalen > 0xffff) -@@ -395,6 +404,10 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, - return ret; - } - -+ status = kmalloc(1, GFP_KERNEL); -+ if (status == NULL) -+ return -ENOMEM; -+ - for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) { - mdelay(LINE6_READ_WRITE_STATUS_DELAY); - -@@ -403,27 +416,32 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_IN, - 0x0012, 0x0000, -- &status, 1, LINE6_TIMEOUT * HZ); -+ status, 1, LINE6_TIMEOUT * HZ); - - if (ret < 0) { - dev_err(line6->ifcdev, - "receiving status failed (error %d)\n", ret); -+ kfree(status); - return ret; - } - -- if (status != 0xff) -+ if (*status != 0xff) - break; - } - -- if (status == 0xff) { -+ if (*status == 0xff) { - dev_err(line6->ifcdev, "write failed after %d retries\n", - count); -+ kfree(status); - return -EIO; -- } else if (status != 0) { -+ } else if (*status != 0) { - dev_err(line6->ifcdev, "write failed (error %d)\n", ret); -+ kfree(status); - return -EIO; - } - -+ kfree(status); -+ - return 0; - } - EXPORT_SYMBOL_GPL(line6_write_data); -diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c -index 6d4c50c..aa658c8 100644 ---- a/sound/usb/line6/toneport.c -+++ b/sound/usb/line6/toneport.c -@@ -367,13 +367,19 @@ static bool toneport_has_source_select(struct usb_line6_toneport *toneport) - */ - static void toneport_setup(struct usb_line6_toneport *toneport) - { -- int ticks; -+ int *ticks; - struct usb_line6 *line6 = &toneport->line6; - struct usb_device *usbdev = line6->usbdev; - -+ ticks = kmalloc(sizeof(int), GFP_KERNEL); -+ if (ticks == NULL) -+ return; -+ - /* sync time on device with host: */ -- ticks = (int)get_seconds(); -- line6_write_data(line6, 0x80c6, &ticks, 4); -+ *ticks = (int)get_seconds(); -+ line6_write_data(line6, 0x80c6, ticks, sizeof(int)); -+ -+ kfree(ticks); - - /* enable device: */ - toneport_send_cmd(usbdev, 0x0301, 0x0000); -diff --git a/tools/gcc/.gitignore b/tools/gcc/.gitignore -new file mode 100644 -index 0000000..de92ed9 ---- /dev/null -+++ b/tools/gcc/.gitignore -@@ -0,0 +1 @@ -+randomize_layout_seed.h -diff --git a/tools/gcc/Makefile b/tools/gcc/Makefile -new file mode 100644 -index 0000000..f1db084 ---- /dev/null -+++ b/tools/gcc/Makefile -@@ -0,0 +1,58 @@ -+#CC := gcc -+#PLUGIN_SOURCE_FILES := pax_plugin.c -+#PLUGIN_OBJECT_FILES := $(patsubst %.c,%.o,$(PLUGIN_SOURCE_FILES)) -+GCCPLUGINS_DIR := $(shell $(CC) -print-file-name=plugin) -+#CFLAGS += -I$(GCCPLUGINS_DIR)/include -fPIC -O2 -Wall -W -std=gnu99 -+ -+ifeq ($(PLUGINCC),$(HOSTCC)) -+HOSTLIBS := hostlibs -+HOST_EXTRACFLAGS += -I$(GCCPLUGINS_DIR)/include -I$(src) -std=gnu99 -ggdb -Wall -W -+export HOST_EXTRACFLAGS -+else -+HOSTLIBS := hostcxxlibs -+HOST_EXTRACXXFLAGS += -I$(GCCPLUGINS_DIR)/include -I$(src) -std=gnu++98 -fno-rtti -fno-exceptions -fasynchronous-unwind-tables -ggdb -Wall -W -Wno-unused-parameter -Wno-narrowing -Wno-unused-variable -+export HOST_EXTRACXXFLAGS -+endif -+ -+export GCCPLUGINS_DIR HOSTLIBS -+ -+$(HOSTLIBS)-$(CONFIG_PAX_CONSTIFY_PLUGIN) := constify_plugin.so -+$(HOSTLIBS)-$(CONFIG_PAX_MEMORY_STACKLEAK) += stackleak_plugin.so -+$(HOSTLIBS)-$(CONFIG_KALLOCSTAT_PLUGIN) += kallocstat_plugin.so -+$(HOSTLIBS)-$(CONFIG_PAX_KERNEXEC_PLUGIN) += kernexec_plugin.so -+$(HOSTLIBS)-$(CONFIG_CHECKER_PLUGIN) += checker_plugin.so -+$(HOSTLIBS)-y += colorize_plugin.so -+$(HOSTLIBS)-$(CONFIG_PAX_LATENT_ENTROPY) += latent_entropy_plugin.so -+$(HOSTLIBS)-$(CONFIG_PAX_MEMORY_STRUCTLEAK) += structleak_plugin.so -+$(HOSTLIBS)-y += initify_plugin.so -+$(HOSTLIBS)-$(CONFIG_GRKERNSEC_RANDSTRUCT) += randomize_layout_plugin.so -+ -+subdir-$(CONFIG_PAX_SIZE_OVERFLOW) := size_overflow_plugin -+subdir- += size_overflow_plugin -+ -+subdir-$(CONFIG_PAX_RAP) += rap_plugin -+subdir- += rap_plugin -+ -+always := $($(HOSTLIBS)-y) -+ -+constify_plugin-objs := constify_plugin.o -+stackleak_plugin-objs := stackleak_plugin.o -+kallocstat_plugin-objs := kallocstat_plugin.o -+kernexec_plugin-objs := kernexec_plugin.o -+checker_plugin-objs := checker_plugin.o -+colorize_plugin-objs := colorize_plugin.o -+latent_entropy_plugin-objs := latent_entropy_plugin.o -+structleak_plugin-objs := structleak_plugin.o -+initify_plugin-objs := initify_plugin.o -+rap_plugin-objs := rap_plugin.o sip.o -+randomize_layout_plugin-objs := randomize_layout_plugin.o -+ -+$(obj)/randomize_layout_plugin.o: $(objtree)/$(obj)/randomize_layout_seed.h -+ -+quiet_cmd_create_randomize_layout_seed = GENSEED $@ -+ cmd_create_randomize_layout_seed = \ -+ $(CONFIG_SHELL) $(srctree)/$(src)/gen-random-seed.sh $@ $(objtree)/include/generated/randomize_layout_hash.h -+$(objtree)/$(obj)/randomize_layout_seed.h: FORCE -+ $(call if_changed,create_randomize_layout_seed) -+ -+targets += randomize_layout_seed.h randomize_layout_hash.h -diff --git a/tools/gcc/checker_plugin.c b/tools/gcc/checker_plugin.c -new file mode 100644 -index 0000000..efaf576 ---- /dev/null -+++ b/tools/gcc/checker_plugin.c -@@ -0,0 +1,496 @@ -+/* -+ * Copyright 2011-2016 by the PaX Team -+ * Licensed under the GPL v2 -+ * -+ * Note: the choice of the license means that the compilation process is -+ * NOT 'eligible' as defined by gcc's library exception to the GPL v3, -+ * but for the kernel it doesn't matter since it doesn't link against -+ * any of the gcc libraries -+ * -+ * gcc plugin to implement various sparse (source code checker) features -+ * -+ * TODO: -+ * - define separate __iomem, __percpu and __rcu address spaces (lots of code to patch) -+ * -+ * BUGS: -+ * - none known -+ */ -+ -+#include "gcc-common.h" -+ -+extern void c_register_addr_space (const char *str, addr_space_t as); -+extern enum machine_mode default_addr_space_pointer_mode (addr_space_t); -+extern enum machine_mode default_addr_space_address_mode (addr_space_t); -+extern bool default_addr_space_valid_pointer_mode(enum machine_mode mode, addr_space_t as); -+extern bool default_addr_space_legitimate_address_p(enum machine_mode mode, rtx mem, bool strict, addr_space_t as); -+extern rtx default_addr_space_legitimize_address(rtx x, rtx oldx, enum machine_mode mode, addr_space_t as); -+ -+int plugin_is_GPL_compatible; -+ -+static struct plugin_info checker_plugin_info = { -+ .version = "201602181345", -+ .help = "user\tturn on user/kernel address space checking\n" -+ "context\tturn on locking context checking\n" -+}; -+ -+#define ADDR_SPACE_KERNEL 0 -+#define ADDR_SPACE_FORCE_KERNEL 1 -+#define ADDR_SPACE_USER 2 -+#define ADDR_SPACE_FORCE_USER 3 -+#define ADDR_SPACE_IOMEM 0 -+#define ADDR_SPACE_FORCE_IOMEM 0 -+#define ADDR_SPACE_PERCPU 0 -+#define ADDR_SPACE_FORCE_PERCPU 0 -+#define ADDR_SPACE_RCU 0 -+#define ADDR_SPACE_FORCE_RCU 0 -+ -+static enum machine_mode checker_addr_space_pointer_mode(addr_space_t addrspace) -+{ -+ return default_addr_space_pointer_mode(ADDR_SPACE_GENERIC); -+} -+ -+static enum machine_mode checker_addr_space_address_mode(addr_space_t addrspace) -+{ -+ return default_addr_space_address_mode(ADDR_SPACE_GENERIC); -+} -+ -+static bool checker_addr_space_valid_pointer_mode(enum machine_mode mode, addr_space_t as) -+{ -+ return default_addr_space_valid_pointer_mode(mode, as); -+} -+ -+static bool checker_addr_space_legitimate_address_p(enum machine_mode mode, rtx mem, bool strict, addr_space_t as) -+{ -+ return default_addr_space_legitimate_address_p(mode, mem, strict, ADDR_SPACE_GENERIC); -+} -+ -+static rtx checker_addr_space_legitimize_address(rtx x, rtx oldx, enum machine_mode mode, addr_space_t as) -+{ -+ return default_addr_space_legitimize_address(x, oldx, mode, as); -+} -+ -+static bool checker_addr_space_subset_p(addr_space_t subset, addr_space_t superset) -+{ -+ if (subset == ADDR_SPACE_FORCE_KERNEL && superset == ADDR_SPACE_KERNEL) -+ return true; -+ -+ if (subset == ADDR_SPACE_FORCE_USER && superset == ADDR_SPACE_USER) -+ return true; -+ -+ if (subset == ADDR_SPACE_FORCE_IOMEM && superset == ADDR_SPACE_IOMEM) -+ return true; -+ -+ if (subset == ADDR_SPACE_KERNEL && superset == ADDR_SPACE_FORCE_USER) -+ return true; -+ -+ if (subset == ADDR_SPACE_KERNEL && superset == ADDR_SPACE_FORCE_IOMEM) -+ return true; -+ -+ if (subset == ADDR_SPACE_USER && superset == ADDR_SPACE_FORCE_KERNEL) -+ return true; -+ -+ if (subset == ADDR_SPACE_IOMEM && superset == ADDR_SPACE_FORCE_KERNEL) -+ return true; -+ -+ return subset == superset; -+} -+ -+static rtx checker_addr_space_convert(rtx op, tree from_type, tree to_type) -+{ -+// addr_space_t from_as = TYPE_ADDR_SPACE(TREE_TYPE(from_type)); -+// addr_space_t to_as = TYPE_ADDR_SPACE(TREE_TYPE(to_type)); -+ -+ return op; -+} -+ -+static void register_checker_address_spaces(void *event_data, void *data) -+{ -+ c_register_addr_space("__kernel", ADDR_SPACE_KERNEL); -+ c_register_addr_space("__force_kernel", ADDR_SPACE_FORCE_KERNEL); -+ c_register_addr_space("__user", ADDR_SPACE_USER); -+ c_register_addr_space("__force_user", ADDR_SPACE_FORCE_USER); -+// c_register_addr_space("__iomem", ADDR_SPACE_IOMEM); -+// c_register_addr_space("__force_iomem", ADDR_SPACE_FORCE_IOMEM); -+// c_register_addr_space("__percpu", ADDR_SPACE_PERCPU); -+// c_register_addr_space("__force_percpu", ADDR_SPACE_FORCE_PERCPU); -+// c_register_addr_space("__rcu", ADDR_SPACE_RCU); -+// c_register_addr_space("__force_rcu", ADDR_SPACE_FORCE_RCU); -+ -+ targetm.addr_space.pointer_mode = checker_addr_space_pointer_mode; -+ targetm.addr_space.address_mode = checker_addr_space_address_mode; -+ targetm.addr_space.valid_pointer_mode = checker_addr_space_valid_pointer_mode; -+ targetm.addr_space.legitimate_address_p = checker_addr_space_legitimate_address_p; -+// targetm.addr_space.legitimize_address = checker_addr_space_legitimize_address; -+ targetm.addr_space.subset_p = checker_addr_space_subset_p; -+ targetm.addr_space.convert = checker_addr_space_convert; -+} -+ -+static bool split_context_attribute(tree args, tree *lock, tree *in, tree *out) -+{ -+ *in = TREE_VALUE(args); -+ -+ if (TREE_CODE(*in) != INTEGER_CST) { -+ *lock = *in; -+ args = TREE_CHAIN(args); -+ *in = TREE_VALUE(args); -+ } else -+ *lock = NULL_TREE; -+ -+ args = TREE_CHAIN(args); -+ if (*lock && !args) -+ return false; -+ -+ *out = TREE_VALUE(args); -+ return true; -+} -+ -+static tree handle_context_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs) -+{ -+ *no_add_attrs = true; -+ tree lock, in, out; -+ -+ if (TREE_CODE(*node) != FUNCTION_DECL) { -+ error("%qE attribute applies to functions only (%qD)", name, *node); -+ return NULL_TREE; -+ } -+ -+ if (!split_context_attribute(args, &lock, &in, &out)) { -+ error("%qE attribute needs two integers after the lock expression", name); -+ return NULL_TREE; -+ } -+ -+ if (TREE_CODE(in) != INTEGER_CST) { -+ error("the 'in' argument of the %qE attribute must be an integer (%qE)", name, in); -+ return NULL_TREE; -+ } -+ -+ if (TREE_CODE(out) != INTEGER_CST) { -+ error("the 'out' argument of the %qE attribute must be an integer (%qE)", name, out); -+ return NULL_TREE; -+ } -+ -+ *no_add_attrs = false; -+ return NULL_TREE; -+} -+ -+static struct attribute_spec context_attr = { -+ .name = "context", -+ .min_length = 2, -+ .max_length = 3, -+ .decl_required = true, -+ .type_required = false, -+ .function_type_required = false, -+ .handler = handle_context_attribute, -+#if BUILDING_GCC_VERSION >= 4007 -+ .affects_type_identity = true -+#endif -+}; -+ -+static void register_attributes(void *event_data, void *data) -+{ -+ register_attribute(&context_attr); -+} -+ -+static const char context_function[] = "__context__"; -+static GTY(()) tree context_function_decl; -+ -+static const char context_error[] = "__context_error__"; -+static GTY(()) tree context_error_decl; -+ -+static void context_start_unit(void __unused *gcc_data, void __unused *user_data) -+{ -+ tree fntype, attr; -+ -+ // void __context__(void *, int); -+ fntype = build_function_type_list(void_type_node, ptr_type_node, integer_type_node, NULL_TREE); -+ context_function_decl = build_fn_decl(context_function, fntype); -+ -+ TREE_PUBLIC(context_function_decl) = 1; -+ TREE_USED(context_function_decl) = 1; -+ DECL_EXTERNAL(context_function_decl) = 1; -+ DECL_ARTIFICIAL(context_function_decl) = 1; -+ DECL_PRESERVE_P(context_function_decl) = 1; -+// TREE_NOTHROW(context_function_decl) = 1; -+// DECL_UNINLINABLE(context_function_decl) = 1; -+ DECL_ASSEMBLER_NAME(context_function_decl); // for LTO -+ lang_hooks.decls.pushdecl(context_function_decl); -+ -+ // void __context_error__(const void *, int) __attribute__((error("context error"))); -+ fntype = build_function_type_list(void_type_node, const_ptr_type_node, integer_type_node, NULL_TREE); -+ context_error_decl = build_fn_decl(context_error, fntype); -+ -+ TREE_PUBLIC(context_error_decl) = 1; -+ TREE_USED(context_error_decl) = 1; -+ DECL_EXTERNAL(context_error_decl) = 1; -+ DECL_ARTIFICIAL(context_error_decl) = 1; -+ DECL_PRESERVE_P(context_error_decl) = 1; -+// TREE_NOTHROW(context_error_decl) = 1; -+// DECL_UNINLINABLE(context_error_decl) = 1; -+ TREE_THIS_VOLATILE(context_error_decl) = 1; -+ DECL_ASSEMBLER_NAME(context_error_decl); -+ -+ attr = tree_cons(NULL, build_string(14, "context error"), NULL); -+ attr = tree_cons(get_identifier("error"), attr, NULL); -+ decl_attributes(&context_error_decl, attr, 0); -+} -+ -+static bool context_gate(void) -+{ -+ tree context_attr; -+ -+return true; -+ -+ context_attr = lookup_attribute("context", DECL_ATTRIBUTES(current_function_decl)); -+ return context_attr != NULL_TREE; -+} -+ -+static basic_block verify_context_before(gimple_stmt_iterator *gsi, tree context, tree inout, tree error) -+{ -+ gimple stmt; -+ basic_block cond_bb, join_bb, true_bb; -+ edge e; -+ location_t loc; -+ const char *file; -+ int line; -+ size_t len; -+ tree filename; -+ -+ stmt = gsi_stmt(*gsi); -+ if (gimple_has_location(stmt)) { -+ loc = gimple_location(stmt); -+ file = gimple_filename(stmt); -+ line = gimple_lineno(stmt); -+ } else { -+ loc = DECL_SOURCE_LOCATION(current_function_decl); -+ file = DECL_SOURCE_FILE(current_function_decl); -+ line = DECL_SOURCE_LINE(current_function_decl); -+ } -+ gcc_assert(file); -+ -+ // if (context != count) __context_error__(__FILE__, __LINE__); -+ stmt = gimple_build_cond(NE_EXPR, context, inout, NULL_TREE, NULL_TREE); -+ gimple_set_location(stmt, loc); -+ gsi_insert_before(gsi, stmt, GSI_NEW_STMT); -+ -+ cond_bb = gsi_bb(*gsi); -+ gcc_assert(!gsi_end_p(*gsi)); -+ gcc_assert(stmt == gsi_stmt(*gsi)); -+ -+ e = split_block(cond_bb, gsi_stmt(*gsi)); -+ cond_bb = e->src; -+ join_bb = e->dest; -+ e->flags = EDGE_FALSE_VALUE; -+ e->probability = REG_BR_PROB_BASE; -+ -+ true_bb = create_empty_bb(EXIT_BLOCK_PTR_FOR_FN(cfun)->prev_bb); -+ make_edge(cond_bb, true_bb, EDGE_TRUE_VALUE); -+ make_edge(true_bb, join_bb, EDGE_FALLTHRU); -+ -+ set_immediate_dominator(CDI_DOMINATORS, true_bb, cond_bb); -+ set_immediate_dominator(CDI_DOMINATORS, join_bb, cond_bb); -+ -+ gcc_assert(cond_bb->loop_father == join_bb->loop_father); -+ add_bb_to_loop(true_bb, cond_bb->loop_father); -+ -+ // insert call to builtin_trap or __context_error__ -+ *gsi = gsi_start_bb(true_bb); -+ -+// stmt = gimple_build_call(builtin_decl_implicit(BUILT_IN_TRAP), 0); -+ len = strlen(file) + 1; -+ filename = build_string(len, file); -+ TREE_TYPE(filename) = build_array_type(unsigned_char_type_node, build_index_type(size_int(len))); -+ filename = build1(ADDR_EXPR, const_ptr_type_node, filename); -+ stmt = gimple_build_call(error, 2, filename, build_int_cst(NULL_TREE, line)); -+ gimple_set_location(stmt, loc); -+ gsi_insert_after(gsi, stmt, GSI_CONTINUE_LINKING); -+ -+ *gsi = gsi_start_nondebug_bb(join_bb); -+ return join_bb; -+} -+ -+static void update_context(gimple_stmt_iterator *gsi, tree context, int diff) -+{ -+ gimple assign; -+ tree op; -+ -+ op = fold_build2_loc(UNKNOWN_LOCATION, PLUS_EXPR, integer_type_node, context, build_int_cst(integer_type_node, diff)); -+ assign = gimple_build_assign(context, op); -+ gsi_insert_after(gsi, assign, GSI_NEW_STMT); -+ update_stmt(assign); -+} -+ -+static basic_block track_context(basic_block bb, tree context) -+{ -+ gimple_stmt_iterator gsi; -+ gimple assign; -+ -+ // adjust context according to the context information on any call stmt -+ for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { -+ gimple stmt = gsi_stmt(gsi); -+ tree fndecl, context_attr; -+ tree lock, in, out; -+ int incount, outcount; -+ -+ if (!is_gimple_call(stmt)) -+ continue; -+ -+ fndecl = gimple_call_fndecl(stmt); -+ if (!fndecl) -+ continue; -+ -+ if (fndecl == context_function_decl) { -+ unsigned int num_ops = gimple_num_ops(stmt); -+ int diff = tree_to_shwi(gimple_op(stmt, num_ops - 1)); -+ -+ gcc_assert(diff); -+ update_context(&gsi, context, diff); -+ continue; -+ } -+ -+ context_attr = lookup_attribute("context", DECL_ATTRIBUTES(fndecl)); -+ if (!context_attr) -+ continue; -+ -+ gcc_assert(split_context_attribute(TREE_VALUE(context_attr), &lock, &in, &out)); -+ incount = tree_to_shwi(in); -+ outcount = tree_to_shwi(out); -+ bb = verify_context_before(&gsi, context, in, context_error_decl); -+ update_context(&gsi, context, outcount - incount); -+ } -+ -+ return bb; -+} -+ -+static bool bb_any_loop(basic_block bb) -+{ -+ return bb_loop_depth(bb) || (bb->flags & BB_IRREDUCIBLE_LOOP); -+} -+ -+static unsigned int context_execute(void) -+{ -+ basic_block bb; -+ gimple assign; -+ gimple_stmt_iterator gsi; -+ tree context_attr, context; -+ tree lock, in, out; -+ -+ loop_optimizer_init(LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS); -+ gcc_assert(current_loops); -+ -+ calculate_dominance_info(CDI_DOMINATORS); -+ calculate_dominance_info(CDI_POST_DOMINATORS); -+ -+ context_attr = lookup_attribute("context", DECL_ATTRIBUTES(current_function_decl)); -+ if (context_attr) { -+ gcc_assert(split_context_attribute(TREE_VALUE(context_attr), &lock, &in, &out)); -+ } else { -+ in = out = integer_zero_node; -+ } -+ -+ // 1. create local context variable -+ context = create_tmp_var(integer_type_node, "context"); -+ add_referenced_var(context); -+ mark_sym_for_renaming(context); -+ -+ // 2. initialize local context variable -+ gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); -+ bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); -+ if (!single_pred_p(bb)) { -+ gcc_assert(bb_any_loop(bb)); -+ split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun))); -+ bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); -+ } -+ gsi = gsi_start_bb(bb); -+ assign = gimple_build_assign(context, in); -+ gsi_insert_before(&gsi, assign, GSI_NEW_STMT); -+ update_stmt(assign); -+ -+ // 3. instrument each BB to track the local context variable -+ FOR_EACH_BB_FN(bb, cfun) { -+ bb = track_context(bb, context); -+ } -+ -+ // 4. verify the local context variable against the expected state -+ if (EDGE_COUNT(EXIT_BLOCK_PTR_FOR_FN(cfun)->preds)) { -+ gcc_assert(single_pred_p(EXIT_BLOCK_PTR_FOR_FN(cfun))); -+ gsi = gsi_last_nondebug_bb(single_pred(EXIT_BLOCK_PTR_FOR_FN(cfun))); -+ verify_context_before(&gsi, context, out, context_error_decl); -+ } -+ -+ free_dominance_info(CDI_DOMINATORS); -+ free_dominance_info(CDI_POST_DOMINATORS); -+ loop_optimizer_finalize(); -+ return 0; -+} -+ -+#define PASS_NAME context -+#define PROPERTIES_REQUIRED PROP_gimple_leh | PROP_cfg -+//#define TODO_FLAGS_START TODO_verify_ssa | TODO_verify_flow | TODO_verify_stmts -+#define TODO_FLAGS_FINISH TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func | TODO_verify_flow | TODO_update_ssa -+#include "gcc-generate-gimple-pass.h" -+ -+int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) -+{ -+ const char * const plugin_name = plugin_info->base_name; -+ const int argc = plugin_info->argc; -+ const struct plugin_argument * const argv = plugin_info->argv; -+ int i; -+ bool enable_user, enable_context; -+ struct register_pass_info context_pass_info; -+ -+ static const struct ggc_root_tab gt_ggc_r_gt_checker[] = { -+ { -+ .base = &context_function_decl, -+ .nelt = 1, -+ .stride = sizeof(context_function_decl), -+ .cb = >_ggc_mx_tree_node, -+ .pchw = >_pch_nx_tree_node -+ }, -+ { -+ .base = &context_error_decl, -+ .nelt = 1, -+ .stride = sizeof(context_error_decl), -+ .cb = >_ggc_mx_tree_node, -+ .pchw = >_pch_nx_tree_node -+ }, -+ LAST_GGC_ROOT_TAB -+ }; -+ -+ context_pass_info.pass = make_context_pass(); -+// context_pass_info.reference_pass_name = "ssa"; -+ context_pass_info.reference_pass_name = "phiprop"; -+ context_pass_info.ref_pass_instance_number = 1; -+ context_pass_info.pos_op = PASS_POS_INSERT_AFTER; -+ -+ if (!plugin_default_version_check(version, &gcc_version)) { -+ error(G_("incompatible gcc/plugin versions")); -+ return 1; -+ } -+ -+ register_callback(plugin_name, PLUGIN_INFO, NULL, &checker_plugin_info); -+ -+ enable_user = false; -+ enable_context = false; -+ for (i = 0; i < argc; ++i) { -+ if (!strcmp(argv[i].key, "user")) { -+ enable_user = true; -+ continue; -+ } -+ if (!strcmp(argv[i].key, "context")) { -+ enable_context = true; -+ continue; -+ } -+ error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); -+ } -+ -+ if (enable_user) -+ register_callback(plugin_name, PLUGIN_PRAGMAS, register_checker_address_spaces, NULL); -+ if (enable_context) { -+ register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); -+ register_callback(plugin_name, PLUGIN_START_UNIT, context_start_unit, NULL); -+ register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, NULL, (void *)>_ggc_r_gt_checker); -+ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &context_pass_info); -+ } -+ -+ return 0; -+} -diff --git a/tools/gcc/colorize_plugin.c b/tools/gcc/colorize_plugin.c -new file mode 100644 -index 0000000..ffe60f6 ---- /dev/null -+++ b/tools/gcc/colorize_plugin.c -@@ -0,0 +1,162 @@ -+/* -+ * Copyright 2012-2016 by PaX Team -+ * Licensed under the GPL v2 -+ * -+ * Note: the choice of the license means that the compilation process is -+ * NOT 'eligible' as defined by gcc's library exception to the GPL v3, -+ * but for the kernel it doesn't matter since it doesn't link against -+ * any of the gcc libraries -+ * -+ * gcc plugin to colorize diagnostic output -+ * -+ */ -+ -+#include "gcc-common.h" -+ -+int plugin_is_GPL_compatible; -+ -+static struct plugin_info colorize_plugin_info = { -+ .version = "201602181345", -+ .help = "color=[never|always|auto]\tdetermine when to colorize\n", -+}; -+ -+#define GREEN "\033[32m\033[K" -+#define LIGHTGREEN "\033[1;32m\033[K" -+#define YELLOW "\033[33m\033[K" -+#define LIGHTYELLOW "\033[1;33m\033[K" -+#define RED "\033[31m\033[K" -+#define LIGHTRED "\033[1;31m\033[K" -+#define BLUE "\033[34m\033[K" -+#define LIGHTBLUE "\033[1;34m\033[K" -+#define BRIGHT "\033[1;m\033[K" -+#define NORMAL "\033[m\033[K" -+ -+static diagnostic_starter_fn old_starter; -+static diagnostic_finalizer_fn old_finalizer; -+ -+static void start_colorize(diagnostic_context *context, diagnostic_info *diagnostic) -+{ -+ const char *color; -+ char *newprefix; -+ -+ switch (diagnostic->kind) { -+ case DK_NOTE: -+ color = LIGHTBLUE; -+ break; -+ -+ case DK_PEDWARN: -+ case DK_WARNING: -+ color = LIGHTYELLOW; -+ break; -+ -+ case DK_ERROR: -+ case DK_FATAL: -+ case DK_ICE: -+ case DK_PERMERROR: -+ case DK_SORRY: -+ color = LIGHTRED; -+ break; -+ -+ default: -+ color = NORMAL; -+ } -+ -+ old_starter(context, diagnostic); -+ if (-1 == asprintf(&newprefix, "%s%s" NORMAL, color, context->printer->prefix)) -+ return; -+ pp_destroy_prefix(context->printer); -+ pp_set_prefix(context->printer, newprefix); -+} -+ -+static void finalize_colorize(diagnostic_context *context, diagnostic_info *diagnostic) -+{ -+ old_finalizer(context, diagnostic); -+} -+ -+static void colorize_arm(void) -+{ -+ old_starter = diagnostic_starter(global_dc); -+ old_finalizer = diagnostic_finalizer(global_dc); -+ -+ diagnostic_starter(global_dc) = start_colorize; -+ diagnostic_finalizer(global_dc) = finalize_colorize; -+} -+ -+static unsigned int colorize_rearm_execute(void) -+{ -+ if (diagnostic_starter(global_dc) == start_colorize) -+ return 0; -+ -+ colorize_arm(); -+ return 0; -+} -+ -+#define PASS_NAME colorize_rearm -+#define NO_GATE -+#include "gcc-generate-simple_ipa-pass.h" -+ -+static void colorize_start_unit(void *gcc_data, void *user_data) -+{ -+ colorize_arm(); -+} -+ -+static bool should_colorize(void) -+{ -+#if BUILDING_GCC_VERSION >= 4009 -+ return false; -+#else -+ char const *t = getenv("TERM"); -+ -+ return t && strcmp(t, "dumb") && isatty(STDERR_FILENO); -+#endif -+} -+ -+int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) -+{ -+ const char * const plugin_name = plugin_info->base_name; -+ const int argc = plugin_info->argc; -+ const struct plugin_argument * const argv = plugin_info->argv; -+ int i; -+ struct register_pass_info colorize_rearm_pass_info; -+ bool colorize; -+ -+ colorize_rearm_pass_info.pass = make_colorize_rearm_pass(); -+ colorize_rearm_pass_info.reference_pass_name = "*free_lang_data"; -+ colorize_rearm_pass_info.ref_pass_instance_number = 1; -+ colorize_rearm_pass_info.pos_op = PASS_POS_INSERT_AFTER; -+ -+ if (!plugin_default_version_check(version, &gcc_version)) { -+ error(G_("incompatible gcc/plugin versions")); -+ return 1; -+ } -+ -+ register_callback(plugin_name, PLUGIN_INFO, NULL, &colorize_plugin_info); -+ -+ colorize = getenv("GCC_COLORS") ? should_colorize() : false; -+ -+ for (i = 0; i < argc; ++i) { -+ if (!strcmp(argv[i].key, "color")) { -+ if (!argv[i].value) { -+ error(G_("no value supplied for option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); -+ continue; -+ } -+ if (!strcmp(argv[i].value, "always")) -+ colorize = true; -+ else if (!strcmp(argv[i].value, "never")) -+ colorize = false; -+ else if (!strcmp(argv[i].value, "auto")) -+ colorize = should_colorize(); -+ else -+ error(G_("invalid option argument '-fplugin-arg-%s-%s=%s'"), plugin_name, argv[i].key, argv[i].value); -+ continue; -+ } -+ error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); -+ } -+ -+ if (colorize) { -+ // TODO: parse GCC_COLORS as used by gcc 4.9+ -+ register_callback(plugin_name, PLUGIN_START_UNIT, &colorize_start_unit, NULL); -+ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &colorize_rearm_pass_info); -+ } -+ return 0; -+} -diff --git a/tools/gcc/constify_plugin.c b/tools/gcc/constify_plugin.c -new file mode 100644 -index 0000000..b52a700 ---- /dev/null -+++ b/tools/gcc/constify_plugin.c -@@ -0,0 +1,521 @@ -+/* -+ * Copyright 2011 by Emese Revfy -+ * Copyright 2011-2016 by PaX Team -+ * Licensed under the GPL v2, or (at your option) v3 -+ * -+ * This gcc plugin constifies all structures which contain only function pointers or are explicitly marked for constification. -+ * -+ * Homepage: -+ * http://www.grsecurity.net/~ephox/const_plugin/ -+ * -+ * Usage: -+ * $ gcc -I`gcc -print-file-name=plugin`/include -fPIC -shared -O2 -o constify_plugin.so constify_plugin.c -+ * $ gcc -fplugin=constify_plugin.so test.c -O2 -+ */ -+ -+#include "gcc-common.h" -+ -+// unused C type flag in all versions 4.5-6 -+#define TYPE_CONSTIFY_VISITED(TYPE) TYPE_LANG_FLAG_4(TYPE) -+ -+int plugin_is_GPL_compatible; -+ -+static bool constify = true; -+ -+static struct plugin_info const_plugin_info = { -+ .version = "201602181345", -+ .help = "no-constify\tturn off constification\n", -+}; -+ -+typedef struct { -+ bool has_fptr_field; -+ bool has_writable_field; -+ bool has_do_const_field; -+ bool has_no_const_field; -+} constify_info; -+ -+static const_tree get_field_type(const_tree field) -+{ -+ return strip_array_types(TREE_TYPE(field)); -+} -+ -+static bool is_fptr(const_tree field) -+{ -+ const_tree ptr = get_field_type(field); -+ -+ if (TREE_CODE(ptr) != POINTER_TYPE) -+ return false; -+ -+ return TREE_CODE(TREE_TYPE(ptr)) == FUNCTION_TYPE; -+} -+ -+/* -+ * determine whether the given structure type meets the requirements for automatic constification, -+ * including the constification attributes on nested structure types -+ */ -+static void constifiable(const_tree node, constify_info *cinfo) -+{ -+ const_tree field; -+ -+ gcc_assert(TREE_CODE(node) == RECORD_TYPE || TREE_CODE(node) == UNION_TYPE); -+ -+ // e.g., pointer to structure fields while still constructing the structure type -+ if (TYPE_FIELDS(node) == NULL_TREE) -+ return; -+ -+ for (field = TYPE_FIELDS(node); field; field = TREE_CHAIN(field)) { -+ const_tree type = get_field_type(field); -+ enum tree_code code = TREE_CODE(type); -+ -+ if (node == type) -+ continue; -+ -+ if (is_fptr(field)) -+ cinfo->has_fptr_field = true; -+ else if (code == RECORD_TYPE || code == UNION_TYPE) { -+ if (lookup_attribute("do_const", TYPE_ATTRIBUTES(type))) -+ cinfo->has_do_const_field = true; -+ else if (lookup_attribute("no_const", TYPE_ATTRIBUTES(type))) -+ cinfo->has_no_const_field = true; -+ else -+ constifiable(type, cinfo); -+ } else if (!TREE_READONLY(field)) -+ cinfo->has_writable_field = true; -+ } -+} -+ -+static bool constified(const_tree node) -+{ -+ constify_info cinfo = { -+ .has_fptr_field = false, -+ .has_writable_field = false, -+ .has_do_const_field = false, -+ .has_no_const_field = false -+ }; -+ -+ gcc_assert(TREE_CODE(node) == RECORD_TYPE || TREE_CODE(node) == UNION_TYPE); -+ -+ if (lookup_attribute("no_const", TYPE_ATTRIBUTES(node))) { -+// gcc_assert(!TYPE_READONLY(node)); -+ return false; -+ } -+ -+ if (lookup_attribute("do_const", TYPE_ATTRIBUTES(node))) { -+ gcc_assert(TYPE_READONLY(node)); -+ return true; -+ } -+ -+ constifiable(node, &cinfo); -+ if ((!cinfo.has_fptr_field || cinfo.has_writable_field || cinfo.has_no_const_field) && !cinfo.has_do_const_field) -+ return false; -+ -+ return TYPE_READONLY(node); -+} -+ -+static void deconstify_tree(tree node); -+ -+static void deconstify_type(tree type) -+{ -+ tree field; -+ -+ gcc_assert(TREE_CODE(type) == RECORD_TYPE || TREE_CODE(type) == UNION_TYPE); -+ -+ for (field = TYPE_FIELDS(type); field; field = TREE_CHAIN(field)) { -+ const_tree fieldtype = get_field_type(field); -+ -+ // special case handling of simple ptr-to-same-array-type members -+ if (TREE_CODE(TREE_TYPE(field)) == POINTER_TYPE) { -+ tree ptrtype = TREE_TYPE(TREE_TYPE(field)); -+ -+ if (TREE_TYPE(TREE_TYPE(field)) == type) -+ continue; -+ if (TREE_CODE(ptrtype) != RECORD_TYPE && TREE_CODE(ptrtype) != UNION_TYPE) -+ continue; -+ if (!constified(ptrtype)) -+ continue; -+ if (TYPE_MAIN_VARIANT(ptrtype) == TYPE_MAIN_VARIANT(type)) { -+ TREE_TYPE(field) = copy_node(TREE_TYPE(field)); -+ TREE_TYPE(TREE_TYPE(field)) = build_qualified_type(type, TYPE_QUALS(ptrtype) & ~TYPE_QUAL_CONST); -+ } -+ continue; -+ } -+ if (TREE_CODE(fieldtype) != RECORD_TYPE && TREE_CODE(fieldtype) != UNION_TYPE) -+ continue; -+ if (!constified(fieldtype)) -+ continue; -+ -+ deconstify_tree(field); -+ TREE_READONLY(field) = 0; -+ } -+ TYPE_READONLY(type) = 0; -+ C_TYPE_FIELDS_READONLY(type) = 0; -+ if (lookup_attribute("do_const", TYPE_ATTRIBUTES(type))) { -+ TYPE_ATTRIBUTES(type) = copy_list(TYPE_ATTRIBUTES(type)); -+ TYPE_ATTRIBUTES(type) = remove_attribute("do_const", TYPE_ATTRIBUTES(type)); -+ } -+} -+ -+static void deconstify_tree(tree node) -+{ -+ tree old_type, new_type, field; -+ -+ old_type = TREE_TYPE(node); -+ while (TREE_CODE(old_type) == ARRAY_TYPE && TREE_CODE(TREE_TYPE(old_type)) != ARRAY_TYPE) { -+ node = TREE_TYPE(node) = copy_node(old_type); -+ old_type = TREE_TYPE(old_type); -+ } -+ -+ gcc_assert(TREE_CODE(old_type) == RECORD_TYPE || TREE_CODE(old_type) == UNION_TYPE); -+ gcc_assert(TYPE_READONLY(old_type) && (TYPE_QUALS(old_type) & TYPE_QUAL_CONST)); -+ -+ new_type = build_qualified_type(old_type, TYPE_QUALS(old_type) & ~TYPE_QUAL_CONST); -+ TYPE_FIELDS(new_type) = copy_list(TYPE_FIELDS(new_type)); -+ for (field = TYPE_FIELDS(new_type); field; field = TREE_CHAIN(field)) -+ DECL_FIELD_CONTEXT(field) = new_type; -+ -+ deconstify_type(new_type); -+ -+ TREE_TYPE(node) = new_type; -+} -+ -+static tree handle_no_const_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs) -+{ -+ tree type; -+ constify_info cinfo = { -+ .has_fptr_field = false, -+ .has_writable_field = false, -+ .has_do_const_field = false, -+ .has_no_const_field = false -+ }; -+ -+ *no_add_attrs = true; -+ if (TREE_CODE(*node) == FUNCTION_DECL) { -+ error("%qE attribute does not apply to functions (%qF)", name, *node); -+ return NULL_TREE; -+ } -+ -+ if (TREE_CODE(*node) == PARM_DECL) { -+ error("%qE attribute does not apply to function parameters (%qD)", name, *node); -+ return NULL_TREE; -+ } -+ -+ if (TREE_CODE(*node) == VAR_DECL) { -+ error("%qE attribute does not apply to variables (%qD)", name, *node); -+ return NULL_TREE; -+ } -+ -+ if (TYPE_P(*node)) { -+ type = *node; -+ } else { -+ if (TREE_CODE(*node) != TYPE_DECL) { -+ error("%qE attribute does not apply to %qD (%qT)", name, *node, TREE_TYPE(*node)); -+ return NULL_TREE; -+ } -+ type = TREE_TYPE(*node); -+ } -+ -+ if (TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE) { -+ error("%qE attribute used on %qT applies to struct and union types only", name, type); -+ return NULL_TREE; -+ } -+ -+ if (lookup_attribute(IDENTIFIER_POINTER(name), TYPE_ATTRIBUTES(type))) { -+ error("%qE attribute is already applied to the type %qT", name, type); -+ return NULL_TREE; -+ } -+ -+ if (TYPE_P(*node)) { -+ if (lookup_attribute("do_const", TYPE_ATTRIBUTES(type))) -+ error("%qE attribute used on type %qT is incompatible with 'do_const'", name, type); -+ else -+ *no_add_attrs = false; -+ return NULL_TREE; -+ } -+ -+ constifiable(type, &cinfo); -+ if ((cinfo.has_fptr_field && !cinfo.has_writable_field && !cinfo.has_no_const_field) || lookup_attribute("do_const", TYPE_ATTRIBUTES(type))) { -+ if (constify) { -+ if TYPE_P(*node) -+ deconstify_type(*node); -+ else -+ deconstify_tree(*node); -+ } -+ if (TYPE_P(*node)) -+ TYPE_CONSTIFY_VISITED(*node) = 1; -+ else -+ TYPE_CONSTIFY_VISITED(TREE_TYPE(*node)) = 1; -+ return NULL_TREE; -+ } -+ -+ if (constify && TYPE_FIELDS(type)) -+ error("%qE attribute used on type %qT that is not constified", name, type); -+ return NULL_TREE; -+} -+ -+static void constify_type(tree type) -+{ -+ TYPE_READONLY(type) = 1; -+ C_TYPE_FIELDS_READONLY(type) = 1; -+ TYPE_CONSTIFY_VISITED(type) = 1; -+// TYPE_ATTRIBUTES(type) = copy_list(TYPE_ATTRIBUTES(type)); -+// TYPE_ATTRIBUTES(type) = tree_cons(get_identifier("do_const"), NULL_TREE, TYPE_ATTRIBUTES(type)); -+} -+ -+static tree handle_do_const_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs) -+{ -+ *no_add_attrs = true; -+ if (!TYPE_P(*node)) { -+ error("%qE attribute applies to types only (%qD)", name, *node); -+ return NULL_TREE; -+ } -+ -+ if (TREE_CODE(*node) != RECORD_TYPE && TREE_CODE(*node) != UNION_TYPE) { -+ error("%qE attribute used on %qT applies to struct and union types only", name, *node); -+ return NULL_TREE; -+ } -+ -+ if (lookup_attribute(IDENTIFIER_POINTER(name), TYPE_ATTRIBUTES(*node))) { -+ error("%qE attribute used on %qT is already applied to the type", name, *node); -+ return NULL_TREE; -+ } -+ -+ if (lookup_attribute("no_const", TYPE_ATTRIBUTES(*node))) { -+ error("%qE attribute used on %qT is incompatible with 'no_const'", name, *node); -+ return NULL_TREE; -+ } -+ -+ *no_add_attrs = false; -+ return NULL_TREE; -+} -+ -+static struct attribute_spec no_const_attr = { -+ .name = "no_const", -+ .min_length = 0, -+ .max_length = 0, -+ .decl_required = false, -+ .type_required = false, -+ .function_type_required = false, -+ .handler = handle_no_const_attribute, -+#if BUILDING_GCC_VERSION >= 4007 -+ .affects_type_identity = true -+#endif -+}; -+ -+static struct attribute_spec do_const_attr = { -+ .name = "do_const", -+ .min_length = 0, -+ .max_length = 0, -+ .decl_required = false, -+ .type_required = false, -+ .function_type_required = false, -+ .handler = handle_do_const_attribute, -+#if BUILDING_GCC_VERSION >= 4007 -+ .affects_type_identity = true -+#endif -+}; -+ -+static void register_attributes(void *event_data, void *data) -+{ -+ register_attribute(&no_const_attr); -+ register_attribute(&do_const_attr); -+} -+ -+static void finish_type(void *event_data, void *data) -+{ -+ tree type = (tree)event_data; -+ constify_info cinfo = { -+ .has_fptr_field = false, -+ .has_writable_field = false, -+ .has_do_const_field = false, -+ .has_no_const_field = false -+ }; -+ -+ if (type == NULL_TREE || type == error_mark_node) -+ return; -+ -+#if BUILDING_GCC_VERSION >= 5000 -+ if (TREE_CODE(type) == ENUMERAL_TYPE) -+ return; -+#endif -+ -+ if (TYPE_FIELDS(type) == NULL_TREE || TYPE_CONSTIFY_VISITED(type)) -+ return; -+ -+ constifiable(type, &cinfo); -+ -+ if (lookup_attribute("no_const", TYPE_ATTRIBUTES(type))) { -+ if ((cinfo.has_fptr_field && !cinfo.has_writable_field && !cinfo.has_no_const_field) || cinfo.has_do_const_field) { -+ deconstify_type(type); -+ TYPE_CONSTIFY_VISITED(type) = 1; -+ } else -+ error("'no_const' attribute used on type %qT that is not constified", type); -+ return; -+ } -+ -+ if (lookup_attribute("do_const", TYPE_ATTRIBUTES(type))) { -+ if (!cinfo.has_writable_field && !cinfo.has_no_const_field) { -+ error("'do_const' attribute used on type %qT that is%sconstified", type, cinfo.has_fptr_field ? " " : " not "); -+ return; -+ } -+ constify_type(type); -+ return; -+ } -+ -+ if (cinfo.has_fptr_field && !cinfo.has_writable_field && !cinfo.has_no_const_field) { -+ if (lookup_attribute("do_const", TYPE_ATTRIBUTES(type))) { -+ error("'do_const' attribute used on type %qT that is constified", type); -+ return; -+ } -+ constify_type(type); -+ return; -+ } -+ -+ deconstify_type(type); -+ TYPE_CONSTIFY_VISITED(type) = 1; -+} -+ -+static void check_global_variables(void *event_data, void *data) -+{ -+ varpool_node_ptr node; -+ -+ FOR_EACH_VARIABLE(node) { -+ tree var = NODE_DECL(node); -+ tree type = TREE_TYPE(var); -+ -+ if (TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE) -+ continue; -+ -+ if (!TYPE_READONLY(type) || !C_TYPE_FIELDS_READONLY(type)) -+ continue; -+ -+ if (!TYPE_CONSTIFY_VISITED(type)) -+ continue; -+ -+ if (DECL_EXTERNAL(var)) -+ continue; -+ -+ if (DECL_INITIAL(var)) -+ continue; -+ -+ // this works around a gcc bug/feature where uninitialized globals -+ // are moved into the .bss section regardless of any constification -+ DECL_INITIAL(var) = build_constructor(type, NULL); -+// inform(DECL_SOURCE_LOCATION(var), "constified variable %qE moved into .rodata", var); -+ } -+} -+ -+static unsigned int check_local_variables_execute(void) -+{ -+ unsigned int ret = 0; -+ tree var; -+ -+ unsigned int i; -+ -+ FOR_EACH_LOCAL_DECL(cfun, i, var) { -+ tree type = TREE_TYPE(var); -+ -+ gcc_assert(DECL_P(var)); -+ if (is_global_var(var)) -+ continue; -+ -+ if (TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE) -+ continue; -+ -+ if (!TYPE_READONLY(type) || !C_TYPE_FIELDS_READONLY(type)) -+ continue; -+ -+ if (!TYPE_CONSTIFY_VISITED(type)) -+ continue; -+ -+ error_at(DECL_SOURCE_LOCATION(var), "constified variable %qE cannot be local", var); -+ ret = 1; -+ } -+ return ret; -+} -+ -+#define PASS_NAME check_local_variables -+#define NO_GATE -+#include "gcc-generate-gimple-pass.h" -+ -+static struct { -+ const char *name; -+ const char *asm_op; -+} sections[] = { -+ {".init.rodata", "\t.section\t.init.rodata,\"a\""}, -+ {".ref.rodata", "\t.section\t.ref.rodata,\"a\""}, -+ {".devinit.rodata", "\t.section\t.devinit.rodata,\"a\""}, -+ {".devexit.rodata", "\t.section\t.devexit.rodata,\"a\""}, -+ {".cpuinit.rodata", "\t.section\t.cpuinit.rodata,\"a\""}, -+ {".cpuexit.rodata", "\t.section\t.cpuexit.rodata,\"a\""}, -+ {".meminit.rodata", "\t.section\t.meminit.rodata,\"a\""}, -+ {".memexit.rodata", "\t.section\t.memexit.rodata,\"a\""}, -+ {".data..read_only", "\t.section\t.data..read_only,\"a\""}, -+}; -+ -+static unsigned int (*old_section_type_flags)(tree decl, const char *name, int reloc); -+ -+static unsigned int constify_section_type_flags(tree decl, const char *name, int reloc) -+{ -+ size_t i; -+ -+ for (i = 0; i < ARRAY_SIZE(sections); i++) -+ if (!strcmp(sections[i].name, name)) -+ return 0; -+ return old_section_type_flags(decl, name, reloc); -+} -+ -+static void constify_start_unit(void *gcc_data, void *user_data) -+{ -+// size_t i; -+ -+// for (i = 0; i < ARRAY_SIZE(sections); i++) -+// sections[i].section = get_unnamed_section(0, output_section_asm_op, sections[i].asm_op); -+// sections[i].section = get_section(sections[i].name, 0, NULL); -+ -+ old_section_type_flags = targetm.section_type_flags; -+ targetm.section_type_flags = constify_section_type_flags; -+} -+ -+int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) -+{ -+ const char * const plugin_name = plugin_info->base_name; -+ const int argc = plugin_info->argc; -+ const struct plugin_argument * const argv = plugin_info->argv; -+ int i; -+ -+ struct register_pass_info check_local_variables_pass_info; -+ -+ check_local_variables_pass_info.pass = make_check_local_variables_pass(); -+ check_local_variables_pass_info.reference_pass_name = "ssa"; -+ check_local_variables_pass_info.ref_pass_instance_number = 1; -+ check_local_variables_pass_info.pos_op = PASS_POS_INSERT_BEFORE; -+ -+ if (!plugin_default_version_check(version, &gcc_version)) { -+ error(G_("incompatible gcc/plugin versions")); -+ return 1; -+ } -+ -+ for (i = 0; i < argc; ++i) { -+ if (!(strcmp(argv[i].key, "no-constify"))) { -+ constify = false; -+ continue; -+ } -+ error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); -+ } -+ -+ if (strncmp(lang_hooks.name, "GNU C", 5) && !strncmp(lang_hooks.name, "GNU C+", 6)) { -+ inform(UNKNOWN_LOCATION, G_("%s supports C only, not %s"), plugin_name, lang_hooks.name); -+ constify = false; -+ } -+ -+ register_callback(plugin_name, PLUGIN_INFO, NULL, &const_plugin_info); -+ if (constify) { -+ register_callback(plugin_name, PLUGIN_ALL_IPA_PASSES_START, check_global_variables, NULL); -+ register_callback(plugin_name, PLUGIN_FINISH_TYPE, finish_type, NULL); -+ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &check_local_variables_pass_info); -+ register_callback(plugin_name, PLUGIN_START_UNIT, constify_start_unit, NULL); -+ } -+ register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); -+ -+ return 0; -+} -diff --git a/tools/gcc/gcc-common.h b/tools/gcc/gcc-common.h -new file mode 100644 -index 0000000..0c0b842 ---- /dev/null -+++ b/tools/gcc/gcc-common.h -@@ -0,0 +1,879 @@ -+#ifndef GCC_COMMON_H_INCLUDED -+#define GCC_COMMON_H_INCLUDED -+ -+#include "bversion.h" -+#if BUILDING_GCC_VERSION >= 6000 -+#include "gcc-plugin.h" -+#else -+#include "plugin.h" -+#endif -+#include "plugin-version.h" -+#include "config.h" -+#include "system.h" -+#include "coretypes.h" -+#include "tm.h" -+#include "line-map.h" -+#include "input.h" -+#include "tree.h" -+ -+#include "tree-inline.h" -+#include "version.h" -+#include "rtl.h" -+#include "tm_p.h" -+#include "flags.h" -+//#include "insn-attr.h" -+//#include "insn-config.h" -+//#include "insn-flags.h" -+#include "hard-reg-set.h" -+//#include "recog.h" -+#include "output.h" -+#include "except.h" -+#include "function.h" -+#include "toplev.h" -+//#include "expr.h" -+#include "basic-block.h" -+#include "intl.h" -+#include "ggc.h" -+//#include "regs.h" -+#include "timevar.h" -+ -+#include "params.h" -+ -+#if BUILDING_GCC_VERSION <= 4009 -+#include "pointer-set.h" -+#else -+#include "hash-map.h" ++#include "tree-inline.h" ++#include "version.h" ++#include "rtl.h" ++#include "tm_p.h" ++#include "flags.h" ++//#include "insn-attr.h" ++//#include "insn-config.h" ++//#include "insn-flags.h" ++#include "hard-reg-set.h" ++//#include "recog.h" ++#include "output.h" ++#include "except.h" ++#include "function.h" ++#include "toplev.h" ++//#include "expr.h" ++#include "basic-block.h" ++#include "intl.h" ++#include "ggc.h" ++//#include "regs.h" ++#include "timevar.h" ++ ++#include "params.h" ++ ++#if BUILDING_GCC_VERSION <= 4009 ++#include "pointer-set.h" ++#else ++#include "hash-map.h" +#endif + +#include "emit-rtl.h" @@ -166240,11 +163512,11 @@ index 0000000..0c0b842 +#endif + +#endif -diff --git a/tools/gcc/gcc-generate-gimple-pass.h b/tools/gcc/gcc-generate-gimple-pass.h +diff --git a/scripts/gcc-plugins/gcc-generate-gimple-pass.h b/scripts/gcc-plugins/gcc-generate-gimple-pass.h new file mode 100644 index 0000000..0b081fe --- /dev/null -+++ b/tools/gcc/gcc-generate-gimple-pass.h ++++ b/scripts/gcc-plugins/gcc-generate-gimple-pass.h @@ -0,0 +1,175 @@ +/* + * Generator for GIMPLE pass related boilerplate code/data @@ -166421,11 +163693,11 @@ index 0000000..0b081fe +#undef __PASS_NAME_PASS_DATA + +#endif /* PASS_NAME */ -diff --git a/tools/gcc/gcc-generate-ipa-pass.h b/tools/gcc/gcc-generate-ipa-pass.h +diff --git a/scripts/gcc-plugins/gcc-generate-ipa-pass.h b/scripts/gcc-plugins/gcc-generate-ipa-pass.h new file mode 100644 index 0000000..9bd926e --- /dev/null -+++ b/tools/gcc/gcc-generate-ipa-pass.h ++++ b/scripts/gcc-plugins/gcc-generate-ipa-pass.h @@ -0,0 +1,289 @@ +/* + * Generator for IPA pass related boilerplate code/data @@ -166716,11 +163988,11 @@ index 0000000..9bd926e +#undef __WRITE_SUMMARY + +#endif /* PASS_NAME */ -diff --git a/tools/gcc/gcc-generate-rtl-pass.h b/tools/gcc/gcc-generate-rtl-pass.h +diff --git a/scripts/gcc-plugins/gcc-generate-rtl-pass.h b/scripts/gcc-plugins/gcc-generate-rtl-pass.h new file mode 100644 index 0000000..1dc67a5 --- /dev/null -+++ b/tools/gcc/gcc-generate-rtl-pass.h ++++ b/scripts/gcc-plugins/gcc-generate-rtl-pass.h @@ -0,0 +1,175 @@ +/* + * Generator for RTL pass related boilerplate code/data @@ -166897,11 +164169,11 @@ index 0000000..1dc67a5 +#undef __PASS_NAME_PASS_DATA + +#endif /* PASS_NAME */ -diff --git a/tools/gcc/gcc-generate-simple_ipa-pass.h b/tools/gcc/gcc-generate-simple_ipa-pass.h +diff --git a/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h b/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h new file mode 100644 index 0000000..a27e2b3 --- /dev/null -+++ b/tools/gcc/gcc-generate-simple_ipa-pass.h ++++ b/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h @@ -0,0 +1,175 @@ +/* + * Generator for SIMPLE_IPA pass related boilerplate code/data @@ -167078,11 +164350,11 @@ index 0000000..a27e2b3 +#undef __PASS_NAME_PASS_DATA + +#endif /* PASS_NAME */ -diff --git a/tools/gcc/gen-random-seed.sh b/tools/gcc/gen-random-seed.sh +diff --git a/scripts/gcc-plugins/gen-random-seed.sh b/scripts/gcc-plugins/gen-random-seed.sh new file mode 100644 index 0000000..7514850 --- /dev/null -+++ b/tools/gcc/gen-random-seed.sh ++++ b/scripts/gcc-plugins/gen-random-seed.sh @@ -0,0 +1,8 @@ +#!/bin/sh + @@ -167092,11 +164364,11 @@ index 0000000..7514850 + HASH=`echo -n "$SEED" | sha256sum | cut -d" " -f1 | tr -d ' \n'` + echo "#define RANDSTRUCT_HASHED_SEED \"$HASH\"" > "$2" +fi -diff --git a/tools/gcc/initify_plugin.c b/tools/gcc/initify_plugin.c +diff --git a/scripts/gcc-plugins/initify_plugin.c b/scripts/gcc-plugins/initify_plugin.c new file mode 100644 index 0000000..bf3eb6c --- /dev/null -+++ b/tools/gcc/initify_plugin.c ++++ b/scripts/gcc-plugins/initify_plugin.c @@ -0,0 +1,536 @@ +/* + * Copyright 2015-2016 by Emese Revfy @@ -167634,11 +164906,11 @@ index 0000000..bf3eb6c + + return 0; +} -diff --git a/tools/gcc/kallocstat_plugin.c b/tools/gcc/kallocstat_plugin.c +diff --git a/scripts/gcc-plugins/kallocstat_plugin.c b/scripts/gcc-plugins/kallocstat_plugin.c new file mode 100644 index 0000000..30ecc9a --- /dev/null -+++ b/tools/gcc/kallocstat_plugin.c ++++ b/scripts/gcc-plugins/kallocstat_plugin.c @@ -0,0 +1,135 @@ +/* + * Copyright 2011-2016 by the PaX Team @@ -167775,11 +165047,11 @@ index 0000000..30ecc9a + + return 0; +} -diff --git a/tools/gcc/kernexec_plugin.c b/tools/gcc/kernexec_plugin.c +diff --git a/scripts/gcc-plugins/kernexec_plugin.c b/scripts/gcc-plugins/kernexec_plugin.c new file mode 100644 index 0000000..e31e92f --- /dev/null -+++ b/tools/gcc/kernexec_plugin.c ++++ b/scripts/gcc-plugins/kernexec_plugin.c @@ -0,0 +1,407 @@ +/* + * Copyright 2011-2016 by the PaX Team @@ -168188,12 +165460,12 @@ index 0000000..e31e92f + + return 0; +} -diff --git a/tools/gcc/latent_entropy_plugin.c b/tools/gcc/latent_entropy_plugin.c +diff --git a/scripts/gcc-plugins/latent_entropy_plugin.c b/scripts/gcc-plugins/latent_entropy_plugin.c new file mode 100644 -index 0000000..50d373c +index 0000000..f08a221 --- /dev/null -+++ b/tools/gcc/latent_entropy_plugin.c -@@ -0,0 +1,422 @@ ++++ b/scripts/gcc-plugins/latent_entropy_plugin.c +@@ -0,0 +1,438 @@ +/* + * Copyright 2012-2016 by the PaX Team + * Licensed under the GPL v2 @@ -168219,11 +165491,13 @@ index 0000000..50d373c + +int plugin_is_GPL_compatible; + ++static bool enabled = true; ++ +static GTY(()) tree latent_entropy_decl; + +static struct plugin_info latent_entropy_plugin_info = { -+ .version = "201604022010", -+ .help = NULL ++ .version = "201605212030", ++ .help = "disable\tturn off latent entropy instrumentation\n", +}; + +static unsigned HOST_WIDE_INT seed; @@ -168586,6 +165860,10 @@ index 0000000..50d373c +int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) +{ + const char * const plugin_name = plugin_info->base_name; ++ const int argc = plugin_info->argc; ++ const struct plugin_argument * const argv = plugin_info->argv; ++ int i; ++ + struct register_pass_info latent_entropy_pass_info; + + latent_entropy_pass_info.pass = make_latent_entropy_pass(); @@ -168608,19 +165886,29 @@ index 0000000..50d373c + return 1; + } + ++ for (i = 0; i < argc; ++i) { ++ if (!(strcmp(argv[i].key, "disable"))) { ++ enabled = false; ++ continue; ++ } ++ error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); ++ } ++ + register_callback(plugin_name, PLUGIN_INFO, NULL, &latent_entropy_plugin_info); -+ register_callback(plugin_name, PLUGIN_START_UNIT, &latent_entropy_start_unit, NULL); -+ register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, NULL, (void *)>_ggc_r_gt_latent_entropy); -+ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &latent_entropy_pass_info); ++ if (enabled) { ++ register_callback(plugin_name, PLUGIN_START_UNIT, &latent_entropy_start_unit, NULL); ++ register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, NULL, (void *)>_ggc_r_gt_latent_entropy); ++ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &latent_entropy_pass_info); ++ } + register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); + + return 0; +} -diff --git a/tools/gcc/randomize_layout_plugin.c b/tools/gcc/randomize_layout_plugin.c +diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c new file mode 100644 index 0000000..a716d7a --- /dev/null -+++ b/tools/gcc/randomize_layout_plugin.c ++++ b/scripts/gcc-plugins/randomize_layout_plugin.c @@ -0,0 +1,940 @@ +/* + * Copyright 2014-2016 by Open Source Security, Inc., Brad Spengler @@ -169562,21 +166850,21 @@ index 0000000..a716d7a + + return 0; +} -diff --git a/tools/gcc/rap_plugin/Makefile b/tools/gcc/rap_plugin/Makefile +diff --git a/scripts/gcc-plugins/rap_plugin/Makefile b/scripts/gcc-plugins/rap_plugin/Makefile new file mode 100644 index 0000000..8171be8 --- /dev/null -+++ b/tools/gcc/rap_plugin/Makefile ++++ b/scripts/gcc-plugins/rap_plugin/Makefile @@ -0,0 +1,4 @@ +$(HOSTLIBS)-$(CONFIG_PAX_RAP) += rap_plugin.so +always := $($(HOSTLIBS)-y) + +rap_plugin-objs := $(patsubst $(srctree)/$(src)/%.c,%.o,$(wildcard $(srctree)/$(src)/*.c)) -diff --git a/tools/gcc/rap_plugin/rap.h b/tools/gcc/rap_plugin/rap.h +diff --git a/scripts/gcc-plugins/rap_plugin/rap.h b/scripts/gcc-plugins/rap_plugin/rap.h new file mode 100644 index 0000000..f6a284d --- /dev/null -+++ b/tools/gcc/rap_plugin/rap.h ++++ b/scripts/gcc-plugins/rap_plugin/rap.h @@ -0,0 +1,36 @@ +#ifndef RAP_H_INCLUDED +#define RAP_H_INCLUDED @@ -169614,11 +166902,11 @@ index 0000000..f6a284d +#endif + +#endif -diff --git a/tools/gcc/rap_plugin/rap_fptr_pass.c b/tools/gcc/rap_plugin/rap_fptr_pass.c +diff --git a/scripts/gcc-plugins/rap_plugin/rap_fptr_pass.c b/scripts/gcc-plugins/rap_plugin/rap_fptr_pass.c new file mode 100644 index 0000000..2f53f14 --- /dev/null -+++ b/tools/gcc/rap_plugin/rap_fptr_pass.c ++++ b/scripts/gcc-plugins/rap_plugin/rap_fptr_pass.c @@ -0,0 +1,220 @@ +/* + * Copyright 2012-2016 by PaX Team @@ -169840,11 +167128,11 @@ index 0000000..2f53f14 +#define PASS_NAME rap_fptr +#define TODO_FLAGS_FINISH TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func | TODO_remove_unused_locals | TODO_update_ssa | TODO_cleanup_cfg | TODO_rebuild_cgraph_edges | TODO_verify_flow +#include "gcc-generate-gimple-pass.h" -diff --git a/tools/gcc/rap_plugin/rap_hash.c b/tools/gcc/rap_plugin/rap_hash.c +diff --git a/scripts/gcc-plugins/rap_plugin/rap_hash.c b/scripts/gcc-plugins/rap_plugin/rap_hash.c new file mode 100644 index 0000000..7c59f38 --- /dev/null -+++ b/tools/gcc/rap_plugin/rap_hash.c ++++ b/scripts/gcc-plugins/rap_plugin/rap_hash.c @@ -0,0 +1,382 @@ +/* + * Copyright 2012-2016 by PaX Team @@ -170228,11 +167516,11 @@ index 0000000..7c59f38 + gcc_assert(rap_imprecise_hashes[uid].hash); + } +} -diff --git a/tools/gcc/rap_plugin/rap_plugin.c b/tools/gcc/rap_plugin/rap_plugin.c +diff --git a/scripts/gcc-plugins/rap_plugin/rap_plugin.c b/scripts/gcc-plugins/rap_plugin/rap_plugin.c new file mode 100644 index 0000000..bca74dc --- /dev/null -+++ b/tools/gcc/rap_plugin/rap_plugin.c ++++ b/scripts/gcc-plugins/rap_plugin/rap_plugin.c @@ -0,0 +1,511 @@ +/* + * Copyright 2012-2016 by PaX Team @@ -170745,11 +168033,11 @@ index 0000000..bca74dc + + return 0; +} -diff --git a/tools/gcc/rap_plugin/sip.c b/tools/gcc/rap_plugin/sip.c +diff --git a/scripts/gcc-plugins/rap_plugin/sip.c b/scripts/gcc-plugins/rap_plugin/sip.c new file mode 100644 index 0000000..65bc1cd --- /dev/null -+++ b/tools/gcc/rap_plugin/sip.c ++++ b/scripts/gcc-plugins/rap_plugin/sip.c @@ -0,0 +1,96 @@ +// SipHash-2-4 adapted by the PaX Team from the public domain version written by +// Jean-Philippe Aumasson @@ -170847,20 +168135,20 @@ index 0000000..65bc1cd + b = v0 ^ v1 ^ v2 ^ v3; + U64TO8_LE(out, b); +} -diff --git a/tools/gcc/size_overflow_plugin/.gitignore b/tools/gcc/size_overflow_plugin/.gitignore +diff --git a/scripts/gcc-plugins/size_overflow_plugin/.gitignore b/scripts/gcc-plugins/size_overflow_plugin/.gitignore new file mode 100644 index 0000000..c4b24b9 --- /dev/null -+++ b/tools/gcc/size_overflow_plugin/.gitignore ++++ b/scripts/gcc-plugins/size_overflow_plugin/.gitignore @@ -0,0 +1,3 @@ +disable_size_overflow_hash.h +size_overflow_hash.h +size_overflow_hash_aux.h -diff --git a/tools/gcc/size_overflow_plugin/Makefile b/tools/gcc/size_overflow_plugin/Makefile +diff --git a/scripts/gcc-plugins/size_overflow_plugin/Makefile b/scripts/gcc-plugins/size_overflow_plugin/Makefile new file mode 100644 index 0000000..f74d85a --- /dev/null -+++ b/tools/gcc/size_overflow_plugin/Makefile ++++ b/scripts/gcc-plugins/size_overflow_plugin/Makefile @@ -0,0 +1,28 @@ +HOST_EXTRACXXFLAGS += $(call hostcc-option, -fno-ipa-icf) + @@ -170890,11 +168178,11 @@ index 0000000..f74d85a + $(call if_changed,build_disable_size_overflow_hash) + +targets += size_overflow_hash.h size_overflow_hash_aux.h disable_size_overflow_hash.h -diff --git a/tools/gcc/size_overflow_plugin/disable_size_overflow_hash.data b/tools/gcc/size_overflow_plugin/disable_size_overflow_hash.data +diff --git a/scripts/gcc-plugins/size_overflow_plugin/disable_size_overflow_hash.data b/scripts/gcc-plugins/size_overflow_plugin/disable_size_overflow_hash.data new file mode 100644 index 0000000..2a420f3 --- /dev/null -+++ b/tools/gcc/size_overflow_plugin/disable_size_overflow_hash.data ++++ b/scripts/gcc-plugins/size_overflow_plugin/disable_size_overflow_hash.data @@ -0,0 +1,12444 @@ +disable_so_interrupt_pnode_gru_message_queue_desc_4 interrupt_pnode gru_message_queue_desc 0 4 NULL +disable_so_bch_btree_insert_fndecl_12 bch_btree_insert fndecl 0 12 NULL @@ -183340,11 +180628,11 @@ index 0000000..2a420f3 +enable_so_inofree_iagctl_5194 inofree iagctl 0 5194 NULL +enable_so_inofreefwd_iag_4921 inofreefwd iag 0 4921 NULL +enable_so_iagnum_iag_23227 iagnum iag 0 23227 NULL -diff --git a/tools/gcc/size_overflow_plugin/generate_size_overflow_hash.sh b/tools/gcc/size_overflow_plugin/generate_size_overflow_hash.sh +diff --git a/scripts/gcc-plugins/size_overflow_plugin/generate_size_overflow_hash.sh b/scripts/gcc-plugins/size_overflow_plugin/generate_size_overflow_hash.sh new file mode 100644 index 0000000..be9724d --- /dev/null -+++ b/tools/gcc/size_overflow_plugin/generate_size_overflow_hash.sh ++++ b/scripts/gcc-plugins/size_overflow_plugin/generate_size_overflow_hash.sh @@ -0,0 +1,103 @@ +#!/bin/bash + @@ -183449,11 +180737,11 @@ index 0000000..be9724d +create_array_elements + +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 +diff --git a/scripts/gcc-plugins/size_overflow_plugin/insert_size_overflow_asm.c b/scripts/gcc-plugins/size_overflow_plugin/insert_size_overflow_asm.c new file mode 100644 index 0000000..ee987da --- /dev/null -+++ b/tools/gcc/size_overflow_plugin/insert_size_overflow_asm.c ++++ b/scripts/gcc-plugins/size_overflow_plugin/insert_size_overflow_asm.c @@ -0,0 +1,369 @@ +/* + * Copyright 2011-2016 by Emese Revfy @@ -183824,11 +181112,11 @@ index 0000000..ee987da +#define TODO_FLAGS_FINISH TODO_dump_func | TODO_verify_ssa | TODO_verify_stmts | TODO_remove_unused_locals | TODO_update_ssa_no_phi | TODO_cleanup_cfg | TODO_ggc_collect | TODO_verify_flow + +#include "gcc-generate-gimple-pass.h" -diff --git a/tools/gcc/size_overflow_plugin/intentional_overflow.c b/tools/gcc/size_overflow_plugin/intentional_overflow.c +diff --git a/scripts/gcc-plugins/size_overflow_plugin/intentional_overflow.c b/scripts/gcc-plugins/size_overflow_plugin/intentional_overflow.c new file mode 100644 -index 0000000..6fcc436 +index 0000000..f29aac6 --- /dev/null -+++ b/tools/gcc/size_overflow_plugin/intentional_overflow.c ++++ b/scripts/gcc-plugins/size_overflow_plugin/intentional_overflow.c @@ -0,0 +1,1166 @@ +/* + * Copyright 2011-2016 by Emese Revfy @@ -184963,7 +182251,7 @@ index 0000000..6fcc436 +{ + const_tree rhs, lhs_type, rhs_type; + const_tree def_rhs1, def_rhs2; -+ gimple def_stmt; ++ const_gimple def_stmt; + gimple def_def_stmt = NULL; + + if (!gimple_assign_cast_p(stmt)) @@ -184996,11 +182284,11 @@ index 0000000..6fcc436 + // _36 = (signed short) _35; + return def_def_stmt && gimple_assign_cast_p(def_def_stmt); +} -diff --git a/tools/gcc/size_overflow_plugin/remove_unnecessary_dup.c b/tools/gcc/size_overflow_plugin/remove_unnecessary_dup.c +diff --git a/scripts/gcc-plugins/size_overflow_plugin/remove_unnecessary_dup.c b/scripts/gcc-plugins/size_overflow_plugin/remove_unnecessary_dup.c new file mode 100644 index 0000000..c910983 --- /dev/null -+++ b/tools/gcc/size_overflow_plugin/remove_unnecessary_dup.c ++++ b/scripts/gcc-plugins/size_overflow_plugin/remove_unnecessary_dup.c @@ -0,0 +1,137 @@ +/* + * Copyright 2011-2016 by Emese Revfy @@ -185139,11 +182427,11 @@ index 0000000..c910983 + } +} + -diff --git a/tools/gcc/size_overflow_plugin/size_overflow.h b/tools/gcc/size_overflow_plugin/size_overflow.h +diff --git a/scripts/gcc-plugins/size_overflow_plugin/size_overflow.h b/scripts/gcc-plugins/size_overflow_plugin/size_overflow.h new file mode 100644 index 0000000..4bd2e7f --- /dev/null -+++ b/tools/gcc/size_overflow_plugin/size_overflow.h ++++ b/scripts/gcc-plugins/size_overflow_plugin/size_overflow.h @@ -0,0 +1,331 @@ +#ifndef SIZE_OVERFLOW_H +#define SIZE_OVERFLOW_H @@ -185476,11 +182764,11 @@ index 0000000..4bd2e7f +extern const char * __unused print_intentional_mark_name(enum intentional_mark mark); + +#endif -diff --git a/tools/gcc/size_overflow_plugin/size_overflow_debug.c b/tools/gcc/size_overflow_plugin/size_overflow_debug.c +diff --git a/scripts/gcc-plugins/size_overflow_plugin/size_overflow_debug.c b/scripts/gcc-plugins/size_overflow_plugin/size_overflow_debug.c new file mode 100644 index 0000000..4098952 --- /dev/null -+++ b/tools/gcc/size_overflow_plugin/size_overflow_debug.c ++++ b/scripts/gcc-plugins/size_overflow_plugin/size_overflow_debug.c @@ -0,0 +1,194 @@ +/* + * Copyright 2011-2016 by Emese Revfy @@ -185676,11 +182964,11 @@ index 0000000..4098952 + + gcc_unreachable(); +} -diff --git a/tools/gcc/size_overflow_plugin/size_overflow_hash.data b/tools/gcc/size_overflow_plugin/size_overflow_hash.data +diff --git a/scripts/gcc-plugins/size_overflow_plugin/size_overflow_hash.data b/scripts/gcc-plugins/size_overflow_plugin/size_overflow_hash.data new file mode 100644 index 0000000..cbb8a80 --- /dev/null -+++ b/tools/gcc/size_overflow_plugin/size_overflow_hash.data ++++ b/scripts/gcc-plugins/size_overflow_plugin/size_overflow_hash.data @@ -0,0 +1,21645 @@ +enable_so_recv_ctrl_pipe_us_data_0 recv_ctrl_pipe us_data 0 0 NULL +enable_so___earlyonly_bootmem_alloc_fndecl_3 __earlyonly_bootmem_alloc fndecl 2-3-4 3 NULL @@ -207327,11 +204615,11 @@ index 0000000..cbb8a80 +enable_so_write_page_nocow_fndecl_65527 write_page_nocow fndecl 2 65527 NULL +enable_so_size_mei_msg_data_65529 size mei_msg_data 0 65529 NULL +enable_so_connector_write_fndecl_65534 connector_write fndecl 3 65534 NULL -diff --git a/tools/gcc/size_overflow_plugin/size_overflow_hash_aux.data b/tools/gcc/size_overflow_plugin/size_overflow_hash_aux.data +diff --git a/scripts/gcc-plugins/size_overflow_plugin/size_overflow_hash_aux.data b/scripts/gcc-plugins/size_overflow_plugin/size_overflow_hash_aux.data new file mode 100644 index 0000000..17bc0d8 --- /dev/null -+++ b/tools/gcc/size_overflow_plugin/size_overflow_hash_aux.data ++++ b/scripts/gcc-plugins/size_overflow_plugin/size_overflow_hash_aux.data @@ -0,0 +1,92 @@ +enable_so_spa_set_aux_vdevs_fndecl_746 spa_set_aux_vdevs fndecl 3 746 NULL +enable_so_zfs_lookup_fndecl_2144 zfs_lookup fndecl 0 2144 NULL @@ -207425,11 +204713,11 @@ index 0000000..17bc0d8 +enable_so_proc_copyin_string_fndecl_62019 proc_copyin_string fndecl 4 62019 NULL +enable_so_random_get_pseudo_bytes_fndecl_64611 random_get_pseudo_bytes fndecl 2 64611 NULL +enable_so_zpios_read_fndecl_64734 zpios_read fndecl 3 64734 NULL -diff --git a/tools/gcc/size_overflow_plugin/size_overflow_ipa.c b/tools/gcc/size_overflow_plugin/size_overflow_ipa.c +diff --git a/scripts/gcc-plugins/size_overflow_plugin/size_overflow_ipa.c b/scripts/gcc-plugins/size_overflow_plugin/size_overflow_ipa.c new file mode 100644 index 0000000..0a679f8 --- /dev/null -+++ b/tools/gcc/size_overflow_plugin/size_overflow_ipa.c ++++ b/scripts/gcc-plugins/size_overflow_plugin/size_overflow_ipa.c @@ -0,0 +1,1163 @@ +/* + * Copyright 2011-2016 by Emese Revfy @@ -207445,1161 +204733,2326 @@ index 0000000..0a679f8 + * with double integer precision (DImode/TImode for 32/64 bit integer types). + * The recomputed argument is checked against TYPE_MAX and an event is logged on overflow and the triggering process is killed. + * -+ * Usage: -+ * $ make -+ * $ make run ++ * Usage: ++ * $ make ++ * $ make run ++ */ ++ ++#include "size_overflow.h" ++#include ++ ++static void walk_use_def_next_functions(struct walk_use_def_data *use_def_data, tree lhs); ++ ++next_interesting_function_t global_next_interesting_function[GLOBAL_NIFN_LEN]; ++static bool global_changed; ++#define PRINT_DATA_FLOW true ++#define NO_PRINT_DATA_FLOW false ++ ++static struct cgraph_node_hook_list *function_insertion_hook_holder; ++static struct cgraph_2node_hook_list *node_duplication_hook_holder; ++ ++struct cgraph_node *get_cnode(const_tree fndecl) ++{ ++ gcc_assert(TREE_CODE(fndecl) == FUNCTION_DECL); ++#if BUILDING_GCC_VERSION <= 4005 ++ return cgraph_get_node(CONST_CAST_TREE(fndecl)); ++#else ++ return cgraph_get_node(fndecl); ++#endif ++} ++ ++static bool compare_next_interesting_functions(next_interesting_function_t cur_node, const char *decl_name, const char *context, unsigned int num) ++{ ++ // Ignore num without a value ++ if (num != NONE_ARGNUM && cur_node->num != num) ++ return false; ++ if (strcmp(cur_node->context, context)) ++ return false; ++ return !strcmp(cur_node->decl_name, decl_name); ++} ++ ++// Return the context of vardecl. If it is in a file scope then the context is vardecl_filebasename ++static const char* get_vardecl_context(const_tree decl) ++{ ++ expanded_location xloc; ++ char *buf, *path; ++ const char *bname; ++ int len; ++ ++ xloc = expand_location(DECL_SOURCE_LOCATION(decl)); ++ gcc_assert(xloc.file); ++ path = xstrdup(xloc.file); ++ bname = basename(path); ++ ++ len = asprintf(&buf, "vardecl_%s", bname); ++ gcc_assert(len > 0); ++ return buf; ++} ++ ++// Return the type name for a function pointer (or "fielddecl" if the type has no name), otherwise either "vardecl" or "fndecl" ++const char* get_decl_context(const_tree decl) ++{ ++ switch (TREE_CODE(decl)) { ++ case FUNCTION_DECL: ++ return "fndecl"; ++ // TODO: Ignore anonymous types for now ++ case FIELD_DECL: ++ return get_type_name_from_field(decl); ++ case VAR_DECL: ++ if (TREE_PUBLIC(decl) || DECL_EXTERNAL(decl)) ++ return "vardecl"; ++ if (TREE_STATIC(decl) && !TREE_PUBLIC(decl)) ++ return get_vardecl_context(decl); ++ // ignore local variable ++ if (!TREE_STATIC(decl) && !DECL_EXTERNAL(decl)) ++ return NULL; ++ default: ++ debug_tree(decl); ++ gcc_unreachable(); ++ } ++} ++ ++// Find the function with the specified argument in the list ++next_interesting_function_t get_global_next_interesting_function_entry(struct fn_raw_data *raw_data) ++{ ++ next_interesting_function_t cur_node, head; ++ ++ head = global_next_interesting_function[raw_data->hash]; ++ for (cur_node = head; cur_node; cur_node = cur_node->next) { ++ if (raw_data->marked != ASM_STMT_SO_MARK && cur_node->marked == ASM_STMT_SO_MARK) ++ continue; ++ if (compare_next_interesting_functions(cur_node, raw_data->decl_str, raw_data->context, raw_data->num)) ++ return cur_node; ++ } ++ return NULL; ++} ++ ++next_interesting_function_t get_global_next_interesting_function_entry_with_hash(struct fn_raw_data *raw_data) ++{ ++ raw_data->hash = get_decl_hash(raw_data->decl, raw_data->decl_str); ++ if (raw_data->hash == NO_HASH) ++ return NULL; ++ ++ raw_data->context = get_decl_context(raw_data->decl); ++ if (!raw_data->context) ++ return NULL; ++ return get_global_next_interesting_function_entry(raw_data); ++} ++ ++next_interesting_function_t create_new_next_interesting_entry(struct fn_raw_data *raw_data, next_interesting_function_t orig_next_node) ++{ ++ next_interesting_function_t new_node; ++ ++ new_node = (next_interesting_function_t)xmalloc(sizeof(*new_node)); ++ new_node->decl_name = xstrdup(raw_data->decl_str); ++ ++ gcc_assert(raw_data->context); ++ new_node->context = xstrdup(raw_data->context); ++ new_node->hash = raw_data->hash; ++ new_node->num = raw_data->num; ++ new_node->next = NULL; ++ new_node->children = NULL; ++ new_node->marked = raw_data->marked; ++ new_node->orig_next_node = orig_next_node; ++ return new_node; ++} ++ ++// Ignore these functions to not explode coverage (+strncmp+fndecl+3+35130+) ++static bool temporary_skip_these_functions(struct fn_raw_data *raw_data) ++{ ++ if (raw_data->hash == 35130 && !strcmp(raw_data->decl_str, "strncmp")) ++ return true; ++ if (raw_data->hash == 46193 && !strcmp(raw_data->decl_str, "strnlen")) ++ return true; ++ if (raw_data->hash == 43267 && !strcmp(raw_data->decl_str, "strncpy")) ++ return true; ++ if (raw_data->hash == 10300 && !strcmp(raw_data->decl_str, "strncpy_from_user")) ++ return true; ++ if (raw_data->hash == 26117 && !strcmp(raw_data->decl_str, "memchr")) ++ return true; ++ if (raw_data->hash == 16203 && !strcmp(raw_data->decl_str, "memchr_inv")) ++ return true; ++ if (raw_data->hash == 24269 && !strcmp(raw_data->decl_str, "memcmp")) ++ return true; ++ if (raw_data->hash == 60390 && !strcmp(raw_data->decl_str, "memcpy")) ++ return true; ++ if (raw_data->hash == 25040 && !strcmp(raw_data->decl_str, "memmove")) ++ return true; ++ if (raw_data->hash == 29763 && !strcmp(raw_data->decl_str, "memset")) ++ return true; ++ return false; ++} ++ ++// Create the main data structure ++next_interesting_function_t create_new_next_interesting_decl(struct fn_raw_data *raw_data, next_interesting_function_t orig_next_node) ++{ ++ enum tree_code decl_code = TREE_CODE(raw_data->decl); ++ ++ gcc_assert(decl_code == FIELD_DECL || decl_code == FUNCTION_DECL || decl_code == VAR_DECL); ++ ++ if (is_vararg(raw_data->decl, raw_data->num)) ++ return NULL; ++ ++ raw_data->hash = get_decl_hash(raw_data->decl, raw_data->decl_str); ++ if (raw_data->hash == NO_HASH) ++ return NULL; ++ if (get_size_overflow_hash_entry_tree(raw_data->decl, raw_data->num, DISABLE_SIZE_OVERFLOW)) ++ return NULL; ++ if (temporary_skip_these_functions(raw_data)) ++ return NULL; ++ ++ gcc_assert(raw_data->num <= MAX_PARAM); ++ // Clones must have an orig_next_node ++ gcc_assert(!made_by_compiler(raw_data->decl) || orig_next_node); ++ ++ raw_data->context = get_decl_context(raw_data->decl); ++ if (!raw_data->context) ++ return NULL; ++ return create_new_next_interesting_entry(raw_data, orig_next_node); ++} ++ ++void add_to_global_next_interesting_function(next_interesting_function_t new_entry) ++{ ++ next_interesting_function_t cur_global_head, cur_global, cur_global_end = NULL; ++ ++ // new_entry is appended to the end of a list ++ new_entry->next = NULL; ++ ++ cur_global_head = global_next_interesting_function[new_entry->hash]; ++ if (!cur_global_head) { ++ global_next_interesting_function[new_entry->hash] = new_entry; ++ return; ++ } ++ ++ ++ for (cur_global = cur_global_head; cur_global; cur_global = cur_global->next) { ++ if (!cur_global->next) ++ cur_global_end = cur_global; ++ ++ if (compare_next_interesting_functions(cur_global, new_entry->decl_name, new_entry->context, new_entry->num)) ++ return; ++ } ++ ++ gcc_assert(cur_global_end); ++ cur_global_end->next = new_entry; ++} ++ ++/* If the interesting function is a clone then find or create its original next_interesting_function_t node ++ * and add it to global_next_interesting_function ++ */ ++static next_interesting_function_t create_orig_next_node_for_a_clone(struct fn_raw_data *clone_raw_data) ++{ ++ struct fn_raw_data orig_raw_data; ++ next_interesting_function_t orig_next_node; ++ enum tree_code decl_code; ++ ++ orig_raw_data.decl = get_orig_fndecl(clone_raw_data->decl); ++ ++ if (DECL_BUILT_IN(orig_raw_data.decl) || DECL_BUILT_IN_CLASS(orig_raw_data.decl) == BUILT_IN_NORMAL) ++ return NULL; ++ ++ if (made_by_compiler(orig_raw_data.decl)) ++ return NULL; ++ ++ decl_code = TREE_CODE(orig_raw_data.decl); ++ if (decl_code == FIELD_DECL || decl_code == VAR_DECL) ++ orig_raw_data.num = clone_raw_data->num; ++ else ++ orig_raw_data.num = get_correct_argnum(clone_raw_data->decl, orig_raw_data.decl, clone_raw_data->num); ++ ++ // Skip over ISRA.162 parm decls ++ if (orig_raw_data.num == CANNOT_FIND_ARG) ++ return NULL; ++ ++ orig_raw_data.decl_str = get_orig_decl_name(orig_raw_data.decl); ++ orig_raw_data.marked = NO_SO_MARK; ++ orig_next_node = get_global_next_interesting_function_entry_with_hash(&orig_raw_data); ++ if (orig_next_node) ++ return orig_next_node; ++ ++ orig_raw_data.marked = clone_raw_data->marked; ++ orig_next_node = create_new_next_interesting_decl(&orig_raw_data, NULL); ++ if (!orig_next_node) ++ return NULL; ++ ++ add_to_global_next_interesting_function(orig_next_node); ++ return orig_next_node; ++} ++ ++// Find or create the next_interesting_function_t node for decl and num ++next_interesting_function_t get_and_create_next_node_from_global_next_nodes(struct fn_raw_data *raw_data, next_interesting_function_t orig_next_node) ++{ ++ next_interesting_function_t cur_next_cnode; ++ ++ if (DECL_NAME(raw_data->decl) == NULL_TREE) ++ return NULL; ++ raw_data->decl_str = DECL_NAME_POINTER(raw_data->decl); ++ ++ cur_next_cnode = get_global_next_interesting_function_entry_with_hash(raw_data); ++ if (cur_next_cnode) ++ goto out; ++ ++ if (!orig_next_node && made_by_compiler(raw_data->decl)) { ++ orig_next_node = create_orig_next_node_for_a_clone(raw_data); ++ if (!orig_next_node) ++ return NULL; ++ } ++ ++ cur_next_cnode = create_new_next_interesting_decl(raw_data, orig_next_node); ++ if (!cur_next_cnode) ++ return NULL; ++ ++ add_to_global_next_interesting_function(cur_next_cnode); ++out: ++ if (cur_next_cnode->marked != raw_data->marked && cur_next_cnode->marked != NO_SO_MARK) ++ return cur_next_cnode; ++ ++ if (raw_data->marked != NO_SO_MARK && cur_next_cnode->marked == NO_SO_MARK) ++ cur_next_cnode->marked = raw_data->marked; ++ ++ return cur_next_cnode; ++} ++ ++static bool has_next_interesting_function_chain_node(next_interesting_function_t next_cnodes_head, struct fn_raw_data *raw_data) ++{ ++ next_interesting_function_t cur_node; ++ ++ raw_data->decl_str = DECL_NAME_POINTER(raw_data->decl); ++ raw_data->context = get_decl_context(raw_data->decl); ++ // Ignore function if there is no context ++ if (!raw_data->context) ++ return true; ++ ++ for (cur_node = next_cnodes_head; cur_node; cur_node = cur_node->next) { ++ if (compare_next_interesting_functions(cur_node, raw_data->decl_str, raw_data->context, raw_data->num)) ++ return true; ++ } ++ return false; ++} ++ ++static void handle_function(struct walk_use_def_data *use_def_data, tree fndecl, const_tree arg) ++{ ++ struct fn_raw_data raw_data; ++ next_interesting_function_t orig_next_node, new_node; ++ ++ gcc_assert(fndecl != NULL_TREE); ++ ++ // ignore builtins to not explode coverage (e.g., memcpy) ++ if (DECL_BUILT_IN(fndecl) || DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL) ++ return; ++ ++ if (get_intentional_attr_type(fndecl) == MARK_TURN_OFF) ++ return; ++ ++ raw_data.decl = fndecl; ++ raw_data.decl_str = DECL_NAME_POINTER(fndecl); ++ raw_data.marked = NO_SO_MARK; ++ ++ // convert arg into its position ++ if (arg == NULL_TREE) ++ raw_data.num = 0; ++ else ++ raw_data.num = find_arg_number_tree(arg, raw_data.decl); ++ if (raw_data.num == CANNOT_FIND_ARG) ++ return; ++ ++ if (has_next_interesting_function_chain_node(use_def_data->next_cnodes_head, &raw_data)) ++ return; ++ ++ if (made_by_compiler(raw_data.decl)) { ++ orig_next_node = create_orig_next_node_for_a_clone(&raw_data); ++ if (!orig_next_node) ++ return; ++ } else ++ orig_next_node = NULL; ++ ++ new_node = create_new_next_interesting_decl(&raw_data, orig_next_node); ++ if (!new_node) ++ return; ++ new_node->next = use_def_data->next_cnodes_head; ++ use_def_data->next_cnodes_head = new_node; ++} ++ ++static void walk_use_def_next_functions_phi(struct walk_use_def_data *use_def_data, const_tree result) ++{ ++ gphi *phi = as_a_gphi(get_def_stmt(result)); ++ unsigned int i, n = gimple_phi_num_args(phi); ++ ++ pointer_set_insert(use_def_data->visited, phi); ++ for (i = 0; i < n; i++) { ++ tree arg = gimple_phi_arg_def(phi, i); ++ ++ walk_use_def_next_functions(use_def_data, arg); ++ } ++} ++ ++static void walk_use_def_next_functions_binary(struct walk_use_def_data *use_def_data, const_tree lhs) ++{ ++ gassign *def_stmt = as_a_gassign(get_def_stmt(lhs)); ++ tree rhs1, rhs2; ++ ++ rhs1 = gimple_assign_rhs1(def_stmt); ++ rhs2 = gimple_assign_rhs2(def_stmt); ++ ++ walk_use_def_next_functions(use_def_data, rhs1); ++ walk_use_def_next_functions(use_def_data, rhs2); ++} ++ ++static void walk_use_def_next_functions_unary(struct walk_use_def_data *use_def_data, const gassign *stmt) ++{ ++ tree rhs1 = gimple_assign_rhs1(stmt); ++ ++ walk_use_def_next_functions(use_def_data, rhs1); ++} ++ ++void __attribute__((weak)) handle_function_ptr_ret(struct walk_use_def_data *use_def_data __unused, const_tree fn_ptr __unused) ++{ ++} ++ ++static void create_and_append_new_next_interesting_field_var_decl(struct walk_use_def_data *use_def_data, struct fn_raw_data *raw_data) ++{ ++ next_interesting_function_t new_node; ++ ++ if (raw_data->decl == NULL_TREE) ++ return; ++ ++ if (DECL_NAME(raw_data->decl) == NULL_TREE) ++ return; ++ ++ raw_data->decl_str = DECL_NAME_POINTER(raw_data->decl); ++ raw_data->num = 0; ++ raw_data->marked = NO_SO_MARK; ++ ++ new_node = create_new_next_interesting_decl(raw_data, NULL); ++ if (!new_node) ++ return; ++ new_node->next = use_def_data->next_cnodes_head; ++ use_def_data->next_cnodes_head = new_node; ++} ++ ++static void handle_struct_fields(struct walk_use_def_data *use_def_data, const_tree node) ++{ ++ struct fn_raw_data raw_data; ++ ++ switch (TREE_CODE(node)) { ++ case ARRAY_REF: ++#if BUILDING_GCC_VERSION >= 4006 ++ case MEM_REF: ++#endif ++ case INDIRECT_REF: ++ case COMPONENT_REF: ++ raw_data.decl = get_ref_field(node); ++ break; ++ // TODO ++ case BIT_FIELD_REF: ++ case VIEW_CONVERT_EXPR: ++ case REALPART_EXPR: ++ case IMAGPART_EXPR: ++ return; ++ default: ++ debug_tree(node); ++ gcc_unreachable(); ++ } ++ ++ if (get_intentional_attr_type(raw_data.decl) == MARK_TURN_OFF) ++ return; ++ ++ create_and_append_new_next_interesting_field_var_decl(use_def_data, &raw_data); ++} ++ ++static void handle_vardecl(struct walk_use_def_data *use_def_data, tree node) ++{ ++ struct fn_raw_data raw_data; ++ ++ raw_data.decl = node; ++ create_and_append_new_next_interesting_field_var_decl(use_def_data, &raw_data); ++} ++ ++/* Find all functions that influence lhs ++ * ++ * Encountered functions are added to the children vector (next_interesting_function_t). + */ ++static void walk_use_def_next_functions(struct walk_use_def_data *use_def_data, tree lhs) ++{ ++ enum tree_code code; ++ const_gimple def_stmt; + -+#include "size_overflow.h" -+#include ++ if (skip_types(lhs)) ++ return; + -+static void walk_use_def_next_functions(struct walk_use_def_data *use_def_data, tree lhs); ++ if (VAR_P(lhs)) { ++ handle_vardecl(use_def_data, lhs); ++ return; ++ } + -+next_interesting_function_t global_next_interesting_function[GLOBAL_NIFN_LEN]; -+static bool global_changed; -+#define PRINT_DATA_FLOW true -+#define NO_PRINT_DATA_FLOW false ++ code = TREE_CODE(lhs); ++ if (code == PARM_DECL) { ++ handle_function(use_def_data, current_function_decl, lhs); ++ return; ++ } + -+static struct cgraph_node_hook_list *function_insertion_hook_holder; -+static struct cgraph_2node_hook_list *node_duplication_hook_holder; ++ if (TREE_CODE_CLASS(code) == tcc_reference) { ++ handle_struct_fields(use_def_data, lhs); ++ return; ++ } + -+struct cgraph_node *get_cnode(const_tree fndecl) ++ if (code != SSA_NAME) ++ return; ++ ++ def_stmt = get_def_stmt(lhs); ++ if (!def_stmt) ++ return; ++ ++ if (pointer_set_insert(use_def_data->visited, def_stmt)) ++ return; ++ ++ switch (gimple_code(def_stmt)) { ++ case GIMPLE_NOP: ++ walk_use_def_next_functions(use_def_data, SSA_NAME_VAR(lhs)); ++ return; ++ case GIMPLE_ASM: ++ if (!is_size_overflow_asm(def_stmt)) ++ return; ++ walk_use_def_next_functions(use_def_data, get_size_overflow_asm_input(as_a_const_gasm(def_stmt))); ++ return; ++ case GIMPLE_CALL: { ++ tree fndecl = gimple_call_fndecl(def_stmt); ++ ++ if (fndecl != NULL_TREE) { ++ handle_function(use_def_data, fndecl, NULL_TREE); ++ return; ++ } ++ fndecl = gimple_call_fn(def_stmt); ++ handle_function_ptr_ret(use_def_data, fndecl); ++ return; ++ } ++ case GIMPLE_PHI: ++ walk_use_def_next_functions_phi(use_def_data, lhs); ++ return; ++ case GIMPLE_ASSIGN: ++ switch (gimple_num_ops(def_stmt)) { ++ case 2: ++ walk_use_def_next_functions_unary(use_def_data, as_a_const_gassign(def_stmt)); ++ return; ++ case 3: ++ walk_use_def_next_functions_binary(use_def_data, lhs); ++ return; ++ } ++ default: ++ debug_gimple_stmt((gimple)def_stmt); ++ error("%s: unknown gimple code", __func__); ++ gcc_unreachable(); ++ } ++} ++ ++// Start the search for next_interesting_function_t children based on the (next_interesting_function_t) parent node ++static next_interesting_function_t search_next_functions(tree node, next_interesting_function_t parent) +{ -+ gcc_assert(TREE_CODE(fndecl) == FUNCTION_DECL); -+#if BUILDING_GCC_VERSION <= 4005 -+ return cgraph_get_node(CONST_CAST_TREE(fndecl)); ++ struct walk_use_def_data use_def_data; ++ ++ use_def_data.parent = parent; ++ use_def_data.next_cnodes_head = NULL; ++ use_def_data.visited = pointer_set_create(); ++ ++ walk_use_def_next_functions(&use_def_data, node); ++ ++ pointer_set_destroy(use_def_data.visited); ++ return use_def_data.next_cnodes_head; ++} ++ ++// True if child already exists in the next_interesting_function_t children vector ++bool has_next_interesting_function_vec(next_interesting_function_t target, next_interesting_function_t next_node) ++{ ++ unsigned int i; ++ next_interesting_function_t cur; ++ ++ gcc_assert(next_node); ++ // handle recursion ++ if (!strcmp(target->decl_name, next_node->decl_name) && target->num == next_node->num) ++ return true; ++ ++#if BUILDING_GCC_VERSION <= 4007 ++ if (VEC_empty(next_interesting_function_t, target->children)) ++ return false; ++ FOR_EACH_VEC_ELT(next_interesting_function_t, target->children, i, cur) { +#else -+ return cgraph_get_node(fndecl); ++ FOR_EACH_VEC_SAFE_ELT(target->children, i, cur) { +#endif ++ if (compare_next_interesting_functions(cur, next_node->decl_name, next_node->context, next_node->num)) ++ return true; ++ } ++ return false; +} + -+static bool compare_next_interesting_functions(next_interesting_function_t cur_node, const char *decl_name, const char *context, unsigned int num) ++void push_child(next_interesting_function_t parent, next_interesting_function_t child) +{ -+ // Ignore num without a value -+ if (num != NONE_ARGNUM && cur_node->num != num) -+ return false; -+ if (strcmp(cur_node->context, context)) -+ return false; -+ return !strcmp(cur_node->decl_name, decl_name); ++ if (!has_next_interesting_function_vec(parent, child)) { ++#if BUILDING_GCC_VERSION <= 4007 ++ VEC_safe_push(next_interesting_function_t, heap, parent->children, child); ++#else ++ vec_safe_push(parent->children, child); ++#endif ++ } +} + -+// Return the context of vardecl. If it is in a file scope then the context is vardecl_filebasename -+static const char* get_vardecl_context(const_tree decl) ++void __attribute__((weak)) check_local_variables(next_interesting_function_t next_node __unused) {} ++ ++// Add children to parent and global_next_interesting_function ++static void collect_data_for_execute(next_interesting_function_t parent, next_interesting_function_t children) +{ -+ expanded_location xloc; -+ char *buf, *path; -+ const char *bname; -+ int len; ++ next_interesting_function_t cur = children; + -+ xloc = expand_location(DECL_SOURCE_LOCATION(decl)); -+ gcc_assert(xloc.file); -+ path = xstrdup(xloc.file); -+ bname = basename(path); ++ gcc_assert(parent); + -+ len = asprintf(&buf, "vardecl_%s", bname); -+ gcc_assert(len > 0); -+ return buf; ++ while (cur) { ++ struct fn_raw_data child_raw_data; ++ next_interesting_function_t next, child; ++ ++ next = cur->next; ++ ++ child_raw_data.decl_str = cur->decl_name; ++ child_raw_data.context = cur->context; ++ child_raw_data.hash = cur->hash; ++ child_raw_data.num = cur->num; ++ child_raw_data.marked = NO_SO_MARK; ++ child = get_global_next_interesting_function_entry(&child_raw_data); ++ if (!child) { ++ add_to_global_next_interesting_function(cur); ++ child = cur; ++ } ++ ++ check_local_variables(child); ++ ++ push_child(parent, child); ++ ++ cur = next; ++ } ++ ++ check_local_variables(parent); +} + -+// Return the type name for a function pointer (or "fielddecl" if the type has no name), otherwise either "vardecl" or "fndecl" -+const char* get_decl_context(const_tree decl) ++next_interesting_function_t __attribute__((weak)) get_and_create_next_node_from_global_next_nodes_fnptr(const_tree fn_ptr __unused, struct fn_raw_data *raw_data __unused) +{ -+ switch (TREE_CODE(decl)) { -+ case FUNCTION_DECL: -+ return "fndecl"; -+ // TODO: Ignore anonymous types for now -+ case FIELD_DECL: -+ return get_type_name_from_field(decl); -+ case VAR_DECL: -+ if (TREE_PUBLIC(decl) || DECL_EXTERNAL(decl)) -+ return "vardecl"; -+ if (TREE_STATIC(decl) && !TREE_PUBLIC(decl)) -+ return get_vardecl_context(decl); -+ // ignore local variable -+ if (!TREE_STATIC(decl) && !DECL_EXTERNAL(decl)) ++ return NULL; ++} ++ ++static next_interesting_function_t create_parent_next_cnode(const_gimple stmt, unsigned int num) ++{ ++ struct fn_raw_data raw_data; ++ ++ raw_data.num = num; ++ raw_data.marked = NO_SO_MARK; ++ ++ switch (gimple_code(stmt)) { ++ case GIMPLE_ASM: ++ raw_data.decl = current_function_decl; ++ raw_data.marked = ASM_STMT_SO_MARK; ++ return get_and_create_next_node_from_global_next_nodes(&raw_data, NULL); ++ case GIMPLE_CALL: ++ raw_data.decl = gimple_call_fndecl(stmt); ++ if (raw_data.decl != NULL_TREE) ++ return get_and_create_next_node_from_global_next_nodes(&raw_data, NULL); ++ raw_data.decl = gimple_call_fn(stmt); ++ return get_and_create_next_node_from_global_next_nodes_fnptr(raw_data.decl, &raw_data); ++ case GIMPLE_RETURN: ++ raw_data.decl = current_function_decl; ++ return get_and_create_next_node_from_global_next_nodes(&raw_data, NULL); ++ case GIMPLE_ASSIGN: { ++ tree lhs = gimple_assign_lhs(stmt); ++ ++ if (VAR_P(lhs)) ++ raw_data.decl = lhs; ++ else ++ raw_data.decl = get_ref_field(lhs); ++ if (raw_data.decl == NULL_TREE) + return NULL; ++ return get_and_create_next_node_from_global_next_nodes(&raw_data, NULL); ++ } + default: -+ debug_tree(decl); ++ debug_gimple_stmt((gimple)stmt); + gcc_unreachable(); + } +} + -+// Find the function with the specified argument in the list -+next_interesting_function_t get_global_next_interesting_function_entry(struct fn_raw_data *raw_data) ++// Handle potential next_interesting_function_t parent if its argument has an integer type ++static void collect_all_possible_size_overflow_fns(const_gimple stmt, tree start_var, unsigned int num) +{ -+ next_interesting_function_t cur_node, head; ++ next_interesting_function_t children_next_cnode, parent_next_cnode; + -+ head = global_next_interesting_function[raw_data->hash]; -+ for (cur_node = head; cur_node; cur_node = cur_node->next) { -+ if (raw_data->marked != ASM_STMT_SO_MARK && cur_node->marked == ASM_STMT_SO_MARK) ++ // skip void return values ++ if (start_var == NULL_TREE) ++ return; ++ ++ if (skip_types(start_var)) ++ return; ++ ++ // handle intentional MARK_TURN_OFF ++ if (check_intentional_size_overflow_asm_and_attribute(start_var) == MARK_TURN_OFF) ++ return; ++ ++ parent_next_cnode = create_parent_next_cnode(stmt, num); ++ if (!parent_next_cnode) ++ return; ++ ++ children_next_cnode = search_next_functions(start_var, parent_next_cnode); ++ collect_data_for_execute(parent_next_cnode, children_next_cnode); ++} ++ ++static void collect_all_possible_size_overflow_fields_and_vars(const gassign *assign) ++{ ++ tree start_var, decl, lhs = gimple_assign_lhs(assign); ++ ++ if (VAR_P(lhs)) ++ decl = lhs; ++ else ++ decl = get_ref_field(lhs); ++ if (decl == NULL_TREE) ++ return; ++ ++ if (get_intentional_attr_type(decl) == MARK_TURN_OFF) ++ return; ++ ++ start_var = gimple_assign_rhs1(assign); ++ collect_all_possible_size_overflow_fns(assign, start_var, 0); ++ ++ start_var = gimple_assign_rhs2(assign); ++ collect_all_possible_size_overflow_fns(assign, start_var, 0); ++ ++#if BUILDING_GCC_VERSION >= 4006 ++ start_var = gimple_assign_rhs3(assign); ++ collect_all_possible_size_overflow_fns(assign, start_var, 0); ++#endif ++} ++ ++// Find potential next_interesting_function_t parents ++static void handle_cgraph_node(struct cgraph_node *node) ++{ ++ basic_block bb; ++ tree cur_fndecl = NODE_DECL(node); ++ ++ set_current_function_decl(cur_fndecl); ++ ++ FOR_EACH_BB_FN(bb, cfun) { ++ gimple_stmt_iterator gsi; ++ ++ for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { ++ tree start_var; ++ gimple stmt = gsi_stmt(gsi); ++ ++ switch (gimple_code(stmt)) { ++ case GIMPLE_RETURN: { ++ const greturn *return_stmt = as_a_const_greturn(stmt); ++ ++ start_var = gimple_return_retval(return_stmt); ++ collect_all_possible_size_overflow_fns(return_stmt, start_var, 0); ++ break; ++ } ++ case GIMPLE_ASM: { ++ const gasm *asm_stmt = as_a_const_gasm(stmt); ++ ++ if (!is_size_overflow_insert_check_asm(asm_stmt)) ++ break; ++ start_var = get_size_overflow_asm_input(asm_stmt); ++ collect_all_possible_size_overflow_fns(asm_stmt, start_var, 0); ++ break; ++ } ++ case GIMPLE_CALL: { ++ unsigned int i, len; ++ const gcall *call = as_a_const_gcall(stmt); ++ tree fndecl = gimple_call_fndecl(call); ++ ++ if (fndecl != NULL_TREE && (DECL_BUILT_IN(fndecl) || DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL)) ++ break; ++ ++ len = gimple_call_num_args(call); ++ for (i = 0; i < len; i++) { ++ start_var = gimple_call_arg(call, i); ++ collect_all_possible_size_overflow_fns(call, start_var, i + 1); ++ } ++ break; ++ } ++ case GIMPLE_ASSIGN: ++ collect_all_possible_size_overflow_fields_and_vars(as_a_const_gassign(stmt)); ++ break; ++ default: ++ break; ++ } ++ } ++ } ++ ++ unset_current_function_decl(); ++} ++ ++/* Collect all potentially interesting function parameters and return values of integer types ++ * and store their data flow dependencies ++ */ ++static void size_overflow_generate_summary(void) ++{ ++ struct cgraph_node *node; ++ ++ size_overflow_register_hooks(); ++ ++ FOR_EACH_FUNCTION(node) { ++ if (is_valid_cgraph_node(node)) ++ handle_cgraph_node(node); ++ } ++} ++ ++static void size_overflow_function_insertion_hook(struct cgraph_node *node __unused, void *data __unused) ++{ ++ debug_cgraph_node(node); ++ gcc_unreachable(); ++} ++ ++/* Handle dst if src is in the global_next_interesting_function list. ++ * If src is a clone then dst inherits the orig_next_node of src otherwise ++ * src will become the orig_next_node of dst. ++ */ ++static void size_overflow_node_duplication_hook(struct cgraph_node *src, struct cgraph_node *dst, void *data __unused) ++{ ++ next_interesting_function_t head, cur; ++ struct fn_raw_data src_raw_data; ++ ++ src_raw_data.decl = NODE_DECL(src); ++ src_raw_data.decl_str = DECL_NAME_POINTER(src_raw_data.decl); ++ src_raw_data.context = get_decl_context(src_raw_data.decl); ++ if (!src_raw_data.context) ++ return; ++ ++ src_raw_data.num = NONE_ARGNUM; ++ src_raw_data.marked = NO_SO_MARK; ++ ++ head = get_global_next_interesting_function_entry_with_hash(&src_raw_data); ++ if (!head) ++ return; ++ ++ for (cur = head; cur; cur = cur->next) { ++ struct fn_raw_data dst_raw_data; ++ next_interesting_function_t orig_next_node, next_node; ++ ++ if (!compare_next_interesting_functions(cur, src_raw_data.decl_str, src_raw_data.context, src_raw_data.num)) + continue; -+ if (compare_next_interesting_functions(cur_node, raw_data->decl_str, raw_data->context, raw_data->num)) -+ return cur_node; ++ ++ dst_raw_data.decl = NODE_DECL(dst); ++ dst_raw_data.decl_str = cgraph_node_name(dst); ++ dst_raw_data.marked = cur->marked; ++ ++ if (!made_by_compiler(dst_raw_data.decl)) ++ break; ++ ++ // For clones use the original node instead ++ if (cur->orig_next_node) ++ orig_next_node = cur->orig_next_node; ++ else ++ orig_next_node = cur; ++ ++ dst_raw_data.num = get_correct_argnum_fndecl(src_raw_data.decl, dst_raw_data.decl, cur->num); ++ if (dst_raw_data.num == CANNOT_FIND_ARG) ++ continue; ++ ++ next_node = create_new_next_interesting_decl(&dst_raw_data, orig_next_node); ++ if (next_node) ++ add_to_global_next_interesting_function(next_node); + } -+ return NULL; +} + -+next_interesting_function_t get_global_next_interesting_function_entry_with_hash(struct fn_raw_data *raw_data) ++void size_overflow_register_hooks(void) +{ -+ raw_data->hash = get_decl_hash(raw_data->decl, raw_data->decl_str); -+ if (raw_data->hash == NO_HASH) -+ return NULL; ++ static bool init_p = false; + -+ raw_data->context = get_decl_context(raw_data->decl); -+ if (!raw_data->context) -+ return NULL; -+ return get_global_next_interesting_function_entry(raw_data); ++ if (init_p) ++ return; ++ init_p = true; ++ ++ function_insertion_hook_holder = cgraph_add_function_insertion_hook(&size_overflow_function_insertion_hook, NULL); ++ node_duplication_hook_holder = cgraph_add_node_duplication_hook(&size_overflow_node_duplication_hook, NULL); +} + -+next_interesting_function_t create_new_next_interesting_entry(struct fn_raw_data *raw_data, next_interesting_function_t orig_next_node) ++static void set_yes_so_mark(next_interesting_function_t next_node) +{ -+ next_interesting_function_t new_node; ++ if (next_node->marked == NO_SO_MARK) { ++ next_node->marked = YES_SO_MARK; ++ global_changed = true; ++ } ++ // Mark the orig decl as well if it's a clone ++ if (next_node->orig_next_node && next_node->orig_next_node->marked == NO_SO_MARK) { ++ next_node->orig_next_node->marked = YES_SO_MARK; ++ global_changed = true; ++ } ++} + -+ new_node = (next_interesting_function_t)xmalloc(sizeof(*new_node)); -+ new_node->decl_name = xstrdup(raw_data->decl_str); ++// Determine whether node or orig node is part of a tracked data flow ++static bool marked_fn(next_interesting_function_t next_node) ++{ ++ bool is_marked_fn, is_marked_orig = false; + -+ gcc_assert(raw_data->context); -+ new_node->context = xstrdup(raw_data->context); -+ new_node->hash = raw_data->hash; -+ new_node->num = raw_data->num; -+ new_node->next = NULL; -+ new_node->children = NULL; -+ new_node->marked = raw_data->marked; -+ new_node->orig_next_node = orig_next_node; -+ return new_node; ++ is_marked_fn = next_node->marked != NO_SO_MARK; ++ ++ if (next_node->orig_next_node) ++ is_marked_orig = next_node->orig_next_node->marked != NO_SO_MARK; ++ ++ return is_marked_fn || is_marked_orig; +} + -+// Ignore these functions to not explode coverage (+strncmp+fndecl+3+35130+) -+static bool temporary_skip_these_functions(struct fn_raw_data *raw_data) ++// Determine whether node or orig node is in the hash table already ++static bool already_in_the_hashtable(next_interesting_function_t next_node) +{ -+ if (raw_data->hash == 35130 && !strcmp(raw_data->decl_str, "strncmp")) -+ return true; -+ if (raw_data->hash == 46193 && !strcmp(raw_data->decl_str, "strnlen")) -+ return true; -+ if (raw_data->hash == 43267 && !strcmp(raw_data->decl_str, "strncpy")) -+ return true; -+ if (raw_data->hash == 10300 && !strcmp(raw_data->decl_str, "strncpy_from_user")) -+ return true; -+ if (raw_data->hash == 26117 && !strcmp(raw_data->decl_str, "memchr")) -+ return true; -+ if (raw_data->hash == 16203 && !strcmp(raw_data->decl_str, "memchr_inv")) -+ return true; -+ if (raw_data->hash == 24269 && !strcmp(raw_data->decl_str, "memcmp")) -+ return true; -+ if (raw_data->hash == 60390 && !strcmp(raw_data->decl_str, "memcpy")) -+ return true; -+ if (raw_data->hash == 25040 && !strcmp(raw_data->decl_str, "memmove")) -+ return true; -+ if (raw_data->hash == 29763 && !strcmp(raw_data->decl_str, "memset")) -+ return true; -+ return false; ++ if (next_node->orig_next_node) ++ next_node = next_node->orig_next_node; ++ return get_size_overflow_hash_entry(next_node->hash, next_node->decl_name, next_node->context, next_node->num) != NULL; +} + -+// Create the main data structure -+next_interesting_function_t create_new_next_interesting_decl(struct fn_raw_data *raw_data, next_interesting_function_t orig_next_node) ++// Propagate the size_overflow marks up the use-def chains ++static bool has_marked_child(next_interesting_function_t next_node) +{ -+ enum tree_code decl_code = TREE_CODE(raw_data->decl); ++ bool ret = false; ++ unsigned int i; ++ next_interesting_function_t child; + -+ gcc_assert(decl_code == FIELD_DECL || decl_code == FUNCTION_DECL || decl_code == VAR_DECL); ++#if BUILDING_GCC_VERSION <= 4007 ++ if (VEC_empty(next_interesting_function_t, next_node->children)) ++ return false; ++ FOR_EACH_VEC_ELT(next_interesting_function_t, next_node->children, i, child) { ++#else ++ FOR_EACH_VEC_SAFE_ELT(next_node->children, i, child) { ++#endif ++ if (marked_fn(child) || already_in_the_hashtable(child)) ++ ret = true; ++ } + -+ if (is_vararg(raw_data->decl, raw_data->num)) -+ return NULL; ++ return ret; ++} + -+ raw_data->hash = get_decl_hash(raw_data->decl, raw_data->decl_str); -+ if (raw_data->hash == NO_HASH) -+ return NULL; -+ if (get_size_overflow_hash_entry_tree(raw_data->decl, raw_data->num, DISABLE_SIZE_OVERFLOW)) -+ return NULL; -+ if (temporary_skip_these_functions(raw_data)) -+ return NULL; ++/* Set YES_SO_MARK on the function, its orig node and children if: ++ * * the function or its orig node or one of its children is in the hash table already ++ * * the function's orig node is marked with YES_SO_MARK or ASM_STMT_SO_MARK ++ * * one of the children is marked with YES_SO_MARK or ASM_STMT_SO_MARK ++ */ ++static bool set_fn_so_mark(next_interesting_function_t next_node) ++{ ++ bool so_fn, so_hashtable, so_child; + -+ gcc_assert(raw_data->num <= MAX_PARAM); -+ // Clones must have an orig_next_node -+ gcc_assert(!made_by_compiler(raw_data->decl) || orig_next_node); ++ so_hashtable = already_in_the_hashtable(next_node); ++ so_fn = marked_fn(next_node); ++ so_child = has_marked_child(next_node); + -+ raw_data->context = get_decl_context(raw_data->decl); -+ if (!raw_data->context) ++ if (!so_fn && !so_hashtable && !so_child) ++ return false; ++ set_yes_so_mark(next_node); ++ return true; ++} ++ ++// Determine if any of the function pointer targets have data flow between the return value and one of the arguments ++static next_interesting_function_t get_same_not_ret_child(next_interesting_function_t parent) ++{ ++ unsigned int i; ++ next_interesting_function_t child; ++ ++#if BUILDING_GCC_VERSION <= 4007 ++ if (VEC_empty(next_interesting_function_t, parent->children)) + return NULL; -+ return create_new_next_interesting_entry(raw_data, orig_next_node); ++ FOR_EACH_VEC_ELT(next_interesting_function_t, parent->children, i, child) { ++#else ++ FOR_EACH_VEC_SAFE_ELT(parent->children, i, child) { ++#endif ++ if (child->num == 0) ++ continue; ++ if (strcmp(parent->decl_name, child->decl_name)) ++ continue; ++ if (!strcmp(child->context, "fndecl")) ++ return child; ++ } ++ return NULL; +} + -+void add_to_global_next_interesting_function(next_interesting_function_t new_entry) ++/* Trace a return value of function pointer type back to an argument via a concrete function ++ fnptr 0 && fn 0 && (fn 0 -> fn 2) => fnptr 2 */ ++static void search_missing_fptr_arg(next_interesting_function_t parent) +{ -+ next_interesting_function_t cur_global_head, cur_global, cur_global_end = NULL; ++ next_interesting_function_t child; ++ unsigned int i; ++#if BUILDING_GCC_VERSION <= 4007 ++ VEC(next_interesting_function_t, heap) *new_children = NULL; ++#else ++ vec *new_children = NULL; ++#endif + -+ // new_entry is appended to the end of a list -+ new_entry->next = NULL; ++ if (parent->num != 0) ++ return; ++ if (!strcmp(parent->context, "fndecl")) ++ return; ++ if (!strncmp(parent->context, "vardecl", sizeof("vardecl") - 1)) ++ return; + -+ cur_global_head = global_next_interesting_function[new_entry->hash]; -+ if (!cur_global_head) { -+ global_next_interesting_function[new_entry->hash] = new_entry; ++ // fnptr 0 && fn 0 ++#if BUILDING_GCC_VERSION <= 4007 ++ if (VEC_empty(next_interesting_function_t, parent->children)) + return; ++ FOR_EACH_VEC_ELT(next_interesting_function_t, parent->children, i, child) { ++#else ++ FOR_EACH_VEC_SAFE_ELT(parent->children, i, child) { ++#endif ++ next_interesting_function_t cur_next_node, tracked_fn; ++ ++ if (child->num != 0) ++ continue; ++ // (fn 0 -> fn 2) ++ tracked_fn = get_same_not_ret_child(child); ++ if (!tracked_fn) ++ continue; ++ ++ // fn 2 => fnptr 2 ++ for (cur_next_node = global_next_interesting_function[parent->hash]; cur_next_node; cur_next_node = cur_next_node->next) { ++ if (cur_next_node->num != tracked_fn->num) ++ continue; ++ ++ if (strcmp(parent->decl_name, cur_next_node->decl_name)) ++ continue; ++ ++ if (!has_next_interesting_function_vec(parent, cur_next_node)) { ++#if BUILDING_GCC_VERSION <= 4007 ++ VEC_safe_push(next_interesting_function_t, heap, new_children, cur_next_node); ++#else ++ vec_safe_push(new_children, cur_next_node); ++#endif ++ } ++ } + } + ++#if BUILDING_GCC_VERSION == 4005 ++ if (VEC_empty(next_interesting_function_t, new_children)) ++ return; ++ FOR_EACH_VEC_ELT(next_interesting_function_t, new_children, i, child) ++ VEC_safe_push(next_interesting_function_t, heap, parent->children, child); ++#elif BUILDING_GCC_VERSION <= 4007 ++ VEC_safe_splice(next_interesting_function_t, heap, parent->children, new_children); ++#else ++ vec_safe_splice(parent->children, new_children); ++#endif ++} ++ ++static void walk_so_marked_fns(next_interesting_function_set *visited, next_interesting_function_t parent, bool debug) ++{ ++ unsigned int i; ++ next_interesting_function_t child; + -+ for (cur_global = cur_global_head; cur_global; cur_global = cur_global->next) { -+ if (!cur_global->next) -+ cur_global_end = cur_global; ++ gcc_assert(parent); ++ if (!set_fn_so_mark(parent)) ++ return; + -+ if (compare_next_interesting_functions(cur_global, new_entry->decl_name, new_entry->context, new_entry->num)) -+ return; ++#if BUILDING_GCC_VERSION <= 4007 ++ if (VEC_empty(next_interesting_function_t, parent->children)) ++ return; ++ FOR_EACH_VEC_ELT(next_interesting_function_t, parent->children, i, child) { ++#else ++ FOR_EACH_VEC_SAFE_ELT(parent->children, i, child) { ++#endif ++ set_yes_so_mark(child); ++ ++ if (in_lto_p && debug == PRINT_DATA_FLOW) { ++ fprintf(stderr, " PARENT: decl: %s-%u context: %s %p\n", parent->decl_name, parent->num, parent->context, parent); ++ fprintf(stderr, " \tCHILD: decl: %s-%u context: %s %p\n", child->decl_name, child->num, child->context, child); ++ } ++ ++ if (!pointer_set_insert(visited, child)) ++ walk_so_marked_fns(visited, child, debug); + } ++} + -+ gcc_assert(cur_global_end); -+ cur_global_end->next = new_entry; ++// Do a depth-first recursive dump of the next_interesting_function_t children vector ++static void print_missing_functions(next_interesting_function_set *visited, next_interesting_function_t parent) ++{ ++ unsigned int i; ++ next_interesting_function_t child; ++ ++ gcc_assert(parent); ++ gcc_assert(parent->marked != NO_SO_MARK); ++ print_missing_function(parent); ++ ++#if BUILDING_GCC_VERSION <= 4007 ++ if (VEC_empty(next_interesting_function_t, parent->children)) ++ return; ++ FOR_EACH_VEC_ELT(next_interesting_function_t, parent->children, i, child) { ++#else ++ FOR_EACH_VEC_SAFE_ELT(parent->children, i, child) { ++#endif ++ gcc_assert(child->marked != NO_SO_MARK); ++ if (!pointer_set_insert(visited, child)) ++ print_missing_functions(visited, child); ++ } +} + -+/* If the interesting function is a clone then find or create its original next_interesting_function_t node -+ * and add it to global_next_interesting_function ++// Set YES_SO_MARK on functions that will be emitted into the hash table ++static void search_so_marked_fns(bool debug) ++{ ++ ++ unsigned int i; ++ next_interesting_function_set *visited; ++ next_interesting_function_t cur_global; ++ ++ visited = next_interesting_function_pointer_set_create(); ++ for (i = 0; i < GLOBAL_NIFN_LEN; i++) { ++ for (cur_global = global_next_interesting_function[i]; cur_global; cur_global = cur_global->next) { ++ if (cur_global->marked == NO_SO_MARK || pointer_set_insert(visited, cur_global)) ++ continue; ++ ++ if (in_lto_p && debug == PRINT_DATA_FLOW) ++ fprintf(stderr, "Data flow: decl: %s-%u context: %s %p\n", cur_global->decl_name, cur_global->num, cur_global->context, cur_global); ++ ++ walk_so_marked_fns(visited, cur_global, debug); ++ ++ if (in_lto_p && debug == PRINT_DATA_FLOW) ++ fprintf(stderr, "\n"); ++ } ++ } ++ pointer_set_destroy(visited); ++} ++ ++// Print functions missing from the hash table ++static void print_so_marked_fns(void) ++{ ++ unsigned int i; ++ next_interesting_function_set *visited; ++ next_interesting_function_t cur_global; ++ ++ visited = next_interesting_function_pointer_set_create(); ++ for (i = 0; i < GLOBAL_NIFN_LEN; i++) { ++ for (cur_global = global_next_interesting_function[i]; cur_global; cur_global = cur_global->next) { ++ if (cur_global->marked != NO_SO_MARK && !pointer_set_insert(visited, cur_global)) ++ print_missing_functions(visited, cur_global); ++ } ++ } ++ pointer_set_destroy(visited); ++} ++ ++void __attribute__((weak)) check_global_variables(next_interesting_function_t cur_global __unused) {} ++ ++// Print all missing interesting functions ++static unsigned int size_overflow_execute(void) ++{ ++ unsigned int i; ++ next_interesting_function_t cur_global; ++ ++ if (flag_lto && !in_lto_p) ++ return 0; ++ ++ // Collect vardecls and funtions reachable by function pointers ++ for (i = 0; i < GLOBAL_NIFN_LEN; i++) { ++ for (cur_global = global_next_interesting_function[i]; cur_global; cur_global = cur_global->next) { ++ check_global_variables(cur_global); ++ search_missing_fptr_arg(cur_global); ++ } ++ } ++ ++ search_so_marked_fns(PRINT_DATA_FLOW); ++ while (global_changed) { ++ global_changed = false; ++ search_so_marked_fns(NO_PRINT_DATA_FLOW); ++ } ++ ++ print_so_marked_fns(); ++ ++ if (in_lto_p) { ++ fprintf(stderr, "%s: SIZE_OVERFLOW EXECUTE\n", __func__); ++ print_global_next_interesting_functions(); ++ } ++ ++ return 0; ++} ++ ++// Omit the IPA/LTO callbacks until https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61311 gets fixed (license concerns) ++#if BUILDING_GCC_VERSION >= 4008 ++void __attribute__((weak)) size_overflow_write_summary(void) {} ++void __attribute__((weak)) size_overflow_write_optimization_summary(void) {} ++#elif BUILDING_GCC_VERSION >= 4006 ++void __attribute__((weak)) size_overflow_write_summary(cgraph_node_set set __unused, varpool_node_set vset __unused) {} ++void __attribute__((weak)) size_overflow_write_optimization_summary(cgraph_node_set set __unused, varpool_node_set vset __unused) {} ++#else ++void __attribute__((weak)) size_overflow_write_summary(cgraph_node_set set __unused) {} ++void __attribute__((weak)) size_overflow_write_optimization_summary(cgraph_node_set set __unused) {} ++#endif ++ ++void __attribute__((weak)) size_overflow_read_summary(void); ++void __attribute__((weak)) size_overflow_read_optimization_summary(void); ++ ++#define PASS_NAME size_overflow ++ ++#define NO_STMT_FIXUP ++#define NO_VARIABLE_TRANSFORM ++#define NO_GATE ++ ++#include "gcc-generate-ipa-pass.h" +diff --git a/scripts/gcc-plugins/size_overflow_plugin/size_overflow_misc.c b/scripts/gcc-plugins/size_overflow_plugin/size_overflow_misc.c +new file mode 100644 +index 0000000..7f459ed +--- /dev/null ++++ b/scripts/gcc-plugins/size_overflow_plugin/size_overflow_misc.c +@@ -0,0 +1,505 @@ ++/* ++ * Copyright 2011-2016 by Emese Revfy ++ * Licensed under the GPL v2, or (at your option) v3 ++ * ++ * Homepage: ++ * https://github.com/ephox-gcc-plugins/size_overflow ++ * ++ * Documentation: ++ * http://forums.grsecurity.net/viewtopic.php?f=7&t=3043 ++ * ++ * This plugin recomputes expressions of function arguments marked by a size_overflow attribute ++ * with double integer precision (DImode/TImode for 32/64 bit integer types). ++ * The recomputed argument is checked against TYPE_MAX and an event is logged on overflow and the triggering process is killed. ++ * ++ * Usage: ++ * $ make ++ * $ make run + */ -+static next_interesting_function_t create_orig_next_node_for_a_clone(struct fn_raw_data *clone_raw_data) ++ ++#include "size_overflow.h" ++ ++bool is_vararg(const_tree fn, unsigned int num) +{ -+ struct fn_raw_data orig_raw_data; -+ next_interesting_function_t orig_next_node; -+ enum tree_code decl_code; ++ tree arg_list; + -+ orig_raw_data.decl = get_orig_fndecl(clone_raw_data->decl); ++ if (num == 0) ++ return false; ++ if (fn == NULL_TREE) ++ return false; ++ if (TREE_CODE(fn) != FUNCTION_DECL) ++ return false; + -+ if (DECL_BUILT_IN(orig_raw_data.decl) || DECL_BUILT_IN_CLASS(orig_raw_data.decl) == BUILT_IN_NORMAL) -+ return NULL; ++ arg_list = TYPE_ARG_TYPES(TREE_TYPE(fn)); ++ if (arg_list == NULL_TREE) ++ return false; + -+ if (made_by_compiler(orig_raw_data.decl)) -+ return NULL; ++ if (tree_last(arg_list) == void_list_node) ++ return false; + -+ decl_code = TREE_CODE(orig_raw_data.decl); -+ if (decl_code == FIELD_DECL || decl_code == VAR_DECL) -+ orig_raw_data.num = clone_raw_data->num; -+ else -+ orig_raw_data.num = get_correct_argnum(clone_raw_data->decl, orig_raw_data.decl, clone_raw_data->num); ++ return num >= (unsigned int)list_length(arg_list); ++} + -+ // Skip over ISRA.162 parm decls -+ if (orig_raw_data.num == CANNOT_FIND_ARG) -+ return NULL; ++// Extract the field decl from memory references ++tree get_ref_field(const_tree ref) ++{ ++ tree field; + -+ orig_raw_data.decl_str = get_orig_decl_name(orig_raw_data.decl); -+ orig_raw_data.marked = NO_SO_MARK; -+ orig_next_node = get_global_next_interesting_function_entry_with_hash(&orig_raw_data); -+ if (orig_next_node) -+ return orig_next_node; ++ // TODO: handle nested memory references ++ switch (TREE_CODE(ref)) { ++ case ARRAY_REF: ++ return NULL_TREE; ++#if BUILDING_GCC_VERSION >= 4006 ++ case MEM_REF: ++#endif ++ case INDIRECT_REF: ++ field = TREE_OPERAND(ref, 0); ++ break; ++ case COMPONENT_REF: ++ field = TREE_OPERAND(ref, 1); ++ break; ++ default: ++ return NULL_TREE; ++ } + -+ orig_raw_data.marked = clone_raw_data->marked; -+ orig_next_node = create_new_next_interesting_decl(&orig_raw_data, NULL); -+ if (!orig_next_node) -+ return NULL; ++ // TODO ++ if (TREE_CODE(field) == SSA_NAME) ++ return NULL_TREE; ++ // TODO ++ if (TREE_CODE(field) != FIELD_DECL) ++ return NULL_TREE; ++ // TODO ++ if (TREE_CODE(field) == ADDR_EXPR) ++ return NULL_TREE; + -+ add_to_global_next_interesting_function(orig_next_node); -+ return orig_next_node; ++ return field; +} + -+// Find or create the next_interesting_function_t node for decl and num -+next_interesting_function_t get_and_create_next_node_from_global_next_nodes(struct fn_raw_data *raw_data, next_interesting_function_t orig_next_node) ++const char *get_type_name_from_field(const_tree field_decl) +{ -+ next_interesting_function_t cur_next_cnode; ++ const_tree context, type_name; + -+ if (DECL_NAME(raw_data->decl) == NULL_TREE) ++ if (TREE_CODE(field_decl) != FIELD_DECL) + return NULL; -+ raw_data->decl_str = DECL_NAME_POINTER(raw_data->decl); + -+ cur_next_cnode = get_global_next_interesting_function_entry_with_hash(raw_data); -+ if (cur_next_cnode) -+ goto out; ++ context = DECL_CONTEXT(field_decl); ++ // TODO ++ if (TREE_CODE(context) != RECORD_TYPE) ++ return NULL; ++ gcc_assert(TREE_CODE(context) == RECORD_TYPE); ++ type_name = TYPE_NAME(TYPE_MAIN_VARIANT(context)); ++ if (type_name == NULL_TREE) ++ return NULL; + -+ if (!orig_next_node && made_by_compiler(raw_data->decl)) { -+ orig_next_node = create_orig_next_node_for_a_clone(raw_data); -+ if (!orig_next_node) -+ return NULL; ++ if (TREE_CODE(type_name) == IDENTIFIER_NODE) ++ return IDENTIFIER_POINTER(type_name); ++ else if (TREE_CODE(type_name) == TYPE_DECL) ++ return DECL_NAME_POINTER(type_name); ++ ++ debug_tree(field_decl); ++ debug_tree(type_name); ++ gcc_unreachable(); ++} ++ ++// Was the function created by the compiler itself? ++bool made_by_compiler(const_tree decl) ++{ ++ enum tree_code decl_code; ++ struct cgraph_node *node; ++ ++ if (FUNCTION_PTR_P(decl)) ++ return false; ++ decl_code = TREE_CODE(decl); ++ if (decl_code == VAR_DECL || decl_code == FIELD_DECL) ++ return false; ++ ++ gcc_assert(decl_code == FUNCTION_DECL); ++ if (DECL_ABSTRACT_ORIGIN(decl) != NULL_TREE && DECL_ABSTRACT_ORIGIN(decl) != decl) ++ return true; ++ if (DECL_ARTIFICIAL(decl)) ++ return true; ++ ++ node = get_cnode(decl); ++ if (!node) ++ return false; ++ return node->clone_of != NULL; ++} ++ ++bool skip_types(const_tree var) ++{ ++ const_tree type; ++ ++ type = TREE_TYPE(var); ++ if (type == NULL_TREE) ++ return true; ++ ++ switch (TREE_CODE(type)) { ++ case INTEGER_TYPE: ++ case ENUMERAL_TYPE: ++ return false; ++ default: ++ return true; + } ++} + -+ cur_next_cnode = create_new_next_interesting_decl(raw_data, orig_next_node); -+ if (!cur_next_cnode) ++gimple get_fnptr_def_stmt(const_tree fn_ptr) ++{ ++ gimple def_stmt; ++ ++ gcc_assert(fn_ptr != NULL_TREE); ++ gcc_assert(FUNCTION_PTR_P(fn_ptr)); ++ ++ if (is_gimple_constant(fn_ptr)) + return NULL; + -+ add_to_global_next_interesting_function(cur_next_cnode); -+out: -+ if (cur_next_cnode->marked != raw_data->marked && cur_next_cnode->marked != NO_SO_MARK) -+ return cur_next_cnode; ++ def_stmt = get_def_stmt(fn_ptr); ++ gcc_assert(def_stmt); ++ return def_stmt; ++} + -+ if (raw_data->marked != NO_SO_MARK && cur_next_cnode->marked == NO_SO_MARK) -+ cur_next_cnode->marked = raw_data->marked; ++gimple get_def_stmt(const_tree node) ++{ ++ gcc_assert(node != NULL_TREE); + -+ return cur_next_cnode; ++ if (TREE_CODE(node) != SSA_NAME) ++ return NULL; ++ return SSA_NAME_DEF_STMT(node); +} + -+static bool has_next_interesting_function_chain_node(next_interesting_function_t next_cnodes_head, struct fn_raw_data *raw_data) ++tree create_new_var(tree type) +{ -+ next_interesting_function_t cur_node; -+ -+ raw_data->decl_str = DECL_NAME_POINTER(raw_data->decl); -+ raw_data->context = get_decl_context(raw_data->decl); -+ // Ignore function if there is no context -+ if (!raw_data->context) -+ return true; ++ tree new_var = create_tmp_var(type, "cicus"); + -+ for (cur_node = next_cnodes_head; cur_node; cur_node = cur_node->next) { -+ if (compare_next_interesting_functions(cur_node, raw_data->decl_str, raw_data->context, raw_data->num)) -+ return true; -+ } -+ return false; ++ add_referenced_var(new_var); ++ return new_var; +} + -+static void handle_function(struct walk_use_def_data *use_def_data, tree fndecl, const_tree arg) ++static bool skip_cast(tree dst_type, const_tree rhs, bool force) +{ -+ struct fn_raw_data raw_data; -+ next_interesting_function_t orig_next_node, new_node; ++ const_gimple def_stmt = get_def_stmt(rhs); + -+ gcc_assert(fndecl != NULL_TREE); ++ if (force) ++ return false; + -+ // ignore builtins to not explode coverage (e.g., memcpy) -+ if (DECL_BUILT_IN(fndecl) || DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL) -+ return; ++ if (is_gimple_constant(rhs)) ++ return false; + -+ if (get_intentional_attr_type(fndecl) == MARK_TURN_OFF) -+ return; ++ if (!def_stmt || gimple_code(def_stmt) == GIMPLE_NOP) ++ return false; + -+ raw_data.decl = fndecl; -+ raw_data.decl_str = DECL_NAME_POINTER(fndecl); -+ raw_data.marked = NO_SO_MARK; ++ if (!types_compatible_p(dst_type, TREE_TYPE(rhs))) ++ return false; + -+ // convert arg into its position -+ if (arg == NULL_TREE) -+ raw_data.num = 0; -+ else -+ raw_data.num = find_arg_number_tree(arg, raw_data.decl); -+ if (raw_data.num == CANNOT_FIND_ARG) -+ return; ++ // DI type can be on 32 bit (from create_assign) but overflow type stays DI ++ if (LONG_TYPE_SIZE == GET_MODE_BITSIZE(SImode)) ++ return false; + -+ if (has_next_interesting_function_chain_node(use_def_data->next_cnodes_head, &raw_data)) -+ return; ++ return true; ++} + -+ if (made_by_compiler(raw_data.decl)) { -+ orig_next_node = create_orig_next_node_for_a_clone(&raw_data); -+ if (!orig_next_node) -+ return; -+ } else -+ orig_next_node = NULL; ++tree cast_a_tree(tree type, tree var) ++{ ++ gcc_assert(type != NULL_TREE); ++ gcc_assert(var != NULL_TREE); ++ gcc_assert(fold_convertible_p(type, var)); + -+ new_node = create_new_next_interesting_decl(&raw_data, orig_next_node); -+ if (!new_node) -+ return; -+ new_node->next = use_def_data->next_cnodes_head; -+ use_def_data->next_cnodes_head = new_node; ++ return fold_convert(type, var); +} + -+static void walk_use_def_next_functions_phi(struct walk_use_def_data *use_def_data, const_tree result) ++gimple build_cast_stmt(struct visited *visited, tree dst_type, tree rhs, tree lhs, gimple_stmt_iterator *gsi, bool before, bool force) +{ -+ gphi *phi = as_a_gphi(get_def_stmt(result)); -+ unsigned int i, n = gimple_phi_num_args(phi); ++ gassign *assign; ++ gimple def_stmt; + -+ pointer_set_insert(use_def_data->visited, phi); -+ for (i = 0; i < n; i++) { -+ tree arg = gimple_phi_arg_def(phi, i); ++ gcc_assert(dst_type != NULL_TREE && rhs != NULL_TREE); ++ gcc_assert(!is_gimple_constant(rhs)); ++ if (gsi_end_p(*gsi) && before == AFTER_STMT) ++ gcc_unreachable(); + -+ walk_use_def_next_functions(use_def_data, arg); ++ def_stmt = get_def_stmt(rhs); ++ if (def_stmt && gimple_code(def_stmt) != GIMPLE_NOP && skip_cast(dst_type, rhs, force) && pointer_set_contains(visited->my_stmts, def_stmt)) ++ return def_stmt; ++ ++ if (lhs == CREATE_NEW_VAR) ++ lhs = create_new_var(dst_type); ++ ++ assign = gimple_build_assign(lhs, cast_a_tree(dst_type, rhs)); ++ ++ if (!gsi_end_p(*gsi)) { ++ location_t loc = gimple_location(gsi_stmt(*gsi)); ++ gimple_set_location(assign, loc); + } ++ ++ gimple_assign_set_lhs(assign, make_ssa_name(lhs, assign)); ++ ++ if (before) ++ gsi_insert_before(gsi, assign, GSI_NEW_STMT); ++ else ++ gsi_insert_after(gsi, assign, GSI_NEW_STMT); ++ update_stmt(assign); ++ return assign; +} + -+static void walk_use_def_next_functions_binary(struct walk_use_def_data *use_def_data, const_tree lhs) ++bool is_size_overflow_type(const_tree var) +{ -+ gassign *def_stmt = as_a_gassign(get_def_stmt(lhs)); -+ tree rhs1, rhs2; ++ const char *name; ++ const_tree type_name, type; + -+ rhs1 = gimple_assign_rhs1(def_stmt); -+ rhs2 = gimple_assign_rhs2(def_stmt); ++ if (var == NULL_TREE) ++ return false; + -+ walk_use_def_next_functions(use_def_data, rhs1); -+ walk_use_def_next_functions(use_def_data, rhs2); -+} ++ type = TREE_TYPE(var); ++ type_name = TYPE_NAME(type); ++ if (type_name == NULL_TREE) ++ return false; + -+static void walk_use_def_next_functions_unary(struct walk_use_def_data *use_def_data, const gassign *stmt) -+{ -+ tree rhs1 = gimple_assign_rhs1(stmt); ++ if (DECL_P(type_name)) ++ name = DECL_NAME_POINTER(type_name); ++ else ++ name = IDENTIFIER_POINTER(type_name); + -+ walk_use_def_next_functions(use_def_data, rhs1); ++ if (!strncmp(name, "size_overflow_type", 18)) ++ return true; ++ return false; +} + -+void __attribute__((weak)) handle_function_ptr_ret(struct walk_use_def_data *use_def_data __unused, const_tree fn_ptr __unused) ++// Determine if a cloned function has all the original arguments ++static bool unchanged_arglist(struct cgraph_node *new_node, struct cgraph_node *old_node) +{ ++ const_tree new_decl_list, old_decl_list; ++ ++ if (new_node->clone_of && new_node->clone.tree_map) ++ return !new_node->clone.args_to_skip; ++ ++ new_decl_list = DECL_ARGUMENTS(NODE_DECL(new_node)); ++ old_decl_list = DECL_ARGUMENTS(NODE_DECL(old_node)); ++ if (new_decl_list != NULL_TREE && old_decl_list != NULL_TREE) ++ gcc_assert(list_length(new_decl_list) == list_length(old_decl_list)); ++ ++ return true; +} + -+static void create_and_append_new_next_interesting_field_var_decl(struct walk_use_def_data *use_def_data, struct fn_raw_data *raw_data) ++unsigned int get_correct_argnum_fndecl(const_tree fndecl, const_tree correct_argnum_of_fndecl, unsigned int num) +{ -+ next_interesting_function_t new_node; -+ -+ if (raw_data->decl == NULL_TREE) -+ return; ++ unsigned int new_num; ++ const_tree fndecl_arg; ++ tree fndecl_arglist = DECL_ARGUMENTS(fndecl); ++ const_tree arg, target_fndecl_arglist; + -+ if (DECL_NAME(raw_data->decl) == NULL_TREE) -+ return; ++ if (num == 0) ++ return num; + -+ raw_data->decl_str = DECL_NAME_POINTER(raw_data->decl); -+ raw_data->num = 0; -+ raw_data->marked = NO_SO_MARK; ++ if (fndecl == correct_argnum_of_fndecl && !DECL_ARTIFICIAL(fndecl)) ++ return num; ++ else if (fndecl == correct_argnum_of_fndecl && DECL_ARTIFICIAL(fndecl)) ++ return CANNOT_FIND_ARG; + -+ new_node = create_new_next_interesting_decl(raw_data, NULL); -+ if (!new_node) -+ return; -+ new_node->next = use_def_data->next_cnodes_head; -+ use_def_data->next_cnodes_head = new_node; -+} ++ target_fndecl_arglist = DECL_ARGUMENTS(correct_argnum_of_fndecl); ++ if (fndecl_arglist == NULL_TREE || target_fndecl_arglist == NULL_TREE) ++ return CANNOT_FIND_ARG; + -+static void handle_struct_fields(struct walk_use_def_data *use_def_data, const_tree node) -+{ -+ struct fn_raw_data raw_data; ++ fndecl_arg = chain_index(num - 1, fndecl_arglist); ++ if (fndecl_arg == NULL_TREE) ++ return CANNOT_FIND_ARG; + -+ switch (TREE_CODE(node)) { -+ case ARRAY_REF: -+#if BUILDING_GCC_VERSION >= 4006 -+ case MEM_REF: -+#endif -+ case INDIRECT_REF: -+ case COMPONENT_REF: -+ raw_data.decl = get_ref_field(node); -+ break; -+ // TODO -+ case BIT_FIELD_REF: -+ case VIEW_CONVERT_EXPR: -+ case REALPART_EXPR: -+ case IMAGPART_EXPR: -+ return; -+ default: -+ debug_tree(node); -+ gcc_unreachable(); ++ for (arg = target_fndecl_arglist, new_num = 1; arg; arg = TREE_CHAIN(arg), new_num++) { ++ if (arg == fndecl_arg || !strcmp(DECL_NAME_POINTER(arg), DECL_NAME_POINTER(fndecl_arg))) ++ return new_num; + } + -+ if (get_intentional_attr_type(raw_data.decl) == MARK_TURN_OFF) -+ return; -+ -+ create_and_append_new_next_interesting_field_var_decl(use_def_data, &raw_data); ++ return CANNOT_FIND_ARG; +} + -+static void handle_vardecl(struct walk_use_def_data *use_def_data, tree node) ++// Find the specified argument in the originally cloned function ++static unsigned int clone_argnum_on_orig(struct cgraph_node *new_node, struct cgraph_node *old_node, unsigned int clone_argnum) +{ -+ struct fn_raw_data raw_data; ++ bitmap args_to_skip; ++ unsigned int i, new_argnum = clone_argnum; + -+ raw_data.decl = node; -+ create_and_append_new_next_interesting_field_var_decl(use_def_data, &raw_data); ++ if (unchanged_arglist(new_node, old_node)) ++ return clone_argnum; ++ ++ gcc_assert(new_node->clone_of && new_node->clone.tree_map); ++ args_to_skip = new_node->clone.args_to_skip; ++ for (i = 0; i < clone_argnum; i++) { ++ if (bitmap_bit_p(args_to_skip, i)) ++ new_argnum++; ++ } ++ return new_argnum; +} + -+/* Find all functions that influence lhs -+ * -+ * Encountered functions are added to the children vector (next_interesting_function_t). -+ */ -+static void walk_use_def_next_functions(struct walk_use_def_data *use_def_data, tree lhs) ++// Find the specified argument in the clone ++static unsigned int orig_argnum_on_clone(struct cgraph_node *new_node, struct cgraph_node *old_node, unsigned int orig_argnum) +{ -+ enum tree_code code; -+ const_gimple def_stmt; ++ bitmap args_to_skip; ++ unsigned int i, new_argnum = orig_argnum; + -+ if (skip_types(lhs)) -+ return; ++ if (unchanged_arglist(new_node, old_node)) ++ return orig_argnum; + -+ if (VAR_P(lhs)) { -+ handle_vardecl(use_def_data, lhs); -+ return; -+ } ++ gcc_assert(new_node->clone_of && new_node->clone.tree_map); ++ args_to_skip = new_node->clone.args_to_skip; ++ if (bitmap_bit_p(args_to_skip, orig_argnum - 1)) ++ // XXX torolni kellene a nodeot ++ return CANNOT_FIND_ARG; + -+ code = TREE_CODE(lhs); -+ if (code == PARM_DECL) { -+ handle_function(use_def_data, current_function_decl, lhs); -+ return; ++ for (i = 0; i < orig_argnum; i++) { ++ if (bitmap_bit_p(args_to_skip, i)) ++ new_argnum--; + } ++ return new_argnum; ++} + -+ if (TREE_CODE_CLASS(code) == tcc_reference) { -+ handle_struct_fields(use_def_data, lhs); -+ return; -+ } ++// Associate the argument between a clone and a cloned function ++static unsigned int get_correct_argnum_cnode(struct cgraph_node *node, struct cgraph_node *correct_argnum_of_node, unsigned int argnum) ++{ ++ bool node_clone, correct_argnum_of_node_clone; ++ const_tree correct_argnum_of_node_decl, node_decl; + -+ if (code != SSA_NAME) -+ return; ++ if (node == correct_argnum_of_node) ++ return argnum; ++ if (argnum == 0) ++ return argnum; + -+ def_stmt = get_def_stmt(lhs); -+ if (!def_stmt) -+ return; ++ correct_argnum_of_node_decl = NODE_DECL(correct_argnum_of_node); ++ gcc_assert(correct_argnum_of_node_decl != NULL_TREE); ++ gcc_assert(correct_argnum_of_node && !DECL_ARTIFICIAL(correct_argnum_of_node_decl)); + -+ if (pointer_set_insert(use_def_data->visited, def_stmt)) -+ return; ++ if (node) { ++ node_decl = NODE_DECL(node); ++ gcc_assert(!DECL_ARTIFICIAL(node_decl)); ++ node_clone = made_by_compiler(node_decl); ++ } else { ++ node_decl = NULL_TREE; ++ node_clone = false; ++ } + -+ switch (gimple_code(def_stmt)) { -+ case GIMPLE_NOP: -+ walk_use_def_next_functions(use_def_data, SSA_NAME_VAR(lhs)); -+ return; -+ case GIMPLE_ASM: -+ if (!is_size_overflow_asm(def_stmt)) -+ return; -+ walk_use_def_next_functions(use_def_data, get_size_overflow_asm_input(as_a_const_gasm(def_stmt))); -+ return; -+ case GIMPLE_CALL: { -+ tree fndecl = gimple_call_fndecl(def_stmt); ++ if (correct_argnum_of_node_decl == node_decl) ++ return argnum; + -+ if (fndecl != NULL_TREE) { -+ handle_function(use_def_data, fndecl, NULL_TREE); -+ return; -+ } -+ fndecl = gimple_call_fn(def_stmt); -+ handle_function_ptr_ret(use_def_data, fndecl); -+ return; -+ } -+ case GIMPLE_PHI: -+ walk_use_def_next_functions_phi(use_def_data, lhs); -+ return; -+ case GIMPLE_ASSIGN: -+ switch (gimple_num_ops(def_stmt)) { -+ case 2: -+ walk_use_def_next_functions_unary(use_def_data, as_a_const_gassign(def_stmt)); -+ return; -+ case 3: -+ walk_use_def_next_functions_binary(use_def_data, lhs); -+ return; -+ } -+ default: -+ debug_gimple_stmt((gimple)def_stmt); -+ error("%s: unknown gimple code", __func__); -+ gcc_unreachable(); ++ correct_argnum_of_node_clone = made_by_compiler(correct_argnum_of_node_decl); ++ // the original decl is lost if both nodes are clones ++ if (node_clone && correct_argnum_of_node_clone) { ++ gcc_assert(unchanged_arglist(node, correct_argnum_of_node)); ++ return argnum; + } ++ ++ if (node_clone && !correct_argnum_of_node_clone) ++ return clone_argnum_on_orig(correct_argnum_of_node, node, argnum); ++ else if (!node_clone && correct_argnum_of_node_clone) ++ return orig_argnum_on_clone(correct_argnum_of_node, node, argnum); ++ ++ if (node) ++ debug_tree(NODE_DECL(node)); ++ debug_tree(correct_argnum_of_node_decl); ++ gcc_unreachable(); +} + -+// Start the search for next_interesting_function_t children based on the (next_interesting_function_t) parent node -+static next_interesting_function_t search_next_functions(tree node, next_interesting_function_t parent) ++unsigned int get_correct_argnum(const_tree decl, const_tree correct_argnum_of_decl, unsigned int argnum) +{ -+ struct walk_use_def_data use_def_data; ++ struct cgraph_node *node, *correct_argnum_of_node; + -+ use_def_data.parent = parent; -+ use_def_data.next_cnodes_head = NULL; -+ use_def_data.visited = pointer_set_create(); ++ gcc_assert(decl != NULL_TREE); ++ gcc_assert(correct_argnum_of_decl != NULL_TREE); + -+ walk_use_def_next_functions(&use_def_data, node); ++ correct_argnum_of_node = get_cnode(correct_argnum_of_decl); ++ if (!correct_argnum_of_node || DECL_ARTIFICIAL(decl) || DECL_ARTIFICIAL(correct_argnum_of_decl)) ++ return get_correct_argnum_fndecl(decl, correct_argnum_of_decl, argnum); + -+ pointer_set_destroy(use_def_data.visited); -+ return use_def_data.next_cnodes_head; ++ node = get_cnode(decl); ++ return get_correct_argnum_cnode(node, correct_argnum_of_node, argnum); +} + -+// True if child already exists in the next_interesting_function_t children vector -+bool has_next_interesting_function_vec(next_interesting_function_t target, next_interesting_function_t next_node) ++// Find the original cloned function ++tree get_orig_fndecl(const_tree clone_fndecl) +{ -+ unsigned int i; -+ next_interesting_function_t cur; ++ struct cgraph_node *node; + -+ gcc_assert(next_node); -+ // handle recursion -+ if (!strcmp(target->decl_name, next_node->decl_name) && target->num == next_node->num) -+ return true; ++ gcc_assert(TREE_CODE(clone_fndecl) == FUNCTION_DECL); + -+#if BUILDING_GCC_VERSION <= 4007 -+ if (VEC_empty(next_interesting_function_t, target->children)) -+ return false; -+ FOR_EACH_VEC_ELT(next_interesting_function_t, target->children, i, cur) { -+#else -+ FOR_EACH_VEC_SAFE_ELT(target->children, i, cur) { -+#endif -+ if (compare_next_interesting_functions(cur, next_node->decl_name, next_node->context, next_node->num)) -+ return true; -+ } -+ return false; ++ if (DECL_ABSTRACT_ORIGIN(clone_fndecl)) ++ return CONST_CAST_TREE(DECL_ABSTRACT_ORIGIN(clone_fndecl)); ++ node = get_cnode(clone_fndecl); ++ if (!node) ++ return CONST_CAST_TREE(clone_fndecl); ++ ++ while (node->clone_of) ++ node = node->clone_of; ++ if (!made_by_compiler(NODE_DECL(node))) ++ return NODE_DECL(node); ++ // Return the cloned decl because it is needed for the transform callback ++ return CONST_CAST_TREE(clone_fndecl); +} + -+void push_child(next_interesting_function_t parent, next_interesting_function_t child) ++static tree get_interesting_fndecl_from_stmt(const gcall *stmt) +{ -+ if (!has_next_interesting_function_vec(parent, child)) { -+#if BUILDING_GCC_VERSION <= 4007 -+ VEC_safe_push(next_interesting_function_t, heap, parent->children, child); -+#else -+ vec_safe_push(parent->children, child); -+#endif -+ } ++ if (gimple_call_num_args(stmt) == 0) ++ return NULL_TREE; ++ return gimple_call_fndecl(stmt); +} + -+void __attribute__((weak)) check_local_variables(next_interesting_function_t next_node __unused) {} -+ -+// Add children to parent and global_next_interesting_function -+static void collect_data_for_execute(next_interesting_function_t parent, next_interesting_function_t children) ++tree get_interesting_orig_fndecl_from_stmt(const gcall *stmt) +{ -+ next_interesting_function_t cur = children; -+ -+ gcc_assert(parent); -+ -+ while (cur) { -+ struct fn_raw_data child_raw_data; -+ next_interesting_function_t next, child; -+ -+ next = cur->next; ++ tree fndecl; + -+ child_raw_data.decl_str = cur->decl_name; -+ child_raw_data.context = cur->context; -+ child_raw_data.hash = cur->hash; -+ child_raw_data.num = cur->num; -+ child_raw_data.marked = NO_SO_MARK; -+ child = get_global_next_interesting_function_entry(&child_raw_data); -+ if (!child) { -+ add_to_global_next_interesting_function(cur); -+ child = cur; -+ } ++ fndecl = get_interesting_fndecl_from_stmt(stmt); ++ if (fndecl == NULL_TREE) ++ return NULL_TREE; ++ return get_orig_fndecl(fndecl); ++} + -+ check_local_variables(child); ++void set_dominance_info(void) ++{ ++ calculate_dominance_info(CDI_DOMINATORS); ++ calculate_dominance_info(CDI_POST_DOMINATORS); ++} + -+ push_child(parent, child); ++void unset_dominance_info(void) ++{ ++ free_dominance_info(CDI_DOMINATORS); ++ free_dominance_info(CDI_POST_DOMINATORS); ++} + -+ cur = next; -+ } ++void set_current_function_decl(tree fndecl) ++{ ++ gcc_assert(fndecl != NULL_TREE); + -+ check_local_variables(parent); ++ push_cfun(DECL_STRUCT_FUNCTION(fndecl)); ++#if BUILDING_GCC_VERSION <= 4007 ++ current_function_decl = fndecl; ++#endif ++ set_dominance_info(); +} + -+next_interesting_function_t __attribute__((weak)) get_and_create_next_node_from_global_next_nodes_fnptr(const_tree fn_ptr __unused, struct fn_raw_data *raw_data __unused) ++void unset_current_function_decl(void) +{ -+ return NULL; ++ unset_dominance_info(); ++#if BUILDING_GCC_VERSION <= 4007 ++ current_function_decl = NULL_TREE; ++#endif ++ pop_cfun(); +} + -+static next_interesting_function_t create_parent_next_cnode(const_gimple stmt, unsigned int num) ++bool is_valid_cgraph_node(struct cgraph_node *node) +{ -+ struct fn_raw_data raw_data; -+ -+ raw_data.num = num; -+ raw_data.marked = NO_SO_MARK; ++ if (cgraph_function_body_availability(node) == AVAIL_NOT_AVAILABLE) ++ return false; ++ if (node->thunk.thunk_p || node->alias) ++ return false; ++ return true; ++} + ++tree get_lhs(const_gimple stmt) ++{ + switch (gimple_code(stmt)) { -+ case GIMPLE_ASM: -+ raw_data.decl = current_function_decl; -+ raw_data.marked = ASM_STMT_SO_MARK; -+ return get_and_create_next_node_from_global_next_nodes(&raw_data, NULL); ++ case GIMPLE_ASSIGN: + case GIMPLE_CALL: -+ raw_data.decl = gimple_call_fndecl(stmt); -+ if (raw_data.decl != NULL_TREE) -+ return get_and_create_next_node_from_global_next_nodes(&raw_data, NULL); -+ raw_data.decl = gimple_call_fn(stmt); -+ return get_and_create_next_node_from_global_next_nodes_fnptr(raw_data.decl, &raw_data); -+ case GIMPLE_RETURN: -+ raw_data.decl = current_function_decl; -+ return get_and_create_next_node_from_global_next_nodes(&raw_data, NULL); -+ case GIMPLE_ASSIGN: { -+ tree lhs = gimple_assign_lhs(stmt); -+ -+ if (VAR_P(lhs)) -+ raw_data.decl = lhs; -+ else -+ raw_data.decl = get_ref_field(lhs); -+ if (raw_data.decl == NULL_TREE) -+ return NULL; -+ return get_and_create_next_node_from_global_next_nodes(&raw_data, NULL); -+ } ++ return gimple_get_lhs(stmt); ++ case GIMPLE_PHI: ++ return gimple_phi_result(stmt); + default: + debug_gimple_stmt((gimple)stmt); + gcc_unreachable(); + } +} + -+// Handle potential next_interesting_function_t parent if its argument has an integer type -+static void collect_all_possible_size_overflow_fns(const_gimple stmt, tree start_var, unsigned int num) -+{ -+ next_interesting_function_t children_next_cnode, parent_next_cnode; +diff --git a/scripts/gcc-plugins/size_overflow_plugin/size_overflow_plugin.c b/scripts/gcc-plugins/size_overflow_plugin/size_overflow_plugin.c +new file mode 100644 +index 0000000..3f8f032 +--- /dev/null ++++ b/scripts/gcc-plugins/size_overflow_plugin/size_overflow_plugin.c +@@ -0,0 +1,290 @@ ++/* ++ * Copyright 2011-2016 by Emese Revfy ++ * Licensed under the GPL v2, or (at your option) v3 ++ * ++ * Homepage: ++ * https://github.com/ephox-gcc-plugins/size_overflow ++ * ++ * Documentation: ++ * http://forums.grsecurity.net/viewtopic.php?f=7&t=3043 ++ * ++ * This plugin recomputes expressions of function arguments marked by a size_overflow attribute ++ * with double integer precision (DImode/TImode for 32/64 bit integer types). ++ * The recomputed argument is checked against TYPE_MAX and an event is logged on overflow and the triggering process is killed. ++ * ++ * Usage: ++ * $ make ++ * $ make run ++ */ + -+ // skip void return values -+ if (start_var == NULL_TREE) -+ return; ++#include "size_overflow.h" + -+ if (skip_types(start_var)) -+ return; ++int plugin_is_GPL_compatible; + -+ // handle intentional MARK_TURN_OFF -+ if (check_intentional_size_overflow_asm_and_attribute(start_var) == MARK_TURN_OFF) -+ return; ++tree report_size_overflow_decl; + -+ parent_next_cnode = create_parent_next_cnode(stmt, num); -+ if (!parent_next_cnode) -+ return; ++tree size_overflow_type_HI; ++tree size_overflow_type_SI; ++tree size_overflow_type_DI; ++tree size_overflow_type_TI; + -+ children_next_cnode = search_next_functions(start_var, parent_next_cnode); -+ collect_data_for_execute(parent_next_cnode, children_next_cnode); -+} ++static struct plugin_info size_overflow_plugin_info = { ++ .version = "20160521", ++ .help = "no-size-overflow\tturn off size overflow checking\n", ++}; + -+static void collect_all_possible_size_overflow_fields_and_vars(const gassign *assign) ++static tree handle_size_overflow_attribute(tree *node, tree __unused name, tree args, int __unused flags, bool *no_add_attrs) +{ -+ tree start_var, decl, lhs = gimple_assign_lhs(assign); -+ -+ if (VAR_P(lhs)) -+ decl = lhs; -+ else -+ decl = get_ref_field(lhs); -+ if (decl == NULL_TREE) -+ return; ++ unsigned int arg_count; ++ enum tree_code code = TREE_CODE(*node); + -+ if (get_intentional_attr_type(decl) == MARK_TURN_OFF) -+ return; ++ switch (code) { ++ case FUNCTION_DECL: ++ arg_count = type_num_arguments(TREE_TYPE(*node)); ++ break; ++ case FUNCTION_TYPE: ++ case METHOD_TYPE: ++ arg_count = type_num_arguments(*node); ++ break; ++ default: ++ *no_add_attrs = true; ++ debug_tree(*node); ++ error("%s: %qE attribute only applies to functions", __func__, name); ++ return NULL_TREE; ++ } + -+ start_var = gimple_assign_rhs1(assign); -+ collect_all_possible_size_overflow_fns(assign, start_var, 0); ++ for (; args; args = TREE_CHAIN(args)) { ++ int cur_val; ++ tree position = TREE_VALUE(args); + -+ start_var = gimple_assign_rhs2(assign); -+ collect_all_possible_size_overflow_fns(assign, start_var, 0); ++ if (TREE_CODE(position) != INTEGER_CST) { ++ error("%s: parameter isn't an integer", __func__); ++ debug_tree(args); ++ *no_add_attrs = true; ++ return NULL_TREE; ++ } + -+#if BUILDING_GCC_VERSION >= 4006 -+ start_var = gimple_assign_rhs3(assign); -+ collect_all_possible_size_overflow_fns(assign, start_var, 0); -+#endif ++ cur_val = tree_to_shwi(position); ++ if (cur_val < 0 || arg_count < (unsigned int)cur_val) { ++ error("%s: parameter %d is outside range.", __func__, cur_val); ++ *no_add_attrs = true; ++ return NULL_TREE; ++ } ++ } ++ return NULL_TREE; +} + -+// Find potential next_interesting_function_t parents -+static void handle_cgraph_node(struct cgraph_node *node) ++static tree handle_intentional_overflow_attribute(tree *node, tree __unused name, tree args, int __unused flags, bool *no_add_attrs) +{ -+ basic_block bb; -+ tree cur_fndecl = NODE_DECL(node); -+ -+ set_current_function_decl(cur_fndecl); -+ -+ FOR_EACH_BB_FN(bb, cfun) { -+ gimple_stmt_iterator gsi; -+ -+ for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { -+ tree start_var; -+ gimple stmt = gsi_stmt(gsi); ++ unsigned int arg_count; ++ HOST_WIDE_INT s_first_arg; ++ enum tree_code code = TREE_CODE(*node); + -+ switch (gimple_code(stmt)) { -+ case GIMPLE_RETURN: { -+ const greturn *return_stmt = as_a_const_greturn(stmt); ++ switch (code) { ++ case FUNCTION_DECL: ++ arg_count = type_num_arguments(TREE_TYPE(*node)); ++ break; ++ case FUNCTION_TYPE: ++ case METHOD_TYPE: ++ arg_count = type_num_arguments(*node); ++ break; ++ case VAR_DECL: ++ case FIELD_DECL: ++ return NULL_TREE; ++ default: ++ *no_add_attrs = true; ++ debug_tree(*node); ++ error("%qE attribute only applies to functions, fields or vars", name); ++ return NULL_TREE; ++ } + -+ start_var = gimple_return_retval(return_stmt); -+ collect_all_possible_size_overflow_fns(return_stmt, start_var, 0); -+ break; -+ } -+ case GIMPLE_ASM: { -+ const gasm *asm_stmt = as_a_const_gasm(stmt); ++ s_first_arg = tree_to_shwi(TREE_VALUE(args)); ++ if (s_first_arg == -1) ++ return NULL_TREE; ++ if (s_first_arg < -1) ++ error("%s: parameter %d is outside range.", __func__, (int)s_first_arg); + -+ if (!is_size_overflow_insert_check_asm(asm_stmt)) -+ break; -+ start_var = get_size_overflow_asm_input(asm_stmt); -+ collect_all_possible_size_overflow_fns(asm_stmt, start_var, 0); -+ break; -+ } -+ case GIMPLE_CALL: { -+ unsigned int i, len; -+ const gcall *call = as_a_const_gcall(stmt); -+ tree fndecl = gimple_call_fndecl(call); ++ for (; args; args = TREE_CHAIN(args)) { ++ unsigned int cur_val; + -+ if (fndecl != NULL_TREE && (DECL_BUILT_IN(fndecl) || DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL)) -+ break; ++ if (TREE_CODE(TREE_VALUE(args)) != INTEGER_CST) { ++ error("%s: parameter isn't an integer", __func__); ++ debug_tree(args); ++ *no_add_attrs = true; ++ return NULL_TREE; ++ } + -+ len = gimple_call_num_args(call); -+ for (i = 0; i < len; i++) { -+ start_var = gimple_call_arg(call, i); -+ collect_all_possible_size_overflow_fns(call, start_var, i + 1); -+ } -+ break; -+ } -+ case GIMPLE_ASSIGN: -+ collect_all_possible_size_overflow_fields_and_vars(as_a_const_gassign(stmt)); -+ break; -+ default: -+ break; -+ } ++ cur_val = (unsigned int)tree_to_uhwi(TREE_VALUE(args)); ++ if (cur_val > arg_count ) { ++ error("%s: parameter %u is outside range. (arg_count: %u)", __func__, cur_val, arg_count); ++ *no_add_attrs = true; ++ return NULL_TREE; + } + } -+ -+ unset_current_function_decl(); ++ return NULL_TREE; +} + -+/* Collect all potentially interesting function parameters and return values of integer types -+ * and store their data flow dependencies -+ */ -+static void size_overflow_generate_summary(void) ++static struct attribute_spec size_overflow_attr = { ++ .name = "size_overflow", ++ .min_length = 1, ++ .max_length = -1, ++ .decl_required = true, ++ .type_required = false, ++ .function_type_required = false, ++ .handler = handle_size_overflow_attribute, ++#if BUILDING_GCC_VERSION >= 4007 ++ .affects_type_identity = false ++#endif ++}; ++ ++static struct attribute_spec intentional_overflow_attr = { ++ .name = "intentional_overflow", ++ .min_length = 1, ++ .max_length = -1, ++ .decl_required = true, ++ .type_required = false, ++ .function_type_required = false, ++ .handler = handle_intentional_overflow_attribute, ++#if BUILDING_GCC_VERSION >= 4007 ++ .affects_type_identity = false ++#endif ++}; ++ ++static void register_attributes(void __unused *event_data, void __unused *data) +{ -+ struct cgraph_node *node; ++ register_attribute(&size_overflow_attr); ++ register_attribute(&intentional_overflow_attr); ++} + -+ size_overflow_register_hooks(); ++static tree create_typedef(tree type, const char* ident) ++{ ++ tree new_type, decl; + -+ FOR_EACH_FUNCTION(node) { -+ if (is_valid_cgraph_node(node)) -+ handle_cgraph_node(node); -+ } ++ new_type = build_variant_type_copy(type); ++ decl = build_decl(BUILTINS_LOCATION, TYPE_DECL, get_identifier(ident), new_type); ++ DECL_ORIGINAL_TYPE(decl) = type; ++ TYPE_NAME(new_type) = decl; ++ return new_type; +} + -+static void size_overflow_function_insertion_hook(struct cgraph_node *node __unused, void *data __unused) ++// Create the noreturn report_size_overflow() function decl. ++static void size_overflow_start_unit(void __unused *gcc_data, void __unused *user_data) +{ -+ debug_cgraph_node(node); -+ gcc_unreachable(); ++ tree const_char_ptr_type_node; ++ tree fntype; ++ ++ const_char_ptr_type_node = build_pointer_type(build_type_variant(char_type_node, 1, 0)); ++ ++ size_overflow_type_HI = create_typedef(intHI_type_node, "size_overflow_type_HI"); ++ size_overflow_type_SI = create_typedef(intSI_type_node, "size_overflow_type_SI"); ++ size_overflow_type_DI = create_typedef(intDI_type_node, "size_overflow_type_DI"); ++ size_overflow_type_TI = create_typedef(intTI_type_node, "size_overflow_type_TI"); ++ ++ // void report_size_overflow(const char *loc_file, unsigned int loc_line, const char *current_func, const char *ssa_var) ++ fntype = build_function_type_list(void_type_node, ++ const_char_ptr_type_node, ++ unsigned_type_node, ++ const_char_ptr_type_node, ++ const_char_ptr_type_node, ++ NULL_TREE); ++ report_size_overflow_decl = build_fn_decl("report_size_overflow", fntype); ++ ++ DECL_ASSEMBLER_NAME(report_size_overflow_decl); ++ TREE_PUBLIC(report_size_overflow_decl) = 1; ++ DECL_EXTERNAL(report_size_overflow_decl) = 1; ++ DECL_ARTIFICIAL(report_size_overflow_decl) = 1; ++// TREE_THIS_VOLATILE(report_size_overflow_decl) = 1; ++// !!! ++ DECL_PRESERVE_P(report_size_overflow_decl) = 1; ++ DECL_UNINLINABLE(report_size_overflow_decl) = 1; ++ TREE_USED(report_size_overflow_decl) = 1; ++ TREE_NOTHROW(report_size_overflow_decl) = 1; +} + -+/* Handle dst if src is in the global_next_interesting_function list. -+ * If src is a clone then dst inherits the orig_next_node of src otherwise -+ * src will become the orig_next_node of dst. -+ */ -+static void size_overflow_node_duplication_hook(struct cgraph_node *src, struct cgraph_node *dst, void *data __unused) ++static bool disable_ubsan_si_overflow_gate(void) +{ -+ next_interesting_function_t head, cur; -+ struct fn_raw_data src_raw_data; ++#if BUILDING_GCC_VERSION >= 4009 ++ flag_sanitize &= ~SANITIZE_SI_OVERFLOW; ++#endif ++ return true; ++} + -+ src_raw_data.decl = NODE_DECL(src); -+ src_raw_data.decl_str = DECL_NAME_POINTER(src_raw_data.decl); -+ src_raw_data.context = get_decl_context(src_raw_data.decl); -+ if (!src_raw_data.context) -+ return; ++#define PASS_NAME disable_ubsan_si_overflow + -+ src_raw_data.num = NONE_ARGNUM; -+ src_raw_data.marked = NO_SO_MARK; ++#define NO_EXECUTE + -+ head = get_global_next_interesting_function_entry_with_hash(&src_raw_data); -+ if (!head) -+ return; ++#include "gcc-generate-gimple-pass.h" + -+ for (cur = head; cur; cur = cur->next) { -+ struct fn_raw_data dst_raw_data; -+ next_interesting_function_t orig_next_node, next_node; ++int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) ++{ ++ int i; ++ const char * const plugin_name = plugin_info->base_name; ++ const int argc = plugin_info->argc; ++ const struct plugin_argument * const argv = plugin_info->argv; ++ bool enable = true; ++ struct register_pass_info insert_size_overflow_asm_pass_info; ++ struct register_pass_info size_overflow_pass_info; ++#if BUILDING_GCC_VERSION >= 4009 ++ struct register_pass_info disable_ubsan_si_overflow_pass_info; ++#endif + -+ if (!compare_next_interesting_functions(cur, src_raw_data.decl_str, src_raw_data.context, src_raw_data.num)) -+ continue; ++ static const struct ggc_root_tab gt_ggc_r_gt_size_overflow[] = { ++ { ++ .base = &report_size_overflow_decl, ++ .nelt = 1, ++ .stride = sizeof(report_size_overflow_decl), ++ .cb = >_ggc_mx_tree_node, ++ .pchw = >_pch_nx_tree_node ++ }, ++ LAST_GGC_ROOT_TAB ++ }; + -+ dst_raw_data.decl = NODE_DECL(dst); -+ dst_raw_data.decl_str = cgraph_node_name(dst); -+ dst_raw_data.marked = cur->marked; ++ insert_size_overflow_asm_pass_info.pass = make_insert_size_overflow_asm_pass(); ++ insert_size_overflow_asm_pass_info.reference_pass_name = "ssa"; ++ insert_size_overflow_asm_pass_info.ref_pass_instance_number = 1; ++ insert_size_overflow_asm_pass_info.pos_op = PASS_POS_INSERT_AFTER; + -+ if (!made_by_compiler(dst_raw_data.decl)) -+ break; ++ size_overflow_pass_info.pass = make_size_overflow_pass(); ++ size_overflow_pass_info.reference_pass_name = "inline"; ++ size_overflow_pass_info.ref_pass_instance_number = 1; ++ size_overflow_pass_info.pos_op = PASS_POS_INSERT_AFTER; + -+ // For clones use the original node instead -+ if (cur->orig_next_node) -+ orig_next_node = cur->orig_next_node; -+ else -+ orig_next_node = cur; ++ if (!plugin_default_version_check(version, &gcc_version)) { ++ error(G_("incompatible gcc/plugin versions")); ++ return 1; ++ } + -+ dst_raw_data.num = get_correct_argnum_fndecl(src_raw_data.decl, dst_raw_data.decl, cur->num); -+ if (dst_raw_data.num == CANNOT_FIND_ARG) ++ for (i = 0; i < argc; ++i) { ++ if (!strcmp(argv[i].key, "no-size-overflow")) { ++ enable = false; + continue; ++ } ++ error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); ++ } + -+ next_node = create_new_next_interesting_decl(&dst_raw_data, orig_next_node); -+ if (next_node) -+ add_to_global_next_interesting_function(next_node); ++ register_callback(plugin_name, PLUGIN_INFO, NULL, &size_overflow_plugin_info); ++ if (enable) { ++#if BUILDING_GCC_VERSION >= 4009 ++ if (flag_sanitize & SANITIZE_SI_OVERFLOW) { ++ error(G_("ubsan SANITIZE_SI_OVERFLOW option is unsupported")); ++ return 1; ++ } ++#endif ++ register_callback(plugin_name, PLUGIN_START_UNIT, &size_overflow_start_unit, NULL); ++ register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, NULL, (void *)>_ggc_r_gt_size_overflow); ++#if BUILDING_GCC_VERSION >= 4009 ++ flag_sanitize |= SANITIZE_SI_OVERFLOW; ++ disable_ubsan_si_overflow_pass_info.pass = make_disable_ubsan_si_overflow_pass(); ++ disable_ubsan_si_overflow_pass_info.reference_pass_name = "ubsan"; ++ disable_ubsan_si_overflow_pass_info.ref_pass_instance_number = 1; ++ disable_ubsan_si_overflow_pass_info.pos_op = PASS_POS_REPLACE; ++ ++ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &disable_ubsan_si_overflow_pass_info); ++#endif ++ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &insert_size_overflow_asm_pass_info); ++ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &size_overflow_pass_info); + } ++ register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); ++ ++ return 0; +} +diff --git a/scripts/gcc-plugins/size_overflow_plugin/size_overflow_plugin_hash.c b/scripts/gcc-plugins/size_overflow_plugin/size_overflow_plugin_hash.c +new file mode 100644 +index 0000000..87af656 +--- /dev/null ++++ b/scripts/gcc-plugins/size_overflow_plugin/size_overflow_plugin_hash.c +@@ -0,0 +1,352 @@ ++/* ++ * Copyright 2011-2016 by Emese Revfy ++ * Licensed under the GPL v2, or (at your option) v3 ++ * ++ * Homepage: ++ * https://github.com/ephox-gcc-plugins/size_overflow ++ * ++ * Documentation: ++ * http://forums.grsecurity.net/viewtopic.php?f=7&t=3043 ++ * ++ * This plugin recomputes expressions of function arguments marked by a size_overflow attribute ++ * with double integer precision (DImode/TImode for 32/64 bit integer types). ++ * The recomputed argument is checked against TYPE_MAX and an event is logged on overflow and the triggering process is killed. ++ * ++ * Usage: ++ * $ make ++ * $ make run ++ */ + -+void size_overflow_register_hooks(void) -+{ -+ static bool init_p = false; ++#include "size_overflow.h" + -+ if (init_p) -+ return; -+ init_p = true; ++#include "size_overflow_hash.h" ++#include "disable_size_overflow_hash.h" ++#include "size_overflow_hash_aux.h" + -+ function_insertion_hook_holder = cgraph_add_function_insertion_hook(&size_overflow_function_insertion_hook, NULL); -+ node_duplication_hook_holder = cgraph_add_node_duplication_hook(&size_overflow_node_duplication_hook, NULL); ++static const_tree get_function_type(const_tree decl) ++{ ++ if (FUNCTION_PTR_P(decl)) ++ return TREE_TYPE(TREE_TYPE(decl)); ++ gcc_assert(TREE_CODE(decl) == FUNCTION_DECL); ++ return TREE_TYPE(decl); +} + -+static void set_yes_so_mark(next_interesting_function_t next_node) ++static unsigned char get_tree_code(const_tree type) +{ -+ if (next_node->marked == NO_SO_MARK) { -+ next_node->marked = YES_SO_MARK; -+ global_changed = true; ++ switch (TREE_CODE(type)) { ++ case ARRAY_TYPE: ++ return 0; ++ case BOOLEAN_TYPE: ++ return 1; ++ case ENUMERAL_TYPE: ++ return 2; ++ case FUNCTION_TYPE: ++ return 3; ++ case INTEGER_TYPE: ++ return 4; ++ case POINTER_TYPE: ++ return 5; ++ case RECORD_TYPE: ++ return 6; ++ case UNION_TYPE: ++ return 7; ++ case VOID_TYPE: ++ return 8; ++ case REAL_TYPE: ++ return 9; ++ case VECTOR_TYPE: ++ return 10; ++ case REFERENCE_TYPE: ++ return 11; ++ case OFFSET_TYPE: ++ return 12; ++ case COMPLEX_TYPE: ++ return 13; ++ default: ++ debug_tree(type); ++ gcc_unreachable(); + } -+ // Mark the orig decl as well if it's a clone -+ if (next_node->orig_next_node && next_node->orig_next_node->marked == NO_SO_MARK) { -+ next_node->orig_next_node->marked = YES_SO_MARK; -+ global_changed = true; ++} ++ ++// http://www.team5150.com/~andrew/noncryptohashzoo2~/CrapWow.html ++static unsigned int CrapWow(const char *key, unsigned int len, unsigned int seed) ++{ ++#define cwfold( a, b, lo, hi ) { p = (unsigned int)(a) * (unsigned long long)(b); lo ^= (unsigned int)p; hi ^= (unsigned int)(p >> 32); } ++#define cwmixa( in ) { cwfold( in, m, k, h ); } ++#define cwmixb( in ) { cwfold( in, n, h, k ); } ++ ++ unsigned int m = 0x57559429; ++ unsigned int n = 0x5052acdb; ++ const unsigned int *key4 = (const unsigned int *)key; ++ unsigned int h = len; ++ unsigned int k = len + seed + n; ++ unsigned long long p; ++ ++ while (len >= 8) { ++ cwmixb(key4[0]) cwmixa(key4[1]) key4 += 2; ++ len -= 8; ++ } ++ if (len >= 4) { ++ cwmixb(key4[0]) key4 += 1; ++ len -= 4; + } ++ if (len) ++ cwmixa(key4[0] & ((1 << (len * 8)) - 1 )); ++ cwmixb(h ^ (k + n)); ++ return k ^ h; ++ ++#undef cwfold ++#undef cwmixa ++#undef cwmixb +} + -+// Determine whether node or orig node is part of a tracked data flow -+static bool marked_fn(next_interesting_function_t next_node) ++static void set_hash(struct decl_hash *decl_hash_data) +{ -+ bool is_marked_fn, is_marked_orig = false; -+ -+ is_marked_fn = next_node->marked != NO_SO_MARK; -+ -+ if (next_node->orig_next_node) -+ is_marked_orig = next_node->orig_next_node->marked != NO_SO_MARK; ++ unsigned int fn, type, codes, seed = 0; + -+ return is_marked_fn || is_marked_orig; ++ fn = CrapWow(decl_hash_data->fn_name, strlen(decl_hash_data->fn_name), seed) & 0xffff; ++ codes = CrapWow((const char*)decl_hash_data->tree_codes, decl_hash_data->tree_codes_len, seed) & 0xffff; ++ type = CrapWow(decl_hash_data->context, strlen(decl_hash_data->context), 0) & 0xffff; ++ decl_hash_data->hash = type ^ fn ^ codes; +} + -+// Determine whether node or orig node is in the hash table already -+static bool already_in_the_hashtable(next_interesting_function_t next_node) ++static void set_decl_type_codes(const_tree type, struct decl_hash *decl_hash_data) +{ -+ if (next_node->orig_next_node) -+ next_node = next_node->orig_next_node; -+ return get_size_overflow_hash_entry(next_node->hash, next_node->decl_name, next_node->context, next_node->num) != NULL; ++ gcc_assert(type != NULL_TREE); ++ gcc_assert(TREE_CODE_CLASS(TREE_CODE(type)) == tcc_type); ++ ++ while (type && decl_hash_data->tree_codes_len < CODES_LIMIT) { ++ decl_hash_data->tree_codes[decl_hash_data->tree_codes_len] = get_tree_code(type); ++ decl_hash_data->tree_codes_len++; ++ type = TREE_TYPE(type); ++ } +} + -+// Propagate the size_overflow marks up the use-def chains -+static bool has_marked_child(next_interesting_function_t next_node) ++static void set_result_codes(const_tree node, struct decl_hash *decl_hash_data) +{ -+ bool ret = false; -+ unsigned int i; -+ next_interesting_function_t child; ++ const_tree result; + -+#if BUILDING_GCC_VERSION <= 4007 -+ if (VEC_empty(next_interesting_function_t, next_node->children)) -+ return false; -+ FOR_EACH_VEC_ELT(next_interesting_function_t, next_node->children, i, child) { -+#else -+ FOR_EACH_VEC_SAFE_ELT(next_node->children, i, child) { -+#endif -+ if (marked_fn(child) || already_in_the_hashtable(child)) -+ ret = true; ++ gcc_assert(node != NULL_TREE); ++ ++ if (DECL_P(node)) { ++ result = DECL_RESULT(node); ++ if (result != NULL_TREE) ++ return set_decl_type_codes(TREE_TYPE(result), decl_hash_data); ++ return set_result_codes(TREE_TYPE(node), decl_hash_data); + } + -+ return ret; ++ gcc_assert(TYPE_P(node)); ++ ++ if (TREE_CODE(node) == FUNCTION_TYPE) ++ return set_result_codes(TREE_TYPE(node), decl_hash_data); ++ ++ return set_decl_type_codes(node, decl_hash_data); +} + -+/* Set YES_SO_MARK on the function, its orig node and children if: -+ * * the function or its orig node or one of its children is in the hash table already -+ * * the function's orig node is marked with YES_SO_MARK or ASM_STMT_SO_MARK -+ * * one of the children is marked with YES_SO_MARK or ASM_STMT_SO_MARK -+ */ -+static bool set_fn_so_mark(next_interesting_function_t next_node) ++static void set_decl_codes(struct decl_hash *decl_hash_data) +{ -+ bool so_fn, so_hashtable, so_child; ++ const_tree arg, type; ++ enum tree_code code; + -+ so_hashtable = already_in_the_hashtable(next_node); -+ so_fn = marked_fn(next_node); -+ so_child = has_marked_child(next_node); ++ if (TREE_CODE(decl_hash_data->decl) == VAR_DECL || TREE_CODE(decl_hash_data->decl) == FIELD_DECL) { ++ set_decl_type_codes(TREE_TYPE(decl_hash_data->decl), decl_hash_data); ++ return; ++ } + -+ if (!so_fn && !so_hashtable && !so_child) -+ return false; -+ set_yes_so_mark(next_node); -+ return true; ++ type = get_function_type(decl_hash_data->decl); ++ code = TREE_CODE(type); ++ gcc_assert(code == FUNCTION_TYPE || code == METHOD_TYPE); ++ ++ if (FUNCTION_PTR_P(decl_hash_data->decl)) ++ set_result_codes(type, decl_hash_data); ++ else ++ set_result_codes(decl_hash_data->decl, decl_hash_data); ++ ++ for (arg = TYPE_ARG_TYPES(type); arg != NULL_TREE && decl_hash_data->tree_codes_len < CODES_LIMIT; arg = TREE_CHAIN(arg)) ++ set_decl_type_codes(TREE_VALUE(arg), decl_hash_data); +} + -+// Determine if any of the function pointer targets have data flow between the return value and one of the arguments -+static next_interesting_function_t get_same_not_ret_child(next_interesting_function_t parent) ++static const struct size_overflow_hash *get_proper_hash_chain(const struct size_overflow_hash *entry, const char *func_name, const char *context) +{ -+ unsigned int i; -+ next_interesting_function_t child; -+ -+#if BUILDING_GCC_VERSION <= 4007 -+ if (VEC_empty(next_interesting_function_t, parent->children)) -+ return NULL; -+ FOR_EACH_VEC_ELT(next_interesting_function_t, parent->children, i, child) { -+#else -+ FOR_EACH_VEC_SAFE_ELT(parent->children, i, child) { -+#endif -+ if (child->num == 0) -+ continue; -+ if (strcmp(parent->decl_name, child->decl_name)) ++ for (; entry; entry = entry->next) { ++ if (strcmp(entry->name, func_name)) + continue; -+ if (!strcmp(child->context, "fndecl")) -+ return child; ++ if (!strcmp(entry->context, context)) ++ return entry; + } + return NULL; +} + -+/* Trace a return value of function pointer type back to an argument via a concrete function -+ fnptr 0 && fn 0 && (fn 0 -> fn 2) => fnptr 2 */ -+static void search_missing_fptr_arg(next_interesting_function_t parent) ++unsigned int get_decl_hash(const_tree decl, const char *decl_name) +{ -+ next_interesting_function_t child; -+ unsigned int i; -+#if BUILDING_GCC_VERSION <= 4007 -+ VEC(next_interesting_function_t, heap) *new_children = NULL; -+#else -+ vec *new_children = NULL; -+#endif -+ -+ if (parent->num != 0) -+ return; -+ if (!strcmp(parent->context, "fndecl")) -+ return; -+ if (!strncmp(parent->context, "vardecl", sizeof("vardecl") - 1)) -+ return; -+ -+ // fnptr 0 && fn 0 -+#if BUILDING_GCC_VERSION <= 4007 -+ if (VEC_empty(next_interesting_function_t, parent->children)) -+ return; -+ FOR_EACH_VEC_ELT(next_interesting_function_t, parent->children, i, child) { -+#else -+ FOR_EACH_VEC_SAFE_ELT(parent->children, i, child) { -+#endif -+ next_interesting_function_t cur_next_node, tracked_fn; -+ -+ if (child->num != 0) -+ continue; -+ // (fn 0 -> fn 2) -+ tracked_fn = get_same_not_ret_child(child); -+ if (!tracked_fn) -+ continue; ++ struct decl_hash decl_hash_data; ++ enum tree_code code = TREE_CODE(decl); + -+ // fn 2 => fnptr 2 -+ for (cur_next_node = global_next_interesting_function[parent->hash]; cur_next_node; cur_next_node = cur_next_node->next) { -+ if (cur_next_node->num != tracked_fn->num) -+ continue; ++ gcc_assert(code == FIELD_DECL || code == FUNCTION_DECL || code == VAR_DECL); + -+ if (strcmp(parent->decl_name, cur_next_node->decl_name)) -+ continue; ++ // skip builtins __builtin_constant_p ++ if (code == FUNCTION_DECL && (DECL_BUILT_IN(decl) || DECL_BUILT_IN_CLASS(decl) == BUILT_IN_NORMAL)) ++ return NO_HASH; + -+ if (!has_next_interesting_function_vec(parent, cur_next_node)) { -+#if BUILDING_GCC_VERSION <= 4007 -+ VEC_safe_push(next_interesting_function_t, heap, new_children, cur_next_node); -+#else -+ vec_safe_push(new_children, cur_next_node); -+#endif -+ } -+ } -+ } ++ decl_hash_data.fn_name = decl_name; ++ decl_hash_data.decl = decl; ++ decl_hash_data.context = get_decl_context(decl); ++ if (!decl_hash_data.context) ++ return NO_HASH; ++ decl_hash_data.tree_codes_len = 0; + -+#if BUILDING_GCC_VERSION == 4005 -+ if (VEC_empty(next_interesting_function_t, new_children)) -+ return; -+ FOR_EACH_VEC_ELT(next_interesting_function_t, new_children, i, child) -+ VEC_safe_push(next_interesting_function_t, heap, parent->children, child); -+#elif BUILDING_GCC_VERSION <= 4007 -+ VEC_safe_splice(next_interesting_function_t, heap, parent->children, new_children); -+#else -+ vec_safe_splice(parent->children, new_children); -+#endif ++ set_decl_codes(&decl_hash_data); ++ gcc_assert(decl_hash_data.tree_codes_len != 0); ++ set_hash(&decl_hash_data); ++ return decl_hash_data.hash; +} + -+static void walk_so_marked_fns(next_interesting_function_set *visited, next_interesting_function_t parent, bool debug) ++const char *get_orig_decl_name(const_tree decl) +{ -+ unsigned int i; -+ next_interesting_function_t child; ++ const char *name; ++ unsigned int len; ++ const void *end; ++ const_tree orig_decl; + -+ gcc_assert(parent); -+ if (!set_fn_so_mark(parent)) -+ return; ++ if (TREE_CODE(decl) == FUNCTION_DECL) ++ orig_decl = DECL_ORIGIN(decl); ++ else ++ orig_decl = decl; + -+#if BUILDING_GCC_VERSION <= 4007 -+ if (VEC_empty(next_interesting_function_t, parent->children)) -+ return; -+ FOR_EACH_VEC_ELT(next_interesting_function_t, parent->children, i, child) { -+#else -+ FOR_EACH_VEC_SAFE_ELT(parent->children, i, child) { -+#endif -+ set_yes_so_mark(child); ++ len = DECL_NAME_LENGTH(orig_decl); ++ name = DECL_NAME_POINTER(orig_decl); + -+ if (in_lto_p && debug == PRINT_DATA_FLOW) { -+ fprintf(stderr, " PARENT: decl: %s-%u context: %s %p\n", parent->decl_name, parent->num, parent->context, parent); -+ fprintf(stderr, " \tCHILD: decl: %s-%u context: %s %p\n", child->decl_name, child->num, child->context, child); -+ } ++ /* Sometimes gcc loses the original cgraph node leaving only clones behind. ++ * In such cases we will extract the name from the clone and use it in the hash table ++ * without checking the parameter number on the original (unavailable) decl. ++ */ + -+ if (!pointer_set_insert(visited, child)) -+ walk_so_marked_fns(visited, child, debug); ++ if (made_by_compiler(orig_decl)) { ++ end = memchr(name, '.', len); ++ if (!end) ++ return xstrndup(name, len); ++ len = (long)end - (long)name; ++ gcc_assert(len > 0); + } ++ ++ return xstrndup(name, len); +} + -+// Do a depth-first recursive dump of the next_interesting_function_t children vector -+static void print_missing_functions(next_interesting_function_set *visited, next_interesting_function_t parent) ++const struct size_overflow_hash *get_disable_size_overflow_hash_entry(unsigned int hash, const char *decl_name, const char *context, unsigned int argnum) +{ -+ unsigned int i; -+ next_interesting_function_t child; -+ -+ gcc_assert(parent); -+ gcc_assert(parent->marked != NO_SO_MARK); -+ print_missing_function(parent); ++ const struct size_overflow_hash *entry, *entry_node; + -+#if BUILDING_GCC_VERSION <= 4007 -+ if (VEC_empty(next_interesting_function_t, parent->children)) -+ return; -+ FOR_EACH_VEC_ELT(next_interesting_function_t, parent->children, i, child) { -+#else -+ FOR_EACH_VEC_SAFE_ELT(parent->children, i, child) { -+#endif -+ gcc_assert(child->marked != NO_SO_MARK); -+ if (!pointer_set_insert(visited, child)) -+ print_missing_functions(visited, child); -+ } ++ entry = disable_size_overflow_hash[hash]; ++ entry_node = get_proper_hash_chain(entry, decl_name, context); ++ if (entry_node && entry_node->param & (1U << argnum)) ++ return entry_node; ++ return NULL; +} + -+// Set YES_SO_MARK on functions that will be emitted into the hash table -+static void search_so_marked_fns(bool debug) ++const struct size_overflow_hash *get_size_overflow_hash_entry(unsigned int hash, const char *decl_name, const char *context, unsigned int argnum) +{ ++ const struct size_overflow_hash *entry, *entry_node; + -+ unsigned int i; -+ next_interesting_function_set *visited; -+ next_interesting_function_t cur_global; -+ -+ visited = next_interesting_function_pointer_set_create(); -+ for (i = 0; i < GLOBAL_NIFN_LEN; i++) { -+ for (cur_global = global_next_interesting_function[i]; cur_global; cur_global = cur_global->next) { -+ if (cur_global->marked == NO_SO_MARK || pointer_set_insert(visited, cur_global)) -+ continue; -+ -+ if (in_lto_p && debug == PRINT_DATA_FLOW) -+ fprintf(stderr, "Data flow: decl: %s-%u context: %s %p\n", cur_global->decl_name, cur_global->num, cur_global->context, cur_global); -+ -+ walk_so_marked_fns(visited, cur_global, debug); ++ entry = size_overflow_hash[hash]; ++ entry_node = get_proper_hash_chain(entry, decl_name, context); ++ if (entry_node && entry_node->param & (1U << argnum)) ++ return entry_node; + -+ if (in_lto_p && debug == PRINT_DATA_FLOW) -+ fprintf(stderr, "\n"); -+ } -+ } -+ pointer_set_destroy(visited); ++ entry = size_overflow_hash_aux[hash]; ++ entry_node = get_proper_hash_chain(entry, decl_name, context); ++ if (entry_node && entry_node->param & (1U << argnum)) ++ return entry_node; ++ return NULL; +} + -+// Print functions missing from the hash table -+static void print_so_marked_fns(void) ++const struct size_overflow_hash *get_size_overflow_hash_entry_tree(const_tree fndecl, unsigned int argnum, bool hash_table) +{ -+ unsigned int i; -+ next_interesting_function_set *visited; -+ next_interesting_function_t cur_global; ++ const_tree orig_decl; ++ unsigned int orig_argnum, hash; ++ const char *decl_name, *context; + -+ visited = next_interesting_function_pointer_set_create(); -+ for (i = 0; i < GLOBAL_NIFN_LEN; i++) { -+ for (cur_global = global_next_interesting_function[i]; cur_global; cur_global = cur_global->next) { -+ if (cur_global->marked != NO_SO_MARK && !pointer_set_insert(visited, cur_global)) -+ print_missing_functions(visited, cur_global); -+ } ++ if (made_by_compiler(fndecl)) { ++ orig_decl = get_orig_fndecl(fndecl); ++ orig_argnum = get_correct_argnum(fndecl, orig_decl, argnum); ++ } else { ++ orig_decl = fndecl; ++ orig_argnum = argnum; + } -+ pointer_set_destroy(visited); -+} + -+void __attribute__((weak)) check_global_variables(next_interesting_function_t cur_global __unused) {} ++ if (orig_argnum == CANNOT_FIND_ARG) ++ return NULL; + -+// Print all missing interesting functions -+static unsigned int size_overflow_execute(void) -+{ -+ unsigned int i; -+ next_interesting_function_t cur_global; ++ decl_name = get_orig_decl_name(orig_decl); ++ hash = get_decl_hash(orig_decl, decl_name); ++ if (hash == NO_HASH) ++ return NULL; + -+ if (flag_lto && !in_lto_p) -+ return 0; ++ context = get_decl_context(orig_decl); ++ if (!context) ++ return NULL; + -+ // Collect vardecls and funtions reachable by function pointers -+ for (i = 0; i < GLOBAL_NIFN_LEN; i++) { -+ for (cur_global = global_next_interesting_function[i]; cur_global; cur_global = cur_global->next) { -+ check_global_variables(cur_global); -+ search_missing_fptr_arg(cur_global); -+ } -+ } ++ if (hash_table == SIZE_OVERFLOW) ++ return get_size_overflow_hash_entry(hash, decl_name, context, orig_argnum); ++ return get_disable_size_overflow_hash_entry(hash, decl_name, context, orig_argnum); ++} + -+ search_so_marked_fns(PRINT_DATA_FLOW); -+ while (global_changed) { -+ global_changed = false; -+ search_so_marked_fns(NO_PRINT_DATA_FLOW); -+ } ++unsigned int find_arg_number_tree(const_tree arg, const_tree func) ++{ ++ tree var; ++ unsigned int argnum = 1; + -+ print_so_marked_fns(); ++ if (DECL_ARGUMENTS(func) == NULL_TREE) ++ return CANNOT_FIND_ARG; + -+ if (in_lto_p) { -+ fprintf(stderr, "%s: SIZE_OVERFLOW EXECUTE\n", __func__); -+ print_global_next_interesting_functions(); ++ if (TREE_CODE(arg) == SSA_NAME) ++ arg = SSA_NAME_VAR(arg); ++ ++ for (var = DECL_ARGUMENTS(func); var; var = TREE_CHAIN(var), argnum++) { ++ if (!operand_equal_p(arg, var, 0) && strcmp(DECL_NAME_POINTER(var), DECL_NAME_POINTER(arg))) ++ continue; ++ if (!skip_types(var)) ++ return argnum; + } + -+ return 0; ++ return CANNOT_FIND_ARG; +} + -+// Omit the IPA/LTO callbacks until https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61311 gets fixed (license concerns) -+#if BUILDING_GCC_VERSION >= 4008 -+void __attribute__((weak)) size_overflow_write_summary(void) {} -+void __attribute__((weak)) size_overflow_write_optimization_summary(void) {} -+#elif BUILDING_GCC_VERSION >= 4006 -+void __attribute__((weak)) size_overflow_write_summary(cgraph_node_set set __unused, varpool_node_set vset __unused) {} -+void __attribute__((weak)) size_overflow_write_optimization_summary(cgraph_node_set set __unused, varpool_node_set vset __unused) {} -+#else -+void __attribute__((weak)) size_overflow_write_summary(cgraph_node_set set __unused) {} -+void __attribute__((weak)) size_overflow_write_optimization_summary(cgraph_node_set set __unused) {} -+#endif ++const_tree get_attribute(const char* attr_name, const_tree decl) ++{ ++ const_tree attr = lookup_attribute(attr_name, DECL_ATTRIBUTES(decl)); ++ if (attr && TREE_VALUE(attr)) ++ return attr; ++ return NULL_TREE; ++} + -+void __attribute__((weak)) size_overflow_read_summary(void); -+void __attribute__((weak)) size_overflow_read_optimization_summary(void); ++/* Check if the function has a size_overflow attribute or it is in the size_overflow hash table. ++ * If the function is missing everywhere then print the missing message into stderr. ++ */ ++void print_missing_function(next_interesting_function_t node) ++{ ++ unsigned int argnum, hash; ++ const struct size_overflow_hash *entry; ++ const char *decl_name; + -+#define PASS_NAME size_overflow ++ if (node->marked == ASM_STMT_SO_MARK) ++ return; + -+#define NO_STMT_FIXUP -+#define NO_VARIABLE_TRANSFORM -+#define NO_GATE ++ if (node->orig_next_node) { ++ hash = node->orig_next_node->hash; ++ decl_name = node->orig_next_node->decl_name; ++ argnum = node->orig_next_node->num; ++ gcc_assert(!strcmp(node->context, node->orig_next_node->context)); ++ } else { ++ hash = node->hash; ++ decl_name = node->decl_name; ++ argnum = node->num; ++ } + -+#include "gcc-generate-ipa-pass.h" -diff --git a/tools/gcc/size_overflow_plugin/size_overflow_misc.c b/tools/gcc/size_overflow_plugin/size_overflow_misc.c ++ entry = get_size_overflow_hash_entry(hash, decl_name, node->context, argnum); ++ if (entry) ++ return; ++ ++ // inform() would be too slow ++ fprintf(stderr, "Function %s is missing from the size_overflow hash table +%s+%s+%u+%u+\n", decl_name, decl_name, node->context, argnum, hash); ++} ++ +diff --git a/scripts/gcc-plugins/size_overflow_plugin/size_overflow_transform.c b/scripts/gcc-plugins/size_overflow_plugin/size_overflow_transform.c new file mode 100644 -index 0000000..7f459ed +index 0000000..eebcf4c --- /dev/null -+++ b/tools/gcc/size_overflow_plugin/size_overflow_misc.c -@@ -0,0 +1,505 @@ ++++ b/scripts/gcc-plugins/size_overflow_plugin/size_overflow_transform.c +@@ -0,0 +1,743 @@ +/* + * Copyright 2011-2016 by Emese Revfy + * Licensed under the GPL v2, or (at your option) v3 @@ -208621,496 +207074,734 @@ index 0000000..7f459ed + +#include "size_overflow.h" + -+bool is_vararg(const_tree fn, unsigned int num) ++static tree cast_to_orig_type(struct visited *visited, gimple stmt, const_tree orig_node, tree new_node) +{ -+ tree arg_list; ++ gimple def_stmt; ++ const_gimple assign; ++ tree result, orig_type = TREE_TYPE(orig_node); ++ gimple_stmt_iterator gsi; + -+ if (num == 0) -+ return false; -+ if (fn == NULL_TREE) -+ return false; -+ if (TREE_CODE(fn) != FUNCTION_DECL) -+ return false; ++ if (gimple_code(stmt) != GIMPLE_PHI) { ++ gsi = gsi_for_stmt(stmt); ++ assign = build_cast_stmt(visited, orig_type, new_node, CREATE_NEW_VAR, &gsi, BEFORE_STMT, false); ++ return get_lhs(assign); ++ } + -+ arg_list = TYPE_ARG_TYPES(TREE_TYPE(fn)); -+ if (arg_list == NULL_TREE) -+ return false; ++ def_stmt = get_def_stmt(new_node); ++ if (gimple_code(def_stmt) == GIMPLE_PHI) ++ gsi = gsi_after_labels(gimple_bb(def_stmt)); ++ else ++ gsi = gsi_for_stmt(def_stmt); + -+ if (tree_last(arg_list) == void_list_node) -+ return false; ++ result = gimple_phi_result(stmt); ++ assign = build_cast_stmt(visited, orig_type, new_node, SSA_NAME_VAR(result), &gsi, AFTER_STMT, false); ++ return get_lhs(assign); ++} + -+ return num >= (unsigned int)list_length(arg_list); ++static void change_size_overflow_asm_input(gasm *stmt, tree new_input) ++{ ++ tree list; ++ ++ gcc_assert(is_size_overflow_insert_check_asm(stmt)); ++ ++ list = build_tree_list(NULL_TREE, build_string(3, "rm")); ++ list = chainon(NULL_TREE, build_tree_list(list, new_input)); ++ gimple_asm_set_input_op(stmt, 0, list); +} + -+// Extract the field decl from memory references -+tree get_ref_field(const_tree ref) ++static void change_field_write_rhs(gassign *assign, const_tree orig_rhs, tree new_rhs) +{ -+ tree field; ++ const_tree rhs1, rhs2, rhs3 = NULL_TREE; ++ ++ rhs1 = gimple_assign_rhs1(assign); ++ if (rhs1 == orig_rhs) { ++ gimple_assign_set_rhs1(assign, new_rhs); ++ return; ++ } ++ ++ rhs2 = gimple_assign_rhs2(assign); ++ if (rhs2 == orig_rhs) { ++ gimple_assign_set_rhs2(assign, new_rhs); ++ return; ++ } + -+ // TODO: handle nested memory references -+ switch (TREE_CODE(ref)) { -+ case ARRAY_REF: -+ return NULL_TREE; +#if BUILDING_GCC_VERSION >= 4006 -+ case MEM_REF: ++ rhs3 = gimple_assign_rhs3(assign); ++ if (rhs3 == orig_rhs) { ++ gimple_assign_set_rhs3(assign, new_rhs); ++ return; ++ } +#endif -+ case INDIRECT_REF: -+ field = TREE_OPERAND(ref, 0); ++ ++ debug_gimple_stmt(assign); ++ fprintf(stderr, "orig_rhs:\n"); ++ debug_tree(orig_rhs); ++ fprintf(stderr, "rhs1:\n"); ++ debug_tree(rhs1); ++ fprintf(stderr, "rhs2:\n"); ++ debug_tree(rhs2); ++ fprintf(stderr, "rhs3:\n"); ++ debug_tree(rhs3); ++ gcc_unreachable(); ++} ++ ++static void change_phi_arg(gphi *phi, tree new_node, unsigned int num) ++{ ++ unsigned int i; ++ location_t loc = gimple_location(phi); ++ ++ for (i = 0; i < gimple_phi_num_args(phi); i++) { ++ if (i == num) ++ add_phi_arg(phi, new_node, gimple_phi_arg_edge(phi, i), loc); ++ } ++} ++ ++static void change_orig_node(struct visited *visited, gimple stmt, const_tree orig_node, tree new_node, unsigned int num) ++{ ++ tree cast_lhs = cast_to_orig_type(visited, stmt, orig_node, new_node); ++ ++ switch (gimple_code(stmt)) { ++ case GIMPLE_RETURN: ++ gimple_return_set_retval(as_a_greturn(stmt), cast_lhs); + break; -+ case COMPONENT_REF: -+ field = TREE_OPERAND(ref, 1); ++ case GIMPLE_CALL: ++ gimple_call_set_arg(as_a_gcall(stmt), num - 1, cast_lhs); ++ break; ++ case GIMPLE_ASM: ++ change_size_overflow_asm_input(as_a_gasm(stmt), cast_lhs); ++ break; ++ case GIMPLE_ASSIGN: ++ change_field_write_rhs(as_a_gassign(stmt), orig_node, cast_lhs); ++ break; ++ case GIMPLE_PHI: ++ change_phi_arg(as_a_gphi(stmt), cast_lhs, num); + break; + default: -+ return NULL_TREE; ++ debug_gimple_stmt(stmt); ++ gcc_unreachable(); + } + -+ // TODO -+ if (TREE_CODE(field) == SSA_NAME) -+ return NULL_TREE; -+ // TODO -+ if (TREE_CODE(field) != FIELD_DECL) -+ return NULL_TREE; -+ // TODO -+ if (TREE_CODE(field) == ADDR_EXPR) -+ return NULL_TREE; ++ update_stmt(stmt); ++} + -+ return field; ++// e.g., 3.8.2, 64, arch/x86/ia32/ia32_signal.c copy_siginfo_from_user32(): compat_ptr() u32 max ++static bool skip_asm_cast(const_tree arg) ++{ ++ gimple def_stmt = get_def_stmt(arg); ++ ++ if (!def_stmt || !gimple_assign_cast_p(def_stmt)) ++ return false; ++ ++ def_stmt = get_def_stmt(gimple_assign_rhs1(def_stmt)); ++ if (is_size_overflow_asm(def_stmt)) ++ return false; ++ return def_stmt && gimple_code(def_stmt) == GIMPLE_ASM; +} + -+const char *get_type_name_from_field(const_tree field_decl) ++static interesting_stmts_t create_interesting_stmts(interesting_stmts_t head, next_interesting_function_t next_node, tree orig_node, gimple first_stmt, unsigned int num) +{ -+ const_tree context, type_name; ++ interesting_stmts_t new_node; + -+ if (TREE_CODE(field_decl) != FIELD_DECL) -+ return NULL; ++ new_node = (interesting_stmts_t )xmalloc(sizeof(*new_node)); ++ new_node->first_stmt = first_stmt; ++ new_node->num = num; ++ new_node->orig_node = orig_node; ++ new_node->next = head; ++ new_node->next_node = next_node; ++ return new_node; ++} + -+ context = DECL_CONTEXT(field_decl); -+ // TODO -+ if (TREE_CODE(context) != RECORD_TYPE) -+ return NULL; -+ gcc_assert(TREE_CODE(context) == RECORD_TYPE); -+ type_name = TYPE_NAME(TYPE_MAIN_VARIANT(context)); -+ if (type_name == NULL_TREE) -+ return NULL; ++static void free_interesting_stmts(interesting_stmts_t head) ++{ ++ while (head) { ++ interesting_stmts_t cur = head->next; ++ free(head); ++ head = cur; ++ } ++} + -+ if (TREE_CODE(type_name) == IDENTIFIER_NODE) -+ return IDENTIFIER_POINTER(type_name); -+ else if (TREE_CODE(type_name) == TYPE_DECL) -+ return DECL_NAME_POINTER(type_name); ++/* This function calls the main recursion function (expand) that duplicates the stmts. Before that it checks the intentional_overflow attribute, ++ * it decides whether the duplication is necessary or not. After expand() it changes the orig node to the duplicated node ++ * in the original stmt (first stmt) and it inserts the overflow check for the arg of the callee or for the return value. ++ */ ++static interesting_stmts_t search_interesting_stmt(interesting_stmts_t head, next_interesting_function_t next_node, gimple first_stmt, tree orig_node, unsigned int num) ++{ ++ enum tree_code orig_code; + -+ debug_tree(field_decl); -+ debug_tree(type_name); -+ gcc_unreachable(); ++ gcc_assert(orig_node != NULL_TREE); ++ ++ if (is_gimple_constant(orig_node)) ++ return head; ++ ++ orig_code = TREE_CODE(orig_node); ++ gcc_assert(orig_code != FIELD_DECL && orig_code != FUNCTION_DECL); ++ ++ if (skip_types(orig_node)) ++ return head; ++ ++ // find a defining marked caller argument or struct field for arg ++ if (check_intentional_size_overflow_asm_and_attribute(orig_node) != MARK_NO) ++ return head; ++ ++ if (skip_asm_cast(orig_node)) ++ return head; ++ ++ return create_interesting_stmts(head, next_node, orig_node, first_stmt, num); +} + -+// Was the function created by the compiler itself? -+bool made_by_compiler(const_tree decl) ++static bool is_signed_error_code_const(const_tree node) +{ -+ enum tree_code decl_code; -+ struct cgraph_node *node; ++ HOST_WIDE_INT constant = tree_to_shwi(node); + -+ if (FUNCTION_PTR_P(decl)) -+ return false; -+ decl_code = TREE_CODE(decl); -+ if (decl_code == VAR_DECL || decl_code == FIELD_DECL) -+ return false; ++ return constant >= -4095 && constant <= -1; ++} + -+ gcc_assert(decl_code == FUNCTION_DECL); -+ if (DECL_ABSTRACT_ORIGIN(decl) != NULL_TREE && DECL_ABSTRACT_ORIGIN(decl) != decl) -+ return true; -+ if (DECL_ARTIFICIAL(decl)) ++static bool is_unsigned_error_code_const(const_tree node) ++{ ++ unsigned HOST_WIDE_INT constant = tree_to_uhwi(node); ++ ++ // ulong -4095 ++ if (constant >= 0xfffffffffffff001) + return true; ++ // uint -4095 ++ return constant >= 0xfffff001; ++} + -+ node = get_cnode(decl); -+ if (!node) ++static bool is_error_code_const(const_tree node) ++{ ++ enum machine_mode mode; ++ ++ if (!is_gimple_constant(node)) + return false; -+ return node->clone_of != NULL; ++ mode = TYPE_MODE(TREE_TYPE(node)); ++ if (mode != SImode && mode != DImode) ++ return false; ++ ++ if (!TYPE_UNSIGNED(TREE_TYPE(node)) && is_signed_error_code_const(node)) ++ return true; ++ return TYPE_UNSIGNED(TREE_TYPE(node)) && is_unsigned_error_code_const(node); +} + -+bool skip_types(const_tree var) ++static bool has_error_code(gphi *phi) +{ -+ const_tree type; ++ unsigned int i, len = gimple_phi_num_args(phi); + -+ type = TREE_TYPE(var); -+ if (type == NULL_TREE) -+ return true; ++ for (i = 0; i < len; i++) { ++ const_tree arg = gimple_phi_arg_def(phi, i); + -+ switch (TREE_CODE(type)) { -+ case INTEGER_TYPE: -+ case ENUMERAL_TYPE: -+ return false; -+ default: ++ if (is_error_code_const(arg)) + return true; + } ++ ++ return false; +} + -+gimple get_fnptr_def_stmt(const_tree fn_ptr) ++static interesting_stmts_t search_interesting_rets(interesting_stmts_t head, next_interesting_function_t next_node_ret, greturn *ret) +{ -+ gimple def_stmt; ++ tree first_node; + -+ gcc_assert(fn_ptr != NULL_TREE); -+ gcc_assert(FUNCTION_PTR_P(fn_ptr)); ++ if (!next_node_ret || next_node_ret->marked == ASM_STMT_SO_MARK) ++ return head; + -+ if (is_gimple_constant(fn_ptr)) -+ return NULL; ++ first_node = gimple_return_retval(ret); ++ if (first_node == NULL_TREE) ++ return head; + -+ def_stmt = get_def_stmt(fn_ptr); -+ gcc_assert(def_stmt); -+ return def_stmt; ++ return search_interesting_stmt(head, next_node_ret, ret, first_node, 0); +} + -+gimple get_def_stmt(const_tree node) ++static void handle_binary_assign(interesting_stmts_t expand_from, gassign *assign, tree rhs) +{ -+ gcc_assert(node != NULL_TREE); ++ tree new_node; ++ gimple def_orig_node; + -+ if (TREE_CODE(node) != SSA_NAME) -+ return NULL; -+ return SSA_NAME_DEF_STMT(node); ++ new_node = expand(expand_from, rhs); ++ if (new_node == NULL_TREE) ++ return; ++ ++ def_orig_node = get_def_stmt(rhs); ++ if (pointer_set_contains(expand_from->visited->no_cast_check, def_orig_node)) ++ return; ++ change_orig_node(expand_from->visited, assign, rhs, new_node, 0); ++ check_size_overflow(expand_from, assign, TREE_TYPE(new_node), new_node, rhs, BEFORE_STMT); +} + -+tree create_new_var(tree type) ++static bool search_error_codes(gimple_set *visited_error_codes, interesting_stmts_t expand_from, tree lhs, bool error_code) +{ -+ tree new_var = create_tmp_var(type, "cicus"); ++ gimple def_stmt; + -+ add_referenced_var(new_var); -+ return new_var; ++ def_stmt = get_def_stmt(lhs); ++ if (!def_stmt || gimple_code(def_stmt) == GIMPLE_NOP) ++ return error_code; ++ ++ if (pointer_set_insert(visited_error_codes, def_stmt)) ++ return error_code; ++ ++ if (is_gimple_constant(lhs)) ++ return error_code; ++ if (skip_types(lhs)) ++ return is_error_code_const(lhs); ++ ++ switch (gimple_code(def_stmt)) { ++ case GIMPLE_CALL: ++ case GIMPLE_ASM: ++ return error_code; ++ case GIMPLE_ASSIGN: { ++ tree rhs1, rhs2; ++ gassign *assign = as_a_gassign(def_stmt); ++ ++ switch (gimple_num_ops(assign)) { ++ case 2: ++ return search_error_codes(visited_error_codes, expand_from, gimple_assign_rhs1(def_stmt), error_code); ++ case 3: ++ if (!error_code) ++ return error_code; ++ ++ /* Run stmt duplication from the binary assignment ops (rhs1 and rhs2) ++ * so that size_overflow checking skips the lhs of the last binary assignment ++ * before the error code PHI. ++ */ ++ rhs1 = gimple_assign_rhs1(assign); ++ handle_binary_assign(expand_from, assign, rhs1); ++ rhs2 = gimple_assign_rhs2(assign); ++ handle_binary_assign(expand_from, assign, rhs2); ++ return error_code; ++ } ++ gcc_unreachable(); ++ } ++ case GIMPLE_PHI: { ++ unsigned int i; ++ ++ error_code = has_error_code(as_a_gphi(def_stmt)); ++ for (i = 0; i < gimple_phi_num_args(def_stmt); i++) { ++ error_code = search_error_codes(visited_error_codes, expand_from, gimple_phi_arg_def(def_stmt, i), error_code); ++ } ++ return error_code; ++ } ++ default: ++ debug_gimple_stmt(def_stmt); ++ error("%s: unknown gimple code", __func__); ++ gcc_unreachable(); ++ } +} + -+static bool skip_cast(tree dst_type, const_tree rhs, bool force) ++static bool handle_error_codes(interesting_stmts_t expand_from) +{ -+ const_gimple def_stmt = get_def_stmt(rhs); ++ bool error_code; ++ gimple_set *visited_error_codes; + -+ if (force) ++ // expand the data flow from a return stmt ++ if (expand_from->next_node->num != 0 || strcmp(expand_from->next_node->context, "fndecl")) + return false; + -+ if (is_gimple_constant(rhs)) -+ return false; ++ visited_error_codes = pointer_set_create(); ++ error_code = search_error_codes(visited_error_codes, expand_from, expand_from->orig_node, false); ++ pointer_set_destroy(visited_error_codes); + -+ if (!def_stmt || gimple_code(def_stmt) == GIMPLE_NOP) -+ return false; ++ return error_code; ++} + -+ if (!types_compatible_p(dst_type, TREE_TYPE(rhs))) -+ return false; ++static void handle_interesting_stmt(struct visited *visited, interesting_stmts_t head) ++{ ++ interesting_stmts_t cur; + -+ // DI type can be on 32 bit (from create_assign) but overflow type stays DI -+ if (LONG_TYPE_SIZE == GET_MODE_BITSIZE(SImode)) -+ return false; ++ for (cur = head; cur; cur = cur->next) { ++ tree new_node; ++ gimple orig_def_stmt; + -+ return true; ++ cur->visited = visited; ++ if (handle_error_codes(cur)) ++ continue; ++ ++ new_node = expand(cur, cur->orig_node); ++ if (new_node == NULL_TREE) ++ continue; ++ ++ orig_def_stmt = get_def_stmt(cur->orig_node); ++ if (pointer_set_contains(visited->no_cast_check, orig_def_stmt)) ++ continue; ++ change_orig_node(visited, cur->first_stmt, cur->orig_node, new_node, cur->num); ++ check_size_overflow(cur, cur->first_stmt, TREE_TYPE(new_node), new_node, cur->orig_node, BEFORE_STMT); ++ } +} + -+tree cast_a_tree(tree type, tree var) ++static next_interesting_function_t get_interesting_function_next_node(tree decl, unsigned int num) +{ -+ gcc_assert(type != NULL_TREE); -+ gcc_assert(var != NULL_TREE); -+ gcc_assert(fold_convertible_p(type, var)); ++ next_interesting_function_t next_node; ++ const struct size_overflow_hash *so_hash; ++ struct fn_raw_data raw_data; + -+ return fold_convert(type, var); ++ raw_data.decl = decl; ++ raw_data.decl_str = DECL_NAME_POINTER(decl); ++ raw_data.num = num; ++ raw_data.marked = YES_SO_MARK; ++ ++ next_node = get_global_next_interesting_function_entry_with_hash(&raw_data); ++ if (next_node && next_node->marked != NO_SO_MARK) ++ return next_node; ++ ++ so_hash = get_size_overflow_hash_entry_tree(raw_data.decl, raw_data.num, SIZE_OVERFLOW); ++ if (so_hash) ++ return get_and_create_next_node_from_global_next_nodes(&raw_data, NULL); ++ return NULL; +} + -+gimple build_cast_stmt(struct visited *visited, tree dst_type, tree rhs, tree lhs, gimple_stmt_iterator *gsi, bool before, bool force) ++tree handle_fnptr_assign(const_gimple stmt) +{ -+ gassign *assign; -+ gimple def_stmt; ++ tree field, rhs, op0; ++ const_tree op0_type; ++ enum tree_code rhs_code; + -+ gcc_assert(dst_type != NULL_TREE && rhs != NULL_TREE); -+ gcc_assert(!is_gimple_constant(rhs)); -+ if (gsi_end_p(*gsi) && before == AFTER_STMT) -+ gcc_unreachable(); ++ // TODO skip binary assignments for now (fs/sync.c _591 = __bpf_call_base + _590;) ++ if (gimple_num_ops(stmt) != 2) ++ return NULL_TREE; + -+ def_stmt = get_def_stmt(rhs); -+ if (def_stmt && gimple_code(def_stmt) != GIMPLE_NOP && skip_cast(dst_type, rhs, force) && pointer_set_contains(visited->my_stmts, def_stmt)) -+ return def_stmt; ++ gcc_assert(gimple_num_ops(stmt) == 2); ++ // TODO skip asm_stmt for now ++ if (gimple_code(stmt) == GIMPLE_ASM) ++ return NULL_TREE; ++ rhs = gimple_assign_rhs1(stmt); ++ if (is_gimple_constant(rhs)) ++ return NULL_TREE; + -+ if (lhs == CREATE_NEW_VAR) -+ lhs = create_new_var(dst_type); ++ rhs_code = TREE_CODE(rhs); ++ if (rhs_code == VAR_DECL) ++ return rhs; + -+ assign = gimple_build_assign(lhs, cast_a_tree(dst_type, rhs)); ++ switch (rhs_code) { ++ case ADDR_EXPR: ++ op0 = TREE_OPERAND(rhs, 0); ++ gcc_assert(TREE_CODE(op0) == FUNCTION_DECL); ++ return op0; ++ case COMPONENT_REF: ++ break; ++ // TODO skip array_ref for now ++ case ARRAY_REF: ++ return NULL_TREE; ++ // TODO skip ssa_name because it can lead to parm_decl ++ case SSA_NAME: ++ return NULL_TREE; ++ // TODO skip mem_ref and indirect_ref for now ++#if BUILDING_GCC_VERSION >= 4006 ++ case MEM_REF: ++#endif ++ case INDIRECT_REF: ++ return NULL_TREE; ++ default: ++ debug_tree(rhs); ++ debug_gimple_stmt((gimple)stmt); ++ gcc_unreachable(); ++ } + -+ if (!gsi_end_p(*gsi)) { -+ location_t loc = gimple_location(gsi_stmt(*gsi)); -+ gimple_set_location(assign, loc); ++ op0 = TREE_OPERAND(rhs, 0); ++ switch (TREE_CODE(op0)) { ++ // TODO skip array_ref and parm_decl for now ++ case ARRAY_REF: ++ case PARM_DECL: ++ return NULL_TREE; ++ case COMPONENT_REF: ++#if BUILDING_GCC_VERSION >= 4006 ++ case MEM_REF: ++#endif ++ case INDIRECT_REF: ++ case VAR_DECL: ++ break; ++ default: ++ debug_tree(op0); ++ gcc_unreachable(); + } + -+ gimple_assign_set_lhs(assign, make_ssa_name(lhs, assign)); ++ op0_type = TREE_TYPE(op0); ++ // TODO skip unions for now ++ if (TREE_CODE(op0_type) == UNION_TYPE) ++ return NULL_TREE; ++ gcc_assert(TREE_CODE(op0_type) == RECORD_TYPE); + -+ if (before) -+ gsi_insert_before(gsi, assign, GSI_NEW_STMT); -+ else -+ gsi_insert_after(gsi, assign, GSI_NEW_STMT); -+ update_stmt(assign); -+ return assign; ++ field = TREE_OPERAND(rhs, 1); ++ gcc_assert(TREE_CODE(field) == FIELD_DECL); ++ return field; +} + -+bool is_size_overflow_type(const_tree var) ++static tree get_fn_or_fnptr_decl(const gcall *call_stmt) +{ -+ const char *name; -+ const_tree type_name, type; -+ -+ if (var == NULL_TREE) -+ return false; ++ const_tree fnptr; ++ const_gimple def_stmt; ++ tree decl = gimple_call_fndecl(call_stmt); + -+ type = TREE_TYPE(var); -+ type_name = TYPE_NAME(type); -+ if (type_name == NULL_TREE) -+ return false; ++ if (decl != NULL_TREE) ++ return decl; + -+ if (DECL_P(type_name)) -+ name = DECL_NAME_POINTER(type_name); -+ else -+ name = IDENTIFIER_POINTER(type_name); ++ fnptr = gimple_call_fn(call_stmt); ++ if (fnptr == NULL_TREE) ++ return NULL_TREE; + -+ if (!strncmp(name, "size_overflow_type", 18)) -+ return true; -+ return false; ++ // !!! assertot kell irni 0-ra, mert csak az lehet ott ++ if (is_gimple_constant(fnptr)) ++ return NULL_TREE; ++ def_stmt = get_fnptr_def_stmt(fnptr); ++ return handle_fnptr_assign(def_stmt); +} + -+// Determine if a cloned function has all the original arguments -+static bool unchanged_arglist(struct cgraph_node *new_node, struct cgraph_node *old_node) ++// Start stmt duplication on marked function parameters ++static interesting_stmts_t search_interesting_calls(interesting_stmts_t head, gcall *call_stmt) +{ -+ const_tree new_decl_list, old_decl_list; ++ tree decl; ++ unsigned int i, len; + -+ if (new_node->clone_of && new_node->clone.tree_map) -+ return !new_node->clone.args_to_skip; ++ len = gimple_call_num_args(call_stmt); ++ if (len == 0) ++ return head; + -+ new_decl_list = DECL_ARGUMENTS(NODE_DECL(new_node)); -+ old_decl_list = DECL_ARGUMENTS(NODE_DECL(old_node)); -+ if (new_decl_list != NULL_TREE && old_decl_list != NULL_TREE) -+ gcc_assert(list_length(new_decl_list) == list_length(old_decl_list)); ++ decl = get_fn_or_fnptr_decl(call_stmt); ++ if (decl == NULL_TREE) ++ return head; + -+ return true; ++ for (i = 0; i < len; i++) { ++ tree arg; ++ next_interesting_function_t next_node; ++ ++ arg = gimple_call_arg(call_stmt, i); ++ if (is_gimple_constant(arg)) ++ continue; ++ if (skip_types(arg)) ++ continue; ++ next_node = get_interesting_function_next_node(decl, i + 1); ++ if (next_node) ++ head = search_interesting_stmt(head, next_node, call_stmt, arg, i + 1); ++ } ++ ++ return head; +} + -+unsigned int get_correct_argnum_fndecl(const_tree fndecl, const_tree correct_argnum_of_fndecl, unsigned int num) ++// Find assignements to structure fields and vardecls ++static interesting_stmts_t search_interesting_structs_vardecls(interesting_stmts_t head, gassign *assign) +{ -+ unsigned int new_num; -+ const_tree fndecl_arg; -+ tree fndecl_arglist = DECL_ARGUMENTS(fndecl); -+ const_tree arg, target_fndecl_arglist; -+ -+ if (num == 0) -+ return num; ++ enum intentional_mark mark; ++ next_interesting_function_t next_node; ++ tree rhs1, rhs2, lhs, decl; ++#if BUILDING_GCC_VERSION >= 4006 ++ tree rhs3; ++#endif + -+ if (fndecl == correct_argnum_of_fndecl && !DECL_ARTIFICIAL(fndecl)) -+ return num; -+ else if (fndecl == correct_argnum_of_fndecl && DECL_ARTIFICIAL(fndecl)) -+ return CANNOT_FIND_ARG; ++ lhs = gimple_assign_lhs(assign); + -+ target_fndecl_arglist = DECL_ARGUMENTS(correct_argnum_of_fndecl); -+ if (fndecl_arglist == NULL_TREE || target_fndecl_arglist == NULL_TREE) -+ return CANNOT_FIND_ARG; ++ if (VAR_P(lhs)) ++ decl = lhs; ++ else ++ decl = get_ref_field(lhs); ++ if (decl == NULL_TREE) ++ return head; ++ if (DECL_NAME(decl) == NULL_TREE) ++ return head; + -+ fndecl_arg = chain_index(num - 1, fndecl_arglist); -+ if (fndecl_arg == NULL_TREE) -+ return CANNOT_FIND_ARG; ++ if (is_bitfield_unnamed_cast(decl, assign)) ++ return head; + -+ for (arg = target_fndecl_arglist, new_num = 1; arg; arg = TREE_CHAIN(arg), new_num++) { -+ if (arg == fndecl_arg || !strcmp(DECL_NAME_POINTER(arg), DECL_NAME_POINTER(fndecl_arg))) -+ return new_num; -+ } ++ next_node = get_interesting_function_next_node(decl, 0); ++ if (!next_node) ++ return head; + -+ return CANNOT_FIND_ARG; -+} ++ mark = get_intentional_attr_type(decl); ++ if (mark != MARK_NO) ++ return head; + -+// Find the specified argument in the originally cloned function -+static unsigned int clone_argnum_on_orig(struct cgraph_node *new_node, struct cgraph_node *old_node, unsigned int clone_argnum) -+{ -+ bitmap args_to_skip; -+ unsigned int i, new_argnum = clone_argnum; ++ rhs1 = gimple_assign_rhs1(assign); ++ head = search_interesting_stmt(head, next_node, assign, rhs1, 0); + -+ if (unchanged_arglist(new_node, old_node)) -+ return clone_argnum; ++ rhs2 = gimple_assign_rhs2(assign); ++ if (rhs2) ++ head = search_interesting_stmt(head, next_node, assign, rhs2, 0); + -+ gcc_assert(new_node->clone_of && new_node->clone.tree_map); -+ args_to_skip = new_node->clone.args_to_skip; -+ for (i = 0; i < clone_argnum; i++) { -+ if (bitmap_bit_p(args_to_skip, i)) -+ new_argnum++; -+ } -+ return new_argnum; ++#if BUILDING_GCC_VERSION >= 4006 ++ rhs3 = gimple_assign_rhs3(assign); ++ if (rhs3) ++ head = search_interesting_stmt(head, next_node, assign, rhs3, 0); ++#endif ++ return head; +} + -+// Find the specified argument in the clone -+static unsigned int orig_argnum_on_clone(struct cgraph_node *new_node, struct cgraph_node *old_node, unsigned int orig_argnum) ++static next_interesting_function_t create_so_asm_next_interesting_function_node(const gasm *stmt) +{ -+ bitmap args_to_skip; -+ unsigned int i, new_argnum = orig_argnum; ++ next_interesting_function_t next_node; ++ struct fn_raw_data raw_data; + -+ if (unchanged_arglist(new_node, old_node)) -+ return orig_argnum; ++ raw_data.decl = NULL_TREE; ++ raw_data.decl_str = gimple_asm_string(stmt); ++ raw_data.context = "attr"; ++ raw_data.hash = 0; ++ raw_data.num = 0; ++ raw_data.marked = ASM_STMT_SO_MARK; + -+ gcc_assert(new_node->clone_of && new_node->clone.tree_map); -+ args_to_skip = new_node->clone.args_to_skip; -+ if (bitmap_bit_p(args_to_skip, orig_argnum - 1)) -+ // XXX torolni kellene a nodeot -+ return CANNOT_FIND_ARG; ++ next_node = get_global_next_interesting_function_entry(&raw_data); ++ if (next_node) ++ return next_node; ++ next_node = create_new_next_interesting_entry(&raw_data, NULL); ++ gcc_assert(next_node); + -+ for (i = 0; i < orig_argnum; i++) { -+ if (bitmap_bit_p(args_to_skip, i)) -+ new_argnum--; -+ } -+ return new_argnum; ++ add_to_global_next_interesting_function(next_node); ++ return next_node; +} + -+// Associate the argument between a clone and a cloned function -+static unsigned int get_correct_argnum_cnode(struct cgraph_node *node, struct cgraph_node *correct_argnum_of_node, unsigned int argnum) ++// Collect interesting stmts for duplication ++static void search_interesting_stmts(struct visited *visited) +{ -+ bool node_clone, correct_argnum_of_node_clone; -+ const_tree correct_argnum_of_node_decl, node_decl; ++ basic_block bb; ++ next_interesting_function_t next_node_ret; ++ interesting_stmts_t head = NULL; + -+ if (node == correct_argnum_of_node) -+ return argnum; -+ if (argnum == 0) -+ return argnum; ++ next_node_ret = get_interesting_function_next_node(current_function_decl, 0); + -+ correct_argnum_of_node_decl = NODE_DECL(correct_argnum_of_node); -+ gcc_assert(correct_argnum_of_node_decl != NULL_TREE); -+ gcc_assert(correct_argnum_of_node && !DECL_ARTIFICIAL(correct_argnum_of_node_decl)); ++ FOR_EACH_BB_FN(bb, cfun) { ++ gimple_stmt_iterator gsi; + -+ if (node) { -+ node_decl = NODE_DECL(node); -+ gcc_assert(!DECL_ARTIFICIAL(node_decl)); -+ node_clone = made_by_compiler(node_decl); -+ } else { -+ node_decl = NULL_TREE; -+ node_clone = false; -+ } ++ for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { ++ gimple stmt = gsi_stmt(gsi); + -+ if (correct_argnum_of_node_decl == node_decl) -+ return argnum; ++ switch (gimple_code(stmt)) { ++ case GIMPLE_ASM: { ++ tree first_node; ++ next_interesting_function_t next_node; ++ const gasm *asm_stmt = as_a_gasm(stmt); + -+ correct_argnum_of_node_clone = made_by_compiler(correct_argnum_of_node_decl); -+ // the original decl is lost if both nodes are clones -+ if (node_clone && correct_argnum_of_node_clone) { -+ gcc_assert(unchanged_arglist(node, correct_argnum_of_node)); -+ return argnum; ++ if (!is_size_overflow_insert_check_asm(asm_stmt)) ++ continue; ++ next_node = create_so_asm_next_interesting_function_node(asm_stmt); ++ first_node = get_size_overflow_asm_input(asm_stmt); ++ head = search_interesting_stmt(head, next_node, stmt, first_node, 0); ++ break; ++ } ++ case GIMPLE_RETURN: ++ head = search_interesting_rets(head, next_node_ret, as_a_greturn(stmt)); ++ break; ++ case GIMPLE_CALL: ++ head = search_interesting_calls(head, as_a_gcall(stmt)); ++ break; ++ case GIMPLE_ASSIGN: ++ /* !!! TODO LTO modeban nincs duplikalas a globalis valtozora, mert a tree mergek ++ * utan mar nem lehet megkulonboztetni attol a globalis valtozotol, aminek a scopeja csak a file ++ * igy a context nem vardecl lesz, hanem vardecl_filenev. De execute-ban kiirja, ha hianyzik a hash tablabol ++ * IPA-ban van duplikalas. ++ */ ++ head = search_interesting_structs_vardecls(head, as_a_gassign(stmt)); ++ break; ++ default: ++ break; ++ } ++ } + } + -+ if (node_clone && !correct_argnum_of_node_clone) -+ return clone_argnum_on_orig(correct_argnum_of_node, node, argnum); -+ else if (!node_clone && correct_argnum_of_node_clone) -+ return orig_argnum_on_clone(correct_argnum_of_node, node, argnum); -+ -+ if (node) -+ debug_tree(NODE_DECL(node)); -+ debug_tree(correct_argnum_of_node_decl); -+ gcc_unreachable(); ++ handle_interesting_stmt(visited, head); ++ free_interesting_stmts(head); +} + -+unsigned int get_correct_argnum(const_tree decl, const_tree correct_argnum_of_decl, unsigned int argnum) ++static struct visited *create_visited(void) +{ -+ struct cgraph_node *node, *correct_argnum_of_node; ++ struct visited *new_node; + -+ gcc_assert(decl != NULL_TREE); -+ gcc_assert(correct_argnum_of_decl != NULL_TREE); ++ new_node = (struct visited *)xmalloc(sizeof(*new_node)); ++ new_node->stmts = pointer_set_create(); ++ new_node->my_stmts = pointer_set_create(); ++ new_node->skip_expr_casts = pointer_set_create(); ++ new_node->no_cast_check = pointer_set_create(); ++ return new_node; ++} + -+ correct_argnum_of_node = get_cnode(correct_argnum_of_decl); -+ if (!correct_argnum_of_node || DECL_ARTIFICIAL(decl) || DECL_ARTIFICIAL(correct_argnum_of_decl)) -+ return get_correct_argnum_fndecl(decl, correct_argnum_of_decl, argnum); ++static void free_visited(struct visited *visited) ++{ ++ pointer_set_destroy(visited->stmts); ++ pointer_set_destroy(visited->my_stmts); ++ pointer_set_destroy(visited->skip_expr_casts); ++ pointer_set_destroy(visited->no_cast_check); + -+ node = get_cnode(decl); -+ return get_correct_argnum_cnode(node, correct_argnum_of_node, argnum); ++ free(visited); +} + -+// Find the original cloned function -+tree get_orig_fndecl(const_tree clone_fndecl) ++// 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(gasm *asm_stmt, tree lhs, tree rhs) +{ -+ struct cgraph_node *node; ++ gassign *assign; ++ gimple_stmt_iterator gsi; + -+ gcc_assert(TREE_CODE(clone_fndecl) == FUNCTION_DECL); ++ // already removed ++ if (gimple_bb(asm_stmt) == NULL) ++ return; ++ gsi = gsi_for_stmt(asm_stmt); + -+ if (DECL_ABSTRACT_ORIGIN(clone_fndecl)) -+ return CONST_CAST_TREE(DECL_ABSTRACT_ORIGIN(clone_fndecl)); -+ node = get_cnode(clone_fndecl); -+ if (!node) -+ return CONST_CAST_TREE(clone_fndecl); ++ assign = gimple_build_assign(lhs, rhs); ++ gsi_insert_before(&gsi, assign, GSI_SAME_STMT); ++ SSA_NAME_DEF_STMT(lhs) = assign; + -+ while (node->clone_of) -+ node = node->clone_of; -+ if (!made_by_compiler(NODE_DECL(node))) -+ return NODE_DECL(node); -+ // Return the cloned decl because it is needed for the transform callback -+ return CONST_CAST_TREE(clone_fndecl); ++ gsi_remove(&gsi, true); +} + -+static tree get_interesting_fndecl_from_stmt(const gcall *stmt) ++// Replace our asm stmts with assignments (they are no longer needed and may interfere with later optimizations) ++static void remove_size_overflow_asm(gimple stmt) +{ -+ if (gimple_call_num_args(stmt) == 0) -+ return NULL_TREE; -+ return gimple_call_fndecl(stmt); -+} ++ gimple_stmt_iterator gsi; ++ tree input, output; + -+tree get_interesting_orig_fndecl_from_stmt(const gcall *stmt) -+{ -+ tree fndecl; ++ if (!is_size_overflow_asm(stmt)) ++ return; + -+ fndecl = get_interesting_fndecl_from_stmt(stmt); -+ if (fndecl == NULL_TREE) -+ return NULL_TREE; -+ return get_orig_fndecl(fndecl); -+} ++ if (gimple_asm_noutputs(as_a_gasm(stmt)) == 0) { ++ gsi = gsi_for_stmt(stmt); + -+void set_dominance_info(void) -+{ -+ calculate_dominance_info(CDI_DOMINATORS); -+ calculate_dominance_info(CDI_POST_DOMINATORS); ++ ipa_remove_stmt_references(cgraph_get_node(current_function_decl), stmt); ++ gsi_remove(&gsi, true); ++ return; ++ } ++ ++ input = gimple_asm_input_op(as_a_gasm(stmt), 0); ++ output = gimple_asm_output_op(as_a_gasm(stmt), 0); ++ replace_size_overflow_asm_with_assign(as_a_gasm(stmt), TREE_VALUE(output), TREE_VALUE(input)); +} + -+void unset_dominance_info(void) ++static void remove_all_size_overflow_asm(void) +{ -+ free_dominance_info(CDI_DOMINATORS); -+ free_dominance_info(CDI_POST_DOMINATORS); ++ basic_block bb; ++ ++ FOR_EACH_BB_FN(bb, cfun) { ++ gimple_stmt_iterator si; ++ ++ for (si = gsi_start_bb(bb); !gsi_end_p(si); gsi_next(&si)) ++ remove_size_overflow_asm(gsi_stmt(si)); ++ } +} + -+void set_current_function_decl(tree fndecl) ++unsigned int size_overflow_function_transform(struct cgraph_node *node __unused) +{ -+ gcc_assert(fndecl != NULL_TREE); ++ struct visited *visited; + -+ push_cfun(DECL_STRUCT_FUNCTION(fndecl)); -+#if BUILDING_GCC_VERSION <= 4007 -+ current_function_decl = fndecl; ++#if BUILDING_GCC_VERSION >= 4008 ++ if (dump_file) { ++ fprintf(dump_file, "BEFORE TRANSFORM -------------------------\n"); ++ size_overflow_dump_function(dump_file, node); ++ } +#endif ++ visited = create_visited(); + set_dominance_info(); -+} + -+void unset_current_function_decl(void) -+{ -+ unset_dominance_info(); -+#if BUILDING_GCC_VERSION <= 4007 -+ current_function_decl = NULL_TREE; -+#endif -+ pop_cfun(); -+} ++ search_interesting_stmts(visited); + -+bool is_valid_cgraph_node(struct cgraph_node *node) -+{ -+ if (cgraph_function_body_availability(node) == AVAIL_NOT_AVAILABLE) -+ return false; -+ if (node->thunk.thunk_p || node->alias) -+ return false; -+ return true; -+} ++ remove_all_size_overflow_asm(); + -+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: -+ debug_gimple_stmt((gimple)stmt); -+ gcc_unreachable(); ++ unset_dominance_info(); ++ free_visited(visited); ++ ++#if BUILDING_GCC_VERSION >= 4008 ++ if (dump_file) { ++ fprintf(dump_file, "AFTER TRANSFORM -------------------------\n"); ++ size_overflow_dump_function(dump_file, node); + } ++#endif ++ return TODO_dump_func | TODO_verify_stmts | TODO_remove_unused_locals | TODO_update_ssa_no_phi | TODO_ggc_collect | TODO_verify_flow; +} -+ -diff --git a/tools/gcc/size_overflow_plugin/size_overflow_plugin.c b/tools/gcc/size_overflow_plugin/size_overflow_plugin.c +diff --git a/scripts/gcc-plugins/size_overflow_plugin/size_overflow_transform_core.c b/scripts/gcc-plugins/size_overflow_plugin/size_overflow_transform_core.c new file mode 100644 -index 0000000..3f8f032 +index 0000000..062204a --- /dev/null -+++ b/tools/gcc/size_overflow_plugin/size_overflow_plugin.c -@@ -0,0 +1,290 @@ ++++ b/scripts/gcc-plugins/size_overflow_plugin/size_overflow_transform_core.c +@@ -0,0 +1,1025 @@ +/* + * Copyright 2011-2016 by Emese Revfy + * Licensed under the GPL v2, or (at your option) v3 @@ -209132,3014 +207823,5055 @@ index 0000000..3f8f032 + +#include "size_overflow.h" + -+int plugin_is_GPL_compatible; ++#define MIN_CHECK true ++#define MAX_CHECK false + -+tree report_size_overflow_decl; ++unsigned int call_count = 0; + -+tree size_overflow_type_HI; -+tree size_overflow_type_SI; -+tree size_overflow_type_DI; -+tree size_overflow_type_TI; ++tree get_size_overflow_type(struct visited *visited, const_gimple stmt, const_tree node) ++{ ++ const_tree type; ++ tree new_type; + -+static struct plugin_info size_overflow_plugin_info = { -+ .version = "20160521", -+ .help = "no-size-overflow\tturn off size overflow checking\n", -+}; ++ gcc_assert(node != NULL_TREE); + -+static tree handle_size_overflow_attribute(tree *node, tree __unused name, tree args, int __unused flags, bool *no_add_attrs) -+{ -+ unsigned int arg_count; -+ enum tree_code code = TREE_CODE(*node); ++ type = TREE_TYPE(node); + -+ switch (code) { -+ case FUNCTION_DECL: -+ arg_count = type_num_arguments(TREE_TYPE(*node)); ++ if (pointer_set_contains(visited->my_stmts, stmt)) ++ return TREE_TYPE(node); ++ ++ switch (TYPE_MODE(type)) { ++ case QImode: ++ case HImode: ++ new_type = size_overflow_type_SI; + break; -+ case FUNCTION_TYPE: -+ case METHOD_TYPE: -+ arg_count = type_num_arguments(*node); ++ case SImode: ++ new_type = size_overflow_type_DI; ++ break; ++ case DImode: ++ if (LONG_TYPE_SIZE == GET_MODE_BITSIZE(SImode)) ++ new_type = TYPE_UNSIGNED(type) ? unsigned_intDI_type_node : intDI_type_node; ++ else ++ new_type = size_overflow_type_TI; ++ break; ++ case TImode: ++ gcc_assert(!TYPE_UNSIGNED(type)); ++ new_type = size_overflow_type_TI; + break; + default: -+ *no_add_attrs = true; -+ debug_tree(*node); -+ error("%s: %qE attribute only applies to functions", __func__, name); -+ return NULL_TREE; ++ debug_tree(node); ++ error("%s: unsupported gcc configuration (%qE).", __func__, current_function_decl); ++ gcc_unreachable(); + } + -+ for (; args; args = TREE_CHAIN(args)) { -+ int cur_val; -+ tree position = TREE_VALUE(args); ++ if (TYPE_QUALS(type) != 0) ++ return build_qualified_type(new_type, TYPE_QUALS(type)); ++ return new_type; ++} + -+ if (TREE_CODE(position) != INTEGER_CST) { -+ error("%s: parameter isn't an integer", __func__); -+ debug_tree(args); -+ *no_add_attrs = true; -+ return NULL_TREE; -+ } ++tree cast_to_new_size_overflow_type(struct visited *visited, gimple stmt, tree rhs, tree size_overflow_type, bool before) ++{ ++ gimple_stmt_iterator gsi; ++ gimple new_stmt; + -+ cur_val = tree_to_shwi(position); -+ if (cur_val < 0 || arg_count < (unsigned int)cur_val) { -+ error("%s: parameter %d is outside range.", __func__, cur_val); -+ *no_add_attrs = true; -+ return NULL_TREE; -+ } -+ } -+ return NULL_TREE; ++ if (rhs == NULL_TREE) ++ return NULL_TREE; ++ ++ gsi = gsi_for_stmt(stmt); ++ new_stmt = build_cast_stmt(visited, size_overflow_type, rhs, CREATE_NEW_VAR, &gsi, before, false); ++ if (gimple_assign_cast_p(new_stmt)) ++ gimple_assign_set_rhs_code(new_stmt, CONVERT_EXPR); ++ pointer_set_insert(visited->my_stmts, new_stmt); ++ ++ return get_lhs(new_stmt); +} + -+static tree handle_intentional_overflow_attribute(tree *node, tree __unused name, tree args, int __unused flags, bool *no_add_attrs) ++tree create_assign(struct visited *visited, gimple oldstmt, tree rhs1, bool before) +{ -+ unsigned int arg_count; -+ HOST_WIDE_INT s_first_arg; -+ enum tree_code code = TREE_CODE(*node); ++ tree lhs, dst_type; ++ gimple_stmt_iterator gsi; + -+ switch (code) { -+ case FUNCTION_DECL: -+ arg_count = type_num_arguments(TREE_TYPE(*node)); ++ if (rhs1 == NULL_TREE) { ++ debug_gimple_stmt(oldstmt); ++ error("%s: rhs1 is NULL_TREE", __func__); ++ gcc_unreachable(); ++ } ++ ++ switch (gimple_code(oldstmt)) { ++ case GIMPLE_ASM: ++ lhs = rhs1; + break; -+ case FUNCTION_TYPE: -+ case METHOD_TYPE: -+ arg_count = type_num_arguments(*node); ++ case GIMPLE_CALL: ++ case GIMPLE_ASSIGN: ++ lhs = gimple_get_lhs(oldstmt); + break; -+ case VAR_DECL: -+ case FIELD_DECL: -+ return NULL_TREE; + default: -+ *no_add_attrs = true; -+ debug_tree(*node); -+ error("%qE attribute only applies to functions, fields or vars", name); -+ return NULL_TREE; ++ debug_gimple_stmt(oldstmt); ++ gcc_unreachable(); + } + -+ s_first_arg = tree_to_shwi(TREE_VALUE(args)); -+ if (s_first_arg == -1) -+ return NULL_TREE; -+ if (s_first_arg < -1) -+ error("%s: parameter %d is outside range.", __func__, (int)s_first_arg); -+ -+ for (; args; args = TREE_CHAIN(args)) { -+ unsigned int cur_val; -+ -+ if (TREE_CODE(TREE_VALUE(args)) != INTEGER_CST) { -+ error("%s: parameter isn't an integer", __func__); -+ debug_tree(args); -+ *no_add_attrs = true; -+ return NULL_TREE; -+ } ++ gsi = gsi_for_stmt(oldstmt); ++ pointer_set_insert(visited->stmts, oldstmt); ++ if (lookup_stmt_eh_lp(oldstmt) != 0) { ++ basic_block next_bb, cur_bb; ++ const_edge e; + -+ cur_val = (unsigned int)tree_to_uhwi(TREE_VALUE(args)); -+ if (cur_val > arg_count ) { -+ error("%s: parameter %u is outside range. (arg_count: %u)", __func__, cur_val, arg_count); -+ *no_add_attrs = true; -+ return NULL_TREE; -+ } -+ } -+ return NULL_TREE; -+} ++ gcc_assert(before == false); ++ gcc_assert(stmt_can_throw_internal(oldstmt)); ++ gcc_assert(gimple_code(oldstmt) == GIMPLE_CALL); ++ gcc_assert(!gsi_end_p(gsi)); + -+static struct attribute_spec size_overflow_attr = { -+ .name = "size_overflow", -+ .min_length = 1, -+ .max_length = -1, -+ .decl_required = true, -+ .type_required = false, -+ .function_type_required = false, -+ .handler = handle_size_overflow_attribute, -+#if BUILDING_GCC_VERSION >= 4007 -+ .affects_type_identity = false -+#endif -+}; ++ cur_bb = gimple_bb(oldstmt); ++ next_bb = cur_bb->next_bb; ++ e = find_edge(cur_bb, next_bb); ++ gcc_assert(e != NULL); ++ gcc_assert(e->flags & EDGE_FALLTHRU); + -+static struct attribute_spec intentional_overflow_attr = { -+ .name = "intentional_overflow", -+ .min_length = 1, -+ .max_length = -1, -+ .decl_required = true, -+ .type_required = false, -+ .function_type_required = false, -+ .handler = handle_intentional_overflow_attribute, -+#if BUILDING_GCC_VERSION >= 4007 -+ .affects_type_identity = false -+#endif -+}; ++ gsi = gsi_after_labels(next_bb); ++ gcc_assert(!gsi_end_p(gsi)); + -+static void register_attributes(void __unused *event_data, void __unused *data) -+{ -+ register_attribute(&size_overflow_attr); -+ register_attribute(&intentional_overflow_attr); -+} ++ before = true; ++ oldstmt = gsi_stmt(gsi); ++ } + -+static tree create_typedef(tree type, const char* ident) -+{ -+ tree new_type, decl; ++ if (is_gimple_constant(rhs1) && TREE_CODE_CLASS(gimple_assign_rhs_code(oldstmt)) == tcc_comparison) ++ dst_type = get_size_overflow_type(visited, oldstmt, rhs1); ++ else ++ dst_type = get_size_overflow_type(visited, oldstmt, lhs); + -+ new_type = build_variant_type_copy(type); -+ decl = build_decl(BUILTINS_LOCATION, TYPE_DECL, get_identifier(ident), new_type); -+ DECL_ORIGINAL_TYPE(decl) = type; -+ TYPE_NAME(new_type) = decl; -+ return new_type; ++ if (is_gimple_constant(rhs1)) ++ return cast_a_tree(dst_type, rhs1); ++ return cast_to_new_size_overflow_type(visited, oldstmt, rhs1, dst_type, before); +} + -+// Create the noreturn report_size_overflow() function decl. -+static void size_overflow_start_unit(void __unused *gcc_data, void __unused *user_data) ++tree dup_assign(struct visited *visited, gassign *oldstmt, const_tree node, tree rhs1, tree rhs2, tree __unused rhs3) +{ -+ tree const_char_ptr_type_node; -+ tree fntype; -+ -+ const_char_ptr_type_node = build_pointer_type(build_type_variant(char_type_node, 1, 0)); ++ gassign *stmt; ++ gimple_stmt_iterator gsi; ++ tree size_overflow_type, new_var, lhs = gimple_assign_lhs(oldstmt); + -+ size_overflow_type_HI = create_typedef(intHI_type_node, "size_overflow_type_HI"); -+ size_overflow_type_SI = create_typedef(intSI_type_node, "size_overflow_type_SI"); -+ size_overflow_type_DI = create_typedef(intDI_type_node, "size_overflow_type_DI"); -+ size_overflow_type_TI = create_typedef(intTI_type_node, "size_overflow_type_TI"); ++ if (pointer_set_contains(visited->my_stmts, oldstmt)) ++ return lhs; + -+ // void report_size_overflow(const char *loc_file, unsigned int loc_line, const char *current_func, const char *ssa_var) -+ fntype = build_function_type_list(void_type_node, -+ const_char_ptr_type_node, -+ unsigned_type_node, -+ const_char_ptr_type_node, -+ const_char_ptr_type_node, -+ NULL_TREE); -+ report_size_overflow_decl = build_fn_decl("report_size_overflow", fntype); ++ if (gimple_num_ops(oldstmt) != 4 && rhs1 == NULL_TREE) { ++ rhs1 = gimple_assign_rhs1(oldstmt); ++ rhs1 = create_assign(visited, oldstmt, rhs1, BEFORE_STMT); ++ } ++ if (gimple_num_ops(oldstmt) == 3 && rhs2 == NULL_TREE) { ++ rhs2 = gimple_assign_rhs2(oldstmt); ++ rhs2 = create_assign(visited, oldstmt, rhs2, BEFORE_STMT); ++ } + -+ DECL_ASSEMBLER_NAME(report_size_overflow_decl); -+ TREE_PUBLIC(report_size_overflow_decl) = 1; -+ DECL_EXTERNAL(report_size_overflow_decl) = 1; -+ DECL_ARTIFICIAL(report_size_overflow_decl) = 1; -+// TREE_THIS_VOLATILE(report_size_overflow_decl) = 1; -+// !!! -+ DECL_PRESERVE_P(report_size_overflow_decl) = 1; -+ DECL_UNINLINABLE(report_size_overflow_decl) = 1; -+ TREE_USED(report_size_overflow_decl) = 1; -+ TREE_NOTHROW(report_size_overflow_decl) = 1; -+} ++ stmt = as_a_gassign(gimple_copy(oldstmt)); ++ gimple_set_location(stmt, gimple_location(oldstmt)); ++ pointer_set_insert(visited->my_stmts, stmt); + -+static bool disable_ubsan_si_overflow_gate(void) -+{ -+#if BUILDING_GCC_VERSION >= 4009 -+ flag_sanitize &= ~SANITIZE_SI_OVERFLOW; -+#endif -+ return true; -+} ++ if (gimple_assign_rhs_code(oldstmt) == WIDEN_MULT_EXPR) ++ gimple_assign_set_rhs_code(stmt, MULT_EXPR); + -+#define PASS_NAME disable_ubsan_si_overflow ++ size_overflow_type = get_size_overflow_type(visited, oldstmt, node); + -+#define NO_EXECUTE ++ new_var = create_new_var(size_overflow_type); ++ new_var = make_ssa_name(new_var, stmt); ++ gimple_assign_set_lhs(stmt, new_var); + -+#include "gcc-generate-gimple-pass.h" ++ if (rhs1 != NULL_TREE) ++ gimple_assign_set_rhs1(stmt, rhs1); + -+int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) -+{ -+ int i; -+ const char * const plugin_name = plugin_info->base_name; -+ const int argc = plugin_info->argc; -+ const struct plugin_argument * const argv = plugin_info->argv; -+ bool enable = true; -+ struct register_pass_info insert_size_overflow_asm_pass_info; -+ struct register_pass_info size_overflow_pass_info; -+#if BUILDING_GCC_VERSION >= 4009 -+ struct register_pass_info disable_ubsan_si_overflow_pass_info; ++ if (rhs2 != NULL_TREE) ++ gimple_assign_set_rhs2(stmt, rhs2); ++#if BUILDING_GCC_VERSION >= 4006 ++ if (rhs3 != NULL_TREE) ++ gimple_assign_set_rhs3(stmt, rhs3); +#endif ++ gimple_set_vuse(stmt, gimple_vuse(oldstmt)); ++ gimple_set_vdef(stmt, gimple_vdef(oldstmt)); + -+ static const struct ggc_root_tab gt_ggc_r_gt_size_overflow[] = { -+ { -+ .base = &report_size_overflow_decl, -+ .nelt = 1, -+ .stride = sizeof(report_size_overflow_decl), -+ .cb = >_ggc_mx_tree_node, -+ .pchw = >_pch_nx_tree_node -+ }, -+ LAST_GGC_ROOT_TAB -+ }; ++ gsi = gsi_for_stmt(oldstmt); ++ gsi_insert_after(&gsi, stmt, GSI_SAME_STMT); ++ update_stmt(stmt); ++ pointer_set_insert(visited->stmts, oldstmt); ++ return gimple_assign_lhs(stmt); ++} + -+ insert_size_overflow_asm_pass_info.pass = make_insert_size_overflow_asm_pass(); -+ insert_size_overflow_asm_pass_info.reference_pass_name = "ssa"; -+ insert_size_overflow_asm_pass_info.ref_pass_instance_number = 1; -+ insert_size_overflow_asm_pass_info.pos_op = PASS_POS_INSERT_AFTER; ++static tree cast_parm_decl(struct visited *visited, tree phi_ssa_name, tree arg, tree size_overflow_type, basic_block bb) ++{ ++ const_gimple assign; ++ gimple_stmt_iterator gsi; ++ basic_block first_bb; + -+ size_overflow_pass_info.pass = make_size_overflow_pass(); -+ size_overflow_pass_info.reference_pass_name = "inline"; -+ size_overflow_pass_info.ref_pass_instance_number = 1; -+ size_overflow_pass_info.pos_op = PASS_POS_INSERT_AFTER; ++ gcc_assert(SSA_NAME_IS_DEFAULT_DEF(arg)); + -+ if (!plugin_default_version_check(version, &gcc_version)) { -+ error(G_("incompatible gcc/plugin versions")); -+ return 1; ++ if (bb->index == 0) { ++ first_bb = split_block_after_labels(ENTRY_BLOCK_PTR_FOR_FN(cfun))->dest; ++ gcc_assert(dom_info_available_p(CDI_DOMINATORS)); ++ set_immediate_dominator(CDI_DOMINATORS, first_bb, ENTRY_BLOCK_PTR_FOR_FN(cfun)); ++ bb = first_bb; + } + -+ for (i = 0; i < argc; ++i) { -+ if (!strcmp(argv[i].key, "no-size-overflow")) { -+ enable = false; -+ continue; -+ } -+ error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); -+ } ++ gsi = gsi_after_labels(bb); ++ assign = build_cast_stmt(visited, size_overflow_type, arg, phi_ssa_name, &gsi, BEFORE_STMT, false); ++ pointer_set_insert(visited->my_stmts, assign); ++ return get_lhs(assign); ++} + -+ register_callback(plugin_name, PLUGIN_INFO, NULL, &size_overflow_plugin_info); -+ if (enable) { -+#if BUILDING_GCC_VERSION >= 4009 -+ if (flag_sanitize & SANITIZE_SI_OVERFLOW) { -+ error(G_("ubsan SANITIZE_SI_OVERFLOW option is unsupported")); -+ return 1; -+ } -+#endif -+ register_callback(plugin_name, PLUGIN_START_UNIT, &size_overflow_start_unit, NULL); -+ register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, NULL, (void *)>_ggc_r_gt_size_overflow); -+#if BUILDING_GCC_VERSION >= 4009 -+ flag_sanitize |= SANITIZE_SI_OVERFLOW; -+ disable_ubsan_si_overflow_pass_info.pass = make_disable_ubsan_si_overflow_pass(); -+ disable_ubsan_si_overflow_pass_info.reference_pass_name = "ubsan"; -+ disable_ubsan_si_overflow_pass_info.ref_pass_instance_number = 1; -+ disable_ubsan_si_overflow_pass_info.pos_op = PASS_POS_REPLACE; ++static tree use_phi_ssa_name(struct visited *visited, tree ssa_name_var, tree new_arg) ++{ ++ gimple_stmt_iterator gsi; ++ const_gimple assign; ++ gimple def_stmt = get_def_stmt(new_arg); + -+ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &disable_ubsan_si_overflow_pass_info); -+#endif -+ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &insert_size_overflow_asm_pass_info); -+ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &size_overflow_pass_info); ++ if (gimple_code(def_stmt) == GIMPLE_PHI) { ++ gsi = gsi_after_labels(gimple_bb(def_stmt)); ++ assign = build_cast_stmt(visited, TREE_TYPE(new_arg), new_arg, ssa_name_var, &gsi, BEFORE_STMT, true); ++ } else { ++ gsi = gsi_for_stmt(def_stmt); ++ assign = build_cast_stmt(visited, TREE_TYPE(new_arg), new_arg, ssa_name_var, &gsi, AFTER_STMT, true); + } -+ register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); + -+ return 0; ++ pointer_set_insert(visited->my_stmts, assign); ++ return get_lhs(assign); +} -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..87af656 ---- /dev/null -+++ b/tools/gcc/size_overflow_plugin/size_overflow_plugin_hash.c -@@ -0,0 +1,352 @@ -+/* -+ * Copyright 2011-2016 by Emese Revfy -+ * Licensed under the GPL v2, or (at your option) v3 -+ * -+ * Homepage: -+ * https://github.com/ephox-gcc-plugins/size_overflow -+ * -+ * Documentation: -+ * http://forums.grsecurity.net/viewtopic.php?f=7&t=3043 -+ * -+ * This plugin recomputes expressions of function arguments marked by a size_overflow attribute -+ * with double integer precision (DImode/TImode for 32/64 bit integer types). -+ * The recomputed argument is checked against TYPE_MAX and an event is logged on overflow and the triggering process is killed. -+ * -+ * Usage: -+ * $ make -+ * $ make run -+ */ + -+#include "size_overflow.h" ++static tree cast_visited_phi_arg(struct visited *visited, tree ssa_name_var, tree arg, tree size_overflow_type) ++{ ++ basic_block bb; ++ gimple_stmt_iterator gsi; ++ const_gimple def_stmt; ++ const_gimple assign; + -+#include "size_overflow_hash.h" -+#include "disable_size_overflow_hash.h" -+#include "size_overflow_hash_aux.h" ++ def_stmt = get_def_stmt(arg); ++ bb = gimple_bb(def_stmt); ++ gcc_assert(bb->index != 0); ++ gsi = gsi_after_labels(bb); + -+static const_tree get_function_type(const_tree decl) -+{ -+ if (FUNCTION_PTR_P(decl)) -+ return TREE_TYPE(TREE_TYPE(decl)); -+ gcc_assert(TREE_CODE(decl) == FUNCTION_DECL); -+ return TREE_TYPE(decl); ++ assign = build_cast_stmt(visited, size_overflow_type, arg, ssa_name_var, &gsi, BEFORE_STMT, false); ++ pointer_set_insert(visited->my_stmts, assign); ++ return get_lhs(assign); +} + -+static unsigned char get_tree_code(const_tree type) ++static tree create_new_phi_arg(struct visited *visited, tree ssa_name_var, tree new_arg, gphi *oldstmt, unsigned int i) +{ -+ switch (TREE_CODE(type)) { -+ case ARRAY_TYPE: -+ return 0; -+ case BOOLEAN_TYPE: -+ return 1; -+ case ENUMERAL_TYPE: -+ return 2; -+ case FUNCTION_TYPE: -+ return 3; -+ case INTEGER_TYPE: -+ return 4; -+ case POINTER_TYPE: -+ return 5; -+ case RECORD_TYPE: -+ return 6; -+ case UNION_TYPE: -+ return 7; -+ case VOID_TYPE: -+ return 8; -+ case REAL_TYPE: -+ return 9; -+ case VECTOR_TYPE: -+ return 10; -+ case REFERENCE_TYPE: -+ return 11; -+ case OFFSET_TYPE: -+ return 12; -+ case COMPLEX_TYPE: -+ return 13; -+ default: -+ debug_tree(type); -+ gcc_unreachable(); -+ } -+} ++ tree size_overflow_type; ++ tree arg; ++ const_gimple def_stmt; + -+// http://www.team5150.com/~andrew/noncryptohashzoo2~/CrapWow.html -+static unsigned int CrapWow(const char *key, unsigned int len, unsigned int seed) -+{ -+#define cwfold( a, b, lo, hi ) { p = (unsigned int)(a) * (unsigned long long)(b); lo ^= (unsigned int)p; hi ^= (unsigned int)(p >> 32); } -+#define cwmixa( in ) { cwfold( in, m, k, h ); } -+#define cwmixb( in ) { cwfold( in, n, h, k ); } ++ if (new_arg != NULL_TREE && is_gimple_constant(new_arg)) ++ return new_arg; + -+ unsigned int m = 0x57559429; -+ unsigned int n = 0x5052acdb; -+ const unsigned int *key4 = (const unsigned int *)key; -+ unsigned int h = len; -+ unsigned int k = len + seed + n; -+ unsigned long long p; ++ arg = gimple_phi_arg_def(oldstmt, i); ++ def_stmt = get_def_stmt(arg); ++ gcc_assert(def_stmt != NULL); ++ size_overflow_type = get_size_overflow_type(visited, oldstmt, arg); + -+ while (len >= 8) { -+ cwmixb(key4[0]) cwmixa(key4[1]) key4 += 2; -+ len -= 8; -+ } -+ if (len >= 4) { -+ cwmixb(key4[0]) key4 += 1; -+ len -= 4; ++ switch (gimple_code(def_stmt)) { ++ case GIMPLE_PHI: ++ return cast_visited_phi_arg(visited, ssa_name_var, arg, size_overflow_type); ++ case GIMPLE_NOP: { ++ basic_block bb; ++ ++ bb = gimple_phi_arg_edge(oldstmt, i)->src; ++ return cast_parm_decl(visited, ssa_name_var, arg, size_overflow_type, bb); + } -+ if (len) -+ cwmixa(key4[0] & ((1 << (len * 8)) - 1 )); -+ cwmixb(h ^ (k + n)); -+ return k ^ h; ++ case GIMPLE_ASM: { ++ gimple_stmt_iterator gsi; ++ const_gimple assign; ++ gimple stmt = get_def_stmt(arg); + -+#undef cwfold -+#undef cwmixa -+#undef cwmixb ++ 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 get_lhs(assign); ++ } ++ default: ++ gcc_assert(new_arg != NULL_TREE); ++ gcc_assert(types_compatible_p(TREE_TYPE(new_arg), size_overflow_type)); ++ return use_phi_ssa_name(visited, ssa_name_var, new_arg); ++ } +} + -+static void set_hash(struct decl_hash *decl_hash_data) ++static gphi *overflow_create_phi_node(struct visited *visited, gphi *oldstmt, tree result) +{ -+ unsigned int fn, type, codes, seed = 0; ++ basic_block bb; ++ gphi *phi; ++ gimple_seq seq; ++ gimple_stmt_iterator gsi = gsi_for_stmt(oldstmt); + -+ fn = CrapWow(decl_hash_data->fn_name, strlen(decl_hash_data->fn_name), seed) & 0xffff; -+ codes = CrapWow((const char*)decl_hash_data->tree_codes, decl_hash_data->tree_codes_len, seed) & 0xffff; -+ type = CrapWow(decl_hash_data->context, strlen(decl_hash_data->context), 0) & 0xffff; -+ decl_hash_data->hash = type ^ fn ^ codes; -+} ++ bb = gsi_bb(gsi); + -+static void set_decl_type_codes(const_tree type, struct decl_hash *decl_hash_data) -+{ -+ gcc_assert(type != NULL_TREE); -+ gcc_assert(TREE_CODE_CLASS(TREE_CODE(type)) == tcc_type); ++ if (result == NULL_TREE) { ++ tree old_result = gimple_phi_result(oldstmt); ++ tree size_overflow_type = get_size_overflow_type(visited, oldstmt, old_result); + -+ while (type && decl_hash_data->tree_codes_len < CODES_LIMIT) { -+ decl_hash_data->tree_codes[decl_hash_data->tree_codes_len] = get_tree_code(type); -+ decl_hash_data->tree_codes_len++; -+ type = TREE_TYPE(type); ++ result = create_new_var(size_overflow_type); + } ++ ++ 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); ++ gsi_remove(&gsi, false); ++ ++ gsi = gsi_for_stmt(oldstmt); ++ gsi_insert_after(&gsi, phi, GSI_NEW_STMT); ++ gimple_set_bb(phi, bb); ++ return phi; +} + -+static void set_result_codes(const_tree node, struct decl_hash *decl_hash_data) ++#if BUILDING_GCC_VERSION <= 4007 ++static tree create_new_phi_node(struct visited *visited, VEC(tree, heap) **args, tree ssa_name_var, gimple oldstmt) ++#else ++static tree create_new_phi_node(struct visited *visited, vec *&args, tree ssa_name_var, gphi *oldstmt) ++#endif +{ -+ const_tree result; -+ -+ gcc_assert(node != NULL_TREE); ++ gphi *new_phi; ++ unsigned int i; ++ tree arg, result; ++ location_t loc = gimple_location(oldstmt); + -+ if (DECL_P(node)) { -+ result = DECL_RESULT(node); -+ if (result != NULL_TREE) -+ return set_decl_type_codes(TREE_TYPE(result), decl_hash_data); -+ return set_result_codes(TREE_TYPE(node), decl_hash_data); -+ } ++#if BUILDING_GCC_VERSION <= 4007 ++ gcc_assert(!VEC_empty(tree, *args)); ++#else ++ gcc_assert(!args->is_empty()); ++#endif + -+ gcc_assert(TYPE_P(node)); ++ new_phi = overflow_create_phi_node(visited, oldstmt, ssa_name_var); ++ result = gimple_phi_result(new_phi); ++ ssa_name_var = SSA_NAME_VAR(result); + -+ if (TREE_CODE(node) == FUNCTION_TYPE) -+ return set_result_codes(TREE_TYPE(node), decl_hash_data); ++#if BUILDING_GCC_VERSION <= 4007 ++ FOR_EACH_VEC_ELT(tree, *args, i, arg) { ++#else ++ FOR_EACH_VEC_SAFE_ELT(args, i, arg) { ++#endif ++ arg = create_new_phi_arg(visited, ssa_name_var, arg, oldstmt, i); ++ add_phi_arg(new_phi, arg, gimple_phi_arg_edge(oldstmt, i), loc); ++ } + -+ return set_decl_type_codes(node, decl_hash_data); ++#if BUILDING_GCC_VERSION <= 4007 ++ VEC_free(tree, heap, *args); ++#else ++ vec_free(args); ++#endif ++ update_stmt(new_phi); ++ pointer_set_insert(visited->my_stmts, new_phi); ++ return result; +} + -+static void set_decl_codes(struct decl_hash *decl_hash_data) ++static tree handle_phi(interesting_stmts_t expand_from, tree orig_result) +{ -+ const_tree arg, type; -+ enum tree_code code; ++#if BUILDING_GCC_VERSION <= 4007 ++ VEC(tree, heap) *args = NULL; ++#else ++ vec *args = NULL; ++#endif ++ unsigned int i, len; ++ tree ssa_name_var = NULL_TREE; ++ gphi *oldstmt = as_a_gphi(get_def_stmt(orig_result)); + -+ if (TREE_CODE(decl_hash_data->decl) == VAR_DECL || TREE_CODE(decl_hash_data->decl) == FIELD_DECL) { -+ set_decl_type_codes(TREE_TYPE(decl_hash_data->decl), decl_hash_data); -+ return; -+ } ++ len = gimple_phi_num_args(oldstmt); ++ pointer_set_insert(expand_from->visited->stmts, oldstmt); ++ for (i = 0; i < len; i++) { ++ tree arg, new_arg; + -+ type = get_function_type(decl_hash_data->decl); -+ code = TREE_CODE(type); -+ gcc_assert(code == FUNCTION_TYPE || code == METHOD_TYPE); ++ arg = gimple_phi_arg_def(oldstmt, i); ++ new_arg = expand(expand_from, arg); + -+ if (FUNCTION_PTR_P(decl_hash_data->decl)) -+ set_result_codes(type, decl_hash_data); -+ else -+ set_result_codes(decl_hash_data->decl, decl_hash_data); ++ if (ssa_name_var == NULL_TREE && new_arg != NULL_TREE) ++ ssa_name_var = SSA_NAME_VAR(new_arg); + -+ for (arg = TYPE_ARG_TYPES(type); arg != NULL_TREE && decl_hash_data->tree_codes_len < CODES_LIMIT; arg = TREE_CHAIN(arg)) -+ set_decl_type_codes(TREE_VALUE(arg), decl_hash_data); -+} ++ if (is_gimple_constant(arg)) { ++ tree size_overflow_type = get_size_overflow_type(expand_from->visited, oldstmt, arg); + -+static const struct size_overflow_hash *get_proper_hash_chain(const struct size_overflow_hash *entry, const char *func_name, const char *context) -+{ -+ for (; entry; entry = entry->next) { -+ if (strcmp(entry->name, func_name)) -+ continue; -+ if (!strcmp(entry->context, context)) -+ return entry; ++ new_arg = cast_a_tree(size_overflow_type, arg); ++ } ++ ++#if BUILDING_GCC_VERSION <= 4007 ++ VEC_safe_push(tree, heap, args, new_arg); ++#else ++ vec_safe_push(args, new_arg); ++#endif + } -+ return NULL; ++ ++#if BUILDING_GCC_VERSION <= 4007 ++ return create_new_phi_node(expand_from->visited, &args, ssa_name_var, oldstmt); ++#else ++ return create_new_phi_node(expand_from->visited, args, ssa_name_var, oldstmt); ++#endif +} + -+unsigned int get_decl_hash(const_tree decl, const char *decl_name) ++static tree create_cast_assign(struct visited *visited, gassign *stmt) +{ -+ struct decl_hash decl_hash_data; -+ enum tree_code code = TREE_CODE(decl); -+ -+ gcc_assert(code == FIELD_DECL || code == FUNCTION_DECL || code == VAR_DECL); -+ -+ // skip builtins __builtin_constant_p -+ if (code == FUNCTION_DECL && (DECL_BUILT_IN(decl) || DECL_BUILT_IN_CLASS(decl) == BUILT_IN_NORMAL)) -+ return NO_HASH; ++ tree rhs1 = gimple_assign_rhs1(stmt); ++ tree lhs = gimple_assign_lhs(stmt); ++ const_tree rhs1_type = TREE_TYPE(rhs1); ++ const_tree lhs_type = TREE_TYPE(lhs); + -+ decl_hash_data.fn_name = decl_name; -+ decl_hash_data.decl = decl; -+ decl_hash_data.context = get_decl_context(decl); -+ if (!decl_hash_data.context) -+ return NO_HASH; -+ decl_hash_data.tree_codes_len = 0; ++ if (TYPE_UNSIGNED(rhs1_type) == TYPE_UNSIGNED(lhs_type)) ++ return create_assign(visited, stmt, lhs, AFTER_STMT); + -+ set_decl_codes(&decl_hash_data); -+ gcc_assert(decl_hash_data.tree_codes_len != 0); -+ set_hash(&decl_hash_data); -+ return decl_hash_data.hash; ++ return create_assign(visited, stmt, rhs1, AFTER_STMT); +} + -+const char *get_orig_decl_name(const_tree decl) ++static bool skip_lhs_cast_check(struct visited *visited, const gassign *stmt) +{ -+ const char *name; -+ unsigned int len; -+ const void *end; -+ const_tree orig_decl; -+ -+ if (TREE_CODE(decl) == FUNCTION_DECL) -+ orig_decl = DECL_ORIGIN(decl); -+ else -+ orig_decl = decl; -+ -+ len = DECL_NAME_LENGTH(orig_decl); -+ name = DECL_NAME_POINTER(orig_decl); ++ const_tree rhs = gimple_assign_rhs1(stmt); ++ const_gimple def_stmt = get_def_stmt(rhs); + -+ /* Sometimes gcc loses the original cgraph node leaving only clones behind. -+ * In such cases we will extract the name from the clone and use it in the hash table -+ * without checking the parameter number on the original (unavailable) decl. -+ */ ++ // 3.8.2 kernel/futex_compat.c compat_exit_robust_list(): get_user() 64 ulong -> int (compat_long_t), int max ++ if (gimple_code(def_stmt) == GIMPLE_ASM) ++ return true; + -+ if (made_by_compiler(orig_decl)) { -+ end = memchr(name, '.', len); -+ if (!end) -+ return xstrndup(name, len); -+ len = (long)end - (long)name; -+ gcc_assert(len > 0); ++ if (is_const_plus_unsigned_signed_truncation(rhs)) { ++ pointer_set_insert(visited->no_cast_check, stmt); ++ return true; + } + -+ return xstrndup(name, len); ++ return false; +} + -+const struct size_overflow_hash *get_disable_size_overflow_hash_entry(unsigned int hash, const char *decl_name, const char *context, unsigned int argnum) ++static tree create_string_param(tree string) +{ -+ const struct size_overflow_hash *entry, *entry_node; ++ tree i_type, a_type; ++ const int length = TREE_STRING_LENGTH(string); + -+ entry = disable_size_overflow_hash[hash]; -+ entry_node = get_proper_hash_chain(entry, decl_name, context); -+ if (entry_node && entry_node->param & (1U << argnum)) -+ return entry_node; -+ return NULL; ++ gcc_assert(length > 0); ++ ++ i_type = build_index_type(build_int_cst(NULL_TREE, length - 1)); ++ a_type = build_array_type(char_type_node, i_type); ++ ++ TREE_TYPE(string) = a_type; ++ TREE_CONSTANT(string) = 1; ++ TREE_READONLY(string) = 1; ++ ++ return build1(ADDR_EXPR, ptr_type_node, string); +} + -+const struct size_overflow_hash *get_size_overflow_hash_entry(unsigned int hash, const char *decl_name, const char *context, unsigned int argnum) ++static void insert_cond(basic_block cond_bb, tree arg, enum tree_code cond_code, tree type_value) +{ -+ const struct size_overflow_hash *entry, *entry_node; -+ -+ entry = size_overflow_hash[hash]; -+ entry_node = get_proper_hash_chain(entry, decl_name, context); -+ if (entry_node && entry_node->param & (1U << argnum)) -+ return entry_node; ++ gcond *cond_stmt; ++ gimple_stmt_iterator gsi = gsi_last_bb(cond_bb); + -+ entry = size_overflow_hash_aux[hash]; -+ entry_node = get_proper_hash_chain(entry, decl_name, context); -+ if (entry_node && entry_node->param & (1U << argnum)) -+ return entry_node; -+ return NULL; ++ cond_stmt = gimple_build_cond(cond_code, arg, type_value, NULL_TREE, NULL_TREE); ++ gsi_insert_after(&gsi, cond_stmt, GSI_CONTINUE_LINKING); ++ update_stmt(cond_stmt); +} + -+const struct size_overflow_hash *get_size_overflow_hash_entry_tree(const_tree fndecl, unsigned int argnum, bool hash_table) ++static void insert_cond_result(interesting_stmts_t expand_from, basic_block bb_true, const_gimple stmt, const_tree arg, bool min) +{ -+ const_tree orig_decl; -+ unsigned int orig_argnum, hash; -+ const char *decl_name, *context; ++ gcall *func_stmt; ++ const_gimple def_stmt; ++ const_tree loc_line; ++ tree loc_file, ssa_name, current_func; ++ expanded_location xloc; ++ char *ssa_name_buf; ++ int len; ++ struct cgraph_edge *edge; ++ struct cgraph_node *report_node; ++ int frequency; ++ gimple_stmt_iterator gsi = gsi_start_bb(bb_true); + -+ if (made_by_compiler(fndecl)) { -+ orig_decl = get_orig_fndecl(fndecl); -+ orig_argnum = get_correct_argnum(fndecl, orig_decl, argnum); -+ } else { -+ orig_decl = fndecl; -+ orig_argnum = argnum; -+ } ++ def_stmt = get_def_stmt(arg); ++ if (gimple_has_location(def_stmt)) ++ xloc = expand_location(gimple_location(def_stmt)); ++ else if (gimple_has_location(stmt)) ++ xloc = expand_location(gimple_location(stmt)); ++ else ++ xloc = expand_location(DECL_SOURCE_LOCATION(current_function_decl)); + -+ if (orig_argnum == CANNOT_FIND_ARG) -+ return NULL; ++ loc_line = build_int_cstu(unsigned_type_node, xloc.line); + -+ decl_name = get_orig_decl_name(orig_decl); -+ hash = get_decl_hash(orig_decl, decl_name); -+ if (hash == NO_HASH) -+ return NULL; ++ loc_file = build_string(strlen(xloc.file) + 1, xloc.file); ++ loc_file = create_string_param(loc_file); + -+ context = get_decl_context(orig_decl); -+ if (!context) -+ return NULL; ++ current_func = build_string(DECL_NAME_LENGTH(current_function_decl) + 1, DECL_NAME_POINTER(current_function_decl)); ++ current_func = create_string_param(current_func); + -+ if (hash_table == SIZE_OVERFLOW) -+ return get_size_overflow_hash_entry(hash, decl_name, context, orig_argnum); -+ return get_disable_size_overflow_hash_entry(hash, decl_name, context, orig_argnum); ++ gcc_assert(DECL_NAME(SSA_NAME_VAR(arg)) != NULL); ++ call_count++; ++ len = asprintf(&ssa_name_buf, "%s_%u %s, count: %u, decl: %s; num: %u; context: %s;\n", DECL_NAME_POINTER(SSA_NAME_VAR(arg)), SSA_NAME_VERSION(arg), min ? "min" : "max", call_count, expand_from->next_node->decl_name, expand_from->next_node->num, expand_from->next_node->context); ++ gcc_assert(len > 0); ++ ssa_name = build_string(len + 1, ssa_name_buf); ++ free(ssa_name_buf); ++ 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 = 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); ++ ++ report_node = cgraph_get_create_node(report_size_overflow_decl); ++ gcc_assert(report_node); ++ frequency = compute_call_stmt_bb_frequency(current_function_decl, bb_true); ++ ++ edge = cgraph_create_edge(get_cnode(current_function_decl), report_node, func_stmt, bb_true->count, frequency, bb_true->loop_depth); ++ gcc_assert(edge != NULL); +} + -+unsigned int find_arg_number_tree(const_tree arg, const_tree func) ++static void insert_check_size_overflow(interesting_stmts_t expand_from, gimple stmt, enum tree_code cond_code, tree arg, tree type_value, bool before, bool min) +{ -+ tree var; -+ unsigned int argnum = 1; ++ basic_block cond_bb, join_bb, bb_true; ++ edge e; ++ gimple_stmt_iterator gsi = gsi_for_stmt(stmt); + -+ if (DECL_ARGUMENTS(func) == NULL_TREE) -+ return CANNOT_FIND_ARG; ++ cond_bb = gimple_bb(stmt); ++ if (before) ++ gsi_prev(&gsi); ++ if (gsi_end_p(gsi)) ++ e = split_block_after_labels(cond_bb); ++ else ++ e = split_block(cond_bb, gsi_stmt(gsi)); ++ cond_bb = e->src; ++ join_bb = e->dest; ++ e->flags = EDGE_FALSE_VALUE; ++ e->probability = REG_BR_PROB_BASE; + -+ if (TREE_CODE(arg) == SSA_NAME) -+ arg = SSA_NAME_VAR(arg); ++ bb_true = create_empty_bb(cond_bb); ++ make_edge(cond_bb, bb_true, EDGE_TRUE_VALUE); ++ make_edge(cond_bb, join_bb, EDGE_FALSE_VALUE); ++ make_edge(bb_true, join_bb, EDGE_FALLTHRU); + -+ for (var = DECL_ARGUMENTS(func); var; var = TREE_CHAIN(var), argnum++) { -+ if (!operand_equal_p(arg, var, 0) && strcmp(DECL_NAME_POINTER(var), DECL_NAME_POINTER(arg))) -+ continue; -+ if (!skip_types(var)) -+ return argnum; ++ gcc_assert(dom_info_available_p(CDI_DOMINATORS)); ++ set_immediate_dominator(CDI_DOMINATORS, bb_true, cond_bb); ++ set_immediate_dominator(CDI_DOMINATORS, join_bb, cond_bb); ++ ++ if (current_loops != NULL) { ++ gcc_assert(cond_bb->loop_father == join_bb->loop_father); ++ add_bb_to_loop(bb_true, cond_bb->loop_father); + } + -+ return CANNOT_FIND_ARG; -+} ++ insert_cond(cond_bb, arg, cond_code, type_value); ++ insert_cond_result(expand_from, bb_true, stmt, arg, min); + -+const_tree get_attribute(const char* attr_name, const_tree decl) -+{ -+ const_tree attr = lookup_attribute(attr_name, DECL_ATTRIBUTES(decl)); -+ if (attr && TREE_VALUE(attr)) -+ return attr; -+ return NULL_TREE; ++// print_the_code_insertions(stmt); +} + -+/* Check if the function has a size_overflow attribute or it is in the size_overflow hash table. -+ * If the function is missing everywhere then print the missing message into stderr. -+ */ -+void print_missing_function(next_interesting_function_t node) ++void check_size_overflow(interesting_stmts_t expand_from, gimple stmt, tree size_overflow_type, tree cast_rhs, tree rhs, bool before) +{ -+ unsigned int argnum, hash; -+ const struct size_overflow_hash *entry; -+ const char *decl_name; ++ const_tree rhs_type = TREE_TYPE(rhs); ++ tree cast_rhs_type, type_max_type, type_min_type, type_max, type_min; + -+ if (node->marked == ASM_STMT_SO_MARK) ++ if (pointer_set_contains(expand_from->visited->no_cast_check, stmt)) + return; + -+ if (node->orig_next_node) { -+ hash = node->orig_next_node->hash; -+ decl_name = node->orig_next_node->decl_name; -+ argnum = node->orig_next_node->num; -+ gcc_assert(!strcmp(node->context, node->orig_next_node->context)); -+ } else { -+ hash = node->hash; -+ decl_name = node->decl_name; -+ argnum = node->num; -+ } ++ gcc_assert(rhs_type != NULL_TREE); ++ if (TREE_CODE(rhs_type) == POINTER_TYPE) ++ return; + -+ entry = get_size_overflow_hash_entry(hash, decl_name, node->context, argnum); -+ if (entry) ++ gcc_assert(TREE_CODE(rhs_type) == INTEGER_TYPE || TREE_CODE(rhs_type) == ENUMERAL_TYPE); ++ ++ if (is_gimple_assign(stmt) && neg_short_add_intentional_overflow(as_a_gassign(stmt))) + return; + -+ // inform() would be too slow -+ fprintf(stderr, "Function %s is missing from the size_overflow hash table +%s+%s+%u+%u+\n", decl_name, decl_name, node->context, argnum, hash); -+} ++ type_max = cast_a_tree(size_overflow_type, TYPE_MAX_VALUE(rhs_type)); ++ // typemax (-1) < typemin (0) ++ if (TREE_OVERFLOW(type_max)) ++ return; + -diff --git a/tools/gcc/size_overflow_plugin/size_overflow_transform.c b/tools/gcc/size_overflow_plugin/size_overflow_transform.c -new file mode 100644 -index 0000000..eebcf4c ---- /dev/null -+++ b/tools/gcc/size_overflow_plugin/size_overflow_transform.c -@@ -0,0 +1,743 @@ -+/* -+ * Copyright 2011-2016 by Emese Revfy -+ * Licensed under the GPL v2, or (at your option) v3 -+ * -+ * Homepage: -+ * https://github.com/ephox-gcc-plugins/size_overflow -+ * -+ * Documentation: -+ * http://forums.grsecurity.net/viewtopic.php?f=7&t=3043 -+ * -+ * This plugin recomputes expressions of function arguments marked by a size_overflow attribute -+ * with double integer precision (DImode/TImode for 32/64 bit integer types). -+ * The recomputed argument is checked against TYPE_MAX and an event is logged on overflow and the triggering process is killed. -+ * -+ * Usage: -+ * $ make -+ * $ make run -+ */ ++ type_min = cast_a_tree(size_overflow_type, TYPE_MIN_VALUE(rhs_type)); + -+#include "size_overflow.h" ++ cast_rhs_type = TREE_TYPE(cast_rhs); ++ type_max_type = TREE_TYPE(type_max); ++ gcc_assert(types_compatible_p(cast_rhs_type, type_max_type)); + -+static tree cast_to_orig_type(struct visited *visited, gimple stmt, const_tree orig_node, tree new_node) ++ insert_check_size_overflow(expand_from, stmt, GT_EXPR, cast_rhs, type_max, before, MAX_CHECK); ++ ++ // special case: get_size_overflow_type(), 32, u64->s ++ if (LONG_TYPE_SIZE == GET_MODE_BITSIZE(SImode) && TYPE_UNSIGNED(size_overflow_type) && !TYPE_UNSIGNED(rhs_type)) ++ return; ++ ++ type_min_type = TREE_TYPE(type_min); ++ gcc_assert(types_compatible_p(type_max_type, type_min_type)); ++ insert_check_size_overflow(expand_from, stmt, LT_EXPR, cast_rhs, type_min, before, MIN_CHECK); ++} ++ ++static tree get_my_stmt_lhs(struct visited *visited, gimple stmt) +{ -+ gimple def_stmt; -+ const_gimple assign; -+ tree result, orig_type = TREE_TYPE(orig_node); + gimple_stmt_iterator gsi; ++ gimple next_stmt = NULL; + -+ if (gimple_code(stmt) != GIMPLE_PHI) { -+ gsi = gsi_for_stmt(stmt); -+ assign = build_cast_stmt(visited, orig_type, new_node, CREATE_NEW_VAR, &gsi, BEFORE_STMT, false); -+ return get_lhs(assign); -+ } ++ gsi = gsi_for_stmt(stmt); + -+ def_stmt = get_def_stmt(new_node); -+ if (gimple_code(def_stmt) == GIMPLE_PHI) -+ gsi = gsi_after_labels(gimple_bb(def_stmt)); -+ else -+ gsi = gsi_for_stmt(def_stmt); ++ do { ++ gsi_next(&gsi); ++ next_stmt = gsi_stmt(gsi); + -+ result = gimple_phi_result(stmt); -+ assign = build_cast_stmt(visited, orig_type, new_node, SSA_NAME_VAR(result), &gsi, AFTER_STMT, false); -+ return get_lhs(assign); -+} ++ if (gimple_code(stmt) == GIMPLE_PHI && !pointer_set_contains(visited->my_stmts, next_stmt)) ++ return NULL_TREE; + -+static void change_size_overflow_asm_input(gasm *stmt, tree new_input) -+{ -+ tree list; ++ if (pointer_set_contains(visited->my_stmts, next_stmt) && !pointer_set_contains(visited->skip_expr_casts, next_stmt)) ++ break; + -+ gcc_assert(is_size_overflow_insert_check_asm(stmt)); ++ gcc_assert(pointer_set_contains(visited->my_stmts, next_stmt)); ++ } while (!gsi_end_p(gsi)); + -+ list = build_tree_list(NULL_TREE, build_string(3, "rm")); -+ list = chainon(NULL_TREE, build_tree_list(list, new_input)); -+ gimple_asm_set_input_op(stmt, 0, list); ++ gcc_assert(next_stmt); ++ return get_lhs(next_stmt); +} + -+static void change_field_write_rhs(gassign *assign, const_tree orig_rhs, tree new_rhs) ++/* When the result of the negation is cast to a signed type then move ++ * the size_overflow cast check before negation. ++ * ssa: ++ * unsigned _588 ++ * _588 = _587 >> 12; ++ * _589 = -_588; ++ * _590 = (long int) _589; ++ */ ++static bool handle_unsigned_neg_or_bit_not(interesting_stmts_t expand_from, const gassign *stmt) +{ -+ const_tree rhs1, rhs2, rhs3 = NULL_TREE; ++ gimple def_neg_stmt, neg_stmt; ++ tree lhs, new_neg_rhs; ++ const_tree rhs, neg_rhs; ++ enum tree_code rhs_code; + -+ rhs1 = gimple_assign_rhs1(assign); -+ if (rhs1 == orig_rhs) { -+ gimple_assign_set_rhs1(assign, new_rhs); -+ return; -+ } ++ rhs = gimple_assign_rhs1(stmt); ++ lhs = gimple_assign_lhs(stmt); ++ if (TYPE_UNSIGNED(TREE_TYPE(lhs)) || !TYPE_UNSIGNED(TREE_TYPE(rhs))) ++ return false; + -+ rhs2 = gimple_assign_rhs2(assign); -+ if (rhs2 == orig_rhs) { -+ gimple_assign_set_rhs2(assign, new_rhs); -+ return; -+ } ++ neg_stmt = get_def_stmt(rhs); ++ if (!neg_stmt || !is_gimple_assign(neg_stmt)) ++ return false; + -+#if BUILDING_GCC_VERSION >= 4006 -+ rhs3 = gimple_assign_rhs3(assign); -+ if (rhs3 == orig_rhs) { -+ gimple_assign_set_rhs3(assign, new_rhs); -+ return; -+ } -+#endif ++ rhs_code = gimple_assign_rhs_code(neg_stmt); ++ if (rhs_code != BIT_NOT_EXPR && rhs_code != NEGATE_EXPR) ++ return false; + -+ debug_gimple_stmt(assign); -+ fprintf(stderr, "orig_rhs:\n"); -+ debug_tree(orig_rhs); -+ fprintf(stderr, "rhs1:\n"); -+ debug_tree(rhs1); -+ fprintf(stderr, "rhs2:\n"); -+ debug_tree(rhs2); -+ fprintf(stderr, "rhs3:\n"); -+ debug_tree(rhs3); -+ gcc_unreachable(); ++ neg_rhs = gimple_assign_rhs1(neg_stmt); ++ def_neg_stmt = get_def_stmt(neg_rhs); ++ if (!def_neg_stmt) ++ return false; ++ ++ new_neg_rhs = get_my_stmt_lhs(expand_from->visited, def_neg_stmt); ++ check_size_overflow(expand_from, neg_stmt, TREE_TYPE(new_neg_rhs), new_neg_rhs, lhs, BEFORE_STMT); ++ pointer_set_insert(expand_from->visited->no_cast_check, stmt); ++ return true; +} + -+static void change_phi_arg(gphi *phi, tree new_node, unsigned int num) ++static tree create_cast_overflow_check(interesting_stmts_t expand_from, tree new_rhs1, gassign *stmt) +{ -+ unsigned int i; -+ location_t loc = gimple_location(phi); ++ bool cast_lhs, cast_rhs; ++ tree lhs = gimple_assign_lhs(stmt); ++ tree rhs = gimple_assign_rhs1(stmt); ++ const_tree lhs_type = TREE_TYPE(lhs); ++ const_tree rhs_type = TREE_TYPE(rhs); ++ enum machine_mode lhs_mode = TYPE_MODE(lhs_type); ++ enum machine_mode rhs_mode = TYPE_MODE(rhs_type); ++ unsigned int lhs_size = GET_MODE_BITSIZE(lhs_mode); ++ unsigned int rhs_size = GET_MODE_BITSIZE(rhs_mode); + -+ for (i = 0; i < gimple_phi_num_args(phi); i++) { -+ if (i == num) -+ add_phi_arg(phi, new_node, gimple_phi_arg_edge(phi, i), loc); ++ static bool check_lhs[3][4] = { ++ // ss su us uu ++ { false, true, true, false }, // lhs > rhs ++ { false, false, false, false }, // lhs = rhs ++ { true, true, true, true }, // lhs < rhs ++ }; ++ ++ static bool check_rhs[3][4] = { ++ // ss su us uu ++ { true, false, true, true }, // lhs > rhs ++ { true, false, true, true }, // lhs = rhs ++ { true, false, true, true }, // lhs < rhs ++ }; ++ ++ if (handle_unsigned_neg_or_bit_not(expand_from, stmt)) ++ return dup_assign(expand_from->visited, stmt, lhs, new_rhs1, NULL_TREE, NULL_TREE); ++ ++ // skip lhs check on HI -> QI cast ++ if (rhs_mode == HImode && lhs_mode == QImode) { ++ pointer_set_insert(expand_from->visited->no_cast_check, stmt); ++ return dup_assign(expand_from->visited, stmt, lhs, new_rhs1, NULL_TREE, NULL_TREE); + } -+} + -+static void change_orig_node(struct visited *visited, gimple stmt, const_tree orig_node, tree new_node, unsigned int num) -+{ -+ tree cast_lhs = cast_to_orig_type(visited, stmt, orig_node, new_node); ++ // skip lhs check on signed SI -> HI cast or signed SI -> QI cast ++ if (rhs_mode == SImode && !TYPE_UNSIGNED(rhs_type) && (lhs_mode == HImode || lhs_mode == QImode)) ++ return create_assign(expand_from->visited, stmt, lhs, AFTER_STMT); + -+ switch (gimple_code(stmt)) { -+ case GIMPLE_RETURN: -+ gimple_return_set_retval(as_a_greturn(stmt), cast_lhs); -+ break; -+ case GIMPLE_CALL: -+ gimple_call_set_arg(as_a_gcall(stmt), num - 1, cast_lhs); -+ break; -+ case GIMPLE_ASM: -+ change_size_overflow_asm_input(as_a_gasm(stmt), cast_lhs); -+ break; -+ case GIMPLE_ASSIGN: -+ change_field_write_rhs(as_a_gassign(stmt), orig_node, cast_lhs); -+ break; -+ case GIMPLE_PHI: -+ change_phi_arg(as_a_gphi(stmt), cast_lhs, num); -+ break; -+ default: -+ debug_gimple_stmt(stmt); -+ gcc_unreachable(); ++ if (lhs_size > rhs_size) { ++ cast_lhs = check_lhs[0][TYPE_UNSIGNED(rhs_type) + 2 * TYPE_UNSIGNED(lhs_type)]; ++ cast_rhs = check_rhs[0][TYPE_UNSIGNED(rhs_type) + 2 * TYPE_UNSIGNED(lhs_type)]; ++ } else if (lhs_size == rhs_size) { ++ cast_lhs = check_lhs[1][TYPE_UNSIGNED(rhs_type) + 2 * TYPE_UNSIGNED(lhs_type)]; ++ cast_rhs = check_rhs[1][TYPE_UNSIGNED(rhs_type) + 2 * TYPE_UNSIGNED(lhs_type)]; ++ } else { ++ cast_lhs = check_lhs[2][TYPE_UNSIGNED(rhs_type) + 2 * TYPE_UNSIGNED(lhs_type)]; ++ cast_rhs = check_rhs[2][TYPE_UNSIGNED(rhs_type) + 2 * TYPE_UNSIGNED(lhs_type)]; + } + -+ update_stmt(stmt); -+} ++ if (!cast_lhs && !cast_rhs) ++ return dup_assign(expand_from->visited, stmt, lhs, new_rhs1, NULL_TREE, NULL_TREE); + -+// e.g., 3.8.2, 64, arch/x86/ia32/ia32_signal.c copy_siginfo_from_user32(): compat_ptr() u32 max -+static bool skip_asm_cast(const_tree arg) -+{ -+ gimple def_stmt = get_def_stmt(arg); ++ if (cast_lhs && !skip_lhs_cast_check(expand_from->visited, stmt)) ++ check_size_overflow(expand_from, stmt, TREE_TYPE(new_rhs1), new_rhs1, lhs, BEFORE_STMT); + -+ if (!def_stmt || !gimple_assign_cast_p(def_stmt)) -+ return false; ++ if (cast_rhs) ++ check_size_overflow(expand_from, stmt, TREE_TYPE(new_rhs1), new_rhs1, rhs, BEFORE_STMT); + -+ def_stmt = get_def_stmt(gimple_assign_rhs1(def_stmt)); -+ if (is_size_overflow_asm(def_stmt)) -+ return false; -+ return def_stmt && gimple_code(def_stmt) == GIMPLE_ASM; ++ return dup_assign(expand_from->visited, stmt, lhs, new_rhs1, NULL_TREE, NULL_TREE); +} + -+static interesting_stmts_t create_interesting_stmts(interesting_stmts_t head, next_interesting_function_t next_node, tree orig_node, gimple first_stmt, unsigned int num) ++static tree handle_unary_rhs(interesting_stmts_t expand_from, gassign *stmt) +{ -+ interesting_stmts_t new_node; ++ enum tree_code rhs_code; ++ tree rhs1, new_rhs1, lhs = gimple_assign_lhs(stmt); + -+ new_node = (interesting_stmts_t )xmalloc(sizeof(*new_node)); -+ new_node->first_stmt = first_stmt; -+ new_node->num = num; -+ new_node->orig_node = orig_node; -+ new_node->next = head; -+ new_node->next_node = next_node; -+ return new_node; -+} ++ if (pointer_set_contains(expand_from->visited->my_stmts, stmt)) ++ return lhs; + -+static void free_interesting_stmts(interesting_stmts_t head) -+{ -+ while (head) { -+ interesting_stmts_t cur = head->next; -+ free(head); -+ head = cur; -+ } -+} ++ rhs1 = gimple_assign_rhs1(stmt); ++ if (TREE_CODE(TREE_TYPE(rhs1)) == POINTER_TYPE) ++ return create_assign(expand_from->visited, stmt, lhs, AFTER_STMT); + -+/* This function calls the main recursion function (expand) that duplicates the stmts. Before that it checks the intentional_overflow attribute, -+ * it decides whether the duplication is necessary or not. After expand() it changes the orig node to the duplicated node -+ * in the original stmt (first stmt) and it inserts the overflow check for the arg of the callee or for the return value. -+ */ -+static interesting_stmts_t search_interesting_stmt(interesting_stmts_t head, next_interesting_function_t next_node, gimple first_stmt, tree orig_node, unsigned int num) -+{ -+ enum tree_code orig_code; ++ new_rhs1 = expand(expand_from, rhs1); + -+ gcc_assert(orig_node != NULL_TREE); ++ if (new_rhs1 == NULL_TREE) ++ return create_cast_assign(expand_from->visited, stmt); + -+ if (is_gimple_constant(orig_node)) -+ return head; ++ if (pointer_set_contains(expand_from->visited->no_cast_check, stmt)) ++ return dup_assign(expand_from->visited, stmt, lhs, new_rhs1, NULL_TREE, NULL_TREE); + -+ orig_code = TREE_CODE(orig_node); -+ gcc_assert(orig_code != FIELD_DECL && orig_code != FUNCTION_DECL); ++#if BUILDING_GCC_VERSION >= 5000 ++ if (short_or_neg_const_ushort(stmt)) { ++ pointer_set_insert(expand_from->visited->no_cast_check, stmt); ++ return dup_assign(expand_from->visited, stmt, lhs, new_rhs1, NULL_TREE, NULL_TREE); ++ } ++#endif + -+ if (skip_types(orig_node)) -+ return head; ++ rhs_code = gimple_assign_rhs_code(stmt); ++ if (rhs_code == BIT_NOT_EXPR || rhs_code == NEGATE_EXPR) { ++ tree size_overflow_type = get_size_overflow_type(expand_from->visited, stmt, rhs1); + -+ // find a defining marked caller argument or struct field for arg -+ if (check_intentional_size_overflow_asm_and_attribute(orig_node) != MARK_NO) -+ return head; ++ new_rhs1 = cast_to_new_size_overflow_type(expand_from->visited, stmt, new_rhs1, size_overflow_type, BEFORE_STMT); ++ check_size_overflow(expand_from, stmt, size_overflow_type, new_rhs1, rhs1, BEFORE_STMT); ++ return create_assign(expand_from->visited, stmt, lhs, AFTER_STMT); ++ } + -+ if (skip_asm_cast(orig_node)) -+ return head; ++ if (!gimple_assign_cast_p(stmt)) ++ return dup_assign(expand_from->visited, stmt, lhs, new_rhs1, NULL_TREE, NULL_TREE); + -+ return create_interesting_stmts(head, next_node, orig_node, first_stmt, num); ++ return create_cast_overflow_check(expand_from, new_rhs1, stmt); +} + -+static bool is_signed_error_code_const(const_tree node) ++static tree handle_unary_ops(interesting_stmts_t expand_from, gassign *stmt) +{ -+ HOST_WIDE_INT constant = tree_to_shwi(node); ++ tree rhs1, lhs = gimple_assign_lhs(stmt); ++ gimple def_stmt = get_def_stmt(lhs); + -+ return constant >= -4095 && constant <= -1; ++ gcc_assert(gimple_code(def_stmt) != GIMPLE_NOP); ++ rhs1 = gimple_assign_rhs1(def_stmt); ++ ++ if (is_gimple_constant(rhs1)) ++ return create_assign(expand_from->visited, def_stmt, lhs, AFTER_STMT); ++ ++ switch (TREE_CODE(rhs1)) { ++ case SSA_NAME: { ++ tree ret = handle_unary_rhs(expand_from, as_a_gassign(def_stmt)); ++ ++ if (gimple_assign_cast_p(stmt)) ++ unsigned_signed_cast_intentional_overflow(expand_from->visited, stmt); ++ return ret; ++ } ++ case ARRAY_REF: ++ case BIT_FIELD_REF: ++ case ADDR_EXPR: ++ case COMPONENT_REF: ++ case INDIRECT_REF: ++#if BUILDING_GCC_VERSION >= 4006 ++ case MEM_REF: ++#endif ++ case TARGET_MEM_REF: ++ case VIEW_CONVERT_EXPR: ++ return create_assign(expand_from->visited, def_stmt, lhs, AFTER_STMT); ++ case PARM_DECL: ++ case VAR_DECL: ++ return create_assign(expand_from->visited, stmt, lhs, AFTER_STMT); ++ ++ default: ++ debug_gimple_stmt(def_stmt); ++ debug_tree(rhs1); ++ gcc_unreachable(); ++ } +} + -+static bool is_unsigned_error_code_const(const_tree node) ++static void __unused print_the_code_insertions(const_gimple stmt) +{ -+ unsigned HOST_WIDE_INT constant = tree_to_uhwi(node); ++ location_t loc = gimple_location(stmt); + -+ // ulong -4095 -+ if (constant >= 0xfffffffffffff001) -+ return true; -+ // uint -4095 -+ return constant >= 0xfffff001; ++ inform(loc, "Integer size_overflow check applied here."); +} + -+static bool is_error_code_const(const_tree node) ++static bool is_from_cast(const_tree node) +{ -+ enum machine_mode mode; ++ gimple def_stmt = get_def_stmt(node); + -+ if (!is_gimple_constant(node)) -+ return false; -+ mode = TYPE_MODE(TREE_TYPE(node)); -+ if (mode != SImode && mode != DImode) ++ if (!def_stmt) + return false; + -+ if (!TYPE_UNSIGNED(TREE_TYPE(node)) && is_signed_error_code_const(node)) ++ if (gimple_assign_cast_p(def_stmt)) + return true; -+ return TYPE_UNSIGNED(TREE_TYPE(node)) && is_unsigned_error_code_const(node); ++ ++ return false; +} + -+static bool has_error_code(gphi *phi) ++// Skip duplication when there is a minus expr and the type of rhs1 or rhs2 is a pointer_type. ++static bool is_ptr_diff(gassign *stmt) +{ -+ unsigned int i, len = gimple_phi_num_args(phi); -+ -+ for (i = 0; i < len; i++) { -+ const_tree arg = gimple_phi_arg_def(phi, i); ++ const_tree rhs1, rhs2, ptr1_rhs, ptr2_rhs; + -+ if (is_error_code_const(arg)) -+ return true; -+ } ++ if (gimple_assign_rhs_code(stmt) != MINUS_EXPR) ++ return false; + -+ return false; -+} ++ rhs1 = gimple_assign_rhs1(stmt); ++ if (!is_from_cast(rhs1)) ++ return false; + -+static interesting_stmts_t search_interesting_rets(interesting_stmts_t head, next_interesting_function_t next_node_ret, greturn *ret) -+{ -+ tree first_node; ++ rhs2 = gimple_assign_rhs2(stmt); ++ if (!is_from_cast(rhs2)) ++ return false; + -+ if (!next_node_ret || next_node_ret->marked == ASM_STMT_SO_MARK) -+ return head; ++ ptr1_rhs = gimple_assign_rhs1(get_def_stmt(rhs1)); ++ ptr2_rhs = gimple_assign_rhs1(get_def_stmt(rhs2)); + -+ first_node = gimple_return_retval(ret); -+ if (first_node == NULL_TREE) -+ return head; ++ if (TREE_CODE(TREE_TYPE(ptr1_rhs)) != POINTER_TYPE && TREE_CODE(TREE_TYPE(ptr2_rhs)) != POINTER_TYPE) ++ return false; + -+ return search_interesting_stmt(head, next_node_ret, ret, first_node, 0); ++ return true; +} + -+static void handle_binary_assign(interesting_stmts_t expand_from, gassign *assign, tree rhs) ++static tree handle_comparison_code_class(interesting_stmts_t expand_from, gassign *stmt, tree new_rhs1, tree new_rhs2) +{ -+ tree new_node; -+ gimple def_orig_node; ++ tree rhs1, rhs2, lhs; + -+ new_node = expand(expand_from, rhs); -+ if (new_node == NULL_TREE) -+ return; ++ rhs1 = gimple_assign_rhs1(stmt); ++ if (!is_gimple_constant(rhs1) && new_rhs1 != NULL_TREE) ++ check_size_overflow(expand_from, stmt, TREE_TYPE(new_rhs1), new_rhs1, rhs1, BEFORE_STMT); + -+ def_orig_node = get_def_stmt(rhs); -+ if (pointer_set_contains(expand_from->visited->no_cast_check, def_orig_node)) -+ return; -+ change_orig_node(expand_from->visited, assign, rhs, new_node, 0); -+ check_size_overflow(expand_from, assign, TREE_TYPE(new_node), new_node, rhs, BEFORE_STMT); ++ lhs = gimple_assign_lhs(stmt); ++ if (new_rhs2 == NULL_TREE) ++ return create_assign(expand_from->visited, stmt, lhs, AFTER_STMT); ++ ++ rhs2 = gimple_assign_rhs2(stmt); ++ if (!is_gimple_constant(rhs2)) ++ check_size_overflow(expand_from, stmt, TREE_TYPE(new_rhs2), new_rhs2, rhs2, BEFORE_STMT); ++ return create_assign(expand_from->visited, stmt, lhs, AFTER_STMT); +} + -+static bool search_error_codes(gimple_set *visited_error_codes, interesting_stmts_t expand_from, tree lhs, bool error_code) ++static tree handle_binary_ops(interesting_stmts_t expand_from, tree lhs) +{ -+ gimple def_stmt; ++ enum intentional_overflow_type res; ++ tree rhs1, rhs2, new_lhs; ++ gassign *def_stmt = as_a_gassign(get_def_stmt(lhs)); ++ tree new_rhs1 = NULL_TREE; ++ tree new_rhs2 = NULL_TREE; + -+ def_stmt = get_def_stmt(lhs); -+ if (!def_stmt || gimple_code(def_stmt) == GIMPLE_NOP) -+ return error_code; ++ if (is_ptr_diff(def_stmt)) ++ return create_assign(expand_from->visited, def_stmt, lhs, AFTER_STMT); + -+ if (pointer_set_insert(visited_error_codes, def_stmt)) -+ return error_code; ++ rhs1 = gimple_assign_rhs1(def_stmt); ++ rhs2 = gimple_assign_rhs2(def_stmt); + -+ if (is_gimple_constant(lhs)) -+ return error_code; -+ if (skip_types(lhs)) -+ return is_error_code_const(lhs); ++ /* no DImode/TImode division in the 32/64 bit kernel */ ++ switch (gimple_assign_rhs_code(def_stmt)) { ++ case RDIV_EXPR: ++ case TRUNC_DIV_EXPR: ++ case CEIL_DIV_EXPR: ++ case FLOOR_DIV_EXPR: ++ case ROUND_DIV_EXPR: ++ case TRUNC_MOD_EXPR: ++ case CEIL_MOD_EXPR: ++ case FLOOR_MOD_EXPR: ++ case ROUND_MOD_EXPR: ++ case EXACT_DIV_EXPR: ++ case POINTER_PLUS_EXPR: ++ case BIT_AND_EXPR: ++ return create_assign(expand_from->visited, def_stmt, lhs, AFTER_STMT); ++ default: ++ break; ++ } + -+ switch (gimple_code(def_stmt)) { -+ case GIMPLE_CALL: -+ case GIMPLE_ASM: -+ return error_code; -+ case GIMPLE_ASSIGN: { -+ tree rhs1, rhs2; -+ gassign *assign = as_a_gassign(def_stmt); ++ new_lhs = handle_integer_truncation(expand_from, lhs); ++ if (new_lhs != NULL_TREE) ++ return new_lhs; + -+ switch (gimple_num_ops(assign)) { -+ case 2: -+ return search_error_codes(visited_error_codes, expand_from, gimple_assign_rhs1(def_stmt), error_code); -+ case 3: -+ if (!error_code) -+ return error_code; ++ if (TREE_CODE(rhs1) == SSA_NAME) ++ new_rhs1 = expand(expand_from, rhs1); ++ if (TREE_CODE(rhs2) == SSA_NAME) ++ new_rhs2 = expand(expand_from, rhs2); + -+ /* Run stmt duplication from the binary assignment ops (rhs1 and rhs2) -+ * so that size_overflow checking skips the lhs of the last binary assignment -+ * before the error code PHI. -+ */ -+ rhs1 = gimple_assign_rhs1(assign); -+ handle_binary_assign(expand_from, assign, rhs1); -+ rhs2 = gimple_assign_rhs2(assign); -+ handle_binary_assign(expand_from, assign, rhs2); -+ return error_code; -+ } -+ gcc_unreachable(); ++ res = add_mul_intentional_overflow(def_stmt); ++ if (res != NO_INTENTIONAL_OVERFLOW) { ++ new_lhs = dup_assign(expand_from->visited, def_stmt, lhs, new_rhs1, new_rhs2, NULL_TREE); ++ insert_cast_expr(expand_from->visited, as_a_gassign(get_def_stmt(new_lhs)), res); ++ return new_lhs; + } -+ case GIMPLE_PHI: { -+ unsigned int i; + -+ error_code = has_error_code(as_a_gphi(def_stmt)); -+ for (i = 0; i < gimple_phi_num_args(def_stmt); i++) { -+ error_code = search_error_codes(visited_error_codes, expand_from, gimple_phi_arg_def(def_stmt, i), error_code); -+ } -+ return error_code; -+ } -+ default: -+ debug_gimple_stmt(def_stmt); -+ error("%s: unknown gimple code", __func__); -+ gcc_unreachable(); ++ if (skip_expr_on_double_type(def_stmt)) { ++ new_lhs = dup_assign(expand_from->visited, def_stmt, lhs, new_rhs1, new_rhs2, NULL_TREE); ++ insert_cast_expr(expand_from->visited, as_a_gassign(get_def_stmt(new_lhs)), NO_INTENTIONAL_OVERFLOW); ++ return new_lhs; + } -+} + -+static bool handle_error_codes(interesting_stmts_t expand_from) -+{ -+ bool error_code; -+ gimple_set *visited_error_codes; ++ if (is_a_neg_overflow(def_stmt, rhs2)) ++ return handle_intentional_overflow(expand_from, true, def_stmt, new_rhs1, NULL_TREE); ++ if (is_a_neg_overflow(def_stmt, rhs1)) ++ return handle_intentional_overflow(expand_from, true, def_stmt, new_rhs2, new_rhs2); + -+ // expand the data flow from a return stmt -+ if (expand_from->next_node->num != 0 || strcmp(expand_from->next_node->context, "fndecl")) -+ return false; + -+ visited_error_codes = pointer_set_create(); -+ error_code = search_error_codes(visited_error_codes, expand_from, expand_from->orig_node, false); -+ pointer_set_destroy(visited_error_codes); ++ if (is_a_constant_overflow(def_stmt, rhs2)) ++ return handle_intentional_overflow(expand_from, !is_a_cast_and_const_overflow(rhs1), def_stmt, new_rhs1, NULL_TREE); ++ if (is_a_constant_overflow(def_stmt, rhs1)) ++ return handle_intentional_overflow(expand_from, !is_a_cast_and_const_overflow(rhs2), def_stmt, new_rhs2, new_rhs2); + -+ return error_code; ++ // the const is between 0 and (signed) MAX ++ if (is_gimple_constant(rhs1)) ++ new_rhs1 = create_assign(expand_from->visited, def_stmt, rhs1, BEFORE_STMT); ++ if (is_gimple_constant(rhs2)) ++ new_rhs2 = create_assign(expand_from->visited, def_stmt, rhs2, BEFORE_STMT); ++ ++ if (TREE_CODE_CLASS(gimple_assign_rhs_code(def_stmt)) == tcc_comparison) ++ return handle_comparison_code_class(expand_from, def_stmt, new_rhs1, new_rhs2); ++ ++ if (uconst_neg_intentional_overflow(def_stmt)) { ++ inform(gimple_location(def_stmt), "%s: gcc intentional overflow", __func__); ++ gcc_unreachable(); ++ } ++ ++ return dup_assign(expand_from->visited, def_stmt, lhs, new_rhs1, new_rhs2, NULL_TREE); +} + -+static void handle_interesting_stmt(struct visited *visited, interesting_stmts_t head) ++#if BUILDING_GCC_VERSION >= 4006 ++static tree get_new_rhs(interesting_stmts_t expand_from, tree size_overflow_type, tree rhs) +{ -+ interesting_stmts_t cur; ++ if (is_gimple_constant(rhs)) ++ return cast_a_tree(size_overflow_type, rhs); ++ if (TREE_CODE(rhs) != SSA_NAME) ++ return NULL_TREE; ++ return expand(expand_from, rhs); ++} + -+ for (cur = head; cur; cur = cur->next) { -+ tree new_node; -+ gimple orig_def_stmt; ++static tree handle_ternary_ops(interesting_stmts_t expand_from, tree lhs) ++{ ++ tree rhs1, rhs2, rhs3, new_rhs1, new_rhs2, new_rhs3, size_overflow_type; ++ gassign *def_stmt = as_a_gassign(get_def_stmt(lhs)); + -+ cur->visited = visited; -+ if (handle_error_codes(cur)) -+ continue; ++ size_overflow_type = get_size_overflow_type(expand_from->visited, def_stmt, lhs); + -+ new_node = expand(cur, cur->orig_node); -+ if (new_node == NULL_TREE) -+ continue; ++ rhs1 = gimple_assign_rhs1(def_stmt); ++ rhs2 = gimple_assign_rhs2(def_stmt); ++ rhs3 = gimple_assign_rhs3(def_stmt); ++ new_rhs1 = get_new_rhs(expand_from, size_overflow_type, rhs1); ++ new_rhs2 = get_new_rhs(expand_from, size_overflow_type, rhs2); ++ new_rhs3 = get_new_rhs(expand_from, size_overflow_type, rhs3); + -+ orig_def_stmt = get_def_stmt(cur->orig_node); -+ if (pointer_set_contains(visited->no_cast_check, orig_def_stmt)) -+ continue; -+ change_orig_node(visited, cur->first_stmt, cur->orig_node, new_node, cur->num); -+ check_size_overflow(cur, cur->first_stmt, TREE_TYPE(new_node), new_node, cur->orig_node, BEFORE_STMT); -+ } ++ return dup_assign(expand_from->visited, def_stmt, lhs, new_rhs1, new_rhs2, new_rhs3); +} ++#endif + -+static next_interesting_function_t get_interesting_function_next_node(tree decl, unsigned int num) ++static tree expand_visited(struct visited *visited, gimple def_stmt) +{ -+ next_interesting_function_t next_node; -+ const struct size_overflow_hash *so_hash; -+ struct fn_raw_data raw_data; ++ gimple_stmt_iterator gsi; ++ enum gimple_code code = gimple_code(def_stmt); + -+ raw_data.decl = decl; -+ raw_data.decl_str = DECL_NAME_POINTER(decl); -+ raw_data.num = num; -+ raw_data.marked = YES_SO_MARK; ++ if (code == GIMPLE_ASM) ++ return NULL_TREE; + -+ next_node = get_global_next_interesting_function_entry_with_hash(&raw_data); -+ if (next_node && next_node->marked != NO_SO_MARK) -+ return next_node; ++ gsi = gsi_for_stmt(def_stmt); ++ gsi_next(&gsi); + -+ so_hash = get_size_overflow_hash_entry_tree(raw_data.decl, raw_data.num, SIZE_OVERFLOW); -+ if (so_hash) -+ return get_and_create_next_node_from_global_next_nodes(&raw_data, NULL); -+ return NULL; ++ if (gimple_code(def_stmt) == GIMPLE_PHI && gsi_end_p(gsi)) ++ return NULL_TREE; ++ return get_my_stmt_lhs(visited, def_stmt); +} + -+tree handle_fnptr_assign(const_gimple stmt) ++tree expand(interesting_stmts_t expand_from, tree lhs) +{ -+ tree field, rhs, op0; -+ const_tree op0_type; -+ enum tree_code rhs_code; ++ gimple def_stmt; + -+ // TODO skip binary assignments for now (fs/sync.c _591 = __bpf_call_base + _590;) -+ if (gimple_num_ops(stmt) != 2) -+ return NULL_TREE; ++ def_stmt = get_def_stmt(lhs); + -+ gcc_assert(gimple_num_ops(stmt) == 2); -+ // TODO skip asm_stmt for now -+ if (gimple_code(stmt) == GIMPLE_ASM) -+ return NULL_TREE; -+ rhs = gimple_assign_rhs1(stmt); -+ if (is_gimple_constant(rhs)) ++ if (!def_stmt || gimple_code(def_stmt) == GIMPLE_NOP) + return NULL_TREE; + -+ rhs_code = TREE_CODE(rhs); -+ if (rhs_code == VAR_DECL) -+ return rhs; ++ if (pointer_set_contains(expand_from->visited->my_stmts, def_stmt)) ++ return lhs; + -+ switch (rhs_code) { -+ case ADDR_EXPR: -+ op0 = TREE_OPERAND(rhs, 0); -+ gcc_assert(TREE_CODE(op0) == FUNCTION_DECL); -+ return op0; -+ case COMPONENT_REF: -+ break; -+ // TODO skip array_ref for now -+ case ARRAY_REF: -+ return NULL_TREE; -+ // TODO skip ssa_name because it can lead to parm_decl -+ case SSA_NAME: ++ if (pointer_set_contains(expand_from->visited->stmts, def_stmt)) ++ return expand_visited(expand_from->visited, def_stmt); ++ ++ if (is_gimple_constant(lhs)) + return NULL_TREE; -+ // TODO skip mem_ref and indirect_ref for now -+#if BUILDING_GCC_VERSION >= 4006 -+ case MEM_REF: -+#endif -+ case INDIRECT_REF: ++ if (skip_types(lhs)) + return NULL_TREE; -+ default: -+ debug_tree(rhs); -+ debug_gimple_stmt((gimple)stmt); -+ gcc_unreachable(); -+ } + -+ op0 = TREE_OPERAND(rhs, 0); -+ switch (TREE_CODE(op0)) { -+ // TODO skip array_ref and parm_decl for now -+ case ARRAY_REF: -+ case PARM_DECL: -+ return NULL_TREE; -+ case COMPONENT_REF: ++ switch (gimple_code(def_stmt)) { ++ case GIMPLE_PHI: ++ return handle_phi(expand_from, lhs); ++ case GIMPLE_CALL: ++ case GIMPLE_ASM: ++ if (is_size_overflow_asm(def_stmt)) ++ return expand(expand_from, get_size_overflow_asm_input(as_a_gasm(def_stmt))); ++ return create_assign(expand_from->visited, def_stmt, lhs, AFTER_STMT); ++ case GIMPLE_ASSIGN: ++ switch (gimple_num_ops(def_stmt)) { ++ case 2: ++ return handle_unary_ops(expand_from, as_a_gassign(def_stmt)); ++ case 3: ++ return handle_binary_ops(expand_from, lhs); +#if BUILDING_GCC_VERSION >= 4006 -+ case MEM_REF: ++ case 4: ++ return handle_ternary_ops(expand_from, lhs); +#endif -+ case INDIRECT_REF: -+ case VAR_DECL: -+ break; ++ } + default: -+ debug_tree(op0); ++ debug_gimple_stmt(def_stmt); ++ error("%s: unknown gimple code", __func__); + gcc_unreachable(); + } -+ -+ op0_type = TREE_TYPE(op0); -+ // TODO skip unions for now -+ if (TREE_CODE(op0_type) == UNION_TYPE) -+ return NULL_TREE; -+ gcc_assert(TREE_CODE(op0_type) == RECORD_TYPE); -+ -+ field = TREE_OPERAND(rhs, 1); -+ gcc_assert(TREE_CODE(field) == FIELD_DECL); -+ return field; +} +diff --git a/scripts/gcc-plugins/stackleak_plugin.c b/scripts/gcc-plugins/stackleak_plugin.c +new file mode 100644 +index 0000000..8b69bd4 +--- /dev/null ++++ b/scripts/gcc-plugins/stackleak_plugin.c +@@ -0,0 +1,350 @@ ++/* ++ * Copyright 2011-2016 by the PaX Team ++ * Licensed under the GPL v2 ++ * ++ * Note: the choice of the license means that the compilation process is ++ * NOT 'eligible' as defined by gcc's library exception to the GPL v3, ++ * but for the kernel it doesn't matter since it doesn't link against ++ * any of the gcc libraries ++ * ++ * gcc plugin to help implement various PaX features ++ * ++ * - track lowest stack pointer ++ * ++ * TODO: ++ * - initialize all local variables ++ * ++ * BUGS: ++ * - none known ++ */ + -+static tree get_fn_or_fnptr_decl(const gcall *call_stmt) -+{ -+ const_tree fnptr; -+ const_gimple def_stmt; -+ tree decl = gimple_call_fndecl(call_stmt); ++#include "gcc-common.h" + -+ if (decl != NULL_TREE) -+ return decl; ++int plugin_is_GPL_compatible; + -+ fnptr = gimple_call_fn(call_stmt); -+ if (fnptr == NULL_TREE) -+ return NULL_TREE; ++static int track_frame_size = -1; ++static const char track_function[] = "pax_track_stack"; ++static const char check_function[] = "pax_check_alloca"; ++static GTY(()) tree track_function_decl; ++static GTY(()) tree check_function_decl; ++static bool init_locals; + -+ // !!! assertot kell irni 0-ra, mert csak az lehet ott -+ if (is_gimple_constant(fnptr)) -+ return NULL_TREE; -+ def_stmt = get_fnptr_def_stmt(fnptr); -+ return handle_fnptr_assign(def_stmt); -+} ++static struct plugin_info stackleak_plugin_info = { ++ .version = "201602181345", ++ .help = "track-lowest-sp=nn\ttrack sp in functions whose frame size is at least nn bytes\n" ++// "initialize-locals\t\tforcibly initialize all stack frames\n" ++}; + -+// Start stmt duplication on marked function parameters -+static interesting_stmts_t search_interesting_calls(interesting_stmts_t head, gcall *call_stmt) ++static void stackleak_check_alloca(gimple_stmt_iterator *gsi) +{ -+ tree decl; -+ unsigned int i, len; -+ -+ len = gimple_call_num_args(call_stmt); -+ if (len == 0) -+ return head; -+ -+ decl = get_fn_or_fnptr_decl(call_stmt); -+ if (decl == NULL_TREE) -+ return head; -+ -+ for (i = 0; i < len; i++) { -+ tree arg; -+ next_interesting_function_t next_node; ++ gimple stmt; ++ gcall *check_alloca; ++ tree alloca_size; ++ cgraph_node_ptr node; ++ int frequency; ++ basic_block bb; + -+ arg = gimple_call_arg(call_stmt, i); -+ if (is_gimple_constant(arg)) -+ continue; -+ if (skip_types(arg)) -+ continue; -+ next_node = get_interesting_function_next_node(decl, i + 1); -+ if (next_node) -+ head = search_interesting_stmt(head, next_node, call_stmt, arg, i + 1); -+ } ++ // insert call to void pax_check_alloca(unsigned long size) ++ alloca_size = gimple_call_arg(gsi_stmt(*gsi), 0); ++ stmt = gimple_build_call(check_function_decl, 1, alloca_size); ++ check_alloca = as_a_gcall(stmt); ++ gsi_insert_before(gsi, check_alloca, GSI_SAME_STMT); + -+ return head; ++ // update the cgraph ++ bb = gimple_bb(check_alloca); ++ node = cgraph_get_create_node(check_function_decl); ++ gcc_assert(node); ++ frequency = compute_call_stmt_bb_frequency(current_function_decl, bb); ++ cgraph_create_edge(cgraph_get_node(current_function_decl), node, check_alloca, bb->count, frequency, bb->loop_depth); +} + -+// Find assignements to structure fields and vardecls -+static interesting_stmts_t search_interesting_structs_vardecls(interesting_stmts_t head, gassign *assign) ++static void stackleak_add_instrumentation(gimple_stmt_iterator *gsi, bool after) +{ -+ enum intentional_mark mark; -+ next_interesting_function_t next_node; -+ tree rhs1, rhs2, lhs, decl; -+#if BUILDING_GCC_VERSION >= 4006 -+ tree rhs3; -+#endif -+ -+ lhs = gimple_assign_lhs(assign); -+ -+ if (VAR_P(lhs)) -+ decl = lhs; -+ else -+ decl = get_ref_field(lhs); -+ if (decl == NULL_TREE) -+ return head; -+ if (DECL_NAME(decl) == NULL_TREE) -+ return head; -+ -+ if (is_bitfield_unnamed_cast(decl, assign)) -+ return head; -+ -+ next_node = get_interesting_function_next_node(decl, 0); -+ if (!next_node) -+ return head; -+ -+ mark = get_intentional_attr_type(decl); -+ if (mark != MARK_NO) -+ return head; -+ -+ rhs1 = gimple_assign_rhs1(assign); -+ head = search_interesting_stmt(head, next_node, assign, rhs1, 0); ++ gimple stmt; ++ gcall *track_stack; ++ cgraph_node_ptr node; ++ int frequency; ++ basic_block bb; + -+ rhs2 = gimple_assign_rhs2(assign); -+ if (rhs2) -+ head = search_interesting_stmt(head, next_node, assign, rhs2, 0); ++ // insert call to void pax_track_stack(void) ++ stmt = gimple_build_call(track_function_decl, 0); ++ track_stack = as_a_gcall(stmt); ++ if (after) ++ gsi_insert_after(gsi, track_stack, GSI_CONTINUE_LINKING); ++ else ++ gsi_insert_before(gsi, track_stack, GSI_SAME_STMT); + -+#if BUILDING_GCC_VERSION >= 4006 -+ rhs3 = gimple_assign_rhs3(assign); -+ if (rhs3) -+ head = search_interesting_stmt(head, next_node, assign, rhs3, 0); -+#endif -+ return head; ++ // update the cgraph ++ bb = gimple_bb(track_stack); ++ node = cgraph_get_create_node(track_function_decl); ++ gcc_assert(node); ++ frequency = compute_call_stmt_bb_frequency(current_function_decl, bb); ++ cgraph_create_edge(cgraph_get_node(current_function_decl), node, track_stack, bb->count, frequency, bb->loop_depth); +} + -+static next_interesting_function_t create_so_asm_next_interesting_function_node(const gasm *stmt) ++static bool is_alloca(gimple stmt) +{ -+ next_interesting_function_t next_node; -+ struct fn_raw_data raw_data; -+ -+ raw_data.decl = NULL_TREE; -+ raw_data.decl_str = gimple_asm_string(stmt); -+ raw_data.context = "attr"; -+ raw_data.hash = 0; -+ raw_data.num = 0; -+ raw_data.marked = ASM_STMT_SO_MARK; ++ if (gimple_call_builtin_p(stmt, BUILT_IN_ALLOCA)) ++ return true; + -+ next_node = get_global_next_interesting_function_entry(&raw_data); -+ if (next_node) -+ return next_node; -+ next_node = create_new_next_interesting_entry(&raw_data, NULL); -+ gcc_assert(next_node); ++#if BUILDING_GCC_VERSION >= 4007 ++ if (gimple_call_builtin_p(stmt, BUILT_IN_ALLOCA_WITH_ALIGN)) ++ return true; ++#endif + -+ add_to_global_next_interesting_function(next_node); -+ return next_node; ++ return false; +} + -+// Collect interesting stmts for duplication -+static void search_interesting_stmts(struct visited *visited) ++static unsigned int stackleak_tree_instrument_execute(void) +{ -+ basic_block bb; -+ next_interesting_function_t next_node_ret; -+ interesting_stmts_t head = NULL; ++ basic_block bb, entry_bb; ++ bool prologue_instrumented = false, is_leaf = true; + -+ next_node_ret = get_interesting_function_next_node(current_function_decl, 0); ++ entry_bb = ENTRY_BLOCK_PTR_FOR_FN(cfun)->next_bb; + ++ // 1. loop through BBs and GIMPLE statements + FOR_EACH_BB_FN(bb, cfun) { + gimple_stmt_iterator gsi; + + for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { -+ gimple stmt = gsi_stmt(gsi); ++ gimple stmt; + -+ switch (gimple_code(stmt)) { -+ case GIMPLE_ASM: { -+ tree first_node; -+ next_interesting_function_t next_node; -+ const gasm *asm_stmt = as_a_gasm(stmt); ++ stmt = gsi_stmt(gsi); + -+ if (!is_size_overflow_insert_check_asm(asm_stmt)) -+ continue; -+ next_node = create_so_asm_next_interesting_function_node(asm_stmt); -+ first_node = get_size_overflow_asm_input(asm_stmt); -+ head = search_interesting_stmt(head, next_node, stmt, first_node, 0); -+ break; -+ } -+ case GIMPLE_RETURN: -+ head = search_interesting_rets(head, next_node_ret, as_a_greturn(stmt)); -+ break; -+ case GIMPLE_CALL: -+ head = search_interesting_calls(head, as_a_gcall(stmt)); -+ break; -+ case GIMPLE_ASSIGN: -+ /* !!! TODO LTO modeban nincs duplikalas a globalis valtozora, mert a tree mergek -+ * utan mar nem lehet megkulonboztetni attol a globalis valtozotol, aminek a scopeja csak a file -+ * igy a context nem vardecl lesz, hanem vardecl_filenev. De execute-ban kiirja, ha hianyzik a hash tablabol -+ * IPA-ban van duplikalas. -+ */ -+ head = search_interesting_structs_vardecls(head, as_a_gassign(stmt)); -+ break; -+ default: -+ break; -+ } ++ if (is_gimple_call(stmt)) ++ is_leaf = false; ++ ++ // gimple match: align 8 built-in BUILT_IN_NORMAL:BUILT_IN_ALLOCA attributes ++ if (!is_alloca(stmt)) ++ continue; ++ ++ // 2. insert stack overflow check before each __builtin_alloca call ++ stackleak_check_alloca(&gsi); ++ ++ // 3. insert track call after each __builtin_alloca call ++ stackleak_add_instrumentation(&gsi, true); ++ if (bb == entry_bb) ++ prologue_instrumented = true; + } + } + -+ handle_interesting_stmt(visited, head); -+ free_interesting_stmts(head); -+} ++ // special cases for some bad linux code: taking the address of static inline functions will materialize them ++ // but we mustn't instrument some of them as the resulting stack alignment required by the function call ABI ++ // will break other assumptions regarding the expected (but not otherwise enforced) register clobbering ABI. ++ // case in point: native_save_fl on amd64 when optimized for size clobbers rdx if it were instrumented here. ++ if (is_leaf && !TREE_PUBLIC(current_function_decl) && DECL_DECLARED_INLINE_P(current_function_decl)) ++ return 0; ++ if (is_leaf && !strncmp(IDENTIFIER_POINTER(DECL_NAME(current_function_decl)), "_paravirt_", 10)) ++ return 0; + -+static struct visited *create_visited(void) -+{ -+ struct visited *new_node; ++ // 4. insert track call at the beginning ++ if (!prologue_instrumented) { ++ gimple_stmt_iterator gsi; + -+ new_node = (struct visited *)xmalloc(sizeof(*new_node)); -+ new_node->stmts = pointer_set_create(); -+ new_node->my_stmts = pointer_set_create(); -+ new_node->skip_expr_casts = pointer_set_create(); -+ new_node->no_cast_check = pointer_set_create(); -+ return new_node; ++ gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); ++ bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); ++ if (!single_pred_p(bb)) { ++// gcc_assert(bb_loop_depth(bb) || (bb->flags & BB_IRREDUCIBLE_LOOP)); ++ split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun))); ++ gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); ++ bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); ++ } ++ gsi = gsi_after_labels(bb); ++ stackleak_add_instrumentation(&gsi, false); ++ } ++ ++ return 0; +} + -+static void free_visited(struct visited *visited) ++static unsigned int stackleak_final_execute(void) +{ -+ pointer_set_destroy(visited->stmts); -+ pointer_set_destroy(visited->my_stmts); -+ pointer_set_destroy(visited->skip_expr_casts); -+ pointer_set_destroy(visited->no_cast_check); ++ rtx_insn *insn, *next; + -+ free(visited); -+} ++ if (cfun->calls_alloca) ++ return 0; + -+// 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(gasm *asm_stmt, tree lhs, tree rhs) -+{ -+ gassign *assign; -+ gimple_stmt_iterator gsi; ++ // keep calls only if function frame is big enough ++ if (get_frame_size() >= track_frame_size) ++ return 0; + -+ // already removed -+ if (gimple_bb(asm_stmt) == NULL) -+ return; -+ gsi = gsi_for_stmt(asm_stmt); ++ // 1. find pax_track_stack calls ++ for (insn = get_insns(); insn; insn = next) { ++ // rtl match: (call_insn 8 7 9 3 (call (mem (symbol_ref ("pax_track_stack") [flags 0x41] ) [0 S1 A8]) (4)) -1 (nil) (nil)) ++ rtx body; + -+ assign = gimple_build_assign(lhs, rhs); -+ gsi_insert_before(&gsi, assign, GSI_SAME_STMT); -+ SSA_NAME_DEF_STMT(lhs) = assign; ++ next = NEXT_INSN(insn); ++ if (!CALL_P(insn)) ++ continue; ++ body = PATTERN(insn); ++ if (GET_CODE(body) != CALL) ++ continue; ++ body = XEXP(body, 0); ++ if (GET_CODE(body) != MEM) ++ continue; ++ body = XEXP(body, 0); ++ if (GET_CODE(body) != SYMBOL_REF) ++ continue; ++// if (strcmp(XSTR(body, 0), track_function)) ++ if (SYMBOL_REF_DECL(body) != track_function_decl) ++ continue; ++// warning(0, "track_frame_size: %d %ld %d", cfun->calls_alloca, get_frame_size(), track_frame_size); ++ // 2. delete call ++ delete_insn_and_edges(insn); ++#if BUILDING_GCC_VERSION >= 4007 ++ if (GET_CODE(next) == NOTE && NOTE_KIND(next) == NOTE_INSN_CALL_ARG_LOCATION) { ++ insn = next; ++ next = NEXT_INSN(insn); ++ delete_insn_and_edges(insn); ++ } ++#endif ++ } + -+ gsi_remove(&gsi, true); ++// print_simple_rtl(stderr, get_insns()); ++// print_rtl(stderr, get_insns()); ++// warning(0, "track_frame_size: %d %ld %d", cfun->calls_alloca, get_frame_size(), track_frame_size); ++ ++ return 0; +} + -+// Replace our asm stmts with assignments (they are no longer needed and may interfere with later optimizations) -+static void remove_size_overflow_asm(gimple stmt) ++static bool stackleak_track_stack_gate(void) +{ -+ gimple_stmt_iterator gsi; -+ tree input, output; ++ tree section; + -+ if (!is_size_overflow_asm(stmt)) -+ return; ++ if (ix86_cmodel != CM_KERNEL) ++ return false; + -+ if (gimple_asm_noutputs(as_a_gasm(stmt)) == 0) { -+ gsi = gsi_for_stmt(stmt); ++ section = lookup_attribute("section", DECL_ATTRIBUTES(current_function_decl)); ++ if (section && TREE_VALUE(section)) { ++ section = TREE_VALUE(TREE_VALUE(section)); + -+ ipa_remove_stmt_references(cgraph_get_node(current_function_decl), stmt); -+ gsi_remove(&gsi, true); -+ return; ++ if (!strncmp(TREE_STRING_POINTER(section), ".init.text", 10)) ++ return false; ++ if (!strncmp(TREE_STRING_POINTER(section), ".devinit.text", 13)) ++ return false; ++ if (!strncmp(TREE_STRING_POINTER(section), ".cpuinit.text", 13)) ++ return false; ++ if (!strncmp(TREE_STRING_POINTER(section), ".meminit.text", 13)) ++ return false; + } + -+ input = gimple_asm_input_op(as_a_gasm(stmt), 0); -+ output = gimple_asm_output_op(as_a_gasm(stmt), 0); -+ replace_size_overflow_asm_with_assign(as_a_gasm(stmt), TREE_VALUE(output), TREE_VALUE(input)); ++ return track_frame_size >= 0; +} + -+static void remove_all_size_overflow_asm(void) ++static void stackleak_start_unit(void *gcc_data, void *user_data) +{ -+ basic_block bb; ++ tree fntype; + -+ FOR_EACH_BB_FN(bb, cfun) { -+ gimple_stmt_iterator si; ++ // void pax_track_stack(void) ++ fntype = build_function_type_list(void_type_node, NULL_TREE); ++ track_function_decl = build_fn_decl(track_function, fntype); ++ DECL_ASSEMBLER_NAME(track_function_decl); // for LTO ++ TREE_PUBLIC(track_function_decl) = 1; ++ TREE_USED(track_function_decl) = 1; ++ DECL_EXTERNAL(track_function_decl) = 1; ++ DECL_ARTIFICIAL(track_function_decl) = 1; ++ DECL_PRESERVE_P(track_function_decl) = 1; + -+ for (si = gsi_start_bb(bb); !gsi_end_p(si); gsi_next(&si)) -+ remove_size_overflow_asm(gsi_stmt(si)); -+ } ++ // void pax_check_alloca(unsigned long) ++ fntype = build_function_type_list(void_type_node, long_unsigned_type_node, NULL_TREE); ++ check_function_decl = build_fn_decl(check_function, fntype); ++ DECL_ASSEMBLER_NAME(check_function_decl); // for LTO ++ TREE_PUBLIC(check_function_decl) = 1; ++ TREE_USED(check_function_decl) = 1; ++ DECL_EXTERNAL(check_function_decl) = 1; ++ DECL_ARTIFICIAL(check_function_decl) = 1; ++ DECL_PRESERVE_P(check_function_decl) = 1; +} + -+unsigned int size_overflow_function_transform(struct cgraph_node *node __unused) ++static bool stackleak_tree_instrument_gate(void) +{ -+ struct visited *visited; ++ return stackleak_track_stack_gate(); ++} + -+#if BUILDING_GCC_VERSION >= 4008 -+ if (dump_file) { -+ fprintf(dump_file, "BEFORE TRANSFORM -------------------------\n"); -+ size_overflow_dump_function(dump_file, node); -+ } -+#endif -+ visited = create_visited(); -+ set_dominance_info(); ++#define PASS_NAME stackleak_tree_instrument ++#define PROPERTIES_REQUIRED PROP_gimple_leh | PROP_cfg ++#define TODO_FLAGS_START TODO_verify_ssa | TODO_verify_flow | TODO_verify_stmts ++#define TODO_FLAGS_FINISH TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func | TODO_update_ssa | TODO_rebuild_cgraph_edges ++#include "gcc-generate-gimple-pass.h" + -+ search_interesting_stmts(visited); ++static bool stackleak_final_gate(void) ++{ ++ return stackleak_track_stack_gate(); ++} + -+ remove_all_size_overflow_asm(); ++#define PASS_NAME stackleak_final ++#define TODO_FLAGS_FINISH TODO_dump_func ++#include "gcc-generate-rtl-pass.h" + -+ unset_dominance_info(); -+ free_visited(visited); ++int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) ++{ ++ const char * const plugin_name = plugin_info->base_name; ++ const int argc = plugin_info->argc; ++ const struct plugin_argument * const argv = plugin_info->argv; ++ int i; ++ struct register_pass_info stackleak_tree_instrument_pass_info; ++ struct register_pass_info stackleak_final_pass_info; ++ static const struct ggc_root_tab gt_ggc_r_gt_stackleak[] = { ++ { ++ .base = &track_function_decl, ++ .nelt = 1, ++ .stride = sizeof(track_function_decl), ++ .cb = >_ggc_mx_tree_node, ++ .pchw = >_pch_nx_tree_node ++ }, ++ { ++ .base = &check_function_decl, ++ .nelt = 1, ++ .stride = sizeof(check_function_decl), ++ .cb = >_ggc_mx_tree_node, ++ .pchw = >_pch_nx_tree_node ++ }, ++ LAST_GGC_ROOT_TAB ++ }; + -+#if BUILDING_GCC_VERSION >= 4008 -+ if (dump_file) { -+ fprintf(dump_file, "AFTER TRANSFORM -------------------------\n"); -+ size_overflow_dump_function(dump_file, node); ++ stackleak_tree_instrument_pass_info.pass = make_stackleak_tree_instrument_pass(); ++// stackleak_tree_instrument_pass_info.reference_pass_name = "tree_profile"; ++ stackleak_tree_instrument_pass_info.reference_pass_name = "optimized"; ++ stackleak_tree_instrument_pass_info.ref_pass_instance_number = 1; ++ stackleak_tree_instrument_pass_info.pos_op = PASS_POS_INSERT_BEFORE; ++ ++ stackleak_final_pass_info.pass = make_stackleak_final_pass(); ++ stackleak_final_pass_info.reference_pass_name = "final"; ++ stackleak_final_pass_info.ref_pass_instance_number = 1; ++ stackleak_final_pass_info.pos_op = PASS_POS_INSERT_BEFORE; ++ ++ if (!plugin_default_version_check(version, &gcc_version)) { ++ error(G_("incompatible gcc/plugin versions")); ++ return 1; + } -+#endif -+ return TODO_dump_func | TODO_verify_stmts | TODO_remove_unused_locals | TODO_update_ssa_no_phi | TODO_ggc_collect | TODO_verify_flow; ++ ++ register_callback(plugin_name, PLUGIN_INFO, NULL, &stackleak_plugin_info); ++ ++ for (i = 0; i < argc; ++i) { ++ if (!strcmp(argv[i].key, "track-lowest-sp")) { ++ if (!argv[i].value) { ++ error(G_("no value supplied for option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); ++ continue; ++ } ++ track_frame_size = atoi(argv[i].value); ++ if (argv[i].value[0] < '0' || argv[i].value[0] > '9' || track_frame_size < 0) ++ error(G_("invalid option argument '-fplugin-arg-%s-%s=%s'"), plugin_name, argv[i].key, argv[i].value); ++ continue; ++ } ++ if (!strcmp(argv[i].key, "initialize-locals")) { ++ if (argv[i].value) { ++ error(G_("invalid option argument '-fplugin-arg-%s-%s=%s'"), plugin_name, argv[i].key, argv[i].value); ++ continue; ++ } ++ init_locals = true; ++ continue; ++ } ++ error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); ++ } ++ ++ register_callback(plugin_name, PLUGIN_START_UNIT, &stackleak_start_unit, NULL); ++ register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, NULL, (void *)>_ggc_r_gt_stackleak); ++ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &stackleak_tree_instrument_pass_info); ++ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &stackleak_final_pass_info); ++ ++ return 0; +} -diff --git a/tools/gcc/size_overflow_plugin/size_overflow_transform_core.c b/tools/gcc/size_overflow_plugin/size_overflow_transform_core.c +diff --git a/scripts/gcc-plugins/structleak_plugin.c b/scripts/gcc-plugins/structleak_plugin.c new file mode 100644 -index 0000000..062204a +index 0000000..d7596e6 --- /dev/null -+++ b/tools/gcc/size_overflow_plugin/size_overflow_transform_core.c -@@ -0,0 +1,1025 @@ ++++ b/scripts/gcc-plugins/structleak_plugin.c +@@ -0,0 +1,239 @@ +/* -+ * Copyright 2011-2016 by Emese Revfy -+ * Licensed under the GPL v2, or (at your option) v3 ++ * Copyright 2013-2016 by PaX Team ++ * Licensed under the GPL v2 + * -+ * Homepage: -+ * https://github.com/ephox-gcc-plugins/size_overflow ++ * Note: the choice of the license means that the compilation process is ++ * NOT 'eligible' as defined by gcc's library exception to the GPL v3, ++ * but for the kernel it doesn't matter since it doesn't link against ++ * any of the gcc libraries + * -+ * Documentation: -+ * http://forums.grsecurity.net/viewtopic.php?f=7&t=3043 ++ * gcc plugin to forcibly initialize certain local variables that could ++ * otherwise leak kernel stack to userland if they aren't properly initialized ++ * by later code + * -+ * This plugin recomputes expressions of function arguments marked by a size_overflow attribute -+ * with double integer precision (DImode/TImode for 32/64 bit integer types). -+ * The recomputed argument is checked against TYPE_MAX and an event is logged on overflow and the triggering process is killed. ++ * Homepage: http://pax.grsecurity.net/ + * + * Usage: -+ * $ make -+ * $ make run ++ * $ # for 4.5/4.6/C based 4.7 ++ * $ gcc -I`gcc -print-file-name=plugin`/include -I`gcc -print-file-name=plugin`/include/c-family -fPIC -shared -O2 -o structleak_plugin.so structleak_plugin.c ++ * $ # for C++ based 4.7/4.8+ ++ * $ g++ -I`g++ -print-file-name=plugin`/include -I`g++ -print-file-name=plugin`/include/c-family -fPIC -shared -O2 -o structleak_plugin.so structleak_plugin.c ++ * $ gcc -fplugin=./structleak_plugin.so test.c -O2 ++ * ++ * TODO: eliminate redundant initializers ++ * increase type coverage + */ + -+#include "size_overflow.h" ++#include "gcc-common.h" + -+#define MIN_CHECK true -+#define MAX_CHECK false ++// unused C type flag in all versions 4.5-6 ++#define TYPE_USERSPACE(TYPE) TYPE_LANG_FLAG_5(TYPE) + -+unsigned int call_count = 0; ++int plugin_is_GPL_compatible; + -+tree get_size_overflow_type(struct visited *visited, const_gimple stmt, const_tree node) -+{ -+ const_tree type; -+ tree new_type; ++static struct plugin_info structleak_plugin_info = { ++ .version = "201602181345", ++ .help = "disable\tdo not activate plugin\n", ++}; + -+ gcc_assert(node != NULL_TREE); ++static tree handle_user_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs) ++{ ++ *no_add_attrs = true; + -+ type = TREE_TYPE(node); ++ // check for types? for now accept everything linux has to offer ++ if (TREE_CODE(*node) != FIELD_DECL) ++ return NULL_TREE; + -+ if (pointer_set_contains(visited->my_stmts, stmt)) -+ return TREE_TYPE(node); ++ *no_add_attrs = false; ++ return NULL_TREE; ++} + -+ switch (TYPE_MODE(type)) { -+ case QImode: -+ case HImode: -+ new_type = size_overflow_type_SI; -+ break; -+ case SImode: -+ new_type = size_overflow_type_DI; -+ break; -+ case DImode: -+ if (LONG_TYPE_SIZE == GET_MODE_BITSIZE(SImode)) -+ new_type = TYPE_UNSIGNED(type) ? unsigned_intDI_type_node : intDI_type_node; -+ else -+ new_type = size_overflow_type_TI; -+ break; -+ case TImode: -+ gcc_assert(!TYPE_UNSIGNED(type)); -+ new_type = size_overflow_type_TI; -+ break; -+ default: -+ debug_tree(node); -+ error("%s: unsupported gcc configuration (%qE).", __func__, current_function_decl); -+ gcc_unreachable(); -+ } ++static struct attribute_spec user_attr = { ++ .name = "user", ++ .min_length = 0, ++ .max_length = 0, ++ .decl_required = false, ++ .type_required = false, ++ .function_type_required = false, ++ .handler = handle_user_attribute, ++#if BUILDING_GCC_VERSION >= 4007 ++ .affects_type_identity = true ++#endif ++}; + -+ if (TYPE_QUALS(type) != 0) -+ return build_qualified_type(new_type, TYPE_QUALS(type)); -+ return new_type; ++static void register_attributes(void *event_data, void *data) ++{ ++ register_attribute(&user_attr); ++// register_attribute(&force_attr); +} + -+tree cast_to_new_size_overflow_type(struct visited *visited, gimple stmt, tree rhs, tree size_overflow_type, bool before) ++static tree get_field_type(tree field) +{ -+ gimple_stmt_iterator gsi; -+ gimple new_stmt; -+ -+ if (rhs == NULL_TREE) -+ return NULL_TREE; -+ -+ gsi = gsi_for_stmt(stmt); -+ new_stmt = build_cast_stmt(visited, size_overflow_type, rhs, CREATE_NEW_VAR, &gsi, before, false); -+ if (gimple_assign_cast_p(new_stmt)) -+ gimple_assign_set_rhs_code(new_stmt, CONVERT_EXPR); -+ pointer_set_insert(visited->my_stmts, new_stmt); -+ -+ return get_lhs(new_stmt); ++ return strip_array_types(TREE_TYPE(field)); +} + -+tree create_assign(struct visited *visited, gimple oldstmt, tree rhs1, bool before) ++static bool is_userspace_type(tree type) +{ -+ tree lhs, dst_type; -+ gimple_stmt_iterator gsi; -+ -+ if (rhs1 == NULL_TREE) { -+ debug_gimple_stmt(oldstmt); -+ error("%s: rhs1 is NULL_TREE", __func__); -+ gcc_unreachable(); -+ } -+ -+ switch (gimple_code(oldstmt)) { -+ case GIMPLE_ASM: -+ lhs = rhs1; -+ break; -+ case GIMPLE_CALL: -+ case GIMPLE_ASSIGN: -+ lhs = gimple_get_lhs(oldstmt); -+ break; -+ default: -+ debug_gimple_stmt(oldstmt); -+ gcc_unreachable(); -+ } -+ -+ gsi = gsi_for_stmt(oldstmt); -+ pointer_set_insert(visited->stmts, oldstmt); -+ if (lookup_stmt_eh_lp(oldstmt) != 0) { -+ basic_block next_bb, cur_bb; -+ const_edge e; -+ -+ gcc_assert(before == false); -+ gcc_assert(stmt_can_throw_internal(oldstmt)); -+ gcc_assert(gimple_code(oldstmt) == GIMPLE_CALL); -+ gcc_assert(!gsi_end_p(gsi)); ++ tree field; + -+ cur_bb = gimple_bb(oldstmt); -+ next_bb = cur_bb->next_bb; -+ e = find_edge(cur_bb, next_bb); -+ gcc_assert(e != NULL); -+ gcc_assert(e->flags & EDGE_FALLTHRU); ++ for (field = TYPE_FIELDS(type); field; field = TREE_CHAIN(field)) { ++ tree fieldtype = get_field_type(field); ++ enum tree_code code = TREE_CODE(fieldtype); + -+ gsi = gsi_after_labels(next_bb); -+ gcc_assert(!gsi_end_p(gsi)); ++ if (code == RECORD_TYPE || code == UNION_TYPE) ++ if (is_userspace_type(fieldtype)) ++ return true; + -+ before = true; -+ oldstmt = gsi_stmt(gsi); ++ if (lookup_attribute("user", DECL_ATTRIBUTES(field))) ++ return true; + } -+ -+ if (is_gimple_constant(rhs1) && TREE_CODE_CLASS(gimple_assign_rhs_code(oldstmt)) == tcc_comparison) -+ dst_type = get_size_overflow_type(visited, oldstmt, rhs1); -+ else -+ dst_type = get_size_overflow_type(visited, oldstmt, lhs); -+ -+ if (is_gimple_constant(rhs1)) -+ return cast_a_tree(dst_type, rhs1); -+ return cast_to_new_size_overflow_type(visited, oldstmt, rhs1, dst_type, before); ++ return false; +} + -+tree dup_assign(struct visited *visited, gassign *oldstmt, const_tree node, tree rhs1, tree rhs2, tree __unused rhs3) ++static void finish_type(void *event_data, void *data) +{ -+ gassign *stmt; -+ gimple_stmt_iterator gsi; -+ tree size_overflow_type, new_var, lhs = gimple_assign_lhs(oldstmt); -+ -+ if (pointer_set_contains(visited->my_stmts, oldstmt)) -+ return lhs; -+ -+ if (gimple_num_ops(oldstmt) != 4 && rhs1 == NULL_TREE) { -+ rhs1 = gimple_assign_rhs1(oldstmt); -+ rhs1 = create_assign(visited, oldstmt, rhs1, BEFORE_STMT); -+ } -+ if (gimple_num_ops(oldstmt) == 3 && rhs2 == NULL_TREE) { -+ rhs2 = gimple_assign_rhs2(oldstmt); -+ rhs2 = create_assign(visited, oldstmt, rhs2, BEFORE_STMT); -+ } -+ -+ stmt = as_a_gassign(gimple_copy(oldstmt)); -+ gimple_set_location(stmt, gimple_location(oldstmt)); -+ pointer_set_insert(visited->my_stmts, stmt); -+ -+ if (gimple_assign_rhs_code(oldstmt) == WIDEN_MULT_EXPR) -+ gimple_assign_set_rhs_code(stmt, MULT_EXPR); -+ -+ size_overflow_type = get_size_overflow_type(visited, oldstmt, node); -+ -+ new_var = create_new_var(size_overflow_type); -+ new_var = make_ssa_name(new_var, stmt); -+ gimple_assign_set_lhs(stmt, new_var); ++ tree type = (tree)event_data; + -+ if (rhs1 != NULL_TREE) -+ gimple_assign_set_rhs1(stmt, rhs1); ++ if (type == NULL_TREE || type == error_mark_node) ++ return; + -+ if (rhs2 != NULL_TREE) -+ gimple_assign_set_rhs2(stmt, rhs2); -+#if BUILDING_GCC_VERSION >= 4006 -+ if (rhs3 != NULL_TREE) -+ gimple_assign_set_rhs3(stmt, rhs3); ++#if BUILDING_GCC_VERSION >= 5000 ++ if (TREE_CODE(type) == ENUMERAL_TYPE) ++ return; +#endif -+ gimple_set_vuse(stmt, gimple_vuse(oldstmt)); -+ gimple_set_vdef(stmt, gimple_vdef(oldstmt)); + -+ gsi = gsi_for_stmt(oldstmt); -+ gsi_insert_after(&gsi, stmt, GSI_SAME_STMT); -+ update_stmt(stmt); -+ pointer_set_insert(visited->stmts, oldstmt); -+ return gimple_assign_lhs(stmt); ++ if (TYPE_USERSPACE(type)) ++ return; ++ ++ if (is_userspace_type(type)) ++ TYPE_USERSPACE(type) = 1; +} + -+static tree cast_parm_decl(struct visited *visited, tree phi_ssa_name, tree arg, tree size_overflow_type, basic_block bb) ++static void initialize(tree var) +{ -+ const_gimple assign; ++ basic_block bb; + gimple_stmt_iterator gsi; -+ basic_block first_bb; ++ tree initializer; ++ gimple init_stmt; + -+ gcc_assert(SSA_NAME_IS_DEFAULT_DEF(arg)); ++ // this is the original entry bb before the forced split ++ bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); + -+ if (bb->index == 0) { -+ first_bb = split_block_after_labels(ENTRY_BLOCK_PTR_FOR_FN(cfun))->dest; -+ gcc_assert(dom_info_available_p(CDI_DOMINATORS)); -+ set_immediate_dominator(CDI_DOMINATORS, first_bb, ENTRY_BLOCK_PTR_FOR_FN(cfun)); -+ bb = first_bb; -+ } ++ // first check if the variable is already initialized, warn otherwise ++ for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { ++ gimple stmt = gsi_stmt(gsi); ++ tree rhs1; + -+ gsi = gsi_after_labels(bb); -+ assign = build_cast_stmt(visited, size_overflow_type, arg, phi_ssa_name, &gsi, BEFORE_STMT, false); -+ pointer_set_insert(visited->my_stmts, assign); -+ return get_lhs(assign); -+} ++ // we're looking for an assignment of a single rhs... ++ if (!gimple_assign_single_p(stmt)) ++ continue; ++ rhs1 = gimple_assign_rhs1(stmt); ++#if BUILDING_GCC_VERSION >= 4007 ++ // ... of a non-clobbering expression... ++ if (TREE_CLOBBER_P(rhs1)) ++ continue; ++#endif ++ // ... to our variable... ++ if (gimple_get_lhs(stmt) != var) ++ continue; ++ // if it's an initializer then we're good ++ if (TREE_CODE(rhs1) == CONSTRUCTOR) ++ return; ++ } + -+static tree use_phi_ssa_name(struct visited *visited, tree ssa_name_var, tree new_arg) -+{ -+ gimple_stmt_iterator gsi; -+ const_gimple assign; -+ gimple def_stmt = get_def_stmt(new_arg); ++ // these aren't the 0days you're looking for ++// inform(DECL_SOURCE_LOCATION(var), "userspace variable will be forcibly initialized"); + -+ if (gimple_code(def_stmt) == GIMPLE_PHI) { -+ gsi = gsi_after_labels(gimple_bb(def_stmt)); -+ assign = build_cast_stmt(visited, TREE_TYPE(new_arg), new_arg, ssa_name_var, &gsi, BEFORE_STMT, true); -+ } else { -+ gsi = gsi_for_stmt(def_stmt); -+ assign = build_cast_stmt(visited, TREE_TYPE(new_arg), new_arg, ssa_name_var, &gsi, AFTER_STMT, true); -+ } ++ // build the initializer expression ++ initializer = build_constructor(TREE_TYPE(var), NULL); + -+ pointer_set_insert(visited->my_stmts, assign); -+ return get_lhs(assign); ++ // build the initializer stmt ++ init_stmt = gimple_build_assign(var, initializer); ++ gsi = gsi_after_labels(single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun))); ++ gsi_insert_before(&gsi, init_stmt, GSI_NEW_STMT); ++ update_stmt(init_stmt); +} + -+static tree cast_visited_phi_arg(struct visited *visited, tree ssa_name_var, tree arg, tree size_overflow_type) ++static unsigned int structleak_execute(void) +{ + basic_block bb; -+ gimple_stmt_iterator gsi; -+ const_gimple def_stmt; -+ const_gimple assign; -+ -+ def_stmt = get_def_stmt(arg); -+ bb = gimple_bb(def_stmt); -+ gcc_assert(bb->index != 0); -+ gsi = gsi_after_labels(bb); -+ -+ assign = build_cast_stmt(visited, size_overflow_type, arg, ssa_name_var, &gsi, BEFORE_STMT, false); -+ pointer_set_insert(visited->my_stmts, assign); -+ return get_lhs(assign); -+} ++ unsigned int ret = 0; ++ tree var; ++ 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; -+ const_gimple def_stmt; ++ // split the first bb where we can put the forced initializers ++ gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); ++ bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); ++ if (!single_pred_p(bb)) { ++// gcc_assert(bb_loop_depth(bb) || (bb->flags & BB_IRREDUCIBLE_LOOP)); ++ split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun))); ++ gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); ++ } + -+ if (new_arg != NULL_TREE && is_gimple_constant(new_arg)) -+ return new_arg; ++ // enumarate all local variables and forcibly initialize our targets ++ FOR_EACH_LOCAL_DECL(cfun, i, var) { ++ tree type = TREE_TYPE(var); + -+ arg = gimple_phi_arg_def(oldstmt, i); -+ def_stmt = get_def_stmt(arg); -+ gcc_assert(def_stmt != NULL); -+ size_overflow_type = get_size_overflow_type(visited, oldstmt, arg); ++ gcc_assert(DECL_P(var)); ++ if (!auto_var_in_fn_p(var, current_function_decl)) ++ continue; + -+ switch (gimple_code(def_stmt)) { -+ case GIMPLE_PHI: -+ return cast_visited_phi_arg(visited, ssa_name_var, arg, size_overflow_type); -+ case GIMPLE_NOP: { -+ basic_block bb; ++ // only care about structure types ++ if (TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE) ++ continue; + -+ bb = gimple_phi_arg_edge(oldstmt, i)->src; -+ return cast_parm_decl(visited, ssa_name_var, arg, size_overflow_type, bb); ++ // if the type is of interest, examine the variable ++ if (TYPE_USERSPACE(type)) ++ initialize(var); + } -+ case GIMPLE_ASM: { -+ gimple_stmt_iterator gsi; -+ const_gimple assign; -+ gimple stmt = get_def_stmt(arg); + -+ 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 get_lhs(assign); -+ } -+ default: -+ gcc_assert(new_arg != NULL_TREE); -+ gcc_assert(types_compatible_p(TREE_TYPE(new_arg), size_overflow_type)); -+ return use_phi_ssa_name(visited, ssa_name_var, new_arg); -+ } ++ return ret; +} + -+static gphi *overflow_create_phi_node(struct visited *visited, gphi *oldstmt, tree result) ++#define PASS_NAME structleak ++#define NO_GATE ++#define PROPERTIES_REQUIRED PROP_cfg ++#define TODO_FLAGS_FINISH TODO_verify_il | TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func | TODO_remove_unused_locals | TODO_update_ssa | TODO_ggc_collect | TODO_verify_flow ++#include "gcc-generate-gimple-pass.h" ++ ++int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) +{ -+ basic_block bb; -+ gphi *phi; -+ gimple_seq seq; -+ gimple_stmt_iterator gsi = gsi_for_stmt(oldstmt); ++ int i; ++ const char * const plugin_name = plugin_info->base_name; ++ const int argc = plugin_info->argc; ++ const struct plugin_argument * const argv = plugin_info->argv; ++ bool enable = true; ++ struct register_pass_info structleak_pass_info; + -+ bb = gsi_bb(gsi); ++ structleak_pass_info.pass = make_structleak_pass(); ++ structleak_pass_info.reference_pass_name = "ssa"; ++ structleak_pass_info.ref_pass_instance_number = 1; ++ structleak_pass_info.pos_op = PASS_POS_INSERT_AFTER; + -+ if (result == NULL_TREE) { -+ tree old_result = gimple_phi_result(oldstmt); -+ tree size_overflow_type = get_size_overflow_type(visited, oldstmt, old_result); ++ if (!plugin_default_version_check(version, &gcc_version)) { ++ error(G_("incompatible gcc/plugin versions")); ++ return 1; ++ } + -+ result = create_new_var(size_overflow_type); ++ if (strncmp(lang_hooks.name, "GNU C", 5) && !strncmp(lang_hooks.name, "GNU C+", 6)) { ++ inform(UNKNOWN_LOCATION, G_("%s supports C only, not %s"), plugin_name, lang_hooks.name); ++ enable = false; + } + -+ 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); -+ gsi_remove(&gsi, false); ++ for (i = 0; i < argc; ++i) { ++ if (!strcmp(argv[i].key, "disable")) { ++ enable = false; ++ continue; ++ } ++ error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); ++ } + -+ gsi = gsi_for_stmt(oldstmt); -+ gsi_insert_after(&gsi, phi, GSI_NEW_STMT); -+ gimple_set_bb(phi, bb); -+ return phi; ++ register_callback(plugin_name, PLUGIN_INFO, NULL, &structleak_plugin_info); ++ if (enable) { ++ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &structleak_pass_info); ++ register_callback(plugin_name, PLUGIN_FINISH_TYPE, finish_type, NULL); ++ } ++ register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); ++ ++ return 0; +} +diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh +index fdebd66..a349e33 100755 +--- a/scripts/headers_install.sh ++++ b/scripts/headers_install.sh +@@ -32,6 +32,7 @@ do + FILE="$(basename "$i")" + sed -r \ + -e 's/([ \t(])(__user|__force|__iomem)[ \t]/\1/g' \ ++ -e 's/__intentional_overflow\([- \t,0-9]*\)//g' \ + -e 's/__attribute_const__([ \t]|$)/\1/g' \ + -e 's@^#include @@' \ + -e 's/(^|[^a-zA-Z0-9])__packed([^a-zA-Z0-9_]|$)/\1__attribute__((packed))\2/g' \ +diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c +index 8fa81e8..a9ac144 100644 +--- a/scripts/kallsyms.c ++++ b/scripts/kallsyms.c +@@ -89,7 +89,7 @@ static inline int is_arm_mapping_symbol(const char *str) + } + + static int check_symbol_range(const char *sym, unsigned long long addr, +- struct addr_range *ranges, int entries) ++ struct addr_range *ranges, size_t entries) + { + size_t i; + struct addr_range *ar; +@@ -178,7 +178,7 @@ static int read_symbol(FILE *in, struct sym_entry *s) + } + + static int symbol_in_range(struct sym_entry *s, struct addr_range *ranges, +- int entries) ++ size_t entries) + { + size_t i; + struct addr_range *ar; +diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h +index 91ca126..5f7cad6 100644 +--- a/scripts/kconfig/lkc.h ++++ b/scripts/kconfig/lkc.h +@@ -108,7 +108,8 @@ void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); + void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); + void menu_add_option(int token, char *arg); + void menu_finalize(struct menu *parent); +-void menu_set_type(int type); ++enum symbol_type; ++void menu_set_type(enum symbol_type type); + + /* util.c */ + struct file *file_lookup(const char *name); +@@ -123,7 +124,7 @@ struct gstr { + * when max_width is not zero long lines in string s (if any) get + * wrapped not to exceed the max_width value + */ +- int max_width; ++ size_t max_width; + }; + struct gstr str_new(void); + void str_free(struct gstr *gs); +diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c +index aed678e..1a703de 100644 +--- a/scripts/kconfig/menu.c ++++ b/scripts/kconfig/menu.c +@@ -109,7 +109,7 @@ void menu_add_dep(struct expr *dep) + current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep)); + } + +-void menu_set_type(int type) ++void menu_set_type(enum symbol_type type) + { + struct symbol *sym = current_entry->sym; + +diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c +index 25cf0c2..eb178ce 100644 +--- a/scripts/kconfig/symbol.c ++++ b/scripts/kconfig/symbol.c +@@ -956,7 +956,7 @@ const char *sym_escape_string_value(const char *in) + + struct sym_match { + struct symbol *sym; +- off_t so, eo; ++ regoff_t so, eo; + }; + + /* Compare matched symbols as thus: +@@ -978,8 +978,8 @@ static int sym_rel_comp(const void *sym1, const void *sym2) + * exactly; if this is the case, we can't decide which comes first, + * and we fallback to sorting alphabetically. + */ +- exact1 = (s1->eo - s1->so) == strlen(s1->sym->name); +- exact2 = (s2->eo - s2->so) == strlen(s2->sym->name); ++ exact1 = (s1->eo - s1->so) == (long)strlen(s1->sym->name); ++ exact2 = (s2->eo - s2->so) == (long)strlen(s2->sym->name); + if (exact1 && !exact2) + return -1; + if (!exact1 && exact2) +diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh +index ba6c34e..ea10bce 100755 +--- a/scripts/link-vmlinux.sh ++++ b/scripts/link-vmlinux.sh +@@ -179,7 +179,7 @@ else + fi; + + # final build of init/ +-${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init ++${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init GCC_PLUGINS_CFLAGS="${GCC_PLUGINS_CFLAGS}" GCC_PLUGINS_AFLAGS="${GCC_PLUGINS_AFLAGS}" + + kallsymso="" + kallsyms_vmlinux="" +diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c +index a915507..27c1b41 100644 +--- a/scripts/mod/file2alias.c ++++ b/scripts/mod/file2alias.c +@@ -156,7 +156,7 @@ static void device_id_check(const char *modname, const char *device_id, + unsigned long size, unsigned long id_size, + void *symval) + { +- int i; ++ unsigned int i; + + if (size % id_size || size < id_size) { + fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo " +@@ -185,7 +185,7 @@ static void device_id_check(const char *modname, const char *device_id, + /* USB is special because the bcdDevice can be matched against a numeric range */ + /* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipNinN" */ + static void do_usb_entry(void *symval, +- unsigned int bcdDevice_initial, int bcdDevice_initial_digits, ++ unsigned int bcdDevice_initial, unsigned int bcdDevice_initial_digits, + unsigned char range_lo, unsigned char range_hi, + unsigned char max, struct module *mod) + { +@@ -295,7 +295,7 @@ static void do_usb_entry_multi(void *symval, struct module *mod) + { + unsigned int devlo, devhi; + unsigned char chi, clo, max; +- int ndigits; ++ unsigned int ndigits; + + DEF_FIELD(symval, usb_device_id, match_flags); + DEF_FIELD(symval, usb_device_id, idVendor); +@@ -619,7 +619,7 @@ static void do_pnp_device_entry(void *symval, unsigned long size, + for (i = 0; i < count; i++) { + DEF_FIELD_ADDR(symval + i*id_size, pnp_device_id, id); + char acpi_id[sizeof(*id)]; +- int j; ++ unsigned int j; + + buf_printf(&mod->dev_table_buf, + "MODULE_ALIAS(\"pnp:d%s*\");\n", *id); +@@ -648,7 +648,7 @@ static void do_pnp_card_entries(void *symval, unsigned long size, + + for (j = 0; j < PNP_MAX_DEVICES; j++) { + const char *id = (char *)(*devs)[j].id; +- int i2, j2; ++ unsigned int i2, j2; + int dup = 0; + + if (!id[0]) +@@ -674,7 +674,7 @@ static void do_pnp_card_entries(void *symval, unsigned long size, + /* add an individual alias for every device entry */ + if (!dup) { + char acpi_id[PNP_ID_LEN]; +- int k; ++ unsigned int k; + + buf_printf(&mod->dev_table_buf, + "MODULE_ALIAS(\"pnp:d%s*\");\n", id); +@@ -999,7 +999,7 @@ static void dmi_ascii_filter(char *d, const char *s) + static int do_dmi_entry(const char *filename, void *symval, + char *alias) + { +- int i, j; ++ unsigned int i, j; + DEF_FIELD_ADDR(symval, dmi_system_id, matches); + sprintf(alias, "dmi*"); + +diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c +index 48958d3..d5ccb52 100644 +--- a/scripts/mod/modpost.c ++++ b/scripts/mod/modpost.c +@@ -37,6 +37,7 @@ static int vmlinux_section_warnings = 1; + static int warn_unresolved = 0; + /* How a symbol is exported */ + static int sec_mismatch_count = 0; ++static int writable_fptr_count = 0; + static int sec_mismatch_verbose = 1; + static int sec_mismatch_fatal = 0; + /* ignore missing files */ +@@ -947,6 +948,7 @@ enum mismatch { + ANY_EXIT_TO_ANY_INIT, + EXPORT_TO_INIT_EXIT, + EXTABLE_TO_NON_TEXT, ++ DATA_TO_TEXT + }; + + /** +@@ -1073,6 +1075,12 @@ static const struct sectioncheck sectioncheck[] = { + .good_tosec = {ALL_TEXT_SECTIONS , NULL}, + .mismatch = EXTABLE_TO_NON_TEXT, + .handler = extable_mismatch_handler, ++}, ++/* Do not reference code from writable data */ ++{ ++ .fromsec = { DATA_SECTIONS, NULL }, ++ .bad_tosec = { ALL_TEXT_SECTIONS, NULL }, ++ .mismatch = DATA_TO_TEXT + } + }; + +@@ -1222,10 +1230,10 @@ static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr, + continue; + if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) + continue; +- if (sym->st_value == addr) +- return sym; + /* Find a symbol nearby - addr are maybe negative */ + d = sym->st_value - addr; ++ if (d == 0) ++ return sym; + if (d < 0) + d = addr - sym->st_value; + if (d < distance) { +@@ -1384,7 +1392,11 @@ static void report_sec_mismatch(const char *modname, + char *prl_from; + char *prl_to; + +- sec_mismatch_count++; ++ if (mismatch->mismatch == DATA_TO_TEXT) ++ writable_fptr_count++; ++ else ++ sec_mismatch_count++; + -+#if BUILDING_GCC_VERSION <= 4007 -+static tree create_new_phi_node(struct visited *visited, VEC(tree, heap) **args, tree ssa_name_var, gimple oldstmt) -+#else -+static tree create_new_phi_node(struct visited *visited, vec *&args, tree ssa_name_var, gphi *oldstmt) + if (!sec_mismatch_verbose) + return; + +@@ -1508,6 +1520,14 @@ static void report_sec_mismatch(const char *modname, + fatal("There's a special handler for this mismatch type, " + "we should never get here."); + break; ++ case DATA_TO_TEXT: ++#if 0 ++ fprintf(stderr, ++ "The %s %s:%s references\n" ++ "the %s %s:%s%s\n", ++ from, fromsec, fromsym, to, tosec, tosym, to_p); +#endif -+{ -+ gphi *new_phi; ++ break; + } + fprintf(stderr, "\n"); + } +@@ -1897,7 +1917,7 @@ static void section_rel(const char *modname, struct elf_info *elf, + static void check_sec_ref(struct module *mod, const char *modname, + struct elf_info *elf) + { +- int i; + unsigned int i; -+ tree arg, result; -+ location_t loc = gimple_location(oldstmt); -+ -+#if BUILDING_GCC_VERSION <= 4007 -+ gcc_assert(!VEC_empty(tree, *args)); -+#else -+ gcc_assert(!args->is_empty()); -+#endif -+ -+ new_phi = overflow_create_phi_node(visited, oldstmt, ssa_name_var); -+ result = gimple_phi_result(new_phi); -+ ssa_name_var = SSA_NAME_VAR(result); -+ -+#if BUILDING_GCC_VERSION <= 4007 -+ FOR_EACH_VEC_ELT(tree, *args, i, arg) { -+#else -+ FOR_EACH_VEC_SAFE_ELT(args, i, arg) { -+#endif -+ arg = create_new_phi_arg(visited, ssa_name_var, arg, oldstmt, i); -+ add_phi_arg(new_phi, arg, gimple_phi_arg_edge(oldstmt, i), loc); -+ } -+ -+#if BUILDING_GCC_VERSION <= 4007 -+ VEC_free(tree, heap, *args); -+#else -+ vec_free(args); -+#endif -+ update_stmt(new_phi); -+ pointer_set_insert(visited->my_stmts, new_phi); -+ return result; -+} -+ -+static tree handle_phi(interesting_stmts_t expand_from, tree orig_result) -+{ -+#if BUILDING_GCC_VERSION <= 4007 -+ VEC(tree, heap) *args = NULL; -+#else -+ vec *args = NULL; -+#endif -+ unsigned int i, len; -+ tree ssa_name_var = NULL_TREE; -+ gphi *oldstmt = as_a_gphi(get_def_stmt(orig_result)); -+ -+ len = gimple_phi_num_args(oldstmt); -+ pointer_set_insert(expand_from->visited->stmts, oldstmt); -+ for (i = 0; i < len; i++) { -+ tree arg, new_arg; -+ -+ arg = gimple_phi_arg_def(oldstmt, i); -+ new_arg = expand(expand_from, arg); -+ -+ if (ssa_name_var == NULL_TREE && new_arg != NULL_TREE) -+ ssa_name_var = SSA_NAME_VAR(new_arg); -+ -+ if (is_gimple_constant(arg)) { -+ tree size_overflow_type = get_size_overflow_type(expand_from->visited, oldstmt, arg); -+ -+ new_arg = cast_a_tree(size_overflow_type, arg); + Elf_Shdr *sechdrs = elf->sechdrs; + + /* Walk through all sections */ +@@ -2028,7 +2048,7 @@ void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf, + va_end(ap); + } + +-void buf_write(struct buffer *buf, const char *s, int len) ++void buf_write(struct buffer *buf, const char *s, unsigned int len) + { + if (buf->size - buf->pos < len) { + buf->size += len + SZ; +@@ -2258,7 +2278,7 @@ static void write_if_changed(struct buffer *b, const char *fname) + if (fstat(fileno(file), &st) < 0) + goto close_write; + +- if (st.st_size != b->pos) ++ if (st.st_size != (off_t)b->pos) + goto close_write; + + tmp = NOFAIL(malloc(b->pos)); +@@ -2496,6 +2516,14 @@ int main(int argc, char **argv) + "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n"); + } + } ++ if (writable_fptr_count) { ++ if (!sec_mismatch_verbose) { ++ warn("modpost: Found %d writable function pointer(s).\n" ++ "To see full details build your kernel with:\n" ++ "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n", ++ writable_fptr_count); + } -+ -+#if BUILDING_GCC_VERSION <= 4007 -+ VEC_safe_push(tree, heap, args, new_arg); -+#else -+ vec_safe_push(args, new_arg); -+#endif + } -+ -+#if BUILDING_GCC_VERSION <= 4007 -+ return create_new_phi_node(expand_from->visited, &args, ssa_name_var, oldstmt); -+#else -+ return create_new_phi_node(expand_from->visited, args, ssa_name_var, oldstmt); -+#endif -+} -+ -+static tree create_cast_assign(struct visited *visited, gassign *stmt) -+{ -+ tree rhs1 = gimple_assign_rhs1(stmt); -+ tree lhs = gimple_assign_lhs(stmt); -+ const_tree rhs1_type = TREE_TYPE(rhs1); -+ const_tree lhs_type = TREE_TYPE(lhs); -+ -+ if (TYPE_UNSIGNED(rhs1_type) == TYPE_UNSIGNED(lhs_type)) -+ return create_assign(visited, stmt, lhs, AFTER_STMT); -+ -+ return create_assign(visited, stmt, rhs1, AFTER_STMT); -+} -+ -+static bool skip_lhs_cast_check(struct visited *visited, const gassign *stmt) -+{ -+ const_tree rhs = gimple_assign_rhs1(stmt); -+ const_gimple def_stmt = get_def_stmt(rhs); -+ -+ // 3.8.2 kernel/futex_compat.c compat_exit_robust_list(): get_user() 64 ulong -> int (compat_long_t), int max -+ if (gimple_code(def_stmt) == GIMPLE_ASM) -+ return true; -+ -+ if (is_const_plus_unsigned_signed_truncation(rhs)) { -+ pointer_set_insert(visited->no_cast_check, stmt); -+ return true; + + return err; + } +diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h +index 6a5e151..f2fbaf5 100644 +--- a/scripts/mod/modpost.h ++++ b/scripts/mod/modpost.h +@@ -98,15 +98,15 @@ void *do_nofail(void *ptr, const char *expr); + + struct buffer { + char *p; +- int pos; +- int size; ++ unsigned int pos; ++ unsigned int size; + }; + + void __attribute__((format(printf, 2, 3))) + buf_printf(struct buffer *buf, const char *fmt, ...); + + void +-buf_write(struct buffer *buf, const char *s, int len); ++buf_write(struct buffer *buf, const char *s, unsigned int len); + + struct module { + struct module *next; +diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c +index 944418d..15291e4 100644 +--- a/scripts/mod/sumversion.c ++++ b/scripts/mod/sumversion.c +@@ -470,7 +470,7 @@ static void write_version(const char *filename, const char *sum, + goto out; + } + +- if (write(fd, sum, strlen(sum)+1) != strlen(sum)+1) { ++ if (write(fd, sum, strlen(sum)+1) != (ssize_t)strlen(sum)+1) { + warn("writing sum in %s failed: %s\n", + filename, strerror(errno)); + goto out; +diff --git a/scripts/module-common.lds b/scripts/module-common.lds +index 73a2c7d..df11b31 100644 +--- a/scripts/module-common.lds ++++ b/scripts/module-common.lds +@@ -6,6 +6,10 @@ + SECTIONS { + /DISCARD/ : { *(.discard) } + ++ .rodata 0: { ++ *(.rodata) *(.rodata.*) ++ *(.data..read_only) + } + __ksymtab 0 : { *(SORT(___ksymtab+*)) } + __ksymtab_gpl 0 : { *(SORT(___ksymtab_gpl+*)) } + __ksymtab_unused 0 : { *(SORT(___ksymtab_unused+*)) } +diff --git a/scripts/package/Makefile b/scripts/package/Makefile +index c2c7389..81b8117 100644 +--- a/scripts/package/Makefile ++++ b/scripts/package/Makefile +@@ -40,7 +40,7 @@ if test "$(objtree)" != "$(srctree)"; then \ + fi ; \ + $(srctree)/scripts/setlocalversion --save-scmversion; \ + ln -sf $(srctree) $(2); \ +-tar -cz $(RCS_TAR_IGNORE) -f $(2).tar.gz \ ++tar --owner=root --group=root -cz $(RCS_TAR_IGNORE) -f $(2).tar.gz \ + $(addprefix $(2)/,$(TAR_CONTENT) $(3)); \ + rm -f $(2) $(objtree)/.scmversion + +diff --git a/scripts/package/builddeb b/scripts/package/builddeb +index 6c3b038..4bac93f 100755 +--- a/scripts/package/builddeb ++++ b/scripts/package/builddeb +@@ -326,6 +326,7 @@ fi + (cd $srctree; find arch/$SRCARCH -name module.lds -o -name Kbuild.platforms -o -name Platform) >> "$objtree/debian/hdrsrcfiles" + (cd $srctree; find $(find arch/$SRCARCH -name include -o -name scripts -type d) -type f) >> "$objtree/debian/hdrsrcfiles" + (cd $objtree; find arch/$SRCARCH/include Module.symvers include scripts -type f) >> "$objtree/debian/hdrobjfiles" ++(cd $objtree; find scripts/gcc-plugins -name \*.so -o -name gcc-common.h) >> "$objtree/debian/hdrobjfiles" + destdir=$kernel_headers_dir/usr/src/linux-headers-$version + mkdir -p "$destdir" + (cd $srctree; tar -c -f - -T -) < "$objtree/debian/hdrsrcfiles" | (cd $destdir; tar -xf -) +diff --git a/scripts/package/mkspec b/scripts/package/mkspec +index fe44d68..3874acb 100755 +--- a/scripts/package/mkspec ++++ b/scripts/package/mkspec +@@ -120,29 +120,40 @@ echo 'rm -f $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE/{build,source}" + echo "mkdir -p "'$RPM_BUILD_ROOT'"/usr/src/kernels/$KERNELRELEASE" + echo "EXCLUDES=\"$RCS_TAR_IGNORE --exclude .tmp_versions --exclude=*vmlinux* --exclude=*.o --exclude=*.ko --exclude=*.cmd --exclude=Documentation --exclude=firmware --exclude .config.old --exclude .missing-syscalls.d\"" + echo "tar "'$EXCLUDES'" -cf- . | (cd "'$RPM_BUILD_ROOT'"/usr/src/kernels/$KERNELRELEASE;tar xvf -)" +-echo 'cd $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE" +-echo "ln -sf /usr/src/kernels/$KERNELRELEASE build" +-echo "ln -sf /usr/src/kernels/$KERNELRELEASE source" + fi + + echo "" + echo "%clean" + echo 'rm -rf $RPM_BUILD_ROOT' + echo "" ++echo "%pre" ++echo 'chmod -f 0500 /boot' ++echo 'if [ -d /lib/modules ]; then' ++echo 'chmod -f 0500 /lib/modules' ++echo 'fi' ++echo 'if [ -d /lib32/modules ]; then' ++echo 'chmod -f 0500 /lib32/modules' ++echo 'fi' ++echo 'if [ -d /lib64/modules ]; then' ++echo 'chmod -f 0500 /lib64/modules' ++echo 'fi' ++echo "" ++echo "%post devel" ++echo "ln -sf /usr/src/kernels/$KERNELRELEASE /lib/modules/$KERNELRELEASE/build" ++echo "ln -sf /usr/src/kernels/$KERNELRELEASE /lib/modules/$KERNELRELEASE/source" ++echo "" + echo "%post" +-echo "if [ -x /sbin/installkernel -a -r /boot/vmlinuz-$KERNELRELEASE -a -r /boot/System.map-$KERNELRELEASE ]; then" +-echo "cp /boot/vmlinuz-$KERNELRELEASE /boot/.vmlinuz-$KERNELRELEASE-rpm" +-echo "cp /boot/System.map-$KERNELRELEASE /boot/.System.map-$KERNELRELEASE-rpm" +-echo "rm -f /boot/vmlinuz-$KERNELRELEASE /boot/System.map-$KERNELRELEASE" +-echo "/sbin/installkernel $KERNELRELEASE /boot/.vmlinuz-$KERNELRELEASE-rpm /boot/.System.map-$KERNELRELEASE-rpm" +-echo "rm -f /boot/.vmlinuz-$KERNELRELEASE-rpm /boot/.System.map-$KERNELRELEASE-rpm" ++echo "if [ -x /sbin/dracut ]; then" ++echo '/sbin/new-kernel-pkg --dracut --mkinitrd --depmod --install --make-default '"$KERNELRELEASE"' || exit $?' ++echo "else" ++echo '/sbin/new-kernel-pkg --mkinitrd --depmod --install --make-default '"$KERNELRELEASE"' || exit $?' + echo "fi" + echo "" + echo "%files" +-echo '%defattr (-, root, root)' +-echo "/lib/modules/$KERNELRELEASE" ++echo '%defattr (400, root, root, 500)' + echo "%exclude /lib/modules/$KERNELRELEASE/build" + echo "%exclude /lib/modules/$KERNELRELEASE/source" ++echo "/lib/modules/$KERNELRELEASE" + echo "/lib/firmware/$KERNELRELEASE" + echo "/boot/*" + echo "" +@@ -152,9 +163,11 @@ echo "/usr/include" + echo "" + if ! $PREBUILT; then + echo "%files devel" +-echo '%defattr (-, root, root)' ++echo '%defattr (400, root, root, 500)' ++echo "%dir /lib/modules/$KERNELRELEASE" + echo "/usr/src/kernels/$KERNELRELEASE" +-echo "/lib/modules/$KERNELRELEASE/build" +-echo "/lib/modules/$KERNELRELEASE/source" ++echo "%attr (500, root, root) /usr/src/kernels/$KERNELRELEASE/scripts/recordmcount" ++echo "%attr (500, root, root) /usr/src/kernels/$KERNELRELEASE/scripts/basic/fixdep" ++echo "%attr (500, root, root) /usr/src/kernels/$KERNELRELEASE/scripts/mod/modpost" + echo "" + fi +diff --git a/scripts/pnmtologo.c b/scripts/pnmtologo.c +index 4718d78..9220d58 100644 +--- a/scripts/pnmtologo.c ++++ b/scripts/pnmtologo.c +@@ -244,14 +244,14 @@ static void write_header(void) + fprintf(out, " * Linux logo %s\n", logoname); + fputs(" */\n\n", out); + fputs("#include \n\n", out); +- fprintf(out, "static unsigned char %s_data[] __initdata = {\n", ++ fprintf(out, "static unsigned char %s_data[] = {\n", + logoname); + } + + static void write_footer(void) + { + fputs("\n};\n\n", out); +- fprintf(out, "const struct linux_logo %s __initconst = {\n", logoname); ++ fprintf(out, "const struct linux_logo %s = {\n", logoname); + fprintf(out, "\t.type\t\t= %s,\n", logo_types[logo_type]); + fprintf(out, "\t.width\t\t= %d,\n", logo_width); + fprintf(out, "\t.height\t\t= %d,\n", logo_height); +@@ -381,7 +381,7 @@ static void write_logo_clut224(void) + fputs("\n};\n\n", out); + + /* write logo clut */ +- fprintf(out, "static unsigned char %s_clut[] __initdata = {\n", ++ fprintf(out, "static unsigned char %s_clut[] = {\n", + logoname); + write_hex_cnt = 0; + for (i = 0; i < logo_clutsize; i++) { +diff --git a/scripts/sortextable.h b/scripts/sortextable.h +index ba87004..3f4852c 100644 +--- a/scripts/sortextable.h ++++ b/scripts/sortextable.h +@@ -108,9 +108,9 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) + const char *secstrtab; + const char *strtab; + char *extab_image; +- int extab_index = 0; +- int i; +- int idx; ++ unsigned int extab_index = 0; ++ unsigned int i; ++ unsigned int idx; + unsigned int num_sections; + unsigned int secindex_strings; + +diff --git a/scripts/tags.sh b/scripts/tags.sh +index 23ba1c6..cad2484 100755 +--- a/scripts/tags.sh ++++ b/scripts/tags.sh +@@ -26,7 +26,7 @@ else + fi + + # ignore userspace tools +-ignore="$ignore ( -path ${tree}tools ) -prune -o" ++ignore="$ignore ( -path \"${tree}tools/[^g]*\" ) -prune -o" + + # Find all available archs + find_all_archs() +diff --git a/security/Kconfig b/security/Kconfig +index e452378..8059bd2 100644 +--- a/security/Kconfig ++++ b/security/Kconfig +@@ -4,6 +4,993 @@ + + menu "Security options" + ++menu "Grsecurity" + -+ return false; -+} -+ -+static tree create_string_param(tree string) -+{ -+ tree i_type, a_type; -+ const int length = TREE_STRING_LENGTH(string); ++ config ARCH_TRACK_EXEC_LIMIT ++ bool + -+ gcc_assert(length > 0); ++ config PAX_KERNEXEC_PLUGIN ++ bool ++ depends on GCC_PLUGINS + -+ i_type = build_index_type(build_int_cst(NULL_TREE, length - 1)); -+ a_type = build_array_type(char_type_node, i_type); ++ config PAX_PER_CPU_PGD ++ bool + -+ TREE_TYPE(string) = a_type; -+ TREE_CONSTANT(string) = 1; -+ TREE_READONLY(string) = 1; ++ config TASK_SIZE_MAX_SHIFT ++ int ++ depends on X86_64 ++ default 47 if !PAX_PER_CPU_PGD ++ default 42 if PAX_PER_CPU_PGD + -+ return build1(ADDR_EXPR, ptr_type_node, string); -+} ++ config PAX_ENABLE_PAE ++ bool ++ default y if (X86_32 && (MPENTIUM4 || MK8 || MPSC || MCORE2 || MATOM)) ++ ++ config PAX_USERCOPY_SLABS ++ bool + -+static void insert_cond(basic_block cond_bb, tree arg, enum tree_code cond_code, tree type_value) -+{ -+ gcond *cond_stmt; -+ gimple_stmt_iterator gsi = gsi_last_bb(cond_bb); ++config GRKERNSEC ++ bool "Grsecurity" ++ select CRYPTO ++ select CRYPTO_SHA256 ++ select PROC_FS ++ select STOP_MACHINE ++ select TTY ++ select DEBUG_KERNEL ++ select DEBUG_LIST ++ select MULTIUSER ++ help ++ If you say Y here, you will be able to configure many features ++ that will enhance the security of your system. It is highly ++ recommended that you say Y here and read through the help ++ for each option so that you fully understand the features and ++ can evaluate their usefulness for your machine. + -+ cond_stmt = gimple_build_cond(cond_code, arg, type_value, NULL_TREE, NULL_TREE); -+ gsi_insert_after(&gsi, cond_stmt, GSI_CONTINUE_LINKING); -+ update_stmt(cond_stmt); -+} ++choice ++ prompt "Configuration Method" ++ depends on GRKERNSEC ++ default GRKERNSEC_CONFIG_CUSTOM ++ help + -+static void insert_cond_result(interesting_stmts_t expand_from, basic_block bb_true, const_gimple stmt, const_tree arg, bool min) -+{ -+ gcall *func_stmt; -+ const_gimple def_stmt; -+ const_tree loc_line; -+ tree loc_file, ssa_name, current_func; -+ expanded_location xloc; -+ char *ssa_name_buf; -+ int len; -+ struct cgraph_edge *edge; -+ struct cgraph_node *report_node; -+ int frequency; -+ gimple_stmt_iterator gsi = gsi_start_bb(bb_true); ++config GRKERNSEC_CONFIG_AUTO ++ bool "Automatic" ++ help ++ If you choose this configuration method, you'll be able to answer a small ++ number of simple questions about how you plan to use this kernel. ++ The settings of grsecurity and PaX will be automatically configured for ++ the highest commonly-used settings within the provided constraints. + -+ def_stmt = get_def_stmt(arg); -+ if (gimple_has_location(def_stmt)) -+ xloc = expand_location(gimple_location(def_stmt)); -+ else if (gimple_has_location(stmt)) -+ xloc = expand_location(gimple_location(stmt)); -+ else -+ xloc = expand_location(DECL_SOURCE_LOCATION(current_function_decl)); ++ If you require additional configuration, custom changes can still be made ++ from the "custom configuration" menu. + -+ loc_line = build_int_cstu(unsigned_type_node, xloc.line); ++config GRKERNSEC_CONFIG_CUSTOM ++ bool "Custom" ++ help ++ If you choose this configuration method, you'll be able to configure all ++ grsecurity and PaX settings manually. Via this method, no options are ++ automatically enabled. + -+ loc_file = build_string(strlen(xloc.file) + 1, xloc.file); -+ loc_file = create_string_param(loc_file); ++ Take note that if menuconfig is exited with this configuration method ++ chosen, you will not be able to use the automatic configuration methods ++ without starting again with a kernel configuration with no grsecurity ++ or PaX options specified inside. + -+ current_func = build_string(DECL_NAME_LENGTH(current_function_decl) + 1, DECL_NAME_POINTER(current_function_decl)); -+ current_func = create_string_param(current_func); ++endchoice + -+ gcc_assert(DECL_NAME(SSA_NAME_VAR(arg)) != NULL); -+ call_count++; -+ len = asprintf(&ssa_name_buf, "%s_%u %s, count: %u, decl: %s; num: %u; context: %s;\n", DECL_NAME_POINTER(SSA_NAME_VAR(arg)), SSA_NAME_VERSION(arg), min ? "min" : "max", call_count, expand_from->next_node->decl_name, expand_from->next_node->num, expand_from->next_node->context); -+ gcc_assert(len > 0); -+ ssa_name = build_string(len + 1, ssa_name_buf); -+ free(ssa_name_buf); -+ ssa_name = create_string_param(ssa_name); ++choice ++ prompt "Usage Type" ++ depends on (GRKERNSEC && GRKERNSEC_CONFIG_AUTO) ++ default GRKERNSEC_CONFIG_SERVER ++ help + -+ // void report_size_overflow(const char *file, unsigned int line, const char *func, const char *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); ++config GRKERNSEC_CONFIG_SERVER ++ bool "Server" ++ help ++ Choose this option if you plan to use this kernel on a server. + -+ report_node = cgraph_get_create_node(report_size_overflow_decl); -+ gcc_assert(report_node); -+ frequency = compute_call_stmt_bb_frequency(current_function_decl, bb_true); ++config GRKERNSEC_CONFIG_DESKTOP ++ bool "Desktop" ++ help ++ Choose this option if you plan to use this kernel on a desktop. + -+ edge = cgraph_create_edge(get_cnode(current_function_decl), report_node, func_stmt, bb_true->count, frequency, bb_true->loop_depth); -+ gcc_assert(edge != NULL); -+} ++endchoice + -+static void insert_check_size_overflow(interesting_stmts_t expand_from, gimple stmt, enum tree_code cond_code, tree arg, tree type_value, bool before, bool min) -+{ -+ basic_block cond_bb, join_bb, bb_true; -+ edge e; -+ gimple_stmt_iterator gsi = gsi_for_stmt(stmt); ++choice ++ prompt "Virtualization Type" ++ depends on (GRKERNSEC && X86 && GRKERNSEC_CONFIG_AUTO) ++ default GRKERNSEC_CONFIG_VIRT_NONE ++ help + -+ cond_bb = gimple_bb(stmt); -+ if (before) -+ gsi_prev(&gsi); -+ if (gsi_end_p(gsi)) -+ e = split_block_after_labels(cond_bb); -+ else -+ e = split_block(cond_bb, gsi_stmt(gsi)); -+ cond_bb = e->src; -+ join_bb = e->dest; -+ e->flags = EDGE_FALSE_VALUE; -+ e->probability = REG_BR_PROB_BASE; ++config GRKERNSEC_CONFIG_VIRT_NONE ++ bool "None" ++ help ++ Choose this option if this kernel will be run on bare metal. + -+ bb_true = create_empty_bb(cond_bb); -+ make_edge(cond_bb, bb_true, EDGE_TRUE_VALUE); -+ make_edge(cond_bb, join_bb, EDGE_FALSE_VALUE); -+ make_edge(bb_true, join_bb, EDGE_FALLTHRU); ++config GRKERNSEC_CONFIG_VIRT_GUEST ++ bool "Guest" ++ help ++ Choose this option if this kernel will be run as a VM guest. + -+ gcc_assert(dom_info_available_p(CDI_DOMINATORS)); -+ set_immediate_dominator(CDI_DOMINATORS, bb_true, cond_bb); -+ set_immediate_dominator(CDI_DOMINATORS, join_bb, cond_bb); ++config GRKERNSEC_CONFIG_VIRT_HOST ++ bool "Host" ++ help ++ Choose this option if this kernel will be run as a VM host. + -+ if (current_loops != NULL) { -+ gcc_assert(cond_bb->loop_father == join_bb->loop_father); -+ add_bb_to_loop(bb_true, cond_bb->loop_father); -+ } ++endchoice + -+ insert_cond(cond_bb, arg, cond_code, type_value); -+ insert_cond_result(expand_from, bb_true, stmt, arg, min); ++choice ++ prompt "Virtualization Hardware" ++ depends on (GRKERNSEC && X86 && GRKERNSEC_CONFIG_AUTO && (GRKERNSEC_CONFIG_VIRT_GUEST || GRKERNSEC_CONFIG_VIRT_HOST)) ++ help + -+// print_the_code_insertions(stmt); -+} ++config GRKERNSEC_CONFIG_VIRT_EPT ++ bool "EPT/RVI Processor Support" ++ depends on X86 ++ help ++ Choose this option if your CPU supports the EPT or RVI features of 2nd-gen ++ hardware virtualization. This allows for additional kernel hardening protections ++ to operate without additional performance impact. + -+void check_size_overflow(interesting_stmts_t expand_from, gimple stmt, tree size_overflow_type, tree cast_rhs, tree rhs, bool before) -+{ -+ const_tree rhs_type = TREE_TYPE(rhs); -+ tree cast_rhs_type, type_max_type, type_min_type, type_max, type_min; ++ To see if your Intel processor supports EPT, see: ++ http://ark.intel.com/Products/VirtualizationTechnology ++ (Most Core i3/5/7 support EPT) + -+ if (pointer_set_contains(expand_from->visited->no_cast_check, stmt)) -+ return; ++ To see if your AMD processor supports RVI, see: ++ http://support.amd.com/us/kbarticles/Pages/GPU120AMDRVICPUsHyperVWin8.aspx + -+ gcc_assert(rhs_type != NULL_TREE); -+ if (TREE_CODE(rhs_type) == POINTER_TYPE) -+ return; ++config GRKERNSEC_CONFIG_VIRT_SOFT ++ bool "First-gen/No Hardware Virtualization" ++ help ++ Choose this option if you use an Atom/Pentium/Core 2 processor that either doesn't ++ support hardware virtualization or doesn't support the EPT/RVI extensions. + -+ gcc_assert(TREE_CODE(rhs_type) == INTEGER_TYPE || TREE_CODE(rhs_type) == ENUMERAL_TYPE); ++endchoice + -+ if (is_gimple_assign(stmt) && neg_short_add_intentional_overflow(as_a_gassign(stmt))) -+ return; ++choice ++ prompt "Virtualization Software" ++ depends on (GRKERNSEC && GRKERNSEC_CONFIG_AUTO && (GRKERNSEC_CONFIG_VIRT_GUEST || GRKERNSEC_CONFIG_VIRT_HOST)) ++ help + -+ type_max = cast_a_tree(size_overflow_type, TYPE_MAX_VALUE(rhs_type)); -+ // typemax (-1) < typemin (0) -+ if (TREE_OVERFLOW(type_max)) -+ return; ++config GRKERNSEC_CONFIG_VIRT_XEN ++ bool "Xen" ++ help ++ Choose this option if this kernel is running as a Xen guest or host. + -+ type_min = cast_a_tree(size_overflow_type, TYPE_MIN_VALUE(rhs_type)); ++config GRKERNSEC_CONFIG_VIRT_VMWARE ++ bool "VMWare" ++ help ++ Choose this option if this kernel is running as a VMWare guest or host. + -+ cast_rhs_type = TREE_TYPE(cast_rhs); -+ type_max_type = TREE_TYPE(type_max); -+ gcc_assert(types_compatible_p(cast_rhs_type, type_max_type)); ++config GRKERNSEC_CONFIG_VIRT_KVM ++ bool "KVM" ++ help ++ Choose this option if this kernel is running as a KVM guest or host. + -+ insert_check_size_overflow(expand_from, stmt, GT_EXPR, cast_rhs, type_max, before, MAX_CHECK); ++config GRKERNSEC_CONFIG_VIRT_VIRTUALBOX ++ bool "VirtualBox" ++ help ++ Choose this option if this kernel is running as a VirtualBox guest or host. + -+ // special case: get_size_overflow_type(), 32, u64->s -+ if (LONG_TYPE_SIZE == GET_MODE_BITSIZE(SImode) && TYPE_UNSIGNED(size_overflow_type) && !TYPE_UNSIGNED(rhs_type)) -+ return; ++config GRKERNSEC_CONFIG_VIRT_HYPERV ++ bool "Hyper-V" ++ help ++ Choose this option if this kernel is running as a Hyper-V guest. + -+ type_min_type = TREE_TYPE(type_min); -+ gcc_assert(types_compatible_p(type_max_type, type_min_type)); -+ insert_check_size_overflow(expand_from, stmt, LT_EXPR, cast_rhs, type_min, before, MIN_CHECK); -+} ++endchoice + -+static tree get_my_stmt_lhs(struct visited *visited, gimple stmt) -+{ -+ gimple_stmt_iterator gsi; -+ gimple next_stmt = NULL; ++choice ++ prompt "Required Priorities" ++ depends on (GRKERNSEC && GRKERNSEC_CONFIG_AUTO) ++ default GRKERNSEC_CONFIG_PRIORITY_PERF ++ help + -+ gsi = gsi_for_stmt(stmt); ++config GRKERNSEC_CONFIG_PRIORITY_PERF ++ bool "Performance" ++ help ++ Choose this option if performance is of highest priority for this deployment ++ of grsecurity. Features like UDEREF on a 64bit kernel, kernel stack clearing, ++ clearing of structures intended for userland, and freed memory sanitizing will ++ be disabled. + -+ do { -+ gsi_next(&gsi); -+ next_stmt = gsi_stmt(gsi); ++config GRKERNSEC_CONFIG_PRIORITY_SECURITY ++ bool "Security" ++ help ++ Choose this option if security is of highest priority for this deployment of ++ grsecurity. UDEREF, kernel stack clearing, clearing of structures intended ++ for userland, and freed memory sanitizing will be enabled for this kernel. ++ In a worst-case scenario, these features can introduce a 20% performance hit ++ (UDEREF on x64 contributing half of this hit). + -+ if (gimple_code(stmt) == GIMPLE_PHI && !pointer_set_contains(visited->my_stmts, next_stmt)) -+ return NULL_TREE; ++endchoice + -+ if (pointer_set_contains(visited->my_stmts, next_stmt) && !pointer_set_contains(visited->skip_expr_casts, next_stmt)) -+ break; ++menu "Default Special Groups" ++depends on (GRKERNSEC && GRKERNSEC_CONFIG_AUTO) + -+ gcc_assert(pointer_set_contains(visited->my_stmts, next_stmt)); -+ } while (!gsi_end_p(gsi)); ++config GRKERNSEC_PROC_GID ++ int "GID exempted from /proc restrictions" ++ default 1001 ++ help ++ Setting this GID determines which group will be exempted from ++ grsecurity's /proc restrictions, allowing users of the specified ++ group to view network statistics and the existence of other users' ++ processes on the system. This GID may also be chosen at boot time ++ via "grsec_proc_gid=" on the kernel commandline. + -+ gcc_assert(next_stmt); -+ return get_lhs(next_stmt); -+} ++config GRKERNSEC_TPE_UNTRUSTED_GID ++ int "GID for TPE-untrusted users" ++ depends on GRKERNSEC_CONFIG_SERVER && GRKERNSEC_TPE && !GRKERNSEC_TPE_INVERT ++ default 1005 ++ help ++ Setting this GID determines which group untrusted users should ++ be added to. These users will be placed under grsecurity's Trusted Path ++ Execution mechanism, preventing them from executing their own binaries. ++ The users will only be able to execute binaries in directories owned and ++ writable only by the root user. If the sysctl option is enabled, a sysctl ++ option with name "tpe_gid" is created. + -+/* When the result of the negation is cast to a signed type then move -+ * the size_overflow cast check before negation. -+ * ssa: -+ * unsigned _588 -+ * _588 = _587 >> 12; -+ * _589 = -_588; -+ * _590 = (long int) _589; -+ */ -+static bool handle_unsigned_neg_or_bit_not(interesting_stmts_t expand_from, const gassign *stmt) -+{ -+ gimple def_neg_stmt, neg_stmt; -+ tree lhs, new_neg_rhs; -+ const_tree rhs, neg_rhs; -+ enum tree_code rhs_code; ++config GRKERNSEC_TPE_TRUSTED_GID ++ int "GID for TPE-trusted users" ++ depends on GRKERNSEC_CONFIG_SERVER && GRKERNSEC_TPE && GRKERNSEC_TPE_INVERT ++ default 1005 ++ help ++ Setting this GID determines what group TPE restrictions will be ++ *disabled* for. If the sysctl option is enabled, a sysctl option ++ with name "tpe_gid" is created. + -+ rhs = gimple_assign_rhs1(stmt); -+ lhs = gimple_assign_lhs(stmt); -+ if (TYPE_UNSIGNED(TREE_TYPE(lhs)) || !TYPE_UNSIGNED(TREE_TYPE(rhs))) -+ return false; ++config GRKERNSEC_SYMLINKOWN_GID ++ int "GID for users with kernel-enforced SymlinksIfOwnerMatch" ++ depends on GRKERNSEC_CONFIG_SERVER ++ default 1006 ++ help ++ Setting this GID determines what group kernel-enforced ++ SymlinksIfOwnerMatch will be enabled for. If the sysctl option ++ is enabled, a sysctl option with name "symlinkown_gid" is created. + -+ neg_stmt = get_def_stmt(rhs); -+ if (!neg_stmt || !is_gimple_assign(neg_stmt)) -+ return false; + -+ rhs_code = gimple_assign_rhs_code(neg_stmt); -+ if (rhs_code != BIT_NOT_EXPR && rhs_code != NEGATE_EXPR) -+ return false; ++endmenu + -+ neg_rhs = gimple_assign_rhs1(neg_stmt); -+ def_neg_stmt = get_def_stmt(neg_rhs); -+ if (!def_neg_stmt) -+ return false; ++menu "Customize Configuration" ++depends on GRKERNSEC + -+ new_neg_rhs = get_my_stmt_lhs(expand_from->visited, def_neg_stmt); -+ check_size_overflow(expand_from, neg_stmt, TREE_TYPE(new_neg_rhs), new_neg_rhs, lhs, BEFORE_STMT); -+ pointer_set_insert(expand_from->visited->no_cast_check, stmt); -+ return true; -+} ++menu "PaX" + -+static tree create_cast_overflow_check(interesting_stmts_t expand_from, tree new_rhs1, gassign *stmt) -+{ -+ bool cast_lhs, cast_rhs; -+ tree lhs = gimple_assign_lhs(stmt); -+ tree rhs = gimple_assign_rhs1(stmt); -+ const_tree lhs_type = TREE_TYPE(lhs); -+ const_tree rhs_type = TREE_TYPE(rhs); -+ enum machine_mode lhs_mode = TYPE_MODE(lhs_type); -+ enum machine_mode rhs_mode = TYPE_MODE(rhs_type); -+ unsigned int lhs_size = GET_MODE_BITSIZE(lhs_mode); -+ unsigned int rhs_size = GET_MODE_BITSIZE(rhs_mode); ++config PAX ++ bool "Enable various PaX features" ++ default y if GRKERNSEC_CONFIG_AUTO ++ depends on GRKERNSEC && (ALPHA || ARM || AVR32 || IA64 || MIPS || PARISC || PPC || SPARC || X86) ++ help ++ This allows you to enable various PaX features. PaX adds ++ intrusion prevention mechanisms to the kernel that reduce ++ the risks posed by exploitable memory corruption bugs. + -+ static bool check_lhs[3][4] = { -+ // ss su us uu -+ { false, true, true, false }, // lhs > rhs -+ { false, false, false, false }, // lhs = rhs -+ { true, true, true, true }, // lhs < rhs -+ }; ++menu "PaX Control" ++ depends on PAX + -+ static bool check_rhs[3][4] = { -+ // ss su us uu -+ { true, false, true, true }, // lhs > rhs -+ { true, false, true, true }, // lhs = rhs -+ { true, false, true, true }, // lhs < rhs -+ }; ++config PAX_SOFTMODE ++ bool 'Support soft mode' ++ help ++ Enabling this option will allow you to run PaX in soft mode, that ++ is, PaX features will not be enforced by default, only on executables ++ marked explicitly. You must also enable PT_PAX_FLAGS or XATTR_PAX_FLAGS ++ support as they are the only way to mark executables for soft mode use. + -+ if (handle_unsigned_neg_or_bit_not(expand_from, stmt)) -+ return dup_assign(expand_from->visited, stmt, lhs, new_rhs1, NULL_TREE, NULL_TREE); ++ Soft mode can be activated by using the "pax_softmode=1" kernel command ++ line option on boot. Furthermore you can control various PaX features ++ at runtime via the entries in /proc/sys/kernel/pax. + -+ // skip lhs check on HI -> QI cast -+ if (rhs_mode == HImode && lhs_mode == QImode) { -+ pointer_set_insert(expand_from->visited->no_cast_check, stmt); -+ return dup_assign(expand_from->visited, stmt, lhs, new_rhs1, NULL_TREE, NULL_TREE); -+ } ++config PAX_EI_PAX ++ bool 'Use legacy ELF header marking' ++ default y if GRKERNSEC_CONFIG_AUTO ++ help ++ Enabling this option will allow you to control PaX features on ++ a per executable basis via the 'chpax' utility available at ++ http://pax.grsecurity.net/. The control flags will be read from ++ an otherwise reserved part of the ELF header. This marking has ++ numerous drawbacks (no support for soft-mode, toolchain does not ++ know about the non-standard use of the ELF header) therefore it ++ has been deprecated in favour of PT_PAX_FLAGS and XATTR_PAX_FLAGS ++ support. + -+ // skip lhs check on signed SI -> HI cast or signed SI -> QI cast -+ if (rhs_mode == SImode && !TYPE_UNSIGNED(rhs_type) && (lhs_mode == HImode || lhs_mode == QImode)) -+ return create_assign(expand_from->visited, stmt, lhs, AFTER_STMT); ++ Note that if you enable PT_PAX_FLAGS or XATTR_PAX_FLAGS marking ++ support as well, they will override the legacy EI_PAX marks. + -+ if (lhs_size > rhs_size) { -+ cast_lhs = check_lhs[0][TYPE_UNSIGNED(rhs_type) + 2 * TYPE_UNSIGNED(lhs_type)]; -+ cast_rhs = check_rhs[0][TYPE_UNSIGNED(rhs_type) + 2 * TYPE_UNSIGNED(lhs_type)]; -+ } else if (lhs_size == rhs_size) { -+ cast_lhs = check_lhs[1][TYPE_UNSIGNED(rhs_type) + 2 * TYPE_UNSIGNED(lhs_type)]; -+ cast_rhs = check_rhs[1][TYPE_UNSIGNED(rhs_type) + 2 * TYPE_UNSIGNED(lhs_type)]; -+ } else { -+ cast_lhs = check_lhs[2][TYPE_UNSIGNED(rhs_type) + 2 * TYPE_UNSIGNED(lhs_type)]; -+ cast_rhs = check_rhs[2][TYPE_UNSIGNED(rhs_type) + 2 * TYPE_UNSIGNED(lhs_type)]; -+ } ++ If you enable none of the marking options then all applications ++ will run with PaX enabled on them by default. + -+ if (!cast_lhs && !cast_rhs) -+ return dup_assign(expand_from->visited, stmt, lhs, new_rhs1, NULL_TREE, NULL_TREE); ++config PAX_PT_PAX_FLAGS ++ bool 'Use ELF program header marking' ++ default y if GRKERNSEC_CONFIG_AUTO ++ help ++ Enabling this option will allow you to control PaX features on ++ a per executable basis via the 'paxctl' utility available at ++ http://pax.grsecurity.net/. The control flags will be read from ++ a PaX specific ELF program header (PT_PAX_FLAGS). This marking ++ has the benefits of supporting both soft mode and being fully ++ integrated into the toolchain (the binutils patch is available ++ from http://pax.grsecurity.net). + -+ if (cast_lhs && !skip_lhs_cast_check(expand_from->visited, stmt)) -+ check_size_overflow(expand_from, stmt, TREE_TYPE(new_rhs1), new_rhs1, lhs, BEFORE_STMT); ++ Note that if you enable the legacy EI_PAX marking support as well, ++ the EI_PAX marks will be overridden by the PT_PAX_FLAGS marks. + -+ if (cast_rhs) -+ check_size_overflow(expand_from, stmt, TREE_TYPE(new_rhs1), new_rhs1, rhs, BEFORE_STMT); ++ If you enable both PT_PAX_FLAGS and XATTR_PAX_FLAGS support then you ++ must make sure that the marks are the same if a binary has both marks. + -+ return dup_assign(expand_from->visited, stmt, lhs, new_rhs1, NULL_TREE, NULL_TREE); -+} ++ If you enable none of the marking options then all applications ++ will run with PaX enabled on them by default. + -+static tree handle_unary_rhs(interesting_stmts_t expand_from, gassign *stmt) -+{ -+ enum tree_code rhs_code; -+ tree rhs1, new_rhs1, lhs = gimple_assign_lhs(stmt); ++config PAX_XATTR_PAX_FLAGS ++ bool 'Use filesystem extended attributes marking' ++ default y if GRKERNSEC_CONFIG_AUTO ++ select CIFS_XATTR if CIFS ++ select EXT2_FS_XATTR if EXT2_FS ++ select EXT3_FS_XATTR if EXT3_FS ++ select F2FS_FS_XATTR if F2FS_FS ++ select JFFS2_FS_XATTR if JFFS2_FS ++ select REISERFS_FS_XATTR if REISERFS_FS ++ select SQUASHFS_XATTR if SQUASHFS ++ select TMPFS_XATTR if TMPFS ++ help ++ Enabling this option will allow you to control PaX features on ++ a per executable basis via the 'setfattr' utility. The control ++ flags will be read from the user.pax.flags extended attribute of ++ the file. This marking has the benefit of supporting binary-only ++ applications that self-check themselves (e.g., skype) and would ++ not tolerate chpax/paxctl changes. The main drawback is that ++ extended attributes are not supported by some filesystems (e.g., ++ isofs, udf, vfat) so copying files through such filesystems will ++ lose the extended attributes and these PaX markings. + -+ if (pointer_set_contains(expand_from->visited->my_stmts, stmt)) -+ return lhs; ++ Note that if you enable the legacy EI_PAX marking support as well, ++ the EI_PAX marks will be overridden by the XATTR_PAX_FLAGS marks. + -+ rhs1 = gimple_assign_rhs1(stmt); -+ if (TREE_CODE(TREE_TYPE(rhs1)) == POINTER_TYPE) -+ return create_assign(expand_from->visited, stmt, lhs, AFTER_STMT); ++ If you enable both PT_PAX_FLAGS and XATTR_PAX_FLAGS support then you ++ must make sure that the marks are the same if a binary has both marks. + -+ new_rhs1 = expand(expand_from, rhs1); ++ If you enable none of the marking options then all applications ++ will run with PaX enabled on them by default. + -+ if (new_rhs1 == NULL_TREE) -+ return create_cast_assign(expand_from->visited, stmt); ++choice ++ prompt 'MAC system integration' ++ default PAX_HAVE_ACL_FLAGS ++ help ++ Mandatory Access Control systems have the option of controlling ++ PaX flags on a per executable basis, choose the method supported ++ by your particular system. + -+ if (pointer_set_contains(expand_from->visited->no_cast_check, stmt)) -+ return dup_assign(expand_from->visited, stmt, lhs, new_rhs1, NULL_TREE, NULL_TREE); ++ - "none": if your MAC system does not interact with PaX, ++ - "direct": if your MAC system defines pax_set_initial_flags() itself, ++ - "hook": if your MAC system uses the pax_set_initial_flags_func callback. + -+#if BUILDING_GCC_VERSION >= 5000 -+ if (short_or_neg_const_ushort(stmt)) { -+ pointer_set_insert(expand_from->visited->no_cast_check, stmt); -+ return dup_assign(expand_from->visited, stmt, lhs, new_rhs1, NULL_TREE, NULL_TREE); -+ } -+#endif ++ NOTE: this option is for developers/integrators only. + -+ rhs_code = gimple_assign_rhs_code(stmt); -+ if (rhs_code == BIT_NOT_EXPR || rhs_code == NEGATE_EXPR) { -+ tree size_overflow_type = get_size_overflow_type(expand_from->visited, stmt, rhs1); ++ config PAX_NO_ACL_FLAGS ++ bool 'none' + -+ new_rhs1 = cast_to_new_size_overflow_type(expand_from->visited, stmt, new_rhs1, size_overflow_type, BEFORE_STMT); -+ check_size_overflow(expand_from, stmt, size_overflow_type, new_rhs1, rhs1, BEFORE_STMT); -+ return create_assign(expand_from->visited, stmt, lhs, AFTER_STMT); -+ } ++ config PAX_HAVE_ACL_FLAGS ++ bool 'direct' + -+ if (!gimple_assign_cast_p(stmt)) -+ return dup_assign(expand_from->visited, stmt, lhs, new_rhs1, NULL_TREE, NULL_TREE); ++ config PAX_HOOK_ACL_FLAGS ++ bool 'hook' ++endchoice + -+ return create_cast_overflow_check(expand_from, new_rhs1, stmt); -+} ++endmenu + -+static tree handle_unary_ops(interesting_stmts_t expand_from, gassign *stmt) -+{ -+ tree rhs1, lhs = gimple_assign_lhs(stmt); -+ gimple def_stmt = get_def_stmt(lhs); ++menu "Non-executable pages" ++ depends on PAX + -+ gcc_assert(gimple_code(def_stmt) != GIMPLE_NOP); -+ rhs1 = gimple_assign_rhs1(def_stmt); ++config PAX_NOEXEC ++ bool "Enforce non-executable pages" ++ default y if GRKERNSEC_CONFIG_AUTO ++ depends on ALPHA || (ARM && (CPU_V6 || CPU_V6K || CPU_V7)) || IA64 || MIPS || PARISC || PPC || S390 || SPARC || X86 ++ help ++ By design some architectures do not allow for protecting memory ++ pages against execution or even if they do, Linux does not make ++ use of this feature. In practice this means that if a page is ++ readable (such as the stack or heap) it is also executable. + -+ if (is_gimple_constant(rhs1)) -+ return create_assign(expand_from->visited, def_stmt, lhs, AFTER_STMT); ++ There is a well known exploit technique that makes use of this ++ fact and a common programming mistake where an attacker can ++ introduce code of his choice somewhere in the attacked program's ++ memory (typically the stack or the heap) and then execute it. + -+ switch (TREE_CODE(rhs1)) { -+ case SSA_NAME: { -+ tree ret = handle_unary_rhs(expand_from, as_a_gassign(def_stmt)); ++ If the attacked program was running with different (typically ++ higher) privileges than that of the attacker, then he can elevate ++ his own privilege level (e.g. get a root shell, write to files for ++ which he does not have write access to, etc). + -+ if (gimple_assign_cast_p(stmt)) -+ unsigned_signed_cast_intentional_overflow(expand_from->visited, stmt); -+ return ret; -+ } -+ case ARRAY_REF: -+ case BIT_FIELD_REF: -+ case ADDR_EXPR: -+ case COMPONENT_REF: -+ case INDIRECT_REF: -+#if BUILDING_GCC_VERSION >= 4006 -+ case MEM_REF: -+#endif -+ case TARGET_MEM_REF: -+ case VIEW_CONVERT_EXPR: -+ return create_assign(expand_from->visited, def_stmt, lhs, AFTER_STMT); -+ case PARM_DECL: -+ case VAR_DECL: -+ return create_assign(expand_from->visited, stmt, lhs, AFTER_STMT); ++ Enabling this option will let you choose from various features ++ that prevent the injection and execution of 'foreign' code in ++ a program. + -+ default: -+ debug_gimple_stmt(def_stmt); -+ debug_tree(rhs1); -+ gcc_unreachable(); -+ } -+} ++ This will also break programs that rely on the old behaviour and ++ expect that dynamically allocated memory via the malloc() family ++ of functions is executable (which it is not). Notable examples ++ are the XFree86 4.x server, the java runtime and wine. + -+static void __unused print_the_code_insertions(const_gimple stmt) -+{ -+ location_t loc = gimple_location(stmt); ++config PAX_PAGEEXEC ++ bool "Paging based non-executable pages" ++ default y if GRKERNSEC_CONFIG_AUTO ++ depends on PAX_NOEXEC && (!X86_32 || M586 || M586TSC || M586MMX || M686 || MPENTIUMII || MPENTIUMIII || MPENTIUMM || MCORE2 || MATOM || MPENTIUM4 || MPSC || MK7 || MK8 || MWINCHIPC6 || MWINCHIP2 || MWINCHIP3D || MVIAC3_2 || MVIAC7) ++ select ARCH_TRACK_EXEC_LIMIT if X86_32 ++ help ++ This implementation is based on the paging feature of the CPU. ++ On i386 without hardware non-executable bit support there is a ++ variable but usually low performance impact, however on Intel's ++ P4 core based CPUs it is very high so you should not enable this ++ for kernels meant to be used on such CPUs. + -+ inform(loc, "Integer size_overflow check applied here."); -+} ++ On alpha, avr32, ia64, parisc, sparc, sparc64, x86_64 and i386 ++ with hardware non-executable bit support there is no performance ++ impact, on ppc the impact is negligible. + -+static bool is_from_cast(const_tree node) -+{ -+ gimple def_stmt = get_def_stmt(node); ++ Note that several architectures require various emulations due to ++ badly designed userland ABIs, this will cause a performance impact ++ but will disappear as soon as userland is fixed. For example, ppc ++ userland MUST have been built with secure-plt by a recent toolchain. + -+ if (!def_stmt) -+ return false; ++config PAX_SEGMEXEC ++ bool "Segmentation based non-executable pages" ++ default y if GRKERNSEC_CONFIG_AUTO ++ depends on PAX_NOEXEC && X86_32 ++ help ++ This implementation is based on the segmentation feature of the ++ CPU and has a very small performance impact, however applications ++ will be limited to a 1.5 GB address space instead of the normal ++ 3 GB. + -+ if (gimple_assign_cast_p(def_stmt)) -+ return true; ++config PAX_EMUTRAMP ++ bool "Emulate trampolines" ++ default y if PARISC || GRKERNSEC_CONFIG_AUTO ++ depends on (PAX_PAGEEXEC || PAX_SEGMEXEC) && (PARISC || X86) ++ help ++ There are some programs and libraries that for one reason or ++ another attempt to execute special small code snippets from ++ non-executable memory pages. Most notable examples are the ++ signal handler return code generated by the kernel itself and ++ the GCC trampolines. + -+ return false; -+} ++ If you enabled CONFIG_PAX_PAGEEXEC or CONFIG_PAX_SEGMEXEC then ++ such programs will no longer work under your kernel. + -+// Skip duplication when there is a minus expr and the type of rhs1 or rhs2 is a pointer_type. -+static bool is_ptr_diff(gassign *stmt) -+{ -+ const_tree rhs1, rhs2, ptr1_rhs, ptr2_rhs; ++ As a remedy you can say Y here and use the 'chpax' or 'paxctl' ++ utilities to enable trampoline emulation for the affected programs ++ yet still have the protection provided by the non-executable pages. + -+ if (gimple_assign_rhs_code(stmt) != MINUS_EXPR) -+ return false; ++ On parisc you MUST enable this option and EMUSIGRT as well, otherwise ++ your system will not even boot. + -+ rhs1 = gimple_assign_rhs1(stmt); -+ if (!is_from_cast(rhs1)) -+ return false; ++ Alternatively you can say N here and use the 'chpax' or 'paxctl' ++ utilities to disable CONFIG_PAX_PAGEEXEC and CONFIG_PAX_SEGMEXEC ++ for the affected files. + -+ rhs2 = gimple_assign_rhs2(stmt); -+ if (!is_from_cast(rhs2)) -+ return false; ++ NOTE: enabling this feature *may* open up a loophole in the ++ protection provided by non-executable pages that an attacker ++ could abuse. Therefore the best solution is to not have any ++ files on your system that would require this option. This can ++ be achieved by not using libc5 (which relies on the kernel ++ signal handler return code) and not using or rewriting programs ++ that make use of the nested function implementation of GCC. ++ Skilled users can just fix GCC itself so that it implements ++ nested function calls in a way that does not interfere with PaX. + -+ ptr1_rhs = gimple_assign_rhs1(get_def_stmt(rhs1)); -+ ptr2_rhs = gimple_assign_rhs1(get_def_stmt(rhs2)); ++config PAX_EMUSIGRT ++ bool "Automatically emulate sigreturn trampolines" ++ depends on PAX_EMUTRAMP && PARISC ++ default y ++ help ++ Enabling this option will have the kernel automatically detect ++ and emulate signal return trampolines executing on the stack ++ that would otherwise lead to task termination. + -+ if (TREE_CODE(TREE_TYPE(ptr1_rhs)) != POINTER_TYPE && TREE_CODE(TREE_TYPE(ptr2_rhs)) != POINTER_TYPE) -+ return false; ++ This solution is intended as a temporary one for users with ++ legacy versions of libc (libc5, glibc 2.0, uClibc before 0.9.17, ++ Modula-3 runtime, etc) or executables linked to such, basically ++ everything that does not specify its own SA_RESTORER function in ++ normal executable memory like glibc 2.1+ does. + -+ return true; -+} ++ On parisc you MUST enable this option, otherwise your system will ++ not even boot. + -+static tree handle_comparison_code_class(interesting_stmts_t expand_from, gassign *stmt, tree new_rhs1, tree new_rhs2) -+{ -+ tree rhs1, rhs2, lhs; ++ NOTE: this feature cannot be disabled on a per executable basis ++ and since it *does* open up a loophole in the protection provided ++ by non-executable pages, the best solution is to not have any ++ files on your system that would require this option. + -+ rhs1 = gimple_assign_rhs1(stmt); -+ if (!is_gimple_constant(rhs1) && new_rhs1 != NULL_TREE) -+ check_size_overflow(expand_from, stmt, TREE_TYPE(new_rhs1), new_rhs1, rhs1, BEFORE_STMT); ++config PAX_MPROTECT ++ bool "Restrict mprotect()" ++ default y if GRKERNSEC_CONFIG_AUTO ++ depends on (PAX_PAGEEXEC || PAX_SEGMEXEC) ++ help ++ Enabling this option will prevent programs from ++ - changing the executable status of memory pages that were ++ not originally created as executable, ++ - making read-only executable pages writable again, ++ - creating executable pages from anonymous memory, ++ - making read-only-after-relocations (RELRO) data pages writable again. + -+ lhs = gimple_assign_lhs(stmt); -+ if (new_rhs2 == NULL_TREE) -+ return create_assign(expand_from->visited, stmt, lhs, AFTER_STMT); ++ You should say Y here to complete the protection provided by ++ the enforcement of non-executable pages. + -+ rhs2 = gimple_assign_rhs2(stmt); -+ if (!is_gimple_constant(rhs2)) -+ check_size_overflow(expand_from, stmt, TREE_TYPE(new_rhs2), new_rhs2, rhs2, BEFORE_STMT); -+ return create_assign(expand_from->visited, stmt, lhs, AFTER_STMT); -+} ++ NOTE: you can use the 'chpax' or 'paxctl' utilities to control ++ this feature on a per file basis. + -+static tree handle_binary_ops(interesting_stmts_t expand_from, tree lhs) -+{ -+ enum intentional_overflow_type res; -+ tree rhs1, rhs2, new_lhs; -+ gassign *def_stmt = as_a_gassign(get_def_stmt(lhs)); -+ tree new_rhs1 = NULL_TREE; -+ tree new_rhs2 = NULL_TREE; ++config PAX_MPROTECT_COMPAT ++ bool "Use legacy/compat protection demoting (read help)" ++ depends on PAX_MPROTECT ++ default n ++ help ++ The current implementation of PAX_MPROTECT denies RWX allocations/mprotects ++ by sending the proper error code to the application. For some older ++ userland, this can cause problems with applications that assume such ++ allocations will not be prevented by PaX or SELinux and other access ++ control systems and have no fallback mechanisms. For modern distros, ++ this option should generally be set to 'N'. ++ ++config PAX_ELFRELOCS ++ bool "Allow ELF text relocations (read help)" ++ depends on PAX_MPROTECT ++ default n ++ help ++ Non-executable pages and mprotect() restrictions are effective ++ in preventing the introduction of new executable code into an ++ attacked task's address space. There remain only two venues ++ for this kind of attack: if the attacker can execute already ++ existing code in the attacked task then he can either have it ++ create and mmap() a file containing his code or have it mmap() ++ an already existing ELF library that does not have position ++ independent code in it and use mprotect() on it to make it ++ writable and copy his code there. While protecting against ++ the former approach is beyond PaX, the latter can be prevented ++ by having only PIC ELF libraries on one's system (which do not ++ need to relocate their code). If you are sure this is your case, ++ as is the case with all modern Linux distributions, then leave ++ this option disabled. You should say 'n' here. + -+ if (is_ptr_diff(def_stmt)) -+ return create_assign(expand_from->visited, def_stmt, lhs, AFTER_STMT); ++config PAX_ETEXECRELOCS ++ bool "Allow ELF ET_EXEC text relocations" ++ depends on PAX_MPROTECT && (ALPHA || IA64 || PARISC) ++ select PAX_ELFRELOCS ++ default y ++ help ++ On some architectures there are incorrectly created applications ++ that require text relocations and would not work without enabling ++ this option. If you are an alpha, ia64 or parisc user, you should ++ enable this option and disable it once you have made sure that ++ none of your applications need it. + -+ rhs1 = gimple_assign_rhs1(def_stmt); -+ rhs2 = gimple_assign_rhs2(def_stmt); ++config PAX_EMUPLT ++ bool "Automatically emulate ELF PLT" ++ depends on PAX_MPROTECT && (ALPHA || PARISC || SPARC) ++ default y ++ help ++ Enabling this option will have the kernel automatically detect ++ and emulate the Procedure Linkage Table entries in ELF files. ++ On some architectures such entries are in writable memory, and ++ become non-executable leading to task termination. Therefore ++ it is mandatory that you enable this option on alpha, parisc, ++ sparc and sparc64, otherwise your system would not even boot. + -+ /* no DImode/TImode division in the 32/64 bit kernel */ -+ switch (gimple_assign_rhs_code(def_stmt)) { -+ case RDIV_EXPR: -+ case TRUNC_DIV_EXPR: -+ case CEIL_DIV_EXPR: -+ case FLOOR_DIV_EXPR: -+ case ROUND_DIV_EXPR: -+ case TRUNC_MOD_EXPR: -+ case CEIL_MOD_EXPR: -+ case FLOOR_MOD_EXPR: -+ case ROUND_MOD_EXPR: -+ case EXACT_DIV_EXPR: -+ case POINTER_PLUS_EXPR: -+ case BIT_AND_EXPR: -+ return create_assign(expand_from->visited, def_stmt, lhs, AFTER_STMT); -+ default: -+ break; -+ } ++ NOTE: this feature *does* open up a loophole in the protection ++ provided by the non-executable pages, therefore the proper ++ solution is to modify the toolchain to produce a PLT that does ++ not need to be writable. + -+ new_lhs = handle_integer_truncation(expand_from, lhs); -+ if (new_lhs != NULL_TREE) -+ return new_lhs; ++config PAX_DLRESOLVE ++ bool 'Emulate old glibc resolver stub' ++ depends on PAX_EMUPLT && SPARC ++ default n ++ help ++ This option is needed if userland has an old glibc (before 2.4) ++ that puts a 'save' instruction into the runtime generated resolver ++ stub that needs special emulation. + -+ if (TREE_CODE(rhs1) == SSA_NAME) -+ new_rhs1 = expand(expand_from, rhs1); -+ if (TREE_CODE(rhs2) == SSA_NAME) -+ new_rhs2 = expand(expand_from, rhs2); ++config PAX_KERNEXEC ++ bool "Enforce non-executable kernel pages" ++ default y if GRKERNSEC_CONFIG_AUTO && (!X86 || GRKERNSEC_CONFIG_VIRT_NONE || (GRKERNSEC_CONFIG_VIRT_EPT && GRKERNSEC_CONFIG_VIRT_GUEST) || (GRKERNSEC_CONFIG_VIRT_EPT && GRKERNSEC_CONFIG_VIRT_KVM)) ++ depends on (X86 || (ARM && (CPU_V6 || CPU_V6K || CPU_V7) && !(ARM_LPAE && MODULES))) && !XEN ++ select PAX_PER_CPU_PGD if X86_64 || (X86_32 && X86_PAE) ++ select PAX_KERNEXEC_PLUGIN if X86_64 ++ select ARM_KERNMEM_PERMS if ARM ++ help ++ This is the kernel land equivalent of PAGEEXEC and MPROTECT, ++ that is, enabling this option will make it harder to inject ++ and execute 'foreign' code in kernel memory itself. + -+ res = add_mul_intentional_overflow(def_stmt); -+ if (res != NO_INTENTIONAL_OVERFLOW) { -+ new_lhs = dup_assign(expand_from->visited, def_stmt, lhs, new_rhs1, new_rhs2, NULL_TREE); -+ insert_cast_expr(expand_from->visited, as_a_gassign(get_def_stmt(new_lhs)), res); -+ return new_lhs; -+ } ++ Note that on amd64, CONFIG_EFI enabled with "efi=old_map" on ++ the kernel command-line will result in an RWX physical map. + -+ if (skip_expr_on_double_type(def_stmt)) { -+ new_lhs = dup_assign(expand_from->visited, def_stmt, lhs, new_rhs1, new_rhs2, NULL_TREE); -+ insert_cast_expr(expand_from->visited, as_a_gassign(get_def_stmt(new_lhs)), NO_INTENTIONAL_OVERFLOW); -+ return new_lhs; -+ } ++ Likewise, the EFI runtime services are necessarily mapped as ++ RWX. If CONFIG_EFI is enabled on an EFI-capable system, it ++ is recommended that you boot with "noefi" on the kernel ++ command-line if possible to eliminate the mapping. + -+ if (is_a_neg_overflow(def_stmt, rhs2)) -+ return handle_intentional_overflow(expand_from, true, def_stmt, new_rhs1, NULL_TREE); -+ if (is_a_neg_overflow(def_stmt, rhs1)) -+ return handle_intentional_overflow(expand_from, true, def_stmt, new_rhs2, new_rhs2); ++choice ++ prompt "Return Address Instrumentation Method" ++ default PAX_KERNEXEC_PLUGIN_METHOD_BTS ++ depends on PAX_KERNEXEC_PLUGIN ++ help ++ Select the method used to instrument function pointer dereferences. ++ Note that binary modules cannot be instrumented by this approach. + ++ Note that the implementation requires a gcc with plugin support, ++ i.e., gcc 4.5 or newer. You may need to install the supporting ++ headers explicitly in addition to the normal gcc package. + -+ if (is_a_constant_overflow(def_stmt, rhs2)) -+ return handle_intentional_overflow(expand_from, !is_a_cast_and_const_overflow(rhs1), def_stmt, new_rhs1, NULL_TREE); -+ if (is_a_constant_overflow(def_stmt, rhs1)) -+ return handle_intentional_overflow(expand_from, !is_a_cast_and_const_overflow(rhs2), def_stmt, new_rhs2, new_rhs2); ++ config PAX_KERNEXEC_PLUGIN_METHOD_BTS ++ bool "bts" ++ help ++ This method is compatible with binary only modules but has ++ a higher runtime overhead. + -+ // the const is between 0 and (signed) MAX -+ if (is_gimple_constant(rhs1)) -+ new_rhs1 = create_assign(expand_from->visited, def_stmt, rhs1, BEFORE_STMT); -+ if (is_gimple_constant(rhs2)) -+ new_rhs2 = create_assign(expand_from->visited, def_stmt, rhs2, BEFORE_STMT); ++ config PAX_KERNEXEC_PLUGIN_METHOD_OR ++ bool "or" ++ depends on !PARAVIRT ++ help ++ This method is incompatible with binary only modules but has ++ a lower runtime overhead. ++endchoice + -+ if (TREE_CODE_CLASS(gimple_assign_rhs_code(def_stmt)) == tcc_comparison) -+ return handle_comparison_code_class(expand_from, def_stmt, new_rhs1, new_rhs2); ++config PAX_KERNEXEC_PLUGIN_METHOD ++ string ++ default "bts" if PAX_KERNEXEC_PLUGIN_METHOD_BTS ++ default "or" if PAX_KERNEXEC_PLUGIN_METHOD_OR ++ default "" + -+ if (uconst_neg_intentional_overflow(def_stmt)) { -+ inform(gimple_location(def_stmt), "%s: gcc intentional overflow", __func__); -+ gcc_unreachable(); -+ } ++config PAX_KERNEXEC_MODULE_TEXT ++ int "Minimum amount of memory reserved for module code" ++ default "8" if (!GRKERNSEC_CONFIG_AUTO || GRKERNSEC_CONFIG_SERVER) ++ default "12" if (GRKERNSEC_CONFIG_AUTO && GRKERNSEC_CONFIG_DESKTOP) ++ depends on PAX_KERNEXEC && X86_32 ++ help ++ Due to implementation details the kernel must reserve a fixed ++ amount of memory for runtime allocated code (such as modules) ++ at compile time that cannot be changed at runtime. Here you ++ can specify the minimum amount in MB that will be reserved. ++ Due to the same implementation details this size will always ++ be rounded up to the next 2/4 MB boundary (depends on PAE) so ++ the actually available memory for runtime allocated code will ++ usually be more than this minimum. + -+ return dup_assign(expand_from->visited, def_stmt, lhs, new_rhs1, new_rhs2, NULL_TREE); -+} ++ The default 4 MB should be enough for most users but if you have ++ an excessive number of modules (e.g., most distribution configs ++ compile many drivers as modules) or use huge modules such as ++ nvidia's kernel driver, you will need to adjust this amount. ++ A good rule of thumb is to look at your currently loaded kernel ++ modules and add up their sizes. + -+#if BUILDING_GCC_VERSION >= 4006 -+static tree get_new_rhs(interesting_stmts_t expand_from, tree size_overflow_type, tree rhs) -+{ -+ if (is_gimple_constant(rhs)) -+ return cast_a_tree(size_overflow_type, rhs); -+ if (TREE_CODE(rhs) != SSA_NAME) -+ return NULL_TREE; -+ return expand(expand_from, rhs); -+} ++endmenu + -+static tree handle_ternary_ops(interesting_stmts_t expand_from, tree lhs) -+{ -+ tree rhs1, rhs2, rhs3, new_rhs1, new_rhs2, new_rhs3, size_overflow_type; -+ gassign *def_stmt = as_a_gassign(get_def_stmt(lhs)); ++menu "Address Space Layout Randomization" ++ depends on PAX + -+ size_overflow_type = get_size_overflow_type(expand_from->visited, def_stmt, lhs); ++config PAX_ASLR ++ bool "Address Space Layout Randomization" ++ default y if GRKERNSEC_CONFIG_AUTO ++ help ++ Many if not most exploit techniques rely on the knowledge of ++ certain addresses in the attacked program. The following options ++ will allow the kernel to apply a certain amount of randomization ++ to specific parts of the program thereby forcing an attacker to ++ guess them in most cases. Any failed guess will most likely crash ++ the attacked program which allows the kernel to detect such attempts ++ and react on them. PaX itself provides no reaction mechanisms, ++ instead it is strongly encouraged that you make use of grsecurity's ++ (http://www.grsecurity.net/) built-in crash detection features or ++ develop one yourself. + -+ rhs1 = gimple_assign_rhs1(def_stmt); -+ rhs2 = gimple_assign_rhs2(def_stmt); -+ rhs3 = gimple_assign_rhs3(def_stmt); -+ new_rhs1 = get_new_rhs(expand_from, size_overflow_type, rhs1); -+ new_rhs2 = get_new_rhs(expand_from, size_overflow_type, rhs2); -+ new_rhs3 = get_new_rhs(expand_from, size_overflow_type, rhs3); ++ By saying Y here you can choose to randomize the following areas: ++ - top of the task's kernel stack ++ - top of the task's userland stack ++ - base address for mmap() requests that do not specify one ++ (this includes all libraries) ++ - base address of the main executable + -+ return dup_assign(expand_from->visited, def_stmt, lhs, new_rhs1, new_rhs2, new_rhs3); -+} -+#endif ++ It is strongly recommended to say Y here as address space layout ++ randomization has negligible impact on performance yet it provides ++ a very effective protection. + -+static tree expand_visited(struct visited *visited, gimple def_stmt) -+{ -+ gimple_stmt_iterator gsi; -+ enum gimple_code code = gimple_code(def_stmt); ++ NOTE: you can use the 'chpax' or 'paxctl' utilities to control ++ this feature on a per file basis. + -+ if (code == GIMPLE_ASM) -+ return NULL_TREE; ++config PAX_RANDKSTACK ++ bool "Randomize kernel stack base" ++ default y if GRKERNSEC_CONFIG_AUTO && !(GRKERNSEC_CONFIG_VIRT_HOST && GRKERNSEC_CONFIG_VIRT_VIRTUALBOX) ++ depends on X86_TSC && X86 ++ help ++ By saying Y here the kernel will randomize every task's kernel ++ stack on every system call. This will not only force an attacker ++ to guess it but also prevent him from making use of possible ++ leaked information about it. + -+ gsi = gsi_for_stmt(def_stmt); -+ gsi_next(&gsi); ++ Since the kernel stack is a rather scarce resource, randomization ++ may cause unexpected stack overflows, therefore you should very ++ carefully test your system. Note that once enabled in the kernel ++ configuration, this feature cannot be disabled on a per file basis. + -+ if (gimple_code(def_stmt) == GIMPLE_PHI && gsi_end_p(gsi)) -+ return NULL_TREE; -+ return get_my_stmt_lhs(visited, def_stmt); -+} ++config PAX_RANDUSTACK ++ bool + -+tree expand(interesting_stmts_t expand_from, tree lhs) -+{ -+ gimple def_stmt; ++config PAX_RANDMMAP ++ bool "Randomize user stack and mmap() bases" ++ default y if GRKERNSEC_CONFIG_AUTO ++ depends on PAX_ASLR ++ select PAX_RANDUSTACK ++ help ++ By saying Y here the kernel will randomize every task's userland ++ stack and use a randomized base address for mmap() requests that ++ do not specify one themselves. + -+ def_stmt = get_def_stmt(lhs); ++ The stack randomization is done in two steps where the second ++ one may apply a big amount of shift to the top of the stack and ++ cause problems for programs that want to use lots of memory (more ++ than 2.5 GB if SEGMEXEC is not active, or 1.25 GB when it is). + -+ if (!def_stmt || gimple_code(def_stmt) == GIMPLE_NOP) -+ return NULL_TREE; ++ As a result of mmap randomization all dynamically loaded libraries ++ will appear at random addresses and therefore be harder to exploit ++ by a technique where an attacker attempts to execute library code ++ for his purposes (e.g. spawn a shell from an exploited program that ++ is running at an elevated privilege level). + -+ if (pointer_set_contains(expand_from->visited->my_stmts, def_stmt)) -+ return lhs; ++ Furthermore, if a program is relinked as a dynamic ELF file, its ++ base address will be randomized as well, completing the full ++ randomization of the address space layout. Attacking such programs ++ becomes a guess game. You can find an example of doing this at ++ http://pax.grsecurity.net/et_dyn.tar.gz and practical samples at ++ http://www.grsecurity.net/grsec-gcc-specs.tar.gz . + -+ if (pointer_set_contains(expand_from->visited->stmts, def_stmt)) -+ return expand_visited(expand_from->visited, def_stmt); ++ NOTE: you can use the 'chpax' or 'paxctl' utilities to control this ++ feature on a per file basis. + -+ if (is_gimple_constant(lhs)) -+ return NULL_TREE; -+ if (skip_types(lhs)) -+ return NULL_TREE; ++endmenu + -+ switch (gimple_code(def_stmt)) { -+ case GIMPLE_PHI: -+ return handle_phi(expand_from, lhs); -+ case GIMPLE_CALL: -+ case GIMPLE_ASM: -+ if (is_size_overflow_asm(def_stmt)) -+ return expand(expand_from, get_size_overflow_asm_input(as_a_gasm(def_stmt))); -+ return create_assign(expand_from->visited, def_stmt, lhs, AFTER_STMT); -+ case GIMPLE_ASSIGN: -+ switch (gimple_num_ops(def_stmt)) { -+ case 2: -+ return handle_unary_ops(expand_from, as_a_gassign(def_stmt)); -+ case 3: -+ return handle_binary_ops(expand_from, lhs); -+#if BUILDING_GCC_VERSION >= 4006 -+ case 4: -+ return handle_ternary_ops(expand_from, lhs); -+#endif -+ } -+ default: -+ debug_gimple_stmt(def_stmt); -+ error("%s: unknown gimple code", __func__); -+ gcc_unreachable(); -+ } -+} -diff --git a/tools/gcc/stackleak_plugin.c b/tools/gcc/stackleak_plugin.c -new file mode 100644 -index 0000000..8b69bd4 ---- /dev/null -+++ b/tools/gcc/stackleak_plugin.c -@@ -0,0 +1,350 @@ -+/* -+ * Copyright 2011-2016 by the PaX Team -+ * Licensed under the GPL v2 -+ * -+ * Note: the choice of the license means that the compilation process is -+ * NOT 'eligible' as defined by gcc's library exception to the GPL v3, -+ * but for the kernel it doesn't matter since it doesn't link against -+ * any of the gcc libraries -+ * -+ * gcc plugin to help implement various PaX features -+ * -+ * - track lowest stack pointer -+ * -+ * TODO: -+ * - initialize all local variables -+ * -+ * BUGS: -+ * - none known -+ */ ++menu "Miscellaneous hardening features" + -+#include "gcc-common.h" ++config PAX_MEMORY_SANITIZE ++ bool "Sanitize all freed memory" ++ default y if (GRKERNSEC_CONFIG_AUTO && GRKERNSEC_CONFIG_PRIORITY_SECURITY) ++ help ++ By saying Y here the kernel will erase memory pages and slab objects ++ as soon as they are freed. This in turn reduces the lifetime of data ++ stored in them, making it less likely that sensitive information such ++ as passwords, cryptographic secrets, etc stay in memory for too long. + -+int plugin_is_GPL_compatible; ++ This is especially useful for programs whose runtime is short, long ++ lived processes and the kernel itself benefit from this as long as ++ they ensure timely freeing of memory that may hold sensitive ++ information. + -+static int track_frame_size = -1; -+static const char track_function[] = "pax_track_stack"; -+static const char check_function[] = "pax_check_alloca"; -+static GTY(()) tree track_function_decl; -+static GTY(()) tree check_function_decl; -+static bool init_locals; ++ A nice side effect of the sanitization of slab objects is the ++ reduction of possible info leaks caused by padding bytes within the ++ leaky structures. Use-after-free bugs for structures containing ++ pointers can also be detected as dereferencing the sanitized pointer ++ will generate an access violation. + -+static struct plugin_info stackleak_plugin_info = { -+ .version = "201602181345", -+ .help = "track-lowest-sp=nn\ttrack sp in functions whose frame size is at least nn bytes\n" -+// "initialize-locals\t\tforcibly initialize all stack frames\n" -+}; ++ The tradeoff is performance impact, on a single CPU system kernel ++ compilation sees a 3% slowdown, other systems and workloads may vary ++ and you are advised to test this feature on your expected workload ++ before deploying it. + -+static void stackleak_check_alloca(gimple_stmt_iterator *gsi) -+{ -+ gimple stmt; -+ gcall *check_alloca; -+ tree alloca_size; -+ cgraph_node_ptr node; -+ int frequency; -+ basic_block bb; ++ The slab sanitization feature excludes a few slab caches per default ++ for performance reasons. To extend the feature to cover those as ++ well, pass "pax_sanitize_slab=full" as kernel command line parameter. + -+ // insert call to void pax_check_alloca(unsigned long size) -+ alloca_size = gimple_call_arg(gsi_stmt(*gsi), 0); -+ stmt = gimple_build_call(check_function_decl, 1, alloca_size); -+ check_alloca = as_a_gcall(stmt); -+ gsi_insert_before(gsi, check_alloca, GSI_SAME_STMT); ++ To reduce the performance penalty by sanitizing pages only, albeit ++ limiting the effectiveness of this feature at the same time, slab ++ sanitization can be disabled with the kernel command line parameter ++ "pax_sanitize_slab=off". + -+ // update the cgraph -+ bb = gimple_bb(check_alloca); -+ node = cgraph_get_create_node(check_function_decl); -+ gcc_assert(node); -+ frequency = compute_call_stmt_bb_frequency(current_function_decl, bb); -+ cgraph_create_edge(cgraph_get_node(current_function_decl), node, check_alloca, bb->count, frequency, bb->loop_depth); -+} ++ Note that this feature does not protect data stored in live pages, ++ e.g., process memory swapped to disk may stay there for a long time. + -+static void stackleak_add_instrumentation(gimple_stmt_iterator *gsi, bool after) -+{ -+ gimple stmt; -+ gcall *track_stack; -+ cgraph_node_ptr node; -+ int frequency; -+ basic_block bb; ++config PAX_MEMORY_STACKLEAK ++ bool "Sanitize kernel stack" ++ default y if (GRKERNSEC_CONFIG_AUTO && GRKERNSEC_CONFIG_PRIORITY_SECURITY) ++ depends on X86 && GCC_PLUGINS ++ help ++ By saying Y here the kernel will erase the kernel stack before it ++ returns from a system call. This in turn reduces the information ++ that a kernel stack leak bug can reveal. + -+ // insert call to void pax_track_stack(void) -+ stmt = gimple_build_call(track_function_decl, 0); -+ track_stack = as_a_gcall(stmt); -+ if (after) -+ gsi_insert_after(gsi, track_stack, GSI_CONTINUE_LINKING); -+ else -+ gsi_insert_before(gsi, track_stack, GSI_SAME_STMT); ++ Note that such a bug can still leak information that was put on ++ the stack by the current system call (the one eventually triggering ++ the bug) but traces of earlier system calls on the kernel stack ++ cannot leak anymore. + -+ // update the cgraph -+ bb = gimple_bb(track_stack); -+ node = cgraph_get_create_node(track_function_decl); -+ gcc_assert(node); -+ frequency = compute_call_stmt_bb_frequency(current_function_decl, bb); -+ cgraph_create_edge(cgraph_get_node(current_function_decl), node, track_stack, bb->count, frequency, bb->loop_depth); -+} ++ The tradeoff is performance impact: on a single CPU system kernel ++ compilation sees a 1% slowdown, other systems and workloads may vary ++ and you are advised to test this feature on your expected workload ++ before deploying it. + -+static bool is_alloca(gimple stmt) -+{ -+ if (gimple_call_builtin_p(stmt, BUILT_IN_ALLOCA)) -+ return true; ++ Note that the full feature requires a gcc with plugin support, ++ i.e., gcc 4.5 or newer. You may need to install the supporting ++ headers explicitly in addition to the normal gcc package. Using ++ older gcc versions means that functions with large enough stack ++ frames may leave uninitialized memory behind that may be exposed ++ to a later syscall leaking the stack. + -+#if BUILDING_GCC_VERSION >= 4007 -+ if (gimple_call_builtin_p(stmt, BUILT_IN_ALLOCA_WITH_ALIGN)) -+ return true; -+#endif ++config PAX_MEMORY_STRUCTLEAK ++ bool "Forcibly initialize local variables copied to userland" ++ default y if (GRKERNSEC_CONFIG_AUTO && GRKERNSEC_CONFIG_PRIORITY_SECURITY) ++ depends on GCC_PLUGINS ++ help ++ By saying Y here the kernel will zero initialize some local ++ variables that are going to be copied to userland. This in ++ turn prevents unintended information leakage from the kernel ++ stack should later code forget to explicitly set all parts of ++ the copied variable. + -+ return false; -+} ++ The tradeoff is less performance impact than PAX_MEMORY_STACKLEAK ++ at a much smaller coverage. + -+static unsigned int stackleak_tree_instrument_execute(void) -+{ -+ basic_block bb, entry_bb; -+ bool prologue_instrumented = false, is_leaf = true; ++ Note that the implementation requires a gcc with plugin support, ++ i.e., gcc 4.5 or newer. You may need to install the supporting ++ headers explicitly in addition to the normal gcc package. + -+ entry_bb = ENTRY_BLOCK_PTR_FOR_FN(cfun)->next_bb; ++config PAX_MEMORY_UDEREF ++ bool "Prevent invalid userland pointer dereference" ++ default y if GRKERNSEC_CONFIG_AUTO && !(X86_64 && GRKERNSEC_CONFIG_PRIORITY_PERF) && !(X86_64 && GRKERNSEC_CONFIG_VIRT_HOST && GRKERNSEC_CONFIG_VIRT_VIRTUALBOX) && (!X86 || GRKERNSEC_CONFIG_VIRT_NONE || GRKERNSEC_CONFIG_VIRT_EPT) ++ depends on (X86 || (ARM && (CPU_V6 || CPU_V6K || CPU_V7) && !ARM_LPAE)) && !UML_X86 && !XEN ++ select PAX_PER_CPU_PGD if X86_64 ++ help ++ By saying Y here the kernel will be prevented from dereferencing ++ userland pointers in contexts where the kernel expects only kernel ++ pointers. This is both a useful runtime debugging feature and a ++ security measure that prevents exploiting a class of kernel bugs. + -+ // 1. loop through BBs and GIMPLE statements -+ FOR_EACH_BB_FN(bb, cfun) { -+ gimple_stmt_iterator gsi; ++ The tradeoff is that some virtualization solutions may experience ++ a huge slowdown and therefore you should not enable this feature ++ for kernels meant to run in such environments. Whether a given VM ++ solution is affected or not is best determined by simply trying it ++ out, the performance impact will be obvious right on boot as this ++ mechanism engages from very early on. A good rule of thumb is that ++ VMs running on CPUs without hardware virtualization support (i.e., ++ the majority of IA-32 CPUs) will likely experience the slowdown. + -+ for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { -+ gimple stmt; ++ On X86_64 the kernel will make use of PCID support when available ++ (Intel's Westmere, Sandy Bridge, etc) for better security (default) ++ or performance impact. Pass pax_weakuderef on the kernel command ++ line to choose the latter. + -+ stmt = gsi_stmt(gsi); ++config PAX_REFCOUNT ++ bool "Prevent various kernel object reference counter overflows" ++ default y if GRKERNSEC_CONFIG_AUTO ++ depends on GRKERNSEC && ((ARM && (CPU_V6 || CPU_V6K || CPU_V7)) || MIPS || PPC || SPARC64 || X86) ++ help ++ By saying Y here the kernel will detect and prevent overflowing ++ various (but not all) kinds of object reference counters. Such ++ overflows can normally occur due to bugs only and are often, if ++ not always, exploitable. + -+ if (is_gimple_call(stmt)) -+ is_leaf = false; ++ The tradeoff is that data structures protected by an overflowed ++ refcount will never be freed and therefore will leak memory. Note ++ that this leak also happens even without this protection but in ++ that case the overflow can eventually trigger the freeing of the ++ data structure while it is still being used elsewhere, resulting ++ in the exploitable situation that this feature prevents. + -+ // gimple match: align 8 built-in BUILT_IN_NORMAL:BUILT_IN_ALLOCA attributes -+ if (!is_alloca(stmt)) -+ continue; ++ Since this has a negligible performance impact, you should enable ++ this feature. + -+ // 2. insert stack overflow check before each __builtin_alloca call -+ stackleak_check_alloca(&gsi); ++config PAX_CONSTIFY_PLUGIN ++ bool "Automatically constify eligible structures" ++ default y ++ depends on !UML && PAX_KERNEXEC ++ help ++ By saying Y here the compiler will automatically constify a class ++ of types that contain only function pointers. This reduces the ++ kernel's attack surface and also produces a better memory layout. + -+ // 3. insert track call after each __builtin_alloca call -+ stackleak_add_instrumentation(&gsi, true); -+ if (bb == entry_bb) -+ prologue_instrumented = true; -+ } -+ } ++ Note that the implementation requires a gcc with plugin support, ++ i.e., gcc 4.5 or newer. You may need to install the supporting ++ headers explicitly in addition to the normal gcc package. ++ ++ Note that if some code really has to modify constified variables ++ then the source code will have to be patched to allow it. Examples ++ can be found in PaX itself (the no_const attribute) and for some ++ out-of-tree modules at http://www.grsecurity.net/~paxguy1/ . + -+ // special cases for some bad linux code: taking the address of static inline functions will materialize them -+ // but we mustn't instrument some of them as the resulting stack alignment required by the function call ABI -+ // will break other assumptions regarding the expected (but not otherwise enforced) register clobbering ABI. -+ // case in point: native_save_fl on amd64 when optimized for size clobbers rdx if it were instrumented here. -+ if (is_leaf && !TREE_PUBLIC(current_function_decl) && DECL_DECLARED_INLINE_P(current_function_decl)) -+ return 0; -+ if (is_leaf && !strncmp(IDENTIFIER_POINTER(DECL_NAME(current_function_decl)), "_paravirt_", 10)) -+ return 0; ++config PAX_USERCOPY ++ bool "Harden heap object copies between kernel and userland" ++ default y if GRKERNSEC_CONFIG_AUTO ++ depends on ARM || IA64 || PPC || SPARC || X86 ++ depends on GRKERNSEC && (SLAB || SLUB || SLOB) ++ select PAX_USERCOPY_SLABS ++ help ++ By saying Y here the kernel will enforce the size of heap objects ++ when they are copied in either direction between the kernel and ++ userland, even if only a part of the heap object is copied. + -+ // 4. insert track call at the beginning -+ if (!prologue_instrumented) { -+ gimple_stmt_iterator gsi; ++ Specifically, this checking prevents information leaking from the ++ kernel heap during kernel to userland copies (if the kernel heap ++ object is otherwise fully initialized) and prevents kernel heap ++ overflows during userland to kernel copies. + -+ gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); -+ bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); -+ if (!single_pred_p(bb)) { -+// gcc_assert(bb_loop_depth(bb) || (bb->flags & BB_IRREDUCIBLE_LOOP)); -+ split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun))); -+ gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); -+ bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); -+ } -+ gsi = gsi_after_labels(bb); -+ stackleak_add_instrumentation(&gsi, false); -+ } ++ Note that the current implementation provides the strictest bounds ++ checks for the SLUB allocator. + -+ return 0; -+} ++ Enabling this option also enables per-slab cache protection against ++ data in a given cache being copied into/out of via userland ++ accessors. Though the whitelist of regions will be reduced over ++ time, it notably protects important data structures like task structs. + -+static unsigned int stackleak_final_execute(void) -+{ -+ rtx_insn *insn, *next; ++ If frame pointers are enabled on x86, this option will also restrict ++ copies into and out of the kernel stack to local variables within a ++ single frame. + -+ if (cfun->calls_alloca) -+ return 0; ++ Since this has a negligible performance impact, you should enable ++ this feature. + -+ // keep calls only if function frame is big enough -+ if (get_frame_size() >= track_frame_size) -+ return 0; ++config PAX_USERCOPY_DEBUG ++ bool ++ depends on X86 && PAX_USERCOPY ++ default n + -+ // 1. find pax_track_stack calls -+ for (insn = get_insns(); insn; insn = next) { -+ // rtl match: (call_insn 8 7 9 3 (call (mem (symbol_ref ("pax_track_stack") [flags 0x41] ) [0 S1 A8]) (4)) -1 (nil) (nil)) -+ rtx body; ++config PAX_SIZE_OVERFLOW ++ bool "Prevent various integer overflows in function size parameters" ++ default y if GRKERNSEC_CONFIG_AUTO ++ depends on GCC_PLUGINS ++ help ++ By saying Y here the kernel recomputes expressions of function ++ arguments marked by a size_overflow attribute with double integer ++ precision (DImode/TImode for 32/64 bit integer types). + -+ next = NEXT_INSN(insn); -+ if (!CALL_P(insn)) -+ continue; -+ body = PATTERN(insn); -+ if (GET_CODE(body) != CALL) -+ continue; -+ body = XEXP(body, 0); -+ if (GET_CODE(body) != MEM) -+ continue; -+ body = XEXP(body, 0); -+ if (GET_CODE(body) != SYMBOL_REF) -+ continue; -+// if (strcmp(XSTR(body, 0), track_function)) -+ if (SYMBOL_REF_DECL(body) != track_function_decl) -+ continue; -+// warning(0, "track_frame_size: %d %ld %d", cfun->calls_alloca, get_frame_size(), track_frame_size); -+ // 2. delete call -+ delete_insn_and_edges(insn); -+#if BUILDING_GCC_VERSION >= 4007 -+ if (GET_CODE(next) == NOTE && NOTE_KIND(next) == NOTE_INSN_CALL_ARG_LOCATION) { -+ insn = next; -+ next = NEXT_INSN(insn); -+ delete_insn_and_edges(insn); -+ } -+#endif -+ } ++ The recomputed argument is checked against TYPE_MAX and an event ++ is logged on overflow and the triggering process is killed. + -+// print_simple_rtl(stderr, get_insns()); -+// print_rtl(stderr, get_insns()); -+// warning(0, "track_frame_size: %d %ld %d", cfun->calls_alloca, get_frame_size(), track_frame_size); ++ Homepage: https://github.com/ephox-gcc-plugins + -+ return 0; -+} ++ Note that the implementation requires a gcc with plugin support, ++ i.e., gcc 4.5 or newer. You may need to install the supporting ++ headers explicitly in addition to the normal gcc package. + -+static bool stackleak_track_stack_gate(void) -+{ -+ tree section; ++config PAX_LATENT_ENTROPY ++ bool "Generate some entropy during boot and runtime" ++ default y if GRKERNSEC_CONFIG_AUTO ++ depends on GCC_PLUGINS ++ help ++ By saying Y here the kernel will instrument some kernel code to ++ extract some entropy from both original and artificially created ++ program state. This will help especially embedded systems where ++ there is little 'natural' source of entropy normally. The cost ++ is some slowdown of the boot process and fork and irq processing. + -+ if (ix86_cmodel != CM_KERNEL) -+ return false; ++ When pax_extra_latent_entropy is passed on the kernel command line, ++ entropy will be extracted from up to the first 4GB of RAM while the ++ runtime memory allocator is being initialized. This costs even more ++ slowdown of the boot process. + -+ section = lookup_attribute("section", DECL_ATTRIBUTES(current_function_decl)); -+ if (section && TREE_VALUE(section)) { -+ section = TREE_VALUE(TREE_VALUE(section)); ++ Note that the implementation requires a gcc with plugin support, ++ i.e., gcc 4.5 or newer. You may need to install the supporting ++ headers explicitly in addition to the normal gcc package. + -+ if (!strncmp(TREE_STRING_POINTER(section), ".init.text", 10)) -+ return false; -+ if (!strncmp(TREE_STRING_POINTER(section), ".devinit.text", 13)) -+ return false; -+ if (!strncmp(TREE_STRING_POINTER(section), ".cpuinit.text", 13)) -+ return false; -+ if (!strncmp(TREE_STRING_POINTER(section), ".meminit.text", 13)) -+ return false; -+ } ++ Note that entropy extracted this way is not cryptographically ++ secure! + -+ return track_frame_size >= 0; -+} ++config PAX_RAP ++ bool "Prevent code reuse attacks" ++ depends on X86_64 ++ default y if GRKERNSEC_CONFIG_AUTO ++ help ++ By saying Y here the kernel will check indirect control transfers ++ in order to detect and prevent attacks that try to hijack control ++ flow by overwriting code pointers. + -+static void stackleak_start_unit(void *gcc_data, void *user_data) -+{ -+ tree fntype; ++ Note that binary modules cannot be instrumented by this approach. + -+ // void pax_track_stack(void) -+ fntype = build_function_type_list(void_type_node, NULL_TREE); -+ track_function_decl = build_fn_decl(track_function, fntype); -+ DECL_ASSEMBLER_NAME(track_function_decl); // for LTO -+ TREE_PUBLIC(track_function_decl) = 1; -+ TREE_USED(track_function_decl) = 1; -+ DECL_EXTERNAL(track_function_decl) = 1; -+ DECL_ARTIFICIAL(track_function_decl) = 1; -+ DECL_PRESERVE_P(track_function_decl) = 1; ++ Note that the implementation requires a gcc with plugin support, ++ i.e., gcc 4.5 or newer. You may need to install the supporting ++ headers explicitly in addition to the normal gcc package. + -+ // void pax_check_alloca(unsigned long) -+ fntype = build_function_type_list(void_type_node, long_unsigned_type_node, NULL_TREE); -+ check_function_decl = build_fn_decl(check_function, fntype); -+ DECL_ASSEMBLER_NAME(check_function_decl); // for LTO -+ TREE_PUBLIC(check_function_decl) = 1; -+ TREE_USED(check_function_decl) = 1; -+ DECL_EXTERNAL(check_function_decl) = 1; -+ DECL_ARTIFICIAL(check_function_decl) = 1; -+ DECL_PRESERVE_P(check_function_decl) = 1; -+} ++endmenu + -+static bool stackleak_tree_instrument_gate(void) -+{ -+ return stackleak_track_stack_gate(); -+} ++endmenu + -+#define PASS_NAME stackleak_tree_instrument -+#define PROPERTIES_REQUIRED PROP_gimple_leh | PROP_cfg -+#define TODO_FLAGS_START TODO_verify_ssa | TODO_verify_flow | TODO_verify_stmts -+#define TODO_FLAGS_FINISH TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func | TODO_update_ssa | TODO_rebuild_cgraph_edges -+#include "gcc-generate-gimple-pass.h" ++source grsecurity/Kconfig + -+static bool stackleak_final_gate(void) -+{ -+ return stackleak_track_stack_gate(); -+} ++endmenu + -+#define PASS_NAME stackleak_final -+#define TODO_FLAGS_FINISH TODO_dump_func -+#include "gcc-generate-rtl-pass.h" ++endmenu + -+int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) + source security/keys/Kconfig + + config SECURITY_DMESG_RESTRICT +@@ -104,7 +1091,7 @@ config INTEL_TXT + config LSM_MMAP_MIN_ADDR + int "Low address space for LSM to protect from user allocation" + depends on SECURITY && SECURITY_SELINUX +- default 32768 if ARM || (ARM64 && COMPAT) ++ default 32768 if ALPHA || ARM || (ARM64 && COMPAT) || PARISC || SPARC32 + default 65536 + help + This is the portion of low virtual memory which should be protected +diff --git a/security/apparmor/file.c b/security/apparmor/file.c +index 913f377..6e392d5 100644 +--- a/security/apparmor/file.c ++++ b/security/apparmor/file.c +@@ -348,8 +348,8 @@ static inline bool xindex_is_subset(u32 link, u32 target) + int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry, + struct path *new_dir, struct dentry *new_dentry) + { +- struct path link = { new_dir->mnt, new_dentry }; +- struct path target = { new_dir->mnt, old_dentry }; ++ struct path link = { .mnt = new_dir->mnt, .dentry = new_dentry }; ++ struct path target = { .mnt = new_dir->mnt, .dentry = old_dentry }; + struct path_cond cond = { + d_backing_inode(old_dentry)->i_uid, + d_backing_inode(old_dentry)->i_mode +diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h +index c28b0f2..3b9fee0 100644 +--- a/security/apparmor/include/policy.h ++++ b/security/apparmor/include/policy.h +@@ -134,7 +134,7 @@ struct aa_namespace { + struct aa_ns_acct acct; + struct aa_profile *unconfined; + struct list_head sub_ns; +- atomic_t uniq_null; ++ atomic_unchecked_t uniq_null; + long uniq_id; + + struct dentry *dents[AAFS_NS_SIZEOF]; +diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c +index dec607c..37fe357 100644 +--- a/security/apparmor/lsm.c ++++ b/security/apparmor/lsm.c +@@ -176,7 +176,7 @@ static int common_perm_dir_dentry(int op, struct path *dir, + struct dentry *dentry, u32 mask, + struct path_cond *cond) + { +- struct path path = { dir->mnt, dentry }; ++ struct path path = { .mnt = dir->mnt, .dentry = dentry }; + + return common_perm(op, &path, mask, cond); + } +@@ -193,7 +193,7 @@ static int common_perm_dir_dentry(int op, struct path *dir, + static int common_perm_mnt_dentry(int op, struct vfsmount *mnt, + struct dentry *dentry, u32 mask) + { +- struct path path = { mnt, dentry }; ++ struct path path = { .mnt = mnt, .dentry = dentry }; + struct path_cond cond = { d_backing_inode(dentry)->i_uid, + d_backing_inode(dentry)->i_mode + }; +@@ -315,8 +315,8 @@ static int apparmor_path_rename(struct path *old_dir, struct dentry *old_dentry, + + profile = aa_current_profile(); + if (!unconfined(profile)) { +- struct path old_path = { old_dir->mnt, old_dentry }; +- struct path new_path = { new_dir->mnt, new_dentry }; ++ struct path old_path = { .mnt = old_dir->mnt, .dentry = old_dentry }; ++ struct path new_path = { .mnt = new_dir->mnt, .dentry = new_dentry }; + struct path_cond cond = { d_backing_inode(old_dentry)->i_uid, + d_backing_inode(old_dentry)->i_mode + }; +@@ -677,11 +677,11 @@ static const struct kernel_param_ops param_ops_aalockpolicy = { + .get = param_get_aalockpolicy + }; + +-static int param_set_audit(const char *val, struct kernel_param *kp); +-static int param_get_audit(char *buffer, struct kernel_param *kp); ++static int param_set_audit(const char *val, const struct kernel_param *kp); ++static int param_get_audit(char *buffer, const struct kernel_param *kp); + +-static int param_set_mode(const char *val, struct kernel_param *kp); +-static int param_get_mode(char *buffer, struct kernel_param *kp); ++static int param_set_mode(const char *val, const struct kernel_param *kp); ++static int param_get_mode(char *buffer, const struct kernel_param *kp); + + /* Flag values, also controllable via /sys/module/apparmor/parameters + * We define special types as we want to do additional mediation. +@@ -791,7 +791,7 @@ static int param_get_aauint(char *buffer, const struct kernel_param *kp) + return param_get_uint(buffer, kp); + } + +-static int param_get_audit(char *buffer, struct kernel_param *kp) ++static int param_get_audit(char *buffer, const struct kernel_param *kp) + { + if (!capable(CAP_MAC_ADMIN)) + return -EPERM; +@@ -802,7 +802,7 @@ static int param_get_audit(char *buffer, struct kernel_param *kp) + return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]); + } + +-static int param_set_audit(const char *val, struct kernel_param *kp) ++static int param_set_audit(const char *val, const struct kernel_param *kp) + { + int i; + if (!capable(CAP_MAC_ADMIN)) +@@ -824,7 +824,7 @@ static int param_set_audit(const char *val, struct kernel_param *kp) + return -EINVAL; + } + +-static int param_get_mode(char *buffer, struct kernel_param *kp) ++static int param_get_mode(char *buffer, const struct kernel_param *kp) + { + if (!capable(CAP_MAC_ADMIN)) + return -EPERM; +@@ -835,7 +835,7 @@ static int param_get_mode(char *buffer, struct kernel_param *kp) + return sprintf(buffer, "%s", aa_profile_mode_names[aa_g_profile_mode]); + } + +-static int param_set_mode(const char *val, struct kernel_param *kp) ++static int param_set_mode(const char *val, const struct kernel_param *kp) + { + int i; + if (!capable(CAP_MAC_ADMIN)) +diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c +index 705c287..81257f1 100644 +--- a/security/apparmor/policy.c ++++ b/security/apparmor/policy.c +@@ -298,7 +298,7 @@ static struct aa_namespace *alloc_namespace(const char *prefix, + /* ns and ns->unconfined share ns->unconfined refcount */ + ns->unconfined->ns = ns; + +- atomic_set(&ns->uniq_null, 0); ++ atomic_set_unchecked(&ns->uniq_null, 0); + + return ns; + +@@ -689,7 +689,7 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat) + { + struct aa_profile *profile = NULL; + char *name; +- int uniq = atomic_inc_return(&parent->ns->uniq_null); ++ int uniq = atomic_inc_return_unchecked(&parent->ns->uniq_null); + + /* freed below */ + name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, GFP_KERNEL); +diff --git a/security/commoncap.c b/security/commoncap.c +index 48071ed..b805e0f 100644 +--- a/security/commoncap.c ++++ b/security/commoncap.c +@@ -438,6 +438,32 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data + return 0; + } + ++/* returns: ++ 1 for suid privilege ++ 2 for sgid privilege ++ 3 for fscap privilege ++*/ ++int is_privileged_binary(const struct dentry *dentry) +{ -+ const char * const plugin_name = plugin_info->base_name; -+ const int argc = plugin_info->argc; -+ const struct plugin_argument * const argv = plugin_info->argv; -+ int i; -+ struct register_pass_info stackleak_tree_instrument_pass_info; -+ struct register_pass_info stackleak_final_pass_info; -+ static const struct ggc_root_tab gt_ggc_r_gt_stackleak[] = { -+ { -+ .base = &track_function_decl, -+ .nelt = 1, -+ .stride = sizeof(track_function_decl), -+ .cb = >_ggc_mx_tree_node, -+ .pchw = >_pch_nx_tree_node -+ }, -+ { -+ .base = &check_function_decl, -+ .nelt = 1, -+ .stride = sizeof(check_function_decl), -+ .cb = >_ggc_mx_tree_node, -+ .pchw = >_pch_nx_tree_node -+ }, -+ LAST_GGC_ROOT_TAB -+ }; -+ -+ stackleak_tree_instrument_pass_info.pass = make_stackleak_tree_instrument_pass(); -+// stackleak_tree_instrument_pass_info.reference_pass_name = "tree_profile"; -+ stackleak_tree_instrument_pass_info.reference_pass_name = "optimized"; -+ stackleak_tree_instrument_pass_info.ref_pass_instance_number = 1; -+ stackleak_tree_instrument_pass_info.pos_op = PASS_POS_INSERT_BEFORE; ++ struct cpu_vfs_cap_data capdata; ++ struct inode *inode = dentry->d_inode; + -+ stackleak_final_pass_info.pass = make_stackleak_final_pass(); -+ stackleak_final_pass_info.reference_pass_name = "final"; -+ stackleak_final_pass_info.ref_pass_instance_number = 1; -+ stackleak_final_pass_info.pos_op = PASS_POS_INSERT_BEFORE; ++ if (!inode || S_ISDIR(inode->i_mode)) ++ return 0; + -+ if (!plugin_default_version_check(version, &gcc_version)) { -+ error(G_("incompatible gcc/plugin versions")); ++ if (inode->i_mode & S_ISUID) + return 1; -+ } -+ -+ register_callback(plugin_name, PLUGIN_INFO, NULL, &stackleak_plugin_info); ++ if ((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) ++ return 2; + -+ for (i = 0; i < argc; ++i) { -+ if (!strcmp(argv[i].key, "track-lowest-sp")) { -+ if (!argv[i].value) { -+ error(G_("no value supplied for option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); -+ continue; -+ } -+ track_frame_size = atoi(argv[i].value); -+ if (argv[i].value[0] < '0' || argv[i].value[0] > '9' || track_frame_size < 0) -+ error(G_("invalid option argument '-fplugin-arg-%s-%s=%s'"), plugin_name, argv[i].key, argv[i].value); -+ continue; -+ } -+ if (!strcmp(argv[i].key, "initialize-locals")) { -+ if (argv[i].value) { -+ error(G_("invalid option argument '-fplugin-arg-%s-%s=%s'"), plugin_name, argv[i].key, argv[i].value); -+ continue; -+ } -+ init_locals = true; -+ continue; -+ } -+ error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); ++ if (!get_vfs_caps_from_disk(dentry, &capdata)) { ++ if (!cap_isclear(capdata.inheritable) || !cap_isclear(capdata.permitted)) ++ return 3; + } + -+ register_callback(plugin_name, PLUGIN_START_UNIT, &stackleak_start_unit, NULL); -+ register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, NULL, (void *)>_ggc_r_gt_stackleak); -+ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &stackleak_tree_instrument_pass_info); -+ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &stackleak_final_pass_info); -+ + return 0; +} -diff --git a/tools/gcc/structleak_plugin.c b/tools/gcc/structleak_plugin.c -new file mode 100644 -index 0000000..d7596e6 ---- /dev/null -+++ b/tools/gcc/structleak_plugin.c -@@ -0,0 +1,239 @@ -+/* -+ * Copyright 2013-2016 by PaX Team -+ * Licensed under the GPL v2 -+ * -+ * Note: the choice of the license means that the compilation process is -+ * NOT 'eligible' as defined by gcc's library exception to the GPL v3, -+ * but for the kernel it doesn't matter since it doesn't link against -+ * any of the gcc libraries -+ * -+ * gcc plugin to forcibly initialize certain local variables that could -+ * otherwise leak kernel stack to userland if they aren't properly initialized -+ * by later code -+ * -+ * Homepage: http://pax.grsecurity.net/ -+ * -+ * Usage: -+ * $ # for 4.5/4.6/C based 4.7 -+ * $ gcc -I`gcc -print-file-name=plugin`/include -I`gcc -print-file-name=plugin`/include/c-family -fPIC -shared -O2 -o structleak_plugin.so structleak_plugin.c -+ * $ # for C++ based 4.7/4.8+ -+ * $ g++ -I`g++ -print-file-name=plugin`/include -I`g++ -print-file-name=plugin`/include/c-family -fPIC -shared -O2 -o structleak_plugin.so structleak_plugin.c -+ * $ gcc -fplugin=./structleak_plugin.so test.c -O2 -+ * -+ * TODO: eliminate redundant initializers -+ * increase type coverage -+ */ + -+#include "gcc-common.h" + /* + * Attempt to get the on-exec apply capability sets for an executable file from + * its xattrs and, if present, apply them to the proposed credentials being +@@ -628,6 +654,9 @@ int cap_bprm_secureexec(struct linux_binprm *bprm) + const struct cred *cred = current_cred(); + kuid_t root_uid = make_kuid(cred->user_ns, 0); + ++ if (gr_acl_enable_at_secure()) ++ return 1; + -+// unused C type flag in all versions 4.5-6 -+#define TYPE_USERSPACE(TYPE) TYPE_LANG_FLAG_5(TYPE) + if (!uid_eq(cred->uid, root_uid)) { + if (bprm->cap_effective) + return 1; +diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h +index 585af61..b7d35ff 100644 +--- a/security/integrity/ima/ima.h ++++ b/security/integrity/ima/ima.h +@@ -125,8 +125,8 @@ int ima_init_template(void); + extern spinlock_t ima_queue_lock; + + struct ima_h_table { +- atomic_long_t len; /* number of stored measurements in the list */ +- atomic_long_t violations; ++ atomic_long_unchecked_t len; /* number of stored measurements in the list */ ++ atomic_long_unchecked_t violations; + struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE]; + }; + extern struct ima_h_table ima_htable; +diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c +index 1d950fb..a8f4eab 100644 +--- a/security/integrity/ima/ima_api.c ++++ b/security/integrity/ima/ima_api.c +@@ -137,7 +137,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename, + int result; + + /* can overflow, only indicator */ +- atomic_long_inc(&ima_htable.violations); ++ atomic_long_inc_unchecked(&ima_htable.violations); + + result = ima_alloc_init_template(&event_data, &entry); + if (result < 0) { +diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c +index f355231..c71f640 100644 +--- a/security/integrity/ima/ima_fs.c ++++ b/security/integrity/ima/ima_fs.c +@@ -30,12 +30,12 @@ static DEFINE_MUTEX(ima_write_mutex); + static int valid_policy = 1; + #define TMPBUFLEN 12 + static ssize_t ima_show_htable_value(char __user *buf, size_t count, +- loff_t *ppos, atomic_long_t *val) ++ loff_t *ppos, atomic_long_unchecked_t *val) + { + char tmpbuf[TMPBUFLEN]; + ssize_t len; + +- len = scnprintf(tmpbuf, TMPBUFLEN, "%li\n", atomic_long_read(val)); ++ len = scnprintf(tmpbuf, TMPBUFLEN, "%li\n", atomic_long_read_unchecked(val)); + return simple_read_from_buffer(buf, count, ppos, tmpbuf, len); + } + +diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c +index 552705d..9920f4fb 100644 +--- a/security/integrity/ima/ima_queue.c ++++ b/security/integrity/ima/ima_queue.c +@@ -83,7 +83,7 @@ static int ima_add_digest_entry(struct ima_template_entry *entry) + INIT_LIST_HEAD(&qe->later); + list_add_tail_rcu(&qe->later, &ima_measurements); + +- atomic_long_inc(&ima_htable.len); ++ atomic_long_inc_unchecked(&ima_htable.len); + key = ima_hash_key(entry->digest); + hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]); + return 0; +diff --git a/security/keys/internal.h b/security/keys/internal.h +index 5105c2c..a5010e6 100644 +--- a/security/keys/internal.h ++++ b/security/keys/internal.h +@@ -90,12 +90,16 @@ extern void key_type_put(struct key_type *ktype); + + extern int __key_link_begin(struct key *keyring, + const struct keyring_index_key *index_key, +- struct assoc_array_edit **_edit); ++ struct assoc_array_edit **_edit) ++ __acquires(&keyring->sem) ++ __acquires(&keyring_serialise_link_sem); + extern int __key_link_check_live_key(struct key *keyring, struct key *key); + extern void __key_link(struct key *key, struct assoc_array_edit **_edit); + extern void __key_link_end(struct key *keyring, + const struct keyring_index_key *index_key, +- struct assoc_array_edit *edit); ++ struct assoc_array_edit *edit) ++ __releases(&keyring->sem) ++ __releases(&keyring_serialise_link_sem); + + extern key_ref_t find_key_to_update(key_ref_t keyring_ref, + const struct keyring_index_key *index_key); +@@ -191,7 +195,7 @@ struct request_key_auth { + void *callout_info; + size_t callout_len; + pid_t pid; +-}; ++} __randomize_layout; + + extern struct key_type key_type_request_key_auth; + extern struct key *request_key_auth_new(struct key *target, +diff --git a/security/keys/key.c b/security/keys/key.c +index 09ef276..ab2894f 100644 +--- a/security/keys/key.c ++++ b/security/keys/key.c +@@ -283,7 +283,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, + + atomic_set(&key->usage, 1); + init_rwsem(&key->sem); +- lockdep_set_class(&key->sem, &type->lock_class); ++ lockdep_set_class(&key->sem, (struct lock_class_key *)&type->lock_class); + key->index_key.type = type; + key->user = user; + key->quotalen = quotalen; +@@ -1077,7 +1077,9 @@ int register_key_type(struct key_type *ktype) + struct key_type *p; + int ret; + +- memset(&ktype->lock_class, 0, sizeof(ktype->lock_class)); ++ pax_open_kernel(); ++ memset((void *)&ktype->lock_class, 0, sizeof(ktype->lock_class)); ++ pax_close_kernel(); + + ret = -EEXIST; + down_write(&key_types_sem); +@@ -1089,7 +1091,7 @@ int register_key_type(struct key_type *ktype) + } + + /* store the type */ +- list_add(&ktype->link, &key_types_list); ++ pax_list_add((struct list_head *)&ktype->link, &key_types_list); + + pr_notice("Key type %s registered\n", ktype->name); + ret = 0; +@@ -1111,7 +1113,7 @@ EXPORT_SYMBOL(register_key_type); + void unregister_key_type(struct key_type *ktype) + { + down_write(&key_types_sem); +- list_del_init(&ktype->link); ++ pax_list_del_init((struct list_head *)&ktype->link); + downgrade_write(&key_types_sem); + key_gc_keytype(ktype); + pr_notice("Key type %s unregistered\n", ktype->name); +@@ -1129,10 +1131,10 @@ void __init key_init(void) + 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); + + /* add the special key types */ +- list_add_tail(&key_type_keyring.link, &key_types_list); +- list_add_tail(&key_type_dead.link, &key_types_list); +- list_add_tail(&key_type_user.link, &key_types_list); +- list_add_tail(&key_type_logon.link, &key_types_list); ++ pax_list_add_tail((struct list_head *)&key_type_keyring.link, &key_types_list); ++ pax_list_add_tail((struct list_head *)&key_type_dead.link, &key_types_list); ++ pax_list_add_tail((struct list_head *)&key_type_user.link, &key_types_list); ++ pax_list_add_tail((struct list_head *)&key_type_logon.link, &key_types_list); + + /* record the root user tracking */ + rb_link_node(&root_key_user.node, +diff --git a/security/keys/keyring.c b/security/keys/keyring.c +index f931ccf..ed9cd36 100644 +--- a/security/keys/keyring.c ++++ b/security/keys/keyring.c +@@ -1071,8 +1071,6 @@ static int keyring_detect_cycle(struct key *A, struct key *B) + int __key_link_begin(struct key *keyring, + const struct keyring_index_key *index_key, + struct assoc_array_edit **_edit) +- __acquires(&keyring->sem) +- __acquires(&keyring_serialise_link_sem) + { + struct assoc_array_edit *edit; + int ret; +@@ -1172,8 +1170,6 @@ void __key_link(struct key *key, struct assoc_array_edit **_edit) + void __key_link_end(struct key *keyring, + const struct keyring_index_key *index_key, + struct assoc_array_edit *edit) +- __releases(&keyring->sem) +- __releases(&keyring_serialise_link_sem) + { + BUG_ON(index_key->type == NULL); + kenter("%d,%s,", keyring->serial, index_key->type->name); +diff --git a/security/min_addr.c b/security/min_addr.c +index f728728..6457a0c 100644 +--- a/security/min_addr.c ++++ b/security/min_addr.c +@@ -14,6 +14,7 @@ unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR; + */ + static void update_mmap_min_addr(void) + { ++#ifndef SPARC + #ifdef CONFIG_LSM_MMAP_MIN_ADDR + if (dac_mmap_min_addr > CONFIG_LSM_MMAP_MIN_ADDR) + mmap_min_addr = dac_mmap_min_addr; +@@ -22,6 +23,7 @@ static void update_mmap_min_addr(void) + #else + mmap_min_addr = dac_mmap_min_addr; + #endif ++#endif + } + + /* +diff --git a/security/selinux/avc.c b/security/selinux/avc.c +index e60c79d..41fb721 100644 +--- a/security/selinux/avc.c ++++ b/security/selinux/avc.c +@@ -71,7 +71,7 @@ struct avc_xperms_node { + struct avc_cache { + struct hlist_head slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */ + spinlock_t slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */ +- atomic_t lru_hint; /* LRU hint for reclaim scan */ ++ atomic_unchecked_t lru_hint; /* LRU hint for reclaim scan */ + atomic_t active_nodes; + u32 latest_notif; /* latest revocation notification */ + }; +@@ -183,7 +183,7 @@ void __init avc_init(void) + spin_lock_init(&avc_cache.slots_lock[i]); + } + atomic_set(&avc_cache.active_nodes, 0); +- atomic_set(&avc_cache.lru_hint, 0); ++ atomic_set_unchecked(&avc_cache.lru_hint, 0); + + avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), + 0, SLAB_PANIC, NULL); +@@ -521,7 +521,7 @@ static inline int avc_reclaim_node(void) + spinlock_t *lock; + + for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++) { +- hvalue = atomic_inc_return(&avc_cache.lru_hint) & (AVC_CACHE_SLOTS - 1); ++ hvalue = atomic_inc_return_unchecked(&avc_cache.lru_hint) & (AVC_CACHE_SLOTS - 1); + head = &avc_cache.slots[hvalue]; + lock = &avc_cache.slots_lock[hvalue]; + +diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h +index 1450f85..a91e0bc 100644 +--- a/security/selinux/include/xfrm.h ++++ b/security/selinux/include/xfrm.h +@@ -48,7 +48,7 @@ static inline void selinux_xfrm_notify_policyload(void) + + rtnl_lock(); + for_each_net(net) { +- atomic_inc(&net->xfrm.flow_cache_genid); ++ atomic_inc_unchecked(&net->xfrm.flow_cache_genid); + rt_genid_bump_all(net); + } + rtnl_unlock(); +diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c +index 2367b10..a0c3c51 100644 +--- a/security/tomoyo/file.c ++++ b/security/tomoyo/file.c +@@ -692,7 +692,7 @@ int tomoyo_path_number_perm(const u8 type, struct path *path, + { + struct tomoyo_request_info r; + struct tomoyo_obj_info obj = { +- .path1 = *path, ++ .path1 = { .mnt = path->mnt, .dentry = path->dentry }, + }; + int error = -ENOMEM; + struct tomoyo_path_info buf; +@@ -740,7 +740,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, + struct tomoyo_path_info buf; + struct tomoyo_request_info r; + struct tomoyo_obj_info obj = { +- .path1 = *path, ++ .path1 = { .mnt = path->mnt, .dentry = path->dentry }, + }; + int idx; + +@@ -786,7 +786,7 @@ int tomoyo_path_perm(const u8 operation, const struct path *path, const char *ta + { + struct tomoyo_request_info r; + struct tomoyo_obj_info obj = { +- .path1 = *path, ++ .path1 = { .mnt = path->mnt, .dentry = path->dentry }, + }; + int error; + struct tomoyo_path_info buf; +@@ -843,7 +843,7 @@ int tomoyo_mkdev_perm(const u8 operation, struct path *path, + { + struct tomoyo_request_info r; + struct tomoyo_obj_info obj = { +- .path1 = *path, ++ .path1 = { .mnt = path->mnt, .dentry = path->dentry }, + }; + int error = -ENOMEM; + struct tomoyo_path_info buf; +@@ -890,8 +890,8 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, + struct tomoyo_path_info buf2; + struct tomoyo_request_info r; + struct tomoyo_obj_info obj = { +- .path1 = *path1, +- .path2 = *path2, ++ .path1 = { .mnt = path1->mnt, .dentry = path1->dentry }, ++ .path2 = { .mnt = path2->mnt, .dentry = path2->dentry } + }; + int idx; + +diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c +index 390c646..f2f8db3 100644 +--- a/security/tomoyo/mount.c ++++ b/security/tomoyo/mount.c +@@ -118,6 +118,10 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, + type == tomoyo_mounts[TOMOYO_MOUNT_MOVE]) { + need_dev = -1; /* dev_name is a directory */ + } else { ++ if (!capable(CAP_SYS_ADMIN)) { ++ error = -EPERM; ++ goto out; ++ } + fstype = get_fs_type(type); + if (!fstype) { + error = -ENODEV; +diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c +index cbf3df4..22b11df 100644 +--- a/security/tomoyo/tomoyo.c ++++ b/security/tomoyo/tomoyo.c +@@ -165,7 +165,7 @@ static int tomoyo_path_truncate(struct path *path) + */ + static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) + { +- struct path path = { parent->mnt, dentry }; ++ struct path path = { .mnt = parent->mnt, .dentry = dentry }; + return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL); + } + +@@ -181,7 +181,7 @@ static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) + static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, + umode_t mode) + { +- struct path path = { parent->mnt, dentry }; ++ struct path path = { .mnt = parent->mnt, .dentry = dentry }; + return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path, + mode & S_IALLUGO); + } +@@ -196,7 +196,7 @@ static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, + */ + static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) + { +- struct path path = { parent->mnt, dentry }; ++ struct path path = { .mnt = parent->mnt, .dentry = dentry }; + return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL); + } + +@@ -212,7 +212,7 @@ static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) + static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, + const char *old_name) + { +- struct path path = { parent->mnt, dentry }; ++ struct path path = { .mnt = parent->mnt, .dentry = dentry }; + return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name); + } + +@@ -229,7 +229,7 @@ static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, + static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, + umode_t mode, unsigned int dev) + { +- struct path path = { parent->mnt, dentry }; ++ struct path path = { .mnt = parent->mnt, .dentry = dentry }; + int type = TOMOYO_TYPE_CREATE; + const unsigned int perm = mode & S_IALLUGO; + +@@ -268,8 +268,8 @@ static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, + static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, + struct dentry *new_dentry) + { +- struct path path1 = { new_dir->mnt, old_dentry }; +- struct path path2 = { new_dir->mnt, new_dentry }; ++ struct path path1 = { .mnt = new_dir->mnt, .dentry = old_dentry }; ++ struct path path2 = { .mnt = new_dir->mnt, .dentry = new_dentry }; + return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2); + } + +@@ -288,8 +288,8 @@ static int tomoyo_path_rename(struct path *old_parent, + struct path *new_parent, + struct dentry *new_dentry) + { +- struct path path1 = { old_parent->mnt, old_dentry }; +- struct path path2 = { new_parent->mnt, new_dentry }; ++ struct path path1 = { .mnt = old_parent->mnt, .dentry = old_dentry }; ++ struct path path2 = { .mnt = new_parent->mnt, .dentry = new_dentry }; + return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2); + } + +@@ -417,7 +417,7 @@ static int tomoyo_sb_mount(const char *dev_name, struct path *path, + */ + static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) + { +- struct path path = { mnt, mnt->mnt_root }; ++ struct path path = { .mnt = mnt, .dentry = mnt->mnt_root }; + return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path, NULL); + } + +diff --git a/security/yama/Kconfig b/security/yama/Kconfig +index 90c605e..bf3a29a 100644 +--- a/security/yama/Kconfig ++++ b/security/yama/Kconfig +@@ -1,6 +1,6 @@ + config SECURITY_YAMA + bool "Yama support" +- depends on SECURITY ++ depends on SECURITY && !GRKERNSEC + default n + help + This selects Yama, which extends DAC support with additional +diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c +index cb6ed10..fb00554 100644 +--- a/security/yama/yama_lsm.c ++++ b/security/yama/yama_lsm.c +@@ -357,7 +357,7 @@ static struct security_hook_list yama_hooks[] = { + static int yama_dointvec_minmax(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) + { +- struct ctl_table table_copy; ++ ctl_table_no_const table_copy; + + if (write && !capable(CAP_SYS_PTRACE)) + return -EPERM; +diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c +index a04edff..6811b91 100644 +--- a/sound/aoa/codecs/onyx.c ++++ b/sound/aoa/codecs/onyx.c +@@ -54,7 +54,7 @@ struct onyx { + spdif_locked:1, + analog_locked:1, + original_mute:2; +- int open_count; ++ local_t open_count; + struct codec_info *codec_info; + + /* mutex serializes concurrent access to the device +@@ -747,7 +747,7 @@ static int onyx_open(struct codec_info_item *cii, + struct onyx *onyx = cii->codec_data; + + mutex_lock(&onyx->mutex); +- onyx->open_count++; ++ local_inc(&onyx->open_count); + mutex_unlock(&onyx->mutex); + + return 0; +@@ -759,8 +759,7 @@ static int onyx_close(struct codec_info_item *cii, + struct onyx *onyx = cii->codec_data; + + mutex_lock(&onyx->mutex); +- onyx->open_count--; +- if (!onyx->open_count) ++ if (local_dec_and_test(&onyx->open_count)) + onyx->spdif_locked = onyx->analog_locked = 0; + mutex_unlock(&onyx->mutex); + +diff --git a/sound/aoa/codecs/onyx.h b/sound/aoa/codecs/onyx.h +index ffd2025..df062c9 100644 +--- a/sound/aoa/codecs/onyx.h ++++ b/sound/aoa/codecs/onyx.h +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + /* PCM3052 register definitions */ + +diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c +index ebc9fdf..61f491e 100644 +--- a/sound/core/oss/pcm_oss.c ++++ b/sound/core/oss/pcm_oss.c +@@ -1193,10 +1193,10 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const + if (in_kernel) { + mm_segment_t fs; + fs = snd_enter_user(); +- ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames); ++ ret = snd_pcm_lib_write(substream, (void __force_user *)ptr, frames); + snd_leave_user(fs); + } else { +- ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames); ++ ret = snd_pcm_lib_write(substream, (void __force_user *)ptr, frames); + } + if (ret != -EPIPE && ret != -ESTRPIPE) + break; +@@ -1236,10 +1236,10 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p + if (in_kernel) { + mm_segment_t fs; + fs = snd_enter_user(); +- ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames); ++ ret = snd_pcm_lib_read(substream, (void __force_user *)ptr, frames); + snd_leave_user(fs); + } else { +- ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames); ++ ret = snd_pcm_lib_read(substream, (void __force_user *)ptr, frames); + } + if (ret == -EPIPE) { + if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { +@@ -1335,7 +1335,7 @@ static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const cha + struct snd_pcm_plugin_channel *channels; + size_t oss_frame_bytes = (runtime->oss.plugin_first->src_width * runtime->oss.plugin_first->src_format.channels) / 8; + if (!in_kernel) { +- if (copy_from_user(runtime->oss.buffer, (const char __force __user *)buf, bytes)) ++ if (copy_from_user(runtime->oss.buffer, (const char __force_user *)buf, bytes)) + return -EFAULT; + buf = runtime->oss.buffer; + } +@@ -1405,7 +1405,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha + } + } else { + tmp = snd_pcm_oss_write2(substream, +- (const char __force *)buf, ++ (const char __force_kernel *)buf, + runtime->oss.period_bytes, 0); + if (tmp <= 0) + goto err; +@@ -1431,7 +1431,7 @@ static ssize_t snd_pcm_oss_read2(struct snd_pcm_substream *substream, char *buf, + struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_sframes_t frames, frames1; + #ifdef CONFIG_SND_PCM_OSS_PLUGINS +- char __user *final_dst = (char __force __user *)buf; ++ char __user *final_dst = (char __force_user *)buf; + if (runtime->oss.plugin_first) { + struct snd_pcm_plugin_channel *channels; + size_t oss_frame_bytes = (runtime->oss.plugin_last->dst_width * runtime->oss.plugin_last->dst_format.channels) / 8; +@@ -1493,7 +1493,7 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use + xfer += tmp; + runtime->oss.buffer_used -= tmp; + } else { +- tmp = snd_pcm_oss_read2(substream, (char __force *)buf, ++ tmp = snd_pcm_oss_read2(substream, (char __force_kernel *)buf, + runtime->oss.period_bytes, 0); + if (tmp <= 0) + goto err; +@@ -1662,7 +1662,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) + size1); + size1 /= runtime->channels; /* frames */ + fs = snd_enter_user(); +- snd_pcm_lib_write(substream, (void __force __user *)runtime->oss.buffer, size1); ++ snd_pcm_lib_write(substream, (void __force_user *)runtime->oss.buffer, size1); + snd_leave_user(fs); + } + } else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) { +diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c +index 1f64ab0..26a7233 100644 +--- a/sound/core/pcm_compat.c ++++ b/sound/core/pcm_compat.c +@@ -31,7 +31,7 @@ static int snd_pcm_ioctl_delay_compat(struct snd_pcm_substream *substream, + int err; + + fs = snd_enter_user(); +- err = snd_pcm_delay(substream, &delay); ++ err = snd_pcm_delay(substream, (snd_pcm_sframes_t __force_user *)&delay); + snd_leave_user(fs); + if (err < 0) + return err; +diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c +index 3a9b66c..2b38b21 100644 +--- a/sound/core/pcm_lib.c ++++ b/sound/core/pcm_lib.c +@@ -1867,8 +1867,9 @@ EXPORT_SYMBOL(snd_pcm_lib_ioctl); + * Even if more than one periods have elapsed since the last call, you + * have to call this only once. + */ +-void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) ++void snd_pcm_period_elapsed(void *_substream) + { ++ struct snd_pcm_substream *substream = _substream; + struct snd_pcm_runtime *runtime; + unsigned long flags; + +diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c +index 9106d8e..e7e2e3c 100644 +--- a/sound/core/pcm_native.c ++++ b/sound/core/pcm_native.c +@@ -3014,11 +3014,11 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + result = snd_pcm_playback_ioctl1(NULL, substream, cmd, +- (void __user *)arg); ++ (void __force_user *)arg); + break; + case SNDRV_PCM_STREAM_CAPTURE: + result = snd_pcm_capture_ioctl1(NULL, substream, cmd, +- (void __user *)arg); ++ (void __force_user *)arg); + break; + default: + result = -EINVAL; +diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c +index 795437b..3650746 100644 +--- a/sound/core/rawmidi.c ++++ b/sound/core/rawmidi.c +@@ -871,9 +871,10 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card, + * + * Return: The size of read data, or a negative error code on failure. + */ +-int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, +- const unsigned char *buffer, int count) ++int snd_rawmidi_receive(void *_substream, const void *_buffer, int count) + { ++ struct snd_rawmidi_substream *substream = _substream; ++ const unsigned char *buffer = _buffer; + unsigned long flags; + int result = 0, count1; + struct snd_rawmidi_runtime *runtime = substream->runtime; +diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c +index b16dbef04..8eb05a4 100644 +--- a/sound/core/seq/oss/seq_oss_synth.c ++++ b/sound/core/seq/oss/seq_oss_synth.c +@@ -653,8 +653,8 @@ snd_seq_oss_synth_info_read(struct snd_info_buffer *buf) + rec->synth_type, rec->synth_subtype, + rec->nr_voices); + snd_iprintf(buf, " capabilities : ioctl %s / load_patch %s\n", +- enabled_str((long)rec->oper.ioctl), +- enabled_str((long)rec->oper.load_patch)); ++ enabled_str(!!rec->oper.ioctl), ++ enabled_str(!!rec->oper.load_patch)); + snd_use_lock_free(&rec->use_lock); + } + } +diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c +index 58e79e0..19751d1 100644 +--- a/sound/core/seq/seq_clientmgr.c ++++ b/sound/core/seq/seq_clientmgr.c +@@ -416,7 +416,7 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, + if (!client->accept_input || (fifo = client->data.user.fifo) == NULL) + return -ENXIO; + +- if (atomic_read(&fifo->overflow) > 0) { ++ if (atomic_read_unchecked(&fifo->overflow) > 0) { + /* buffer overflow is detected */ + snd_seq_fifo_clear(fifo); + /* return error code */ +@@ -446,7 +446,7 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, + count -= sizeof(struct snd_seq_event); + buf += sizeof(struct snd_seq_event); + err = snd_seq_expand_var_event(&cell->event, count, +- (char __force *)buf, 0, ++ (char __force_kernel *)buf, 0, + sizeof(struct snd_seq_event)); + if (err < 0) + break; +@@ -1062,13 +1062,13 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, + } + /* set user space pointer */ + event.data.ext.len = extlen | SNDRV_SEQ_EXT_USRPTR; +- event.data.ext.ptr = (char __force *)buf ++ event.data.ext.ptr = (char __force_kernel *)buf + + sizeof(struct snd_seq_event); + len += extlen; /* increment data length */ + } else { + #ifdef CONFIG_COMPAT + if (client->convert32 && snd_seq_ev_is_varusr(&event)) { +- void *ptr = (void __force *)compat_ptr(event.data.raw32.d[1]); ++ void *ptr = (void __force_kernel *)compat_ptr(event.data.raw32.d[1]); + event.data.ext.ptr = ptr; + } + #endif +@@ -2423,7 +2423,7 @@ int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg) + if (client == NULL) + return -ENXIO; + fs = snd_enter_user(); +- result = snd_seq_do_ioctl(client, cmd, (void __force __user *)arg); ++ result = snd_seq_do_ioctl(client, cmd, (void __force_user *)arg); + snd_leave_user(fs); + return result; + } +diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c +index 6517590..9905cee 100644 +--- a/sound/core/seq/seq_compat.c ++++ b/sound/core/seq/seq_compat.c +@@ -60,7 +60,7 @@ static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned + data->kernel = NULL; + + fs = snd_enter_user(); +- err = snd_seq_do_ioctl(client, cmd, data); ++ err = snd_seq_do_ioctl(client, cmd, (void __force_user *)data); + snd_leave_user(fs); + if (err < 0) + goto error; +diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c +index 1d5acbe..5f55223 100644 +--- a/sound/core/seq/seq_fifo.c ++++ b/sound/core/seq/seq_fifo.c +@@ -50,7 +50,7 @@ struct snd_seq_fifo *snd_seq_fifo_new(int poolsize) + spin_lock_init(&f->lock); + snd_use_lock_init(&f->use_lock); + init_waitqueue_head(&f->input_sleep); +- atomic_set(&f->overflow, 0); ++ atomic_set_unchecked(&f->overflow, 0); + + f->head = NULL; + f->tail = NULL; +@@ -96,7 +96,7 @@ void snd_seq_fifo_clear(struct snd_seq_fifo *f) + unsigned long flags; + + /* clear overflow flag */ +- atomic_set(&f->overflow, 0); ++ atomic_set_unchecked(&f->overflow, 0); + + snd_use_lock_sync(&f->use_lock); + spin_lock_irqsave(&f->lock, flags); +@@ -123,7 +123,7 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f, + err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL); /* always non-blocking */ + if (err < 0) { + if ((err == -ENOMEM) || (err == -EAGAIN)) +- atomic_inc(&f->overflow); ++ atomic_inc_unchecked(&f->overflow); + snd_use_lock_free(&f->use_lock); + return err; + } +diff --git a/sound/core/seq/seq_fifo.h b/sound/core/seq/seq_fifo.h +index 062c446..a4b6f4c 100644 +--- a/sound/core/seq/seq_fifo.h ++++ b/sound/core/seq/seq_fifo.h +@@ -35,7 +35,7 @@ struct snd_seq_fifo { + spinlock_t lock; + snd_use_lock_t use_lock; + wait_queue_head_t input_sleep; +- atomic_t overflow; ++ atomic_unchecked_t overflow; + + }; + +diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c +index c850345..ec0a853 100644 +--- a/sound/core/seq/seq_memory.c ++++ b/sound/core/seq/seq_memory.c +@@ -87,7 +87,7 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event, + + if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) { + char buf[32]; +- char __user *curptr = (char __force __user *)event->data.ext.ptr; ++ char __user *curptr = (char __force_user *)event->data.ext.ptr; + while (len > 0) { + int size = sizeof(buf); + if (len < size) +@@ -126,15 +126,19 @@ EXPORT_SYMBOL(snd_seq_dump_var_event); + * expand the variable length event to linear buffer space. + */ + +-static int seq_copy_in_kernel(char **bufptr, const void *src, int size) ++static int seq_copy_in_kernel(void *_bufptr, const void *src, int size) + { ++ char **bufptr = (char **)_bufptr; ++ + memcpy(*bufptr, src, size); + *bufptr += size; + return 0; + } + +-static int seq_copy_in_user(char __user **bufptr, const void *src, int size) ++static int seq_copy_in_user(void *_bufptr, const void *src, int size) + { ++ char __user **bufptr = (char __user **)_bufptr; ++ + if (copy_to_user(*bufptr, src, size)) + return -EFAULT; + *bufptr += size; +@@ -158,13 +162,13 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char + if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) { + if (! in_kernel) + return -EINVAL; +- if (copy_from_user(buf, (void __force __user *)event->data.ext.ptr, len)) ++ if (copy_from_user(buf, (void __force_user *)event->data.ext.ptr, len)) + return -EFAULT; + return newlen; + } + err = snd_seq_dump_var_event(event, +- in_kernel ? (snd_seq_dump_func_t)seq_copy_in_kernel : +- (snd_seq_dump_func_t)seq_copy_in_user, ++ in_kernel ? seq_copy_in_kernel : ++ seq_copy_in_user, + &buf); + return err < 0 ? err : newlen; + } +@@ -344,7 +348,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, + tmp->event = src->event; + src = src->next; + } else if (is_usrptr) { +- if (copy_from_user(&tmp->event, (char __force __user *)buf, size)) { ++ if (copy_from_user(&tmp->event, (char __force_user *)buf, size)) { + err = -EFAULT; + goto __error; + } +diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c +index 5dd0ee2..0208e35 100644 +--- a/sound/core/seq/seq_midi.c ++++ b/sound/core/seq/seq_midi.c +@@ -111,8 +111,9 @@ static void snd_midi_input_event(struct snd_rawmidi_substream *substream) + } + } + +-static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, int count) ++static int dump_midi(void *_substream, const void *buf, int count) + { ++ struct snd_rawmidi_substream *substream = _substream; + struct snd_rawmidi_runtime *runtime; + int tmp; + +@@ -148,7 +149,7 @@ static int event_process_midi(struct snd_seq_event *ev, int direct, + pr_debug("ALSA: seq_midi: invalid sysex event flags = 0x%x\n", ev->flags); + return 0; + } +- snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream); ++ snd_seq_dump_var_event(ev, dump_midi, substream); + snd_midi_event_reset_decode(msynth->parser); + } else { + if (msynth->parser == NULL) +diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c +index c82ed3e..e11d039 100644 +--- a/sound/core/seq/seq_virmidi.c ++++ b/sound/core/seq/seq_virmidi.c +@@ -90,7 +90,7 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, + if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { + if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) + continue; +- snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)snd_rawmidi_receive, vmidi->substream); ++ snd_seq_dump_var_event(ev, snd_rawmidi_receive, vmidi->substream); + } else { + len = snd_midi_event_decode(vmidi->parser, msg, sizeof(msg), ev); + if (len > 0) +diff --git a/sound/core/sound.c b/sound/core/sound.c +index 175f9e4..3518d31 100644 +--- a/sound/core/sound.c ++++ b/sound/core/sound.c +@@ -86,7 +86,7 @@ static void snd_request_other(int minor) + case SNDRV_MINOR_TIMER: str = "snd-timer"; break; + default: return; + } +- request_module(str); ++ request_module("%s", str); + } + + #endif /* modular kernel */ +diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c +index 2a008a9..a1efb3f 100644 +--- a/sound/drivers/mts64.c ++++ b/sound/drivers/mts64.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + + #define CARD_NAME "Miditerminal 4140" + #define DRIVER_NAME "MTS64" +@@ -67,7 +68,7 @@ struct mts64 { + struct pardevice *pardev; + int pardev_claimed; + +- int open_count; ++ local_t open_count; + int current_midi_output_port; + int current_midi_input_port; + u8 mode[MTS64_NUM_INPUT_PORTS]; +@@ -687,7 +688,7 @@ static int snd_mts64_rawmidi_open(struct snd_rawmidi_substream *substream) + { + struct mts64 *mts = substream->rmidi->private_data; + +- if (mts->open_count == 0) { ++ if (local_read(&mts->open_count) == 0) { + /* We don't need a spinlock here, because this is just called + if the device has not been opened before. + So there aren't any IRQs from the device */ +@@ -695,7 +696,7 @@ static int snd_mts64_rawmidi_open(struct snd_rawmidi_substream *substream) + + msleep(50); + } +- ++(mts->open_count); ++ local_inc(&mts->open_count); + + return 0; + } +@@ -705,8 +706,7 @@ static int snd_mts64_rawmidi_close(struct snd_rawmidi_substream *substream) + struct mts64 *mts = substream->rmidi->private_data; + unsigned long flags; + +- --(mts->open_count); +- if (mts->open_count == 0) { ++ if (local_dec_return(&mts->open_count) == 0) { + /* We need the spinlock_irqsave here because we can still + have IRQs at this point */ + spin_lock_irqsave(&mts->lock, flags); +@@ -715,8 +715,8 @@ static int snd_mts64_rawmidi_close(struct snd_rawmidi_substream *substream) + + msleep(500); + +- } else if (mts->open_count < 0) +- mts->open_count = 0; ++ } else if (local_read(&mts->open_count) < 0) ++ local_set(&mts->open_count, 0); + + return 0; + } +diff --git a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c +index 89c7aa0..6d75e49 100644 +--- a/sound/drivers/opl4/opl4_lib.c ++++ b/sound/drivers/opl4/opl4_lib.c +@@ -29,7 +29,7 @@ MODULE_AUTHOR("Clemens Ladisch "); + MODULE_DESCRIPTION("OPL4 driver"); + MODULE_LICENSE("GPL"); + +-static void inline snd_opl4_wait(struct snd_opl4 *opl4) ++static inline void snd_opl4_wait(struct snd_opl4 *opl4) + { + int timeout = 10; + while ((inb(opl4->fm_port) & OPL4_STATUS_BUSY) && --timeout > 0) +diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c +index 464385a..46ab3f6 100644 +--- a/sound/drivers/portman2x4.c ++++ b/sound/drivers/portman2x4.c +@@ -48,6 +48,7 @@ + #include + #include + #include ++#include + + #define CARD_NAME "Portman 2x4" + #define DRIVER_NAME "portman" +@@ -85,7 +86,7 @@ struct portman { + struct pardevice *pardev; + int pardev_claimed; + +- int open_count; ++ local_t open_count; + int mode[PORTMAN_NUM_INPUT_PORTS]; + struct snd_rawmidi_substream *midi_input[PORTMAN_NUM_INPUT_PORTS]; + }; +diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c +index bebddc6..f5976be 100644 +--- a/sound/firewire/amdtp-am824.c ++++ b/sound/firewire/amdtp-am824.c +@@ -314,7 +314,7 @@ void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port, + struct amdtp_am824 *p = s->protocol; + + if (port < p->midi_ports) +- ACCESS_ONCE(p->midi[port]) = midi; ++ ACCESS_ONCE_RW(p->midi[port]) = midi; + } + EXPORT_SYMBOL_GPL(amdtp_am824_midi_trigger); + +diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c +index ed29026..933d2ae 100644 +--- a/sound/firewire/amdtp-stream.c ++++ b/sound/firewire/amdtp-stream.c +@@ -344,7 +344,7 @@ static void update_pcm_pointers(struct amdtp_stream *s, + ptr = s->pcm_buffer_pointer + frames; + if (ptr >= pcm->runtime->buffer_size) + ptr -= pcm->runtime->buffer_size; +- ACCESS_ONCE(s->pcm_buffer_pointer) = ptr; ++ ACCESS_ONCE_RW(s->pcm_buffer_pointer) = ptr; + + s->pcm_period_pointer += frames; + if (s->pcm_period_pointer >= pcm->runtime->period_size) { +@@ -811,7 +811,7 @@ EXPORT_SYMBOL(amdtp_stream_pcm_pointer); + void amdtp_stream_update(struct amdtp_stream *s) + { + /* Precomputing. */ +- ACCESS_ONCE(s->source_node_id_field) = ++ ACCESS_ONCE_RW(s->source_node_id_field) = + (fw_parent_device(s->unit)->card->node_id << CIP_SID_SHIFT) & + CIP_SID_MASK; + } +diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h +index 8775704..8fea566 100644 +--- a/sound/firewire/amdtp-stream.h ++++ b/sound/firewire/amdtp-stream.h +@@ -215,7 +215,7 @@ static inline bool amdtp_stream_pcm_running(struct amdtp_stream *s) + static inline void amdtp_stream_pcm_trigger(struct amdtp_stream *s, + struct snd_pcm_substream *pcm) + { +- ACCESS_ONCE(s->pcm) = pcm; ++ ACCESS_ONCE_RW(s->pcm) = pcm; + } + + static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc) +diff --git a/sound/firewire/digi00x/amdtp-dot.c b/sound/firewire/digi00x/amdtp-dot.c +index 0ac92ab..a2081aa 100644 +--- a/sound/firewire/digi00x/amdtp-dot.c ++++ b/sound/firewire/digi00x/amdtp-dot.c +@@ -365,7 +365,7 @@ void amdtp_dot_midi_trigger(struct amdtp_stream *s, unsigned int port, + struct amdtp_dot *p = s->protocol; + + if (port < p->midi_ports) +- ACCESS_ONCE(p->midi[port]) = midi; ++ ACCESS_ONCE_RW(p->midi[port]) = midi; + } + + static unsigned int process_tx_data_blocks(struct amdtp_stream *s, +diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c +index 48d6dca..a0266c23 100644 +--- a/sound/firewire/isight.c ++++ b/sound/firewire/isight.c +@@ -96,7 +96,7 @@ static void isight_update_pointers(struct isight *isight, unsigned int count) + ptr += count; + if (ptr >= runtime->buffer_size) + ptr -= runtime->buffer_size; +- ACCESS_ONCE(isight->buffer_pointer) = ptr; ++ ACCESS_ONCE_RW(isight->buffer_pointer) = ptr; + + isight->period_counter += count; + if (isight->period_counter >= runtime->period_size) { +@@ -293,7 +293,7 @@ static int isight_hw_params(struct snd_pcm_substream *substream, + if (err < 0) + return err; + +- ACCESS_ONCE(isight->pcm_active) = true; ++ ACCESS_ONCE_RW(isight->pcm_active) = true; + + return 0; + } +@@ -331,7 +331,7 @@ static int isight_hw_free(struct snd_pcm_substream *substream) + { + struct isight *isight = substream->private_data; + +- ACCESS_ONCE(isight->pcm_active) = false; ++ ACCESS_ONCE_RW(isight->pcm_active) = false; + + mutex_lock(&isight->mutex); + isight_stop_streaming(isight); +@@ -424,10 +424,10 @@ static int isight_trigger(struct snd_pcm_substream *substream, int cmd) + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: +- ACCESS_ONCE(isight->pcm_running) = true; ++ ACCESS_ONCE_RW(isight->pcm_running) = true; + break; + case SNDRV_PCM_TRIGGER_STOP: +- ACCESS_ONCE(isight->pcm_running) = false; ++ ACCESS_ONCE_RW(isight->pcm_running) = false; + break; + default: + return -EINVAL; +diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c +index bb53eb3..670cd89 100644 +--- a/sound/firewire/oxfw/oxfw-scs1x.c ++++ b/sound/firewire/oxfw/oxfw-scs1x.c +@@ -278,9 +278,9 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *stream, int up) + + if (up) { + scs->input_escape_count = 0; +- ACCESS_ONCE(scs->input) = stream; ++ ACCESS_ONCE_RW(scs->input) = stream; + } else { +- ACCESS_ONCE(scs->input) = NULL; ++ ACCESS_ONCE_RW(scs->input) = NULL; + } + } + +@@ -310,10 +310,10 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *stream, int up) + scs->output_escaped = false; + scs->output_idle = false; + +- ACCESS_ONCE(scs->output) = stream; ++ ACCESS_ONCE_RW(scs->output) = stream; + tasklet_schedule(&scs->tasklet); + } else { +- ACCESS_ONCE(scs->output) = NULL; ++ ACCESS_ONCE_RW(scs->output) = NULL; + } + } + static void midi_playback_drain(struct snd_rawmidi_substream *stream) +diff --git a/sound/oss/sb_audio.c b/sound/oss/sb_audio.c +index dc91072..d85a10a 100644 +--- a/sound/oss/sb_audio.c ++++ b/sound/oss/sb_audio.c +@@ -900,7 +900,7 @@ sb16_copy_from_user(int dev, + buf16 = (signed short *)(localbuf + localoffs); + while (c) + { +- locallen = (c >= LBUFCOPYSIZE ? LBUFCOPYSIZE : c); ++ locallen = ((unsigned)c >= LBUFCOPYSIZE ? LBUFCOPYSIZE : c); + if (copy_from_user(lbuf8, + userbuf+useroffs + p, + locallen)) +diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c +index 213a416..aeab5c9 100644 +--- a/sound/oss/swarm_cs4297a.c ++++ b/sound/oss/swarm_cs4297a.c +@@ -2623,7 +2623,6 @@ static int __init cs4297a_init(void) + { + struct cs4297a_state *s; + u32 pwr, id; +- mm_segment_t fs; + int rval; + u64 cfg; + int mdio_val; +@@ -2709,22 +2708,23 @@ static int __init cs4297a_init(void) + if (!rval) { + char *sb1250_duart_present; + ++#if 0 ++ mm_segment_t fs; + fs = get_fs(); + set_fs(KERNEL_DS); +-#if 0 + val = SOUND_MASK_LINE; + mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long) &val); + for (i = 0; i < ARRAY_SIZE(initvol); i++) { + val = initvol[i].vol; + mixer_ioctl(s, initvol[i].mixch, (unsigned long) &val); + } ++ set_fs(fs); + // cs4297a_write_ac97(s, 0x18, 0x0808); + #else + // cs4297a_write_ac97(s, 0x5e, 0x180); + cs4297a_write_ac97(s, 0x02, 0x0808); + cs4297a_write_ac97(s, 0x18, 0x0808); + #endif +- set_fs(fs); + + list_add(&s->list, &cs4297a_devs); + +diff --git a/sound/pci/als300.c b/sound/pci/als300.c +index add3176..c9394d9 100644 +--- a/sound/pci/als300.c ++++ b/sound/pci/als300.c +@@ -647,7 +647,7 @@ static int snd_als300_create(struct snd_card *card, + struct snd_als300 **rchip) + { + struct snd_als300 *chip; +- void *irq_handler; ++ irq_handler_t irq_handler; + int err; + + static struct snd_device_ops ops = { +diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c +index 1677143..85aca1d 100644 +--- a/sound/pci/aw2/aw2-alsa.c ++++ b/sound/pci/aw2/aw2-alsa.c +@@ -458,7 +458,6 @@ static int snd_aw2_pcm_prepare_playback(struct snd_pcm_substream *substream) + + /* Define Interrupt callback */ + snd_aw2_saa7146_define_it_playback_callback(pcm_device->stream_number, +- (snd_aw2_saa7146_it_cb) + snd_pcm_period_elapsed, + (void *)substream); + +@@ -487,7 +486,6 @@ static int snd_aw2_pcm_prepare_capture(struct snd_pcm_substream *substream) + + /* Define Interrupt callback */ + snd_aw2_saa7146_define_it_capture_callback(pcm_device->stream_number, +- (snd_aw2_saa7146_it_cb) + snd_pcm_period_elapsed, + (void *)substream); + +diff --git a/sound/pci/aw2/aw2-saa7146.c b/sound/pci/aw2/aw2-saa7146.c +index 1d78904..d9c1056 100644 +--- a/sound/pci/aw2/aw2-saa7146.c ++++ b/sound/pci/aw2/aw2-saa7146.c +@@ -262,7 +262,7 @@ void snd_aw2_saa7146_define_it_playback_callback(unsigned int stream_number, + { + if (stream_number < NB_STREAM_PLAYBACK) { + arr_substream_it_playback_cb[stream_number].p_it_callback = +- (snd_aw2_saa7146_it_cb) p_it_callback; ++ p_it_callback; + arr_substream_it_playback_cb[stream_number].p_callback_param = + (void *)p_callback_param; + } +@@ -275,7 +275,7 @@ void snd_aw2_saa7146_define_it_capture_callback(unsigned int stream_number, + { + if (stream_number < NB_STREAM_CAPTURE) { + arr_substream_it_capture_cb[stream_number].p_it_callback = +- (snd_aw2_saa7146_it_cb) p_it_callback; ++ p_it_callback; + arr_substream_it_capture_cb[stream_number].p_callback_param = + (void *)p_callback_param; + } +diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c +index 5fcbb06..f4b85df 100644 +--- a/sound/pci/ctxfi/ctamixer.c ++++ b/sound/pci/ctxfi/ctamixer.c +@@ -297,8 +297,9 @@ static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer) + return 0; + } + +-int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr) ++int amixer_mgr_create(struct hw *hw, void **_ramixer_mgr) + { ++ struct amixer_mgr **ramixer_mgr = (struct amixer_mgr **)_ramixer_mgr; + int err; + struct amixer_mgr *amixer_mgr; + +@@ -326,8 +327,10 @@ error: + return err; + } + +-int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr) ++int amixer_mgr_destroy(void *_amixer_mgr) + { ++ struct amixer_mgr *amixer_mgr = _amixer_mgr; + -+int plugin_is_GPL_compatible; + rsc_mgr_uninit(&amixer_mgr->mgr); + kfree(amixer_mgr); + return 0; +@@ -452,8 +455,9 @@ static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum) + return 0; + } + +-int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr) ++int sum_mgr_create(struct hw *hw, void **_rsum_mgr) + { ++ struct sum_mgr **rsum_mgr = (struct sum_mgr **)_rsum_mgr; + int err; + struct sum_mgr *sum_mgr; + +@@ -481,8 +485,10 @@ error: + return err; + } + +-int sum_mgr_destroy(struct sum_mgr *sum_mgr) ++int sum_mgr_destroy(void *_sum_mgr) + { ++ struct sum_mgr *sum_mgr = _sum_mgr; + -+static struct plugin_info structleak_plugin_info = { -+ .version = "201602181345", -+ .help = "disable\tdo not activate plugin\n", -+}; + rsc_mgr_uninit(&sum_mgr->mgr); + kfree(sum_mgr); + return 0; +diff --git a/sound/pci/ctxfi/ctamixer.h b/sound/pci/ctxfi/ctamixer.h +index 2de18aa..2fbd01b 100644 +--- a/sound/pci/ctxfi/ctamixer.h ++++ b/sound/pci/ctxfi/ctamixer.h +@@ -47,8 +47,8 @@ struct sum_mgr { + }; + + /* Constructor and destructor of daio resource manager */ +-int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr); +-int sum_mgr_destroy(struct sum_mgr *sum_mgr); ++int sum_mgr_create(struct hw *hw, void **rsum_mgr); ++int sum_mgr_destroy(void *sum_mgr); + + /* Define the descriptor of a amixer resource */ + struct amixer_rsc_ops; +@@ -93,7 +93,7 @@ struct amixer_mgr { + }; + + /* Constructor and destructor of amixer resource manager */ +-int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr); +-int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr); ++int amixer_mgr_create(struct hw *hw, void **ramixer_mgr); ++int amixer_mgr_destroy(void *amixer_mgr); + + #endif /* CTAMIXER_H */ +diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c +index 977a598..a787004 100644 +--- a/sound/pci/ctxfi/ctatc.c ++++ b/sound/pci/ctxfi/ctatc.c +@@ -113,16 +113,16 @@ static struct { + int (*create)(struct hw *hw, void **rmgr); + int (*destroy)(void *mgr); + } rsc_mgr_funcs[NUM_RSCTYP] = { +- [SRC] = { .create = (create_t)src_mgr_create, +- .destroy = (destroy_t)src_mgr_destroy }, +- [SRCIMP] = { .create = (create_t)srcimp_mgr_create, +- .destroy = (destroy_t)srcimp_mgr_destroy }, +- [AMIXER] = { .create = (create_t)amixer_mgr_create, +- .destroy = (destroy_t)amixer_mgr_destroy }, +- [SUM] = { .create = (create_t)sum_mgr_create, +- .destroy = (destroy_t)sum_mgr_destroy }, +- [DAIO] = { .create = (create_t)daio_mgr_create, +- .destroy = (destroy_t)daio_mgr_destroy } ++ [SRC] = { .create = src_mgr_create, ++ .destroy = src_mgr_destroy }, ++ [SRCIMP] = { .create = srcimp_mgr_create, ++ .destroy = srcimp_mgr_destroy }, ++ [AMIXER] = { .create = amixer_mgr_create, ++ .destroy = amixer_mgr_destroy }, ++ [SUM] = { .create = sum_mgr_create, ++ .destroy = sum_mgr_destroy }, ++ [DAIO] = { .create = daio_mgr_create, ++ .destroy = daio_mgr_destroy } + }; + + static int +diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c +index 7f089cb..6bea28e 100644 +--- a/sound/pci/ctxfi/ctdaio.c ++++ b/sound/pci/ctxfi/ctdaio.c +@@ -687,8 +687,9 @@ static int daio_mgr_commit_write(struct daio_mgr *mgr) + return 0; + } + +-int daio_mgr_create(struct hw *hw, struct daio_mgr **rdaio_mgr) ++int daio_mgr_create(struct hw *hw, void **_rdaio_mgr) + { ++ struct daio_mgr **rdaio_mgr = (struct daio_mgr **)_rdaio_mgr; + int err, i; + struct daio_mgr *daio_mgr; + struct imapper *entry; +@@ -741,8 +742,9 @@ error1: + return err; + } + +-int daio_mgr_destroy(struct daio_mgr *daio_mgr) ++int daio_mgr_destroy(void *_daio_mgr) + { ++ struct daio_mgr *daio_mgr = _daio_mgr; + unsigned long flags; + + /* free daio input mapper list */ +diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h +index a30be73..91b8dbd 100644 +--- a/sound/pci/ctxfi/ctdaio.h ++++ b/sound/pci/ctxfi/ctdaio.h +@@ -119,7 +119,7 @@ struct daio_mgr { + }; + + /* Constructor and destructor of daio resource manager */ +-int daio_mgr_create(struct hw *hw, struct daio_mgr **rdaio_mgr); +-int daio_mgr_destroy(struct daio_mgr *daio_mgr); ++int daio_mgr_create(struct hw *hw, void **rdaio_mgr); ++int daio_mgr_destroy(void *daio_mgr); + + #endif /* CTDAIO_H */ +diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c +index a5a72df..f86edb8 100644 +--- a/sound/pci/ctxfi/ctsrc.c ++++ b/sound/pci/ctxfi/ctsrc.c +@@ -544,8 +544,9 @@ static int src_mgr_commit_write(struct src_mgr *mgr) + return 0; + } + +-int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr) ++int src_mgr_create(struct hw *hw, void **_rsrc_mgr) + { ++ struct src_mgr **rsrc_mgr = (struct src_mgr **)_rsrc_mgr; + int err, i; + struct src_mgr *src_mgr; + +@@ -584,8 +585,10 @@ error1: + return err; + } + +-int src_mgr_destroy(struct src_mgr *src_mgr) ++int src_mgr_destroy(void *_src_mgr) + { ++ struct src_mgr *src_mgr = _src_mgr; + -+static tree handle_user_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs) + rsc_mgr_uninit(&src_mgr->mgr); + kfree(src_mgr); + +@@ -828,8 +831,9 @@ static int srcimp_imap_delete(struct srcimp_mgr *mgr, struct imapper *entry) + return err; + } + +-int srcimp_mgr_create(struct hw *hw, struct srcimp_mgr **rsrcimp_mgr) ++int srcimp_mgr_create(struct hw *hw, void **_rsrcimp_mgr) + { ++ struct srcimp_mgr **rsrcimp_mgr = (struct srcimp_mgr **)_rsrcimp_mgr; + int err; + struct srcimp_mgr *srcimp_mgr; + struct imapper *entry; +@@ -873,8 +877,9 @@ error1: + return err; + } + +-int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr) ++int srcimp_mgr_destroy(void *_srcimp_mgr) + { ++ struct srcimp_mgr *srcimp_mgr = _srcimp_mgr; + unsigned long flags; + + /* free src input mapper list */ +diff --git a/sound/pci/ctxfi/ctsrc.h b/sound/pci/ctxfi/ctsrc.h +index 92944a0..fc78ed4 100644 +--- a/sound/pci/ctxfi/ctsrc.h ++++ b/sound/pci/ctxfi/ctsrc.h +@@ -143,10 +143,10 @@ struct srcimp_mgr { + }; + + /* Constructor and destructor of SRC resource manager */ +-int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr); +-int src_mgr_destroy(struct src_mgr *src_mgr); ++int src_mgr_create(struct hw *hw, void **rsrc_mgr); ++int src_mgr_destroy(void *src_mgr); + /* Constructor and destructor of SRCIMP resource manager */ +-int srcimp_mgr_create(struct hw *hw, struct srcimp_mgr **rsrc_mgr); +-int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr); ++int srcimp_mgr_create(struct hw *hw, void **rsrc_mgr); ++int srcimp_mgr_destroy(void *srcimp_mgr); + + #endif /* CTSRC_H */ +diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c +index 8374188..f073778 100644 +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -1743,7 +1743,7 @@ static int get_kctl_0dB_offset(struct hda_codec *codec, + /* FIXME: set_fs() hack for obtaining user-space TLV data */ + mm_segment_t fs = get_fs(); + set_fs(get_ds()); +- if (!kctl->tlv.c(kctl, 0, sizeof(_tlv), _tlv)) ++ if (!kctl->tlv.c(kctl, 0, sizeof(_tlv), (unsigned int __force_user *)_tlv)) + tlv = _tlv; + set_fs(fs); + } else if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) +diff --git a/sound/pci/ymfpci/ymfpci.h b/sound/pci/ymfpci/ymfpci.h +index 149d4cb..7784769 100644 +--- a/sound/pci/ymfpci/ymfpci.h ++++ b/sound/pci/ymfpci/ymfpci.h +@@ -358,7 +358,7 @@ struct snd_ymfpci { + spinlock_t reg_lock; + spinlock_t voice_lock; + wait_queue_head_t interrupt_sleep; +- atomic_t interrupt_sleep_count; ++ atomic_unchecked_t interrupt_sleep_count; + struct snd_info_entry *proc_entry; + const struct firmware *dsp_microcode; + const struct firmware *controller_microcode; +diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c +index 4c26076..a13f370 100644 +--- a/sound/pci/ymfpci/ymfpci_main.c ++++ b/sound/pci/ymfpci/ymfpci_main.c +@@ -204,8 +204,8 @@ static void snd_ymfpci_hw_stop(struct snd_ymfpci *chip) + if ((snd_ymfpci_readl(chip, YDSXGR_STATUS) & 2) == 0) + break; + } +- if (atomic_read(&chip->interrupt_sleep_count)) { +- atomic_set(&chip->interrupt_sleep_count, 0); ++ if (atomic_read_unchecked(&chip->interrupt_sleep_count)) { ++ atomic_set_unchecked(&chip->interrupt_sleep_count, 0); + wake_up(&chip->interrupt_sleep); + } + __end: +@@ -789,7 +789,7 @@ static void snd_ymfpci_irq_wait(struct snd_ymfpci *chip) + continue; + init_waitqueue_entry(&wait, current); + add_wait_queue(&chip->interrupt_sleep, &wait); +- atomic_inc(&chip->interrupt_sleep_count); ++ atomic_inc_unchecked(&chip->interrupt_sleep_count); + schedule_timeout_uninterruptible(msecs_to_jiffies(50)); + remove_wait_queue(&chip->interrupt_sleep, &wait); + } +@@ -827,8 +827,8 @@ static irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id) + snd_ymfpci_writel(chip, YDSXGR_MODE, mode); + spin_unlock(&chip->reg_lock); + +- if (atomic_read(&chip->interrupt_sleep_count)) { +- atomic_set(&chip->interrupt_sleep_count, 0); ++ if (atomic_read_unchecked(&chip->interrupt_sleep_count)) { ++ atomic_set_unchecked(&chip->interrupt_sleep_count, 0); + wake_up(&chip->interrupt_sleep); + } + } +@@ -2384,7 +2384,7 @@ int snd_ymfpci_create(struct snd_card *card, + spin_lock_init(&chip->reg_lock); + spin_lock_init(&chip->voice_lock); + init_waitqueue_head(&chip->interrupt_sleep); +- atomic_set(&chip->interrupt_sleep_count, 0); ++ atomic_set_unchecked(&chip->interrupt_sleep_count, 0); + chip->card = card; + chip->pci = pci; + chip->irq = -1; +diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c +index d6f4abb..5d59f0c 100644 +--- a/sound/soc/codecs/cx20442.c ++++ b/sound/soc/codecs/cx20442.c +@@ -263,6 +263,12 @@ static int v253_hangup(struct tty_struct *tty) + return 0; + } + ++static int v253_hw_write(void *client, const char *buf, int count) +{ -+ *no_add_attrs = true; -+ -+ // check for types? for now accept everything linux has to offer -+ if (TREE_CODE(*node) != FIELD_DECL) -+ return NULL_TREE; -+ -+ *no_add_attrs = false; -+ return NULL_TREE; ++ struct tty_struct *tty = client; ++ return tty->ops->write(client, buf, count); +} + -+static struct attribute_spec user_attr = { -+ .name = "user", -+ .min_length = 0, -+ .max_length = 0, -+ .decl_required = false, -+ .type_required = false, -+ .function_type_required = false, -+ .handler = handle_user_attribute, -+#if BUILDING_GCC_VERSION >= 4007 -+ .affects_type_identity = true -+#endif -+}; -+ -+static void register_attributes(void *event_data, void *data) + /* Line discipline .receive_buf() */ + static void v253_receive(struct tty_struct *tty, + const unsigned char *cp, char *fp, int count) +@@ -280,7 +286,7 @@ static void v253_receive(struct tty_struct *tty, + + /* Set up codec driver access to modem controls */ + cx20442->control_data = tty; +- codec->hw_write = (hw_write_t)tty->ops->write; ++ codec->hw_write = v253_hw_write; + codec->component.card->pop_time = 1; + } + } +diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c +index 160d61a..cd7a4ac 100644 +--- a/sound/soc/codecs/sti-sas.c ++++ b/sound/soc/codecs/sti-sas.c +@@ -591,11 +591,13 @@ static int sti_sas_driver_probe(struct platform_device *pdev) + sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops; + + /* Set dapms*/ +- sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets; +- sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets; ++ pax_open_kernel(); ++ const_cast(sti_sas_driver.dapm_widgets) = drvdata->dev_data->dapm_widgets; ++ const_cast(sti_sas_driver.num_dapm_widgets) = drvdata->dev_data->num_dapm_widgets; + +- sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes; +- sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes; ++ const_cast(sti_sas_driver.dapm_routes) = drvdata->dev_data->dapm_routes; ++ const_cast(sti_sas_driver.num_dapm_routes) = drvdata->dev_data->num_dapm_routes; ++ pax_close_kernel(); + + /* Store context */ + dev_set_drvdata(&pdev->dev, drvdata); +diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c +index f7a6ce7..82310c8 100644 +--- a/sound/soc/codecs/tlv320dac33.c ++++ b/sound/soc/codecs/tlv320dac33.c +@@ -1375,13 +1375,18 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai, + return 0; + } + ++static int dac33_hw_write(void *client, const char *buf, int count) +{ -+ register_attribute(&user_attr); -+// register_attribute(&force_attr); ++ return i2c_master_send(client, buf, count); +} + -+static tree get_field_type(tree field) + static int dac33_soc_probe(struct snd_soc_codec *codec) + { + struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); + int ret = 0; + + codec->control_data = dac33->control_data; +- codec->hw_write = (hw_write_t) i2c_master_send; ++ codec->hw_write = dac33_hw_write; + dac33->codec = codec; + + /* Read the tlv320dac33 ID registers */ +diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c +index 35f0469..7c25cd5 100644 +--- a/sound/soc/codecs/uda1380.c ++++ b/sound/soc/codecs/uda1380.c +@@ -687,6 +687,11 @@ static struct snd_soc_dai_driver uda1380_dai[] = { + }, + }; + ++static int uda1380_hw_write(void *client, const char *buf, int count) +{ -+ return strip_array_types(TREE_TYPE(field)); ++ return i2c_master_send(client, buf, count); +} + -+static bool is_userspace_type(tree type) -+{ -+ tree field; -+ -+ for (field = TYPE_FIELDS(type); field; field = TREE_CHAIN(field)) { -+ tree fieldtype = get_field_type(field); -+ enum tree_code code = TREE_CODE(fieldtype); -+ -+ if (code == RECORD_TYPE || code == UNION_TYPE) -+ if (is_userspace_type(fieldtype)) -+ return true; -+ -+ if (lookup_attribute("user", DECL_ATTRIBUTES(field))) -+ return true; -+ } -+ return false; -+} + static int uda1380_probe(struct snd_soc_codec *codec) + { + struct uda1380_platform_data *pdata =codec->dev->platform_data; +@@ -695,7 +700,7 @@ static int uda1380_probe(struct snd_soc_codec *codec) + + uda1380->codec = codec; + +- codec->hw_write = (hw_write_t)i2c_master_send; ++ codec->hw_write = uda1380_hw_write; + codec->control_data = uda1380->control_data; + + if (!pdata) +diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h +index cbb4075..edda3dd 100644 +--- a/sound/soc/intel/skylake/skl-sst-dsp.h ++++ b/sound/soc/intel/skylake/skl-sst-dsp.h +@@ -117,14 +117,14 @@ struct skl_dsp_fw_ops { + int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, char *mod_name); + int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id); + +-}; ++} __no_const; + + struct skl_dsp_loader_ops { + int (*alloc_dma_buf)(struct device *dev, + struct snd_dma_buffer *dmab, size_t size); + int (*free_dma_buf)(struct device *dev, + struct snd_dma_buffer *dmab); +-}; ++} __no_const; + + struct skl_load_module_info { + u16 mod_id; +diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c +index 7e0acd8..b4b2acb 100644 +--- a/sound/soc/soc-ac97.c ++++ b/sound/soc/soc-ac97.c +@@ -416,8 +416,10 @@ int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops, + if (ret) + return ret; + +- ops->warm_reset = snd_soc_ac97_warm_reset; +- ops->reset = snd_soc_ac97_reset; ++ pax_open_kernel(); ++ const_cast(ops->warm_reset) = snd_soc_ac97_warm_reset; ++ const_cast(ops->reset) = snd_soc_ac97_reset; ++ pax_close_kernel(); + + snd_ac97_rst_cfg = cfg; + return 0; +diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c +index 8382ffa..86af7d0 100644 +--- a/sound/soc/xtensa/xtfpga-i2s.c ++++ b/sound/soc/xtensa/xtfpga-i2s.c +@@ -437,7 +437,7 @@ static int xtfpga_pcm_trigger(struct snd_pcm_substream *substream, int cmd) + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: +- ACCESS_ONCE(i2s->tx_ptr) = 0; ++ ACCESS_ONCE_RW(i2s->tx_ptr) = 0; + rcu_assign_pointer(i2s->tx_substream, substream); + xtfpga_pcm_refill_fifo(i2s); + break; +diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c +index a020920..55579f6 100644 +--- a/sound/synth/emux/emux_seq.c ++++ b/sound/synth/emux/emux_seq.c +@@ -33,13 +33,13 @@ static int snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *inf + * MIDI emulation operators + */ + static struct snd_midi_op emux_ops = { +- snd_emux_note_on, +- snd_emux_note_off, +- snd_emux_key_press, +- snd_emux_terminate_note, +- snd_emux_control, +- snd_emux_nrpn, +- snd_emux_sysex, ++ .note_on = snd_emux_note_on, ++ .note_off = snd_emux_note_off, ++ .key_press = snd_emux_key_press, ++ .note_terminate = snd_emux_terminate_note, ++ .control = snd_emux_control, ++ .nrpn = snd_emux_nrpn, ++ .sysex = snd_emux_sysex, + }; + + +diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c +index 81b7da8..bb2676f 100644 +--- a/sound/usb/line6/driver.c ++++ b/sound/usb/line6/driver.c +@@ -307,7 +307,7 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data, + { + struct usb_device *usbdev = line6->usbdev; + int ret; +- unsigned char len; ++ unsigned char *plen; + unsigned count; + + if (address > 0xffff || datalen > 0xff) +@@ -324,6 +324,10 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data, + return ret; + } + ++ plen = kmalloc(1, GFP_KERNEL); ++ if (plen == NULL) ++ return -ENOMEM; + -+static void finish_type(void *event_data, void *data) -+{ -+ tree type = (tree)event_data; + /* Wait for data length. We'll get 0xff until length arrives. */ + for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) { + mdelay(LINE6_READ_WRITE_STATUS_DELAY); +@@ -331,30 +335,35 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data, + ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | + USB_DIR_IN, +- 0x0012, 0x0000, &len, 1, ++ 0x0012, 0x0000, plen, 1, + LINE6_TIMEOUT * HZ); + if (ret < 0) { + dev_err(line6->ifcdev, + "receive length failed (error %d)\n", ret); ++ kfree(plen); + return ret; + } + +- if (len != 0xff) ++ if (*plen != 0xff) + break; + } + +- if (len == 0xff) { ++ if (*plen == 0xff) { + dev_err(line6->ifcdev, "read failed after %d retries\n", + count); ++ kfree(plen); + return -EIO; +- } else if (len != datalen) { ++ } else if (*plen != datalen) { + /* should be equal or something went wrong */ + dev_err(line6->ifcdev, + "length mismatch (expected %d, got %d)\n", +- (int)datalen, (int)len); ++ (int)datalen, (int)*plen); ++ kfree(plen); + return -EIO; + } + ++ kfree(plen); + -+ if (type == NULL_TREE || type == error_mark_node) -+ return; + /* receive the result: */ + ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, +@@ -378,7 +387,7 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, + { + struct usb_device *usbdev = line6->usbdev; + int ret; +- unsigned char status; ++ unsigned char *status; + int count; + + if (address > 0xffff || datalen > 0xffff) +@@ -395,6 +404,10 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, + return ret; + } + ++ status = kmalloc(1, GFP_KERNEL); ++ if (status == NULL) ++ return -ENOMEM; + -+#if BUILDING_GCC_VERSION >= 5000 -+ if (TREE_CODE(type) == ENUMERAL_TYPE) -+ return; -+#endif + for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) { + mdelay(LINE6_READ_WRITE_STATUS_DELAY); + +@@ -403,27 +416,32 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | + USB_DIR_IN, + 0x0012, 0x0000, +- &status, 1, LINE6_TIMEOUT * HZ); ++ status, 1, LINE6_TIMEOUT * HZ); + + if (ret < 0) { + dev_err(line6->ifcdev, + "receiving status failed (error %d)\n", ret); ++ kfree(status); + return ret; + } + +- if (status != 0xff) ++ if (*status != 0xff) + break; + } + +- if (status == 0xff) { ++ if (*status == 0xff) { + dev_err(line6->ifcdev, "write failed after %d retries\n", + count); ++ kfree(status); + return -EIO; +- } else if (status != 0) { ++ } else if (*status != 0) { + dev_err(line6->ifcdev, "write failed (error %d)\n", ret); ++ kfree(status); + return -EIO; + } + ++ kfree(status); + -+ if (TYPE_USERSPACE(type)) + return 0; + } + EXPORT_SYMBOL_GPL(line6_write_data); +diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c +index 6d4c50c..aa658c8 100644 +--- a/sound/usb/line6/toneport.c ++++ b/sound/usb/line6/toneport.c +@@ -367,13 +367,19 @@ static bool toneport_has_source_select(struct usb_line6_toneport *toneport) + */ + static void toneport_setup(struct usb_line6_toneport *toneport) + { +- int ticks; ++ int *ticks; + struct usb_line6 *line6 = &toneport->line6; + struct usb_device *usbdev = line6->usbdev; + ++ ticks = kmalloc(sizeof(int), GFP_KERNEL); ++ if (ticks == NULL) + return; + -+ if (is_userspace_type(type)) -+ TYPE_USERSPACE(type) = 1; -+} -+ -+static void initialize(tree var) -+{ -+ basic_block bb; -+ gimple_stmt_iterator gsi; -+ tree initializer; -+ gimple init_stmt; -+ -+ // this is the original entry bb before the forced split -+ bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); -+ -+ // first check if the variable is already initialized, warn otherwise -+ for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { -+ gimple stmt = gsi_stmt(gsi); -+ tree rhs1; -+ -+ // we're looking for an assignment of a single rhs... -+ if (!gimple_assign_single_p(stmt)) -+ continue; -+ rhs1 = gimple_assign_rhs1(stmt); -+#if BUILDING_GCC_VERSION >= 4007 -+ // ... of a non-clobbering expression... -+ if (TREE_CLOBBER_P(rhs1)) -+ continue; -+#endif -+ // ... to our variable... -+ if (gimple_get_lhs(stmt) != var) -+ continue; -+ // if it's an initializer then we're good -+ if (TREE_CODE(rhs1) == CONSTRUCTOR) -+ return; -+ } -+ -+ // these aren't the 0days you're looking for -+// inform(DECL_SOURCE_LOCATION(var), "userspace variable will be forcibly initialized"); -+ -+ // build the initializer expression -+ initializer = build_constructor(TREE_TYPE(var), NULL); -+ -+ // build the initializer stmt -+ init_stmt = gimple_build_assign(var, initializer); -+ gsi = gsi_after_labels(single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun))); -+ gsi_insert_before(&gsi, init_stmt, GSI_NEW_STMT); -+ update_stmt(init_stmt); -+} -+ -+static unsigned int structleak_execute(void) -+{ -+ basic_block bb; -+ unsigned int ret = 0; -+ tree var; -+ unsigned int i; -+ -+ // split the first bb where we can put the forced initializers -+ gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); -+ bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); -+ if (!single_pred_p(bb)) { -+// gcc_assert(bb_loop_depth(bb) || (bb->flags & BB_IRREDUCIBLE_LOOP)); -+ split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun))); -+ gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); -+ } -+ -+ // enumarate all local variables and forcibly initialize our targets -+ FOR_EACH_LOCAL_DECL(cfun, i, var) { -+ tree type = TREE_TYPE(var); -+ -+ gcc_assert(DECL_P(var)); -+ if (!auto_var_in_fn_p(var, current_function_decl)) -+ continue; -+ -+ // only care about structure types -+ if (TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE) -+ continue; -+ -+ // if the type is of interest, examine the variable -+ if (TYPE_USERSPACE(type)) -+ initialize(var); -+ } -+ -+ return ret; -+} -+ -+#define PASS_NAME structleak -+#define NO_GATE -+#define PROPERTIES_REQUIRED PROP_cfg -+#define TODO_FLAGS_FINISH TODO_verify_il | TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func | TODO_remove_unused_locals | TODO_update_ssa | TODO_ggc_collect | TODO_verify_flow -+#include "gcc-generate-gimple-pass.h" -+ -+int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) -+{ -+ int i; -+ const char * const plugin_name = plugin_info->base_name; -+ const int argc = plugin_info->argc; -+ const struct plugin_argument * const argv = plugin_info->argv; -+ bool enable = true; -+ struct register_pass_info structleak_pass_info; -+ -+ structleak_pass_info.pass = make_structleak_pass(); -+ structleak_pass_info.reference_pass_name = "ssa"; -+ structleak_pass_info.ref_pass_instance_number = 1; -+ structleak_pass_info.pos_op = PASS_POS_INSERT_AFTER; -+ -+ if (!plugin_default_version_check(version, &gcc_version)) { -+ error(G_("incompatible gcc/plugin versions")); -+ return 1; -+ } -+ -+ if (strncmp(lang_hooks.name, "GNU C", 5) && !strncmp(lang_hooks.name, "GNU C+", 6)) { -+ inform(UNKNOWN_LOCATION, G_("%s supports C only, not %s"), plugin_name, lang_hooks.name); -+ enable = false; -+ } -+ -+ for (i = 0; i < argc; ++i) { -+ if (!strcmp(argv[i].key, "disable")) { -+ enable = false; -+ continue; -+ } -+ error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); -+ } -+ -+ register_callback(plugin_name, PLUGIN_INFO, NULL, &structleak_plugin_info); -+ if (enable) { -+ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &structleak_pass_info); -+ register_callback(plugin_name, PLUGIN_FINISH_TYPE, finish_type, NULL); -+ } -+ register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); + /* sync time on device with host: */ +- ticks = (int)get_seconds(); +- line6_write_data(line6, 0x80c6, &ticks, 4); ++ *ticks = (int)get_seconds(); ++ line6_write_data(line6, 0x80c6, ticks, sizeof(int)); + -+ return 0; -+} ++ kfree(ticks); + + /* enable device: */ + toneport_send_cmd(usbdev, 0x0301, 0x0000); diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h index fa7208a..d568e71 100644 --- a/tools/include/linux/compiler.h