diff --git a/Documentation/dontdiff b/Documentation/dontdiff index 9de9813..1462492 100644 --- a/Documentation/dontdiff +++ b/Documentation/dontdiff @@ -3,9 +3,11 @@ *.bc *.bin *.bz2 +*.c.[012]*.* *.cis *.cpio *.csp +*.dbg *.dsp *.dvi *.elf @@ -15,6 +17,7 @@ *.gcov *.gen.S *.gif +*.gmo *.grep *.grp *.gz @@ -51,14 +54,17 @@ *.tab.h *.tex *.ver +*.vim *.xml *.xz *_MODULES +*_reg_safe.h *_vga16.c *~ \#*# *.9 -.* +.[^g]* +.gen* .*.d .mm 53c700_d.h @@ -72,9 +78,11 @@ Image Module.markers Module.symvers PENDING +PERF* SCCS System.map* TAGS +TRACEEVENT-CFLAGS aconf af_names.h aic7*reg.h* @@ -83,6 +91,7 @@ aic7*seq.h* aicasm aicdb.h* altivec*.c +ashldi3.S asm-offsets.h asm_offsets.h autoconf.h* @@ -95,32 +104,40 @@ bounds.h bsetup btfixupprep build +builtin-policy.h bvmlinux bzImage* capability_names.h capflags.c classlist.h* +clut_vga16.c +common-cmds.h comp*.log compile.h* conf config config-* config_data.h* +config.c config.mak config.mak.autogen +config.tmp conmakehash consolemap_deftbl.c* cpustr.h crc32table.h* cscope.* defkeymap.c +devicetable-offsets.h devlist.h* dnotify_test docproc dslm +dtc-lexer.lex.c elf2ecoff elfconfig.h* evergreen_reg_safe.h +exception_policy.conf fixdep flask.h fore200e_mkfirm @@ -128,12 +145,15 @@ fore200e_pca_fw.c* gconf gconf.glade.h gen-devlist +gen-kdb_cmds.c gen_crc32table gen_init_cpio generated genheaders genksyms *_gray256.c +hash +hid-example hpet_example hugepage-mmap hugepage-shm @@ -148,14 +168,14 @@ int32.c int4.c int8.c kallsyms -kconfig +kern_constants.h keywords.c ksym.c* ksym.h* kxgettext lex.c lex.*.c -linux +lib1funcs.S logo_*.c logo_*_clut224.c logo_*_mono.c @@ -165,14 +185,15 @@ mach-types.h machtypes.h map map_hugetlb -media mconf +mdp miboot* mk_elfconfig mkboot mkbugboot mkcpustr mkdep +mkpiggy mkprep mkregtable mktables @@ -188,6 +209,8 @@ oui.c* page-types parse.c parse.h +parse-events* +pasyms.h patches* pca200e.bin pca200e_ecd.bin2 @@ -197,6 +220,7 @@ perf-archive piggyback piggy.gzip piggy.S +pmu-* pnmtologo ppc_defs.h* pss_boot.h @@ -206,7 +230,12 @@ r200_reg_safe.h r300_reg_safe.h r420_reg_safe.h r600_reg_safe.h +randomize_layout_hash.h +randomize_layout_seed.h +realmode.lds +realmode.relocs recordmcount +regdb.c relocs rlim_names.h rn50_reg_safe.h @@ -216,8 +245,12 @@ series setup setup.bin setup.elf +signing_key* +size_overflow_hash.h sImage +slabinfo sm_tbl* +sortextable split-include syscalltab.h tables.c @@ -227,6 +260,7 @@ tftpboot.img timeconst.h times.h* trix_boot.h +user_constants.h utsrelease.h* vdso-syms.lds vdso.lds @@ -238,13 +272,17 @@ vdso32.lds vdso32.so.dbg vdso64.lds vdso64.so.dbg +vdsox32.lds +vdsox32-syms.lds version.h* vmImage vmlinux vmlinux-* vmlinux.aout vmlinux.bin.all +vmlinux.bin.bz2 vmlinux.lds +vmlinux.relocs vmlinuz voffset.h vsyscall.lds @@ -252,9 +290,12 @@ vsyscall_32.lds wanxlfw.inc uImage unifdef +utsrelease.h wakeup.bin wakeup.elf wakeup.lds +x509* zImage* zconf.hash.c +zconf.lex.c zoffset.h diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index 13f888a..250729b 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -23,10 +23,11 @@ This document describes the Linux kernel Makefiles. === 4 Host Program support --- 4.1 Simple Host Program --- 4.2 Composite Host Programs - --- 4.3 Using C++ for host programs - --- 4.4 Controlling compiler options for host programs - --- 4.5 When host programs are actually built - --- 4.6 Using hostprogs-$(CONFIG_FOO) + --- 4.3 Defining shared libraries + --- 4.4 Using C++ for host programs + --- 4.5 Controlling compiler options for host programs + --- 4.6 When host programs are actually built + --- 4.7 Using hostprogs-$(CONFIG_FOO) === 5 Kbuild clean infrastructure @@ -643,7 +644,29 @@ Both possibilities are described in the following. Finally, the two .o files are linked to the executable, lxdialog. Note: The syntax -y is not permitted for host-programs. ---- 4.3 Using C++ for host programs +--- 4.3 Defining shared libraries + + Objects with extension .so are considered shared libraries, and + will be compiled as position independent objects. + Kbuild provides support for shared libraries, but the usage + shall be restricted. + In the following example the libkconfig.so shared library is used + to link the executable conf. + + Example: + #scripts/kconfig/Makefile + hostprogs-y := conf + conf-objs := conf.o libkconfig.so + libkconfig-objs := expr.o type.o + + Shared libraries always require a corresponding -objs line, and + in the example above the shared library libkconfig is composed by + the two objects expr.o and type.o. + expr.o and type.o will be built as position independent code and + linked as a shared library libkconfig.so. C++ is not supported for + shared libraries. + +--- 4.4 Using C++ for host programs kbuild offers support for host programs written in C++. This was introduced solely to support kconfig, and is not recommended @@ -666,7 +689,7 @@ Both possibilities are described in the following. qconf-cxxobjs := qconf.o qconf-objs := check.o ---- 4.4 Controlling compiler options for host programs +--- 4.5 Controlling compiler options for host programs When compiling host programs, it is possible to set specific flags. The programs will always be compiled utilising $(HOSTCC) passed @@ -694,7 +717,7 @@ Both possibilities are described in the following. When linking qconf, it will be passed the extra option "-L$(QTDIR)/lib". ---- 4.5 When host programs are actually built +--- 4.6 When host programs are actually built Kbuild will only build host-programs when they are referenced as a prerequisite. @@ -725,7 +748,7 @@ Both possibilities are described in the following. This will tell kbuild to build lxdialog even if not referenced in any rule. ---- 4.6 Using hostprogs-$(CONFIG_FOO) +--- 4.7 Using hostprogs-$(CONFIG_FOO) A typical pattern in a Kbuild file looks like this: diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 22a4b68..0ec4c2a 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1246,6 +1246,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Format: such that (rxsize & ~0x1fffc0) == 0. Default: 1024 + grsec_proc_gid= [GRKERNSEC_PROC_USERGROUP] Chooses GID to + ignore grsecurity's /proc restrictions + + grsec_sysfs_restrict= Format: 0 | 1 + Default: 1 + Disables GRKERNSEC_SYSFS_RESTRICT if enabled in config + hashdist= [KNL,NUMA] Large hashes allocated during boot are distributed across NUMA nodes. Defaults on for 64-bit NUMA, off otherwise. @@ -2379,6 +2386,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. noexec=on: enable non-executable mappings (default) noexec=off: disable non-executable mappings + nopcid [X86-64] + Disable PCID (Process-Context IDentifier) even if it + is supported by the processor. + nosmap [X86] Disable SMAP (Supervisor Mode Access Prevention) even if it is supported by processor. @@ -2677,6 +2688,35 @@ bytes respectively. Such letter suffixes can also be entirely omitted. the specified number of seconds. This is to be used if your oopses keep scrolling off the screen. + pax_nouderef [X86] disables UDEREF. Most likely needed under certain + virtualization environments that don't cope well with the + expand down segment used by UDEREF on X86-32 or the frequent + page table updates on X86-64. + + pax_sanitize_slab= + Format: { 0 | 1 | off | fast | full } + Options '0' and '1' are only provided for backward + compatibility, 'off' or 'fast' should be used instead. + 0|off : disable slab object sanitization + 1|fast: enable slab object sanitization excluding + whitelisted slabs (default) + full : sanitize all slabs, even the whitelisted ones + + pax_softmode= 0/1 to disable/enable PaX softmode on boot already. + + pax_extra_latent_entropy + Enable a very simple form of latent entropy extraction + from the first 4GB of memory as the bootmem allocator + passes the memory pages to the buddy allocator. + + pax_size_overflow_report_only + Enables rate-limited logging of size_overflow plugin + violations while disabling killing of the violating + task. + + pax_weakuderef [X86-64] enables the weaker but faster form of UDEREF + when the processor supports PCID. + pcbit= [HW,ISDN] pcd. [PARIDE] diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 6fccb69..60c7c7a 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -41,6 +41,7 @@ show up in /proc/sys/kernel: - kptr_restrict - kstack_depth_to_print [ X86 only ] - l2cr [ PPC only ] +- modify_ldt [ X86 only ] - modprobe ==> Documentation/debugging-modules.txt - modules_disabled - msg_next_id [ sysv ipc ] @@ -391,6 +392,20 @@ This flag controls the L2 cache of G3 processor boards. If ============================================================== +modify_ldt: (X86 only) + +Enables (1) or disables (0) the modify_ldt syscall. Modifying the LDT +(Local Descriptor Table) may be needed to run a 16-bit or segmented code +such as Dosemu or Wine. This is done via a system call which is not needed +to run portable applications, and which can sometimes be abused to exploit +some weaknesses of the architecture, opening new vulnerabilities. + +This sysctl allows one to increase the system's security by disabling the +system call, or to restore compatibility with specific applications when it +was already disabled. + +============================================================== + modules_disabled: A toggle value indicating if modules are allowed to be loaded diff --git a/Makefile b/Makefile index 2070d16..0bc2be1 100644 --- a/Makefile +++ b/Makefile @@ -298,7 +298,9 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ HOSTCC = gcc HOSTCXX = g++ HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu89 -HOSTCXXFLAGS = -O2 +HOSTCFLAGS = -W -Wno-unused-parameter -Wno-missing-field-initializers -fno-delete-null-pointer-checks +HOSTCFLAGS += $(call cc-option, -Wno-empty-body) +HOSTCXXFLAGS = -O2 -Wall -W -Wno-array-bounds 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 @@ -615,6 +617,85 @@ endif # Tell gcc to never replace conditional load with a non-conditional one KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0) +ifndef DISABLE_PAX_PLUGINS +ifeq ($(call cc-ifversion, -ge, 0408, y), y) +PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(HOSTCXX)" "$(HOSTCXX)" "$(CC)") +else +PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(HOSTCC)" "$(HOSTCXX)" "$(CC)") +endif +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_GRKERNSEC_RANDSTRUCT +RANDSTRUCT_PLUGIN_CFLAGS := -fplugin=$(objtree)/tools/gcc/randomize_layout_plugin.so -DRANDSTRUCT_PLUGIN +ifdef CONFIG_GRKERNSEC_RANDSTRUCT_PERFORMANCE +RANDSTRUCT_PLUGIN_CFLAGS += -fplugin-arg-randomize_layout_plugin-performance-mode +endif +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 +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 += $(RANDSTRUCT_PLUGIN_CFLAGS) +GCC_PLUGINS_AFLAGS := $(KERNEXEC_PLUGIN_AFLAGS) +export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS CONSTIFY_PLUGIN LATENT_ENTROPY_PLUGIN_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) +ifeq ($(call cc-ifversion, -ge, 0408, y), y) + $(CONFIG_SHELL) -x $(srctree)/scripts/gcc-plugin.sh "$(HOSTCXX)" "$(HOSTCXX)" "$(CC)" +else + $(CONFIG_SHELL) -x $(srctree)/scripts/gcc-plugin.sh "$(HOSTCC)" "$(HOSTCXX)" "$(CC)" +endif + $(error Your gcc installation does not support plugins. If the necessary headers for plugin support are missing, they should be installed. On Debian, apt-get install gcc--plugin-dev. If you choose to ignore this error and lessen the improvements provided by this patch, re-run make with the DISABLE_PAX_PLUGINS=y argument.)) +else + $(Q)echo "warning, your gcc version does not support plugins, you should upgrade it to gcc 4.5 at least" +endif + $(Q)echo "PAX_MEMORY_STACKLEAK, constification, PAX_LATENT_ENTROPY and other features will be less secure. PAX_SIZE_OVERFLOW will not be active." +endif +endif + ifdef CONFIG_READABLE_ASM # Disable optimizations that make assembler listings hard to read. # reorder blocks reorders the control in the function @@ -707,7 +788,7 @@ KBUILD_CFLAGS += $(call cc-option, -gsplit-dwarf, -g) else KBUILD_CFLAGS += -g endif -KBUILD_AFLAGS += -Wa,-gdwarf-2 +KBUILD_AFLAGS += -Wa,--gdwarf-2 endif ifdef CONFIG_DEBUG_INFO_DWARF4 KBUILD_CFLAGS += $(call cc-option, -gdwarf-4,) @@ -878,7 +959,7 @@ export mod_sign_cmd ifeq ($(KBUILD_EXTMOD),) -core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ +core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ grsecurity/ vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ @@ -928,6 +1009,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) @@ -937,7 +1020,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 @@ -980,10 +1063,13 @@ 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 $(Q)$(MAKE) $(build)=. # All the preparing.. +prepare: KBUILD_CFLAGS := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS)) prepare: prepare0 # Generate some files @@ -1091,6 +1177,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.'; @@ -1106,7 +1194,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 @@ -1172,7 +1260,10 @@ 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 \ - signing_key.x509.signer vmlinux-gdb.py + signing_key.x509.signer vmlinux-gdb.py \ + tools/gcc/size_overflow_plugin/size_overflow_hash_aux.h \ + tools/gcc/size_overflow_plugin/size_overflow_hash.h \ + tools/gcc/randomize_layout_seed.h # clean - Delete most, but leave enough to build external modules # @@ -1211,7 +1302,7 @@ distclean: mrproper @find $(srctree) $(RCS_FIND_IGNORE) \ \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ - -o -name '.*.rej' -o -name '*%' -o -name 'core' \) \ + -o -name '.*.rej' -o -name '*.so' -o -name '*%' -o -name 'core' \) \ -type f -print | xargs rm -f @@ -1377,6 +1468,8 @@ PHONY += $(module-dirs) modules $(module-dirs): crmodverdir $(objtree)/Module.symvers $(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@) +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 @@ -1518,17 +1611,21 @@ else target-dir = $(if $(KBUILD_EXTMOD),$(dir $<),$(dir $@)) endif -%.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 $@) @@ -1540,11 +1637,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) diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h index e8c9560..b585f83 100644 --- a/arch/alpha/include/asm/atomic.h +++ b/arch/alpha/include/asm/atomic.h @@ -251,4 +251,14 @@ static inline long atomic64_dec_if_positive(atomic64_t *v) #define atomic_dec(v) atomic_sub(1,(v)) #define atomic64_dec(v) atomic64_sub(1,(v)) +#define atomic64_read_unchecked(v) atomic64_read(v) +#define atomic64_set_unchecked(v, i) atomic64_set((v), (i)) +#define atomic64_add_unchecked(a, v) atomic64_add((a), (v)) +#define atomic64_add_return_unchecked(a, v) atomic64_add_return((a), (v)) +#define atomic64_sub_unchecked(a, v) atomic64_sub((a), (v)) +#define atomic64_inc_unchecked(v) atomic64_inc(v) +#define atomic64_inc_return_unchecked(v) atomic64_inc_return(v) +#define atomic64_dec_unchecked(v) atomic64_dec(v) +#define atomic64_cmpxchg_unchecked(v, o, n) atomic64_cmpxchg((v), (o), (n)) + #endif /* _ALPHA_ATOMIC_H */ diff --git a/arch/alpha/include/asm/cache.h b/arch/alpha/include/asm/cache.h index ad368a9..fbe0f25 100644 --- a/arch/alpha/include/asm/cache.h +++ b/arch/alpha/include/asm/cache.h @@ -4,19 +4,19 @@ #ifndef __ARCH_ALPHA_CACHE_H #define __ARCH_ALPHA_CACHE_H +#include /* Bytes per L1 (data) cache line. */ #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EV6) -# define L1_CACHE_BYTES 64 # define L1_CACHE_SHIFT 6 #else /* Both EV4 and EV5 are write-through, read-allocate, direct-mapped, physical. */ -# define L1_CACHE_BYTES 32 # define L1_CACHE_SHIFT 5 #endif +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #define SMP_CACHE_BYTES L1_CACHE_BYTES #endif diff --git a/arch/alpha/include/asm/elf.h b/arch/alpha/include/asm/elf.h index 968d999..d36b2df 100644 --- a/arch/alpha/include/asm/elf.h +++ b/arch/alpha/include/asm/elf.h @@ -91,6 +91,13 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x1000000) +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE (current->personality & ADDR_LIMIT_32BIT ? 0x10000 : 0x120000000UL) + +#define PAX_DELTA_MMAP_LEN (current->personality & ADDR_LIMIT_32BIT ? 14 : 28) +#define PAX_DELTA_STACK_LEN (current->personality & ADDR_LIMIT_32BIT ? 14 : 19) +#endif + /* $0 is set by ld.so to a pointer to a function which might be registered using atexit. This provides a mean for the dynamic linker to call DT_FINI functions for shared libraries that have diff --git a/arch/alpha/include/asm/pgalloc.h b/arch/alpha/include/asm/pgalloc.h index aab14a0..b4fa3e7 100644 --- a/arch/alpha/include/asm/pgalloc.h +++ b/arch/alpha/include/asm/pgalloc.h @@ -29,6 +29,12 @@ pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd) pgd_set(pgd, pmd); } +static inline void +pgd_populate_kernel(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd) +{ + pgd_populate(mm, pgd, pmd); +} + extern pgd_t *pgd_alloc(struct mm_struct *mm); static inline void diff --git a/arch/alpha/include/asm/pgtable.h b/arch/alpha/include/asm/pgtable.h index a9a1195..e9b8417 100644 --- a/arch/alpha/include/asm/pgtable.h +++ b/arch/alpha/include/asm/pgtable.h @@ -101,6 +101,17 @@ struct vm_area_struct; #define PAGE_SHARED __pgprot(_PAGE_VALID | __ACCESS_BITS) #define PAGE_COPY __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW) #define PAGE_READONLY __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW) + +#ifdef CONFIG_PAX_PAGEEXEC +# define PAGE_SHARED_NOEXEC __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOE) +# define PAGE_COPY_NOEXEC __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW | _PAGE_FOE) +# define PAGE_READONLY_NOEXEC __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW | _PAGE_FOE) +#else +# define PAGE_SHARED_NOEXEC PAGE_SHARED +# define PAGE_COPY_NOEXEC PAGE_COPY +# define PAGE_READONLY_NOEXEC PAGE_READONLY +#endif + #define PAGE_KERNEL __pgprot(_PAGE_VALID | _PAGE_ASM | _PAGE_KRE | _PAGE_KWE) #define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | __ACCESS_BITS | (x)) diff --git a/arch/alpha/kernel/module.c b/arch/alpha/kernel/module.c index 2fd00b7..cfd5069 100644 --- a/arch/alpha/kernel/module.c +++ b/arch/alpha/kernel/module.c @@ -160,7 +160,7 @@ apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, /* The small sections were sorted to the end of the segment. The following should definitely cover them. */ - gp = (u64)me->module_core + me->core_size - 0x8000; + gp = (u64)me->module_core_rw + me->core_size_rw - 0x8000; got = sechdrs[me->arch.gotsecindex].sh_addr; for (i = 0; i < n; i++) { diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 6cc0816..3dd424d 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -1300,10 +1300,11 @@ SYSCALL_DEFINE1(old_adjtimex, struct timex32 __user *, txc_p) generic version except that we know how to honor ADDR_LIMIT_32BIT. */ static unsigned long -arch_get_unmapped_area_1(unsigned long addr, unsigned long len, - unsigned long limit) +arch_get_unmapped_area_1(struct file *filp, unsigned long addr, unsigned long len, + unsigned long limit, unsigned long flags) { struct vm_unmapped_area_info info; + unsigned long offset = gr_rand_threadstack_offset(current->mm, filp, flags); info.flags = 0; info.length = len; @@ -1311,6 +1312,7 @@ arch_get_unmapped_area_1(unsigned long addr, unsigned long len, info.high_limit = limit; info.align_mask = 0; info.align_offset = 0; + info.threadstack_offset = offset; return vm_unmapped_area(&info); } @@ -1343,20 +1345,24 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, merely specific addresses, but regions of memory -- perhaps this feature should be incorporated into all ports? */ +#ifdef CONFIG_PAX_RANDMMAP + if (!(current->mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + if (addr) { - addr = arch_get_unmapped_area_1 (PAGE_ALIGN(addr), len, limit); + addr = arch_get_unmapped_area_1 (filp, PAGE_ALIGN(addr), len, limit, flags); if (addr != (unsigned long) -ENOMEM) return addr; } /* Next, try allocating at TASK_UNMAPPED_BASE. */ - addr = arch_get_unmapped_area_1 (PAGE_ALIGN(TASK_UNMAPPED_BASE), - len, limit); + addr = arch_get_unmapped_area_1 (filp, PAGE_ALIGN(current->mm->mmap_base), len, limit, flags); + if (addr != (unsigned long) -ENOMEM) return addr; /* Finally, try allocating in low memory. */ - addr = arch_get_unmapped_area_1 (PAGE_SIZE, len, limit); + addr = arch_get_unmapped_area_1 (filp, PAGE_SIZE, len, limit, flags); return addr; } diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c index 4a905bd..0a4da53 100644 --- a/arch/alpha/mm/fault.c +++ b/arch/alpha/mm/fault.c @@ -52,6 +52,124 @@ __load_new_mm_context(struct mm_struct *next_mm) __reload_thread(pcb); } +#ifdef CONFIG_PAX_PAGEEXEC +/* + * PaX: decide what to do with offenders (regs->pc = fault address) + * + * returns 1 when task should be killed + * 2 when patched PLT trampoline was detected + * 3 when unpatched PLT trampoline was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + +#ifdef CONFIG_PAX_EMUPLT + int err; + + do { /* PaX: patched PLT emulation #1 */ + unsigned int ldah, ldq, jmp; + + err = get_user(ldah, (unsigned int *)regs->pc); + err |= get_user(ldq, (unsigned int *)(regs->pc+4)); + err |= get_user(jmp, (unsigned int *)(regs->pc+8)); + + if (err) + break; + + if ((ldah & 0xFFFF0000U) == 0x277B0000U && + (ldq & 0xFFFF0000U) == 0xA77B0000U && + jmp == 0x6BFB0000U) + { + unsigned long r27, addr; + unsigned long addrh = (ldah | 0xFFFFFFFFFFFF0000UL) << 16; + unsigned long addrl = ldq | 0xFFFFFFFFFFFF0000UL; + + addr = regs->r27 + ((addrh ^ 0x80000000UL) + 0x80000000UL) + ((addrl ^ 0x8000UL) + 0x8000UL); + err = get_user(r27, (unsigned long *)addr); + if (err) + break; + + regs->r27 = r27; + regs->pc = r27; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #2 */ + unsigned int ldah, lda, br; + + err = get_user(ldah, (unsigned int *)regs->pc); + err |= get_user(lda, (unsigned int *)(regs->pc+4)); + err |= get_user(br, (unsigned int *)(regs->pc+8)); + + if (err) + break; + + if ((ldah & 0xFFFF0000U) == 0x277B0000U && + (lda & 0xFFFF0000U) == 0xA77B0000U && + (br & 0xFFE00000U) == 0xC3E00000U) + { + unsigned long addr = br | 0xFFFFFFFFFFE00000UL; + unsigned long addrh = (ldah | 0xFFFFFFFFFFFF0000UL) << 16; + unsigned long addrl = lda | 0xFFFFFFFFFFFF0000UL; + + regs->r27 += ((addrh ^ 0x80000000UL) + 0x80000000UL) + ((addrl ^ 0x8000UL) + 0x8000UL); + regs->pc += 12 + (((addr ^ 0x00100000UL) + 0x00100000UL) << 2); + return 2; + } + } while (0); + + do { /* PaX: unpatched PLT emulation */ + unsigned int br; + + err = get_user(br, (unsigned int *)regs->pc); + + if (!err && (br & 0xFFE00000U) == 0xC3800000U) { + unsigned int br2, ldq, nop, jmp; + unsigned long addr = br | 0xFFFFFFFFFFE00000UL, resolver; + + addr = regs->pc + 4 + (((addr ^ 0x00100000UL) + 0x00100000UL) << 2); + err = get_user(br2, (unsigned int *)addr); + err |= get_user(ldq, (unsigned int *)(addr+4)); + err |= get_user(nop, (unsigned int *)(addr+8)); + err |= get_user(jmp, (unsigned int *)(addr+12)); + err |= get_user(resolver, (unsigned long *)(addr+16)); + + if (err) + break; + + if (br2 == 0xC3600000U && + ldq == 0xA77B000CU && + nop == 0x47FF041FU && + jmp == 0x6B7B0000U) + { + regs->r28 = regs->pc+4; + regs->r27 = addr+16; + regs->pc = resolver; + return 3; + } + } + } while (0); +#endif + + return 1; +} + +void pax_report_insns(struct pt_regs *regs, void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk(KERN_CONT "???????? "); + else + printk(KERN_CONT "%08x ", c); + } + printk("\n"); +} +#endif /* * This routine handles page faults. It determines the address, @@ -132,8 +250,29 @@ retry: good_area: si_code = SEGV_ACCERR; if (cause < 0) { - if (!(vma->vm_flags & VM_EXEC)) + if (!(vma->vm_flags & VM_EXEC)) { + +#ifdef CONFIG_PAX_PAGEEXEC + if (!(mm->pax_flags & MF_PAX_PAGEEXEC) || address != regs->pc) + goto bad_area; + + up_read(&mm->mmap_sem); + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_PAX_EMUPLT + case 2: + case 3: + return; +#endif + + } + pax_report_fault(regs, (void *)regs->pc, (void *)rdusp()); + do_group_exit(SIGKILL); +#else goto bad_area; +#endif + + } } else if (!cause) { /* Allow reads even for write-only mappings */ if (!(vma->vm_flags & (VM_READ | VM_WRITE))) diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 78c0621..94cd626 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -487,6 +487,7 @@ config ARC_DBG_TLB_MISS_COUNT bool "Profile TLB Misses" default n select DEBUG_FS + depends on !GRKERNSEC_KMEM help 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 639411f..82e6320 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1785,7 +1785,7 @@ config ALIGNMENT_TRAP config UACCESS_WITH_MEMCPY bool "Use kernel mem{cpy,set}() for {copy_to,clear}_user()" - depends on MMU + depends on MMU && !PAX_MEMORY_UDEREF default y if CPU_FEROCEON help Implement faster copy_to_user and clear_user methods for CPU @@ -2022,6 +2022,7 @@ config KEXEC depends on (!SMP || PM_SLEEP_SMP) depends on !CPU_V7M select KEXEC_CORE + depends on !GRKERNSEC_KMEM 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 diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 0cfd7f947..63ed4c0 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -7,6 +7,7 @@ config ARM_PTDUMP depends on DEBUG_KERNEL depends on MMU select DEBUG_FS + depends on !GRKERNSEC_KMEM ---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/include/asm/atomic.h b/arch/arm/include/asm/atomic.h index fe3ef39..60e6ae2 100644 --- a/arch/arm/include/asm/atomic.h +++ b/arch/arm/include/asm/atomic.h @@ -18,17 +18,41 @@ #include #include +#ifdef CONFIG_GENERIC_ATOMIC64 +#include +#endif + #define ATOMIC_INIT(i) { (i) } #ifdef __KERNEL__ +#ifdef CONFIG_THUMB2_KERNEL +#define REFCOUNT_TRAP_INSN "bkpt 0xf1" +#else +#define REFCOUNT_TRAP_INSN "bkpt 0xf103" +#endif + +#define _ASM_EXTABLE(from, to) \ +" .pushsection __ex_table,\"a\"\n"\ +" .align 3\n" \ +" .long " #from ", " #to"\n" \ +" .popsection" + /* * On ARM, ordinary assignment (str instruction) doesn't clear the local * strex/ldrex monitor on some implementations. The reason we can use it for * atomic_set() is the clrex or dummy strex done on every exception return. */ #define atomic_read(v) ACCESS_ONCE((v)->counter) +static inline int atomic_read_unchecked(const atomic_unchecked_t *v) +{ + return ACCESS_ONCE(v->counter); +} #define atomic_set(v,i) (((v)->counter) = (i)) +static inline void atomic_set_unchecked(atomic_unchecked_t *v, int i) +{ + v->counter = i; +} #if __LINUX_ARM_ARCH__ >= 6 @@ -38,38 +62,64 @@ * to ensure that the update happens. */ -#define ATOMIC_OP(op, c_op, asm_op) \ -static inline void atomic_##op(int i, atomic_t *v) \ +#ifdef CONFIG_PAX_REFCOUNT +#define __OVERFLOW_POST \ + " bvc 3f\n" \ + "2: " REFCOUNT_TRAP_INSN "\n"\ + "3:\n" +#define __OVERFLOW_POST_RETURN \ + " bvc 3f\n" \ +" mov %0, %1\n" \ + "2: " REFCOUNT_TRAP_INSN "\n"\ + "3:\n" +#define __OVERFLOW_EXTABLE \ + "4:\n" \ + _ASM_EXTABLE(2b, 4b) +#else +#define __OVERFLOW_POST +#define __OVERFLOW_POST_RETURN +#define __OVERFLOW_EXTABLE +#endif + +#define __ATOMIC_OP(op, suffix, c_op, asm_op, post_op, extable) \ +static inline void atomic_##op##suffix(int i, atomic##suffix##_t *v) \ { \ unsigned long tmp; \ int result; \ \ prefetchw(&v->counter); \ - __asm__ __volatile__("@ atomic_" #op "\n" \ + __asm__ __volatile__("@ atomic_" #op #suffix "\n" \ "1: ldrex %0, [%3]\n" \ " " #asm_op " %0, %0, %4\n" \ + post_op \ " strex %1, %0, [%3]\n" \ " teq %1, #0\n" \ -" bne 1b" \ +" bne 1b\n" \ + extable \ : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) \ : "r" (&v->counter), "Ir" (i) \ : "cc"); \ } \ -#define ATOMIC_OP_RETURN(op, c_op, asm_op) \ -static inline int atomic_##op##_return_relaxed(int i, atomic_t *v) \ +#define ATOMIC_OP(op, c_op, asm_op) __ATOMIC_OP(op, _unchecked, c_op, asm_op, , )\ + __ATOMIC_OP(op, , c_op, asm_op##s, __OVERFLOW_POST, __OVERFLOW_EXTABLE) + +#define __ATOMIC_OP_RETURN(op, suffix, c_op, asm_op, post_op, extable) \ +static inline int atomic_##op##_return##suffix##_relaxed(int i, atomic##suffix##_t *v)\ { \ unsigned long tmp; \ int result; \ \ prefetchw(&v->counter); \ \ - __asm__ __volatile__("@ atomic_" #op "_return\n" \ + __asm__ __volatile__("@ atomic_" #op "_return" #suffix "\n" \ "1: ldrex %0, [%3]\n" \ " " #asm_op " %0, %0, %4\n" \ + post_op \ " strex %1, %0, [%3]\n" \ " teq %1, #0\n" \ -" bne 1b" \ +" bne 1b\n" \ + extable \ : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) \ : "r" (&v->counter), "Ir" (i) \ : "cc"); \ @@ -78,8 +128,12 @@ static inline int atomic_##op##_return_relaxed(int i, atomic_t *v) \ } #define atomic_add_return_relaxed atomic_add_return_relaxed +#define atomic_add_return_unchecked atomic_add_return_unchecked_relaxed #define atomic_sub_return_relaxed atomic_sub_return_relaxed +#define ATOMIC_OP_RETURN(op, c_op, asm_op) __ATOMIC_OP_RETURN(op, _unchecked, c_op, asm_op, , )\ + __ATOMIC_OP_RETURN(op, , c_op, asm_op##s, __OVERFLOW_POST_RETURN, __OVERFLOW_EXTABLE) + static inline int atomic_cmpxchg_relaxed(atomic_t *ptr, int old, int new) { int oldval; @@ -113,12 +167,24 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) __asm__ __volatile__ ("@ atomic_add_unless\n" "1: ldrex %0, [%4]\n" " teq %0, %5\n" -" beq 2f\n" -" add %1, %0, %6\n" +" beq 4f\n" +" adds %1, %0, %6\n" + +#ifdef CONFIG_PAX_REFCOUNT +" bvc 3f\n" +"2: " REFCOUNT_TRAP_INSN "\n" +"3:\n" +#endif + " strex %2, %1, [%4]\n" " teq %2, #0\n" " bne 1b\n" -"2:" +"4:" + +#ifdef CONFIG_PAX_REFCOUNT + _ASM_EXTABLE(2b, 4b) +#endif + : "=&r" (oldval), "=&r" (newval), "=&r" (tmp), "+Qo" (v->counter) : "r" (&v->counter), "r" (u), "r" (a) : "cc"); @@ -129,14 +195,36 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) return oldval; } +static inline int atomic_cmpxchg_unchecked(atomic_unchecked_t *ptr, int old, int new) +{ + unsigned long oldval, res; + + smp_mb(); + + do { + __asm__ __volatile__("@ atomic_cmpxchg_unchecked\n" + "ldrex %1, [%3]\n" + "mov %0, #0\n" + "teq %1, %4\n" + "strexeq %0, %5, [%3]\n" + : "=&r" (res), "=&r" (oldval), "+Qo" (ptr->counter) + : "r" (&ptr->counter), "Ir" (old), "r" (new) + : "cc"); + } while (res); + + smp_mb(); + + return oldval; +} + #else /* ARM_ARCH_6 */ #ifdef CONFIG_SMP #error SMP not supported on pre-ARMv6 CPUs #endif -#define ATOMIC_OP(op, c_op, asm_op) \ -static inline void atomic_##op(int i, atomic_t *v) \ +#define __ATOMIC_OP(op, suffix, c_op, asm_op) \ +static inline void atomic_##op##suffix(int i, atomic##suffix##_t *v) \ { \ unsigned long flags; \ \ @@ -145,8 +233,11 @@ static inline void atomic_##op(int i, atomic_t *v) \ raw_local_irq_restore(flags); \ } \ -#define ATOMIC_OP_RETURN(op, c_op, asm_op) \ -static inline int atomic_##op##_return(int i, atomic_t *v) \ +#define ATOMIC_OP(op, c_op, asm_op) __ATOMIC_OP(op, , c_op, asm_op) \ + __ATOMIC_OP(op, _unchecked, c_op, asm_op) + +#define __ATOMIC_OP_RETURN(op, suffix, c_op, asm_op) \ +static inline int atomic_##op##_return##suffix(int i, atomic##suffix##_t *v)\ { \ unsigned long flags; \ int val; \ @@ -159,6 +250,9 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return val; \ } +#define ATOMIC_OP_RETURN(op, c_op, asm_op) __ATOMIC_OP_RETURN(op, , c_op, asm_op)\ + __ATOMIC_OP_RETURN(op, _unchecked, c_op, asm_op) + static inline int atomic_cmpxchg(atomic_t *v, int old, int new) { int ret; @@ -173,6 +267,11 @@ static inline int atomic_cmpxchg(atomic_t *v, int old, int new) return ret; } +static inline int atomic_cmpxchg_unchecked(atomic_unchecked_t *v, int old, int new) +{ + return atomic_cmpxchg((atomic_t *)v, old, new); +} + static inline int __atomic_add_unless(atomic_t *v, int a, int u) { int c, old; @@ -201,16 +300,38 @@ ATOMIC_OP(xor, ^=, eor) #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN +#undef __ATOMIC_OP_RETURN #undef ATOMIC_OP +#undef __ATOMIC_OP #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) +static inline int atomic_xchg_unchecked(atomic_unchecked_t *v, int new) +{ + return xchg_relaxed(&v->counter, new); +} #define atomic_inc(v) atomic_add(1, v) +static inline void atomic_inc_unchecked(atomic_unchecked_t *v) +{ + atomic_add_unchecked(1, v); +} #define atomic_dec(v) atomic_sub(1, v) +static inline void atomic_dec_unchecked(atomic_unchecked_t *v) +{ + atomic_sub_unchecked(1, v); +} #define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0) +static inline int atomic_inc_and_test_unchecked(atomic_unchecked_t *v) +{ + return atomic_add_return_unchecked(1, v) == 0; +} #define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) #define atomic_inc_return(v) (atomic_add_return(1, v)) +static inline int atomic_inc_return_unchecked(atomic_unchecked_t *v) +{ + return atomic_add_return_unchecked(1, v); +} #define atomic_dec_return(v) (atomic_sub_return(1, v)) #define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) @@ -221,6 +342,14 @@ typedef struct { long long counter; } atomic64_t; +#ifdef CONFIG_PAX_REFCOUNT +typedef struct { + long long counter; +} atomic64_unchecked_t; +#else +typedef atomic64_t atomic64_unchecked_t; +#endif + #define ATOMIC64_INIT(i) { (i) } #ifdef CONFIG_ARM_LPAE @@ -237,6 +366,19 @@ static inline long long atomic64_read(const atomic64_t *v) return result; } +static inline long long atomic64_read_unchecked(const atomic64_unchecked_t *v) +{ + long long result; + + __asm__ __volatile__("@ atomic64_read_unchecked\n" +" ldrd %0, %H0, [%1]" + : "=&r" (result) + : "r" (&v->counter), "Qo" (v->counter) + ); + + return result; +} + static inline void atomic64_set(atomic64_t *v, long long i) { __asm__ __volatile__("@ atomic64_set\n" @@ -245,6 +387,15 @@ static inline void atomic64_set(atomic64_t *v, long long i) : "r" (&v->counter), "r" (i) ); } + +static inline void atomic64_set_unchecked(atomic64_unchecked_t *v, long long i) +{ + __asm__ __volatile__("@ atomic64_set_unchecked\n" +" strd %2, %H2, [%1]" + : "=Qo" (v->counter) + : "r" (&v->counter), "r" (i) + ); +} #else static inline long long atomic64_read(const atomic64_t *v) { @@ -259,6 +410,19 @@ static inline long long atomic64_read(const atomic64_t *v) return result; } +static inline long long atomic64_read_unchecked(const atomic64_unchecked_t *v) +{ + long long result; + + __asm__ __volatile__("@ atomic64_read_unchecked\n" +" ldrexd %0, %H0, [%1]" + : "=&r" (result) + : "r" (&v->counter), "Qo" (v->counter) + ); + + return result; +} + static inline void atomic64_set(atomic64_t *v, long long i) { long long tmp; @@ -273,43 +437,73 @@ static inline void atomic64_set(atomic64_t *v, long long i) : "r" (&v->counter), "r" (i) : "cc"); } + +static inline void atomic64_set_unchecked(atomic64_unchecked_t *v, long long i) +{ + long long tmp; + + prefetchw(&v->counter); + __asm__ __volatile__("@ atomic64_set_unchecked\n" +"1: ldrexd %0, %H0, [%2]\n" +" strexd %0, %3, %H3, [%2]\n" +" teq %0, #0\n" +" bne 1b" + : "=&r" (tmp), "=Qo" (v->counter) + : "r" (&v->counter), "r" (i) + : "cc"); +} #endif -#define ATOMIC64_OP(op, op1, op2) \ -static inline void atomic64_##op(long long i, atomic64_t *v) \ +#undef __OVERFLOW_POST_RETURN +#define __OVERFLOW_POST_RETURN \ + " bvc 3f\n" \ +" mov %0, %1\n" \ +" mov %H0, %H1\n" \ + "2: " REFCOUNT_TRAP_INSN "\n"\ + "3:\n" + +#define __ATOMIC64_OP(op, suffix, op1, op2, post_op, extable) \ +static inline void atomic64_##op##suffix(long long i, atomic64##suffix##_t *v)\ { \ long long result; \ unsigned long tmp; \ \ prefetchw(&v->counter); \ - __asm__ __volatile__("@ atomic64_" #op "\n" \ + __asm__ __volatile__("@ atomic64_" #op #suffix "\n" \ "1: ldrexd %0, %H0, [%3]\n" \ " " #op1 " %Q0, %Q0, %Q4\n" \ " " #op2 " %R0, %R0, %R4\n" \ + post_op \ " strexd %1, %0, %H0, [%3]\n" \ " teq %1, #0\n" \ -" bne 1b" \ +" bne 1b\n" \ + extable \ : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) \ : "r" (&v->counter), "r" (i) \ : "cc"); \ } \ -#define ATOMIC64_OP_RETURN(op, op1, op2) \ +#define ATOMIC64_OP(op, op1, op2) __ATOMIC64_OP(op, _unchecked, op1, op2, , ) \ + __ATOMIC64_OP(op, , op1, op2##s, __OVERFLOW_POST, __OVERFLOW_EXTABLE) + +#define __ATOMIC64_OP_RETURN(op, suffix, op1, op2, post_op, extable) \ static inline long long \ -atomic64_##op##_return_relaxed(long long i, atomic64_t *v) \ +atomic64_##op##_return##suffix##_relaxed(long long i, atomic64##suffix##_t *v) \ { \ long long result; \ unsigned long tmp; \ \ prefetchw(&v->counter); \ \ - __asm__ __volatile__("@ atomic64_" #op "_return\n" \ + __asm__ __volatile__("@ atomic64_" #op "_return" #suffix "\n" \ "1: ldrexd %0, %H0, [%3]\n" \ " " #op1 " %Q0, %Q0, %Q4\n" \ " " #op2 " %R0, %R0, %R4\n" \ + post_op \ " strexd %1, %0, %H0, [%3]\n" \ " teq %1, #0\n" \ -" bne 1b" \ +" bne 1b\n" \ + extable \ : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) \ : "r" (&v->counter), "r" (i) \ : "cc"); \ @@ -317,6 +511,9 @@ atomic64_##op##_return_relaxed(long long i, atomic64_t *v) \ return result; \ } +#define ATOMIC64_OP_RETURN(op, op1, op2) __ATOMIC64_OP_RETURN(op, _unchecked, op1, op2, , ) \ + __ATOMIC64_OP_RETURN(op, , op1, op2##s, __OVERFLOW_POST_RETURN, __OVERFLOW_EXTABLE) + #define ATOMIC64_OPS(op, op1, op2) \ ATOMIC64_OP(op, op1, op2) \ ATOMIC64_OP_RETURN(op, op1, op2) @@ -325,6 +522,7 @@ ATOMIC64_OPS(add, adds, adc) ATOMIC64_OPS(sub, subs, sbc) #define atomic64_add_return_relaxed atomic64_add_return_relaxed +#define atomic64_add_return_unchecked atomic64_add_return_unchecked_relaxed #define atomic64_sub_return_relaxed atomic64_sub_return_relaxed #define atomic64_andnot atomic64_andnot @@ -336,7 +534,12 @@ ATOMIC64_OP(xor, eor, eor) #undef ATOMIC64_OPS #undef ATOMIC64_OP_RETURN +#undef __ATOMIC64_OP_RETURN #undef ATOMIC64_OP +#undef __ATOMIC64_OP +#undef __OVERFLOW_EXTABLE +#undef __OVERFLOW_POST_RETURN +#undef __OVERFLOW_POST static inline long long atomic64_cmpxchg_relaxed(atomic64_t *ptr, long long old, long long new) @@ -361,6 +564,33 @@ atomic64_cmpxchg_relaxed(atomic64_t *ptr, long long old, long long new) return oldval; } #define atomic64_cmpxchg_relaxed atomic64_cmpxchg_relaxed +#define atomic64_cmpxchg_unchecked atomic64_cmpxchg_unchecked_relaxed + +static inline long long +atomic64_cmpxchg_unchecked_relaxed(atomic64_unchecked_t *ptr, long long old, + long long new) +{ + long long oldval; + unsigned long res; + + smp_mb(); + + do { + __asm__ __volatile__("@ atomic64_cmpxchg_unchecked\n" + "ldrexd %1, %H1, [%3]\n" + "mov %0, #0\n" + "teq %1, %4\n" + "teqeq %H1, %H4\n" + "strexdeq %0, %5, %H5, [%3]" + : "=&r" (res), "=&r" (oldval), "+Qo" (ptr->counter) + : "r" (&ptr->counter), "r" (old), "r" (new) + : "cc"); + } while (res); + + smp_mb(); + + return oldval; +} static inline long long atomic64_xchg_relaxed(atomic64_t *ptr, long long new) { @@ -385,21 +615,35 @@ static inline long long atomic64_xchg_relaxed(atomic64_t *ptr, long long new) static inline long long atomic64_dec_if_positive(atomic64_t *v) { long long result; - unsigned long tmp; + u64 tmp; smp_mb(); prefetchw(&v->counter); __asm__ __volatile__("@ atomic64_dec_if_positive\n" -"1: ldrexd %0, %H0, [%3]\n" -" subs %Q0, %Q0, #1\n" -" sbc %R0, %R0, #0\n" +"1: ldrexd %1, %H1, [%3]\n" +" subs %Q0, %Q1, #1\n" +" sbcs %R0, %R1, #0\n" + +#ifdef CONFIG_PAX_REFCOUNT +" bvc 3f\n" +" mov %Q0, %Q1\n" +" mov %R0, %R1\n" +"2: " REFCOUNT_TRAP_INSN "\n" +"3:\n" +#endif + " teq %R0, #0\n" -" bmi 2f\n" +" bmi 4f\n" " strexd %1, %0, %H0, [%3]\n" " teq %1, #0\n" " bne 1b\n" -"2:" +"4:\n" + +#ifdef CONFIG_PAX_REFCOUNT + _ASM_EXTABLE(2b, 4b) +#endif + : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) : "r" (&v->counter) : "cc"); @@ -423,13 +667,25 @@ static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u) " teq %0, %5\n" " teqeq %H0, %H5\n" " moveq %1, #0\n" -" beq 2f\n" +" beq 4f\n" " adds %Q0, %Q0, %Q6\n" -" adc %R0, %R0, %R6\n" +" adcs %R0, %R0, %R6\n" + +#ifdef CONFIG_PAX_REFCOUNT +" bvc 3f\n" +"2: " REFCOUNT_TRAP_INSN "\n" +"3:\n" +#endif + " strexd %2, %0, %H0, [%4]\n" " teq %2, #0\n" " bne 1b\n" -"2:" +"4:\n" + +#ifdef CONFIG_PAX_REFCOUNT + _ASM_EXTABLE(2b, 4b) +#endif + : "=&r" (val), "+r" (ret), "=&r" (tmp), "+Qo" (v->counter) : "r" (&v->counter), "r" (u), "r" (a) : "cc"); @@ -442,10 +698,13 @@ static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u) #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) #define atomic64_inc(v) atomic64_add(1LL, (v)) +#define atomic64_inc_unchecked(v) atomic64_add_unchecked(1LL, (v)) #define atomic64_inc_return(v) atomic64_add_return(1LL, (v)) +#define atomic64_inc_return_unchecked(v) atomic64_add_return_unchecked(1LL, (v)) #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) #define atomic64_sub_and_test(a, v) (atomic64_sub_return((a), (v)) == 0) #define atomic64_dec(v) atomic64_sub(1LL, (v)) +#define atomic64_dec_unchecked(v) atomic64_sub_unchecked(1LL, (v)) #define atomic64_dec_return(v) atomic64_sub_return(1LL, (v)) #define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL) diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h index 75fe66b..ba3dee4 100644 --- a/arch/arm/include/asm/cache.h +++ b/arch/arm/include/asm/cache.h @@ -4,8 +4,10 @@ #ifndef __ASMARM_CACHE_H #define __ASMARM_CACHE_H +#include + #define L1_CACHE_SHIFT CONFIG_ARM_L1_CACHE_SHIFT -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) /* * Memory returned by kmalloc() may be used for DMA, so we must make @@ -24,5 +26,6 @@ #endif #define __read_mostly __attribute__((__section__(".data..read_mostly"))) +#define __read_only __attribute__ ((__section__(".data..read_only"))) #endif diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index d5525bf..e55725d 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -116,7 +116,7 @@ struct cpu_cache_fns { void (*dma_unmap_area)(const void *, size_t, int); void (*dma_flush_range)(const void *, const void *); -}; +} __no_const; /* * Select the calling method diff --git a/arch/arm/include/asm/checksum.h b/arch/arm/include/asm/checksum.h index 5233151..87a71fa 100644 --- a/arch/arm/include/asm/checksum.h +++ b/arch/arm/include/asm/checksum.h @@ -37,7 +37,19 @@ __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum); __wsum -csum_partial_copy_from_user(const void __user *src, void *dst, int len, __wsum sum, int *err_ptr); +__csum_partial_copy_from_user(const void __user *src, void *dst, int len, __wsum sum, int *err_ptr); + +static inline __wsum +csum_partial_copy_from_user(const void __user *src, void *dst, int len, __wsum sum, int *err_ptr) +{ + __wsum ret; + pax_open_userland(); + ret = __csum_partial_copy_from_user(src, dst, len, sum, err_ptr); + pax_close_userland(); + return ret; +} + + /* * Fold a partial checksum without adding pseudo headers diff --git a/arch/arm/include/asm/cmpxchg.h b/arch/arm/include/asm/cmpxchg.h index 916a274..f988f55 100644 --- a/arch/arm/include/asm/cmpxchg.h +++ b/arch/arm/include/asm/cmpxchg.h @@ -105,6 +105,10 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size (__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), \ sizeof(*(ptr))); \ }) +#define xchg_unchecked(ptr, x) ({ \ + (__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), \ + sizeof(*(ptr))); \ +}) #include diff --git a/arch/arm/include/asm/cpuidle.h b/arch/arm/include/asm/cpuidle.h index 0f84249..8e83c55 100644 --- a/arch/arm/include/asm/cpuidle.h +++ b/arch/arm/include/asm/cpuidle.h @@ -32,7 +32,7 @@ struct device_node; struct cpuidle_ops { int (*suspend)(int cpu, unsigned long arg); int (*init)(struct device_node *, int cpu); -}; +} __no_const; struct of_cpuidle_method { const char *method; diff --git a/arch/arm/include/asm/domain.h b/arch/arm/include/asm/domain.h index fc8ba16..8b84f53 100644 --- a/arch/arm/include/asm/domain.h +++ b/arch/arm/include/asm/domain.h @@ -42,7 +42,6 @@ #define DOMAIN_USER 1 #define DOMAIN_IO 0 #endif -#define DOMAIN_VECTORS 3 /* * Domain types @@ -51,9 +50,27 @@ #define DOMAIN_CLIENT 1 #ifdef CONFIG_CPU_USE_DOMAINS #define DOMAIN_MANAGER 3 +#define DOMAIN_VECTORS 3 #else + +#ifdef CONFIG_PAX_KERNEXEC #define DOMAIN_MANAGER 1 +#define DOMAIN_KERNEXEC 3 +#else +#define DOMAIN_MANAGER 1 +#endif + +#ifdef CONFIG_PAX_MEMORY_UDEREF +#define DOMAIN_USERCLIENT 0 +#define DOMAIN_UDEREF 1 +#define DOMAIN_VECTORS DOMAIN_KERNEL +#else +#define DOMAIN_USERCLIENT 1 +#define DOMAIN_VECTORS DOMAIN_USER +#endif + #endif +#define DOMAIN_KERNELCLIENT 1 #define domain_mask(dom) ((3) << (2 * (dom))) #define domain_val(dom,type) ((type) << (2 * (dom))) @@ -62,7 +79,7 @@ #define DACR_INIT \ (domain_val(DOMAIN_USER, DOMAIN_NOACCESS) | \ domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ - domain_val(DOMAIN_IO, DOMAIN_CLIENT) | \ + domain_val(DOMAIN_IO, DOMAIN_KERNELCLIENT) | \ domain_val(DOMAIN_VECTORS, DOMAIN_CLIENT)) #else #define DACR_INIT \ diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h index d2315ff..f60b47b 100644 --- a/arch/arm/include/asm/elf.h +++ b/arch/arm/include/asm/elf.h @@ -117,7 +117,14 @@ int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs); the loader. We need to make sure that it is out of the way of the program that it will "exec", and that there is sufficient room for the brk. */ -#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) +#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) + +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE 0x00008000UL + +#define PAX_DELTA_MMAP_LEN ((current->personality == PER_LINUX_32BIT) ? 16 : 10) +#define PAX_DELTA_STACK_LEN ((current->personality == PER_LINUX_32BIT) ? 16 : 10) +#endif /* When the program starts, a1 contains a pointer to a function to be registered with atexit, as per the SVR4 ABI. A value of 0 means we diff --git a/arch/arm/include/asm/fncpy.h b/arch/arm/include/asm/fncpy.h index de53547..52b9a28 100644 --- a/arch/arm/include/asm/fncpy.h +++ b/arch/arm/include/asm/fncpy.h @@ -81,7 +81,9 @@ BUG_ON((uintptr_t)(dest_buf) & (FNCPY_ALIGN - 1) || \ (__funcp_address & ~(uintptr_t)1 & (FNCPY_ALIGN - 1))); \ \ + pax_open_kernel(); \ memcpy(dest_buf, (void const *)(__funcp_address & ~1), size); \ + pax_close_kernel(); \ flush_icache_range((unsigned long)(dest_buf), \ (unsigned long)(dest_buf) + (size)); \ \ diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h index 6795368..b784325 100644 --- a/arch/arm/include/asm/futex.h +++ b/arch/arm/include/asm/futex.h @@ -52,6 +52,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) return -EFAULT; + pax_open_userland(); + smp_mb(); /* Prefetching cannot fault */ prefetchw(uaddr); @@ -71,6 +73,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, uaccess_restore(__ua_flags); smp_mb(); + pax_close_userland(); + *uval = val; return ret; } @@ -107,6 +111,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, return -EFAULT; preempt_disable(); + pax_open_userland(); + __ua_flags = uaccess_save_and_enable(); __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n" "1: " TUSER(ldr) " %1, [%4]\n" @@ -119,6 +125,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, : "cc", "memory"); uaccess_restore(__ua_flags); + pax_close_userland(); + *uval = val; preempt_enable(); @@ -146,6 +154,7 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) preempt_disable(); #endif pagefault_disable(); + pax_open_userland(); switch (op) { case FUTEX_OP_SET: @@ -167,6 +176,7 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) ret = -ENOSYS; } + pax_close_userland(); pagefault_enable(); #ifndef CONFIG_SMP preempt_enable(); diff --git a/arch/arm/include/asm/kmap_types.h b/arch/arm/include/asm/kmap_types.h index 83eb2f7..ed77159 100644 --- a/arch/arm/include/asm/kmap_types.h +++ b/arch/arm/include/asm/kmap_types.h @@ -4,6 +4,6 @@ /* * This is the "bare minimum". AIO seems to require this. */ -#define KM_TYPE_NR 16 +#define KM_TYPE_NR 17 #endif diff --git a/arch/arm/include/asm/mach/dma.h b/arch/arm/include/asm/mach/dma.h index 9e614a1..3302cca 100644 --- a/arch/arm/include/asm/mach/dma.h +++ b/arch/arm/include/asm/mach/dma.h @@ -22,7 +22,7 @@ struct dma_ops { int (*residue)(unsigned int, dma_t *); /* optional */ int (*setspeed)(unsigned int, dma_t *, int); /* optional */ const char *type; -}; +} __do_const; struct dma_struct { void *addr; /* single DMA address */ diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h index f98c7f3..e5c626d 100644 --- a/arch/arm/include/asm/mach/map.h +++ b/arch/arm/include/asm/mach/map.h @@ -23,17 +23,19 @@ struct map_desc { /* types 0-3 are defined in asm/io.h */ enum { - MT_UNCACHED = 4, - MT_CACHECLEAN, - MT_MINICLEAN, + MT_UNCACHED_RW = 4, + MT_CACHECLEAN_RO, + MT_MINICLEAN_RO, MT_LOW_VECTORS, MT_HIGH_VECTORS, - MT_MEMORY_RWX, + __MT_MEMORY_RWX, MT_MEMORY_RW, - MT_ROM, - MT_MEMORY_RWX_NONCACHED, + MT_MEMORY_RX, + MT_ROM_RX, + MT_MEMORY_RW_NONCACHED, + MT_MEMORY_RX_NONCACHED, MT_MEMORY_RW_DTCM, - MT_MEMORY_RWX_ITCM, + MT_MEMORY_RX_ITCM, MT_MEMORY_RW_SO, MT_MEMORY_DMA_READY, }; diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h index c2bf24f..69e437c 100644 --- a/arch/arm/include/asm/outercache.h +++ b/arch/arm/include/asm/outercache.h @@ -39,7 +39,7 @@ struct outer_cache_fns { /* This is an ARM L2C thing */ void (*write_sec)(unsigned long, unsigned); void (*configure)(const struct l2x0_regs *); -}; +} __no_const; extern struct outer_cache_fns outer_cache; diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h index 4355f0e..cd9168e 100644 --- a/arch/arm/include/asm/page.h +++ b/arch/arm/include/asm/page.h @@ -23,6 +23,7 @@ #else +#include #include /* @@ -114,7 +115,7 @@ struct cpu_user_fns { void (*cpu_clear_user_highpage)(struct page *page, unsigned long vaddr); void (*cpu_copy_user_highpage)(struct page *to, struct page *from, unsigned long vaddr, struct vm_area_struct *vma); -}; +} __no_const; #ifdef MULTI_USER extern struct cpu_user_fns cpu_user; diff --git a/arch/arm/include/asm/pgalloc.h b/arch/arm/include/asm/pgalloc.h index 19cfab5..3f5c7e9 100644 --- a/arch/arm/include/asm/pgalloc.h +++ b/arch/arm/include/asm/pgalloc.h @@ -17,6 +17,7 @@ #include #include #include +#include #define check_pgt_cache() do { } while (0) @@ -43,6 +44,11 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) set_pud(pud, __pud(__pa(pmd) | PMD_TYPE_TABLE)); } +static inline void pud_populate_kernel(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) +{ + pud_populate(mm, pud, pmd); +} + #else /* !CONFIG_ARM_LPAE */ /* @@ -51,6 +57,7 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) #define pmd_alloc_one(mm,addr) ({ BUG(); ((pmd_t *)2); }) #define pmd_free(mm, pmd) do { } while (0) #define pud_populate(mm,pmd,pte) BUG() +#define pud_populate_kernel(mm,pmd,pte) BUG() #endif /* CONFIG_ARM_LPAE */ @@ -128,6 +135,19 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte) __free_page(pte); } +static inline void __section_update(pmd_t *pmdp, unsigned long addr, pmdval_t prot) +{ +#ifdef CONFIG_ARM_LPAE + pmdp[0] = __pmd(pmd_val(pmdp[0]) | prot); +#else + if (addr & SECTION_SIZE) + pmdp[1] = __pmd(pmd_val(pmdp[1]) | prot); + else + pmdp[0] = __pmd(pmd_val(pmdp[0]) | prot); +#endif + flush_pmd_entry(pmdp); +} + static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte, pmdval_t prot) { diff --git a/arch/arm/include/asm/pgtable-2level-hwdef.h b/arch/arm/include/asm/pgtable-2level-hwdef.h index d0131ee..23a0939 100644 --- a/arch/arm/include/asm/pgtable-2level-hwdef.h +++ b/arch/arm/include/asm/pgtable-2level-hwdef.h @@ -28,7 +28,7 @@ /* * - section */ -#define PMD_SECT_PXN (_AT(pmdval_t, 1) << 0) /* v7 */ +#define PMD_SECT_PXN (_AT(pmdval_t, 1) << 0) /* v7 */ #define PMD_SECT_BUFFERABLE (_AT(pmdval_t, 1) << 2) #define PMD_SECT_CACHEABLE (_AT(pmdval_t, 1) << 3) #define PMD_SECT_XN (_AT(pmdval_t, 1) << 4) /* v6 */ @@ -40,6 +40,7 @@ #define PMD_SECT_nG (_AT(pmdval_t, 1) << 17) /* v6 */ #define PMD_SECT_SUPER (_AT(pmdval_t, 1) << 18) /* v6 */ #define PMD_SECT_AF (_AT(pmdval_t, 0)) +#define PMD_SECT_RDONLY (_AT(pmdval_t, 0)) #define PMD_SECT_UNCACHED (_AT(pmdval_t, 0)) #define PMD_SECT_BUFFERED (PMD_SECT_BUFFERABLE) @@ -69,6 +70,7 @@ * - extended small page/tiny page */ #define PTE_EXT_XN (_AT(pteval_t, 1) << 0) /* v6 */ +#define PTE_EXT_PXN (_AT(pteval_t, 1) << 2) /* v7 */ #define PTE_EXT_AP_MASK (_AT(pteval_t, 3) << 4) #define PTE_EXT_AP0 (_AT(pteval_t, 1) << 4) #define PTE_EXT_AP1 (_AT(pteval_t, 2) << 4) diff --git a/arch/arm/include/asm/pgtable-2level.h b/arch/arm/include/asm/pgtable-2level.h index aeddd28..207745c 100644 --- a/arch/arm/include/asm/pgtable-2level.h +++ b/arch/arm/include/asm/pgtable-2level.h @@ -127,6 +127,9 @@ #define L_PTE_SHARED (_AT(pteval_t, 1) << 10) /* shared(v6), coherent(xsc3) */ #define L_PTE_NONE (_AT(pteval_t, 1) << 11) +/* Two-level page tables only have PXN in the PGD, not in the PTE. */ +#define L_PTE_PXN (_AT(pteval_t, 0)) + /* * These are the memory types, defined to be compatible with * pre-ARMv6 CPUs cacheable and bufferable bits: n/a,n/a,C,B diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h index a745a2a..481350a 100644 --- a/arch/arm/include/asm/pgtable-3level.h +++ b/arch/arm/include/asm/pgtable-3level.h @@ -80,6 +80,7 @@ #define L_PTE_USER (_AT(pteval_t, 1) << 6) /* AP[1] */ #define L_PTE_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */ #define L_PTE_YOUNG (_AT(pteval_t, 1) << 10) /* AF */ +#define L_PTE_PXN (_AT(pteval_t, 1) << 53) /* PXN */ #define L_PTE_XN (_AT(pteval_t, 1) << 54) /* XN */ #define L_PTE_DIRTY (_AT(pteval_t, 1) << 55) #define L_PTE_SPECIAL (_AT(pteval_t, 1) << 56) @@ -91,10 +92,12 @@ #define L_PMD_SECT_SPLITTING (_AT(pmdval_t, 1) << 56) #define L_PMD_SECT_NONE (_AT(pmdval_t, 1) << 57) #define L_PMD_SECT_RDONLY (_AT(pteval_t, 1) << 58) +#define PMD_SECT_RDONLY PMD_SECT_AP2 /* * To be used in assembly code with the upper page attributes. */ +#define L_PTE_PXN_HIGH (1 << (53 - 32)) #define L_PTE_XN_HIGH (1 << (54 - 32)) #define L_PTE_DIRTY_HIGH (1 << (55 - 32)) diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index f403541..b10df68 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -33,6 +33,9 @@ #include #endif +#define ktla_ktva(addr) (addr) +#define ktva_ktla(addr) (addr) + /* * Just any arbitrary offset to the start of the vmalloc VM area: the * current 8MB value just means that there will be a 8MB "hole" after the @@ -48,6 +51,9 @@ #define LIBRARY_TEXT_START 0x0c000000 #ifndef __ASSEMBLY__ +extern pteval_t __supported_pte_mask; +extern pmdval_t __supported_pmd_mask; + extern void __pte_error(const char *file, int line, pte_t); extern void __pmd_error(const char *file, int line, pmd_t); extern void __pgd_error(const char *file, int line, pgd_t); @@ -56,6 +62,48 @@ extern void __pgd_error(const char *file, int line, pgd_t); #define pmd_ERROR(pmd) __pmd_error(__FILE__, __LINE__, pmd) #define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd) +#define __HAVE_ARCH_PAX_OPEN_KERNEL +#define __HAVE_ARCH_PAX_CLOSE_KERNEL + +#if defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) +#include +#include +#include + +static inline int test_domain(int domain, int domaintype) +{ + return ((current_thread_info()->cpu_domain) & domain_val(domain, 3)) == domain_val(domain, domaintype); +} +#endif + +#ifdef CONFIG_PAX_KERNEXEC +static inline unsigned long pax_open_kernel(void) { +#ifdef CONFIG_ARM_LPAE + /* TODO */ +#else + preempt_disable(); + BUG_ON(test_domain(DOMAIN_KERNEL, DOMAIN_KERNEXEC)); + modify_domain(DOMAIN_KERNEL, DOMAIN_KERNEXEC); +#endif + return 0; +} + +static inline unsigned long pax_close_kernel(void) { +#ifdef CONFIG_ARM_LPAE + /* TODO */ +#else + BUG_ON(test_domain(DOMAIN_KERNEL, DOMAIN_MANAGER)); + /* DOMAIN_MANAGER = "client" under KERNEXEC */ + modify_domain(DOMAIN_KERNEL, DOMAIN_MANAGER); + preempt_enable_no_resched(); +#endif + return 0; +} +#else +static inline unsigned long pax_open_kernel(void) { return 0; } +static inline unsigned long pax_close_kernel(void) { return 0; } +#endif + /* * This is the lowest virtual address we can permit any user space * mapping to be mapped at. This is particularly important for @@ -75,8 +123,8 @@ extern void __pgd_error(const char *file, int line, pgd_t); /* * The pgprot_* and protection_map entries will be fixed up in runtime * to include the cachable and bufferable bits based on memory policy, - * as well as any architecture dependent bits like global/ASID and SMP - * shared mapping bits. + * as well as any architecture dependent bits like global/ASID, PXN, + * and SMP shared mapping bits. */ #define _L_PTE_DEFAULT L_PTE_PRESENT | L_PTE_YOUNG @@ -307,7 +355,7 @@ static inline pte_t pte_mknexec(pte_t pte) static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { const pteval_t mask = L_PTE_XN | L_PTE_RDONLY | L_PTE_USER | - L_PTE_NONE | L_PTE_VALID; + L_PTE_NONE | L_PTE_VALID | __supported_pte_mask; pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask); return pte; } diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index ef35665..d69146d 100644 --- a/arch/arm/include/asm/smp.h +++ b/arch/arm/include/asm/smp.h @@ -108,7 +108,7 @@ struct smp_operations { int (*cpu_disable)(unsigned int cpu); #endif #endif -}; +} __no_const; struct of_cpu_method { const char *method; diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 776757d..5a598df 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -143,6 +143,10 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, #define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */ #define TIF_SYSCALL_TRACEPOINT 6 /* syscall tracepoint instrumentation */ #define TIF_SECCOMP 7 /* seccomp syscall filtering active */ +/* within 8 bits of TIF_SYSCALL_TRACE + * to meet flexible second operand requirements + */ +#define TIF_GRSEC_SETXID 8 #define TIF_NOHZ 12 /* in adaptive nohz mode */ #define TIF_USING_IWMMXT 17 @@ -158,10 +162,11 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) #define _TIF_SECCOMP (1 << TIF_SECCOMP) #define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT) +#define _TIF_GRSEC_SETXID (1 << TIF_GRSEC_SETXID) /* Checks for any syscall work in entry-common.S */ #define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \ - _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP) + _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | _TIF_GRSEC_SETXID) /* * Change these and you break ASM code in entry-common.S diff --git a/arch/arm/include/asm/tls.h b/arch/arm/include/asm/tls.h index 5f833f7..76e6644 100644 --- a/arch/arm/include/asm/tls.h +++ b/arch/arm/include/asm/tls.h @@ -3,6 +3,7 @@ #include #include +#include #ifdef __ASSEMBLY__ #include @@ -89,7 +90,9 @@ static inline void set_tls(unsigned long val) * at 0xffff0fe0 must be used instead. (see * entry-armv.S for details) */ + pax_open_kernel(); *((unsigned int *)0xffff0ff0) = val; + pax_close_kernel(); #endif } diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 8cc85a4..5f24fe2 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -18,6 +18,7 @@ #include #include #include +#include #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS #include @@ -99,11 +100,38 @@ extern int __put_user_bad(void); static inline void set_fs(mm_segment_t fs) { current_thread_info()->addr_limit = fs; - modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER); + modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_KERNELCLIENT : DOMAIN_MANAGER); } #define segment_eq(a, b) ((a) == (b)) +#define __HAVE_ARCH_PAX_OPEN_USERLAND +#define __HAVE_ARCH_PAX_CLOSE_USERLAND + +static inline void pax_open_userland(void) +{ + +#ifdef CONFIG_PAX_MEMORY_UDEREF + if (segment_eq(get_fs(), USER_DS)) { + BUG_ON(test_domain(DOMAIN_USER, DOMAIN_UDEREF)); + modify_domain(DOMAIN_USER, DOMAIN_UDEREF); + } +#endif + +} + +static inline void pax_close_userland(void) +{ + +#ifdef CONFIG_PAX_MEMORY_UDEREF + if (segment_eq(get_fs(), USER_DS)) { + BUG_ON(test_domain(DOMAIN_USER, DOMAIN_NOACCESS)); + modify_domain(DOMAIN_USER, DOMAIN_NOACCESS); + } +#endif + +} + #define __addr_ok(addr) ({ \ unsigned long flag; \ __asm__("cmp %2, %0; movlo %0, #0" \ @@ -229,8 +257,12 @@ extern int __get_user_64t_4(void *); #define get_user(x, p) \ ({ \ + int __e; \ might_fault(); \ - __get_user_check(x, p); \ + pax_open_userland(); \ + __e = __get_user_check((x), (p)); \ + pax_close_userland(); \ + __e; \ }) extern int __put_user_1(void *, unsigned int); @@ -277,8 +309,12 @@ extern int __put_user_8(void *, unsigned long long); #define put_user(x, p) \ ({ \ + int __e; \ might_fault(); \ - __put_user_check(x, p); \ + pax_open_userland(); \ + __e = __put_user_check((x), (p)); \ + pax_close_userland(); \ + __e; \ }) #else /* CONFIG_MMU */ @@ -302,6 +338,7 @@ static inline void set_fs(mm_segment_t fs) #endif /* CONFIG_MMU */ +#define access_ok_noprefault(type, addr, size) access_ok((type), (addr), (size)) #define access_ok(type, addr, size) (__range_ok(addr, size) == 0) #define user_addr_max() \ @@ -319,13 +356,17 @@ static inline void set_fs(mm_segment_t fs) #define __get_user(x, ptr) \ ({ \ long __gu_err = 0; \ + pax_open_userland(); \ __get_user_err((x), (ptr), __gu_err); \ + pax_close_userland(); \ __gu_err; \ }) #define __get_user_error(x, ptr, err) \ ({ \ + pax_open_userland(); \ __get_user_err((x), (ptr), err); \ + pax_close_userland(); \ (void) 0; \ }) @@ -392,13 +433,17 @@ do { \ #define __put_user(x, ptr) \ ({ \ long __pu_err = 0; \ + pax_open_userland(); \ __put_user_err((x), (ptr), __pu_err); \ + pax_close_userland(); \ __pu_err; \ }) #define __put_user_error(x, ptr, err) \ ({ \ + pax_open_userland(); \ __put_user_err((x), (ptr), err); \ + pax_close_userland(); \ (void) 0; \ }) @@ -490,35 +535,41 @@ do { \ #ifdef CONFIG_MMU -extern unsigned long __must_check +extern unsigned long __must_check __size_overflow(3) arm_copy_from_user(void *to, const void __user *from, unsigned long n); -static inline unsigned long __must_check +static inline unsigned long __must_check __size_overflow(3) __copy_from_user(void *to, const void __user *from, unsigned long n) { - unsigned int __ua_flags = uaccess_save_and_enable(); + unsigned int __ua_flags; + + check_object_size(to, n, false); + __ua_flags = uaccess_save_and_enable(); n = arm_copy_from_user(to, from, n); uaccess_restore(__ua_flags); return n; } -extern unsigned long __must_check +extern unsigned long __must_check __size_overflow(3) arm_copy_to_user(void __user *to, const void *from, unsigned long n); -extern unsigned long __must_check +extern unsigned long __must_check __size_overflow(3) __copy_to_user_std(void __user *to, const void *from, unsigned long n); static inline unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n) { - unsigned int __ua_flags = uaccess_save_and_enable(); + unsigned int __ua_flags; + + check_object_size(from, n, true); + __ua_flags = uaccess_save_and_enable(); n = arm_copy_to_user(to, from, n); uaccess_restore(__ua_flags); return n; } -extern unsigned long __must_check +extern unsigned long __must_check __size_overflow(2) arm_clear_user(void __user *addr, unsigned long n); -extern unsigned long __must_check +extern unsigned long __must_check __size_overflow(2) __clear_user_std(void __user *addr, unsigned long n); static inline unsigned long __must_check @@ -538,6 +589,9 @@ __clear_user(void __user *addr, unsigned long n) static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) { + if ((long)n < 0) + return n; + if (access_ok(VERIFY_READ, from, n)) n = __copy_from_user(to, from, n); else /* security hole - plug it */ @@ -547,6 +601,9 @@ static inline unsigned long __must_check copy_from_user(void *to, const void __u static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) { + if ((long)n < 0) + return n; + if (access_ok(VERIFY_WRITE, to, n)) n = __copy_to_user(to, from, n); return n; diff --git a/arch/arm/include/uapi/asm/ptrace.h b/arch/arm/include/uapi/asm/ptrace.h index 5af0ed1..cea83883 100644 --- a/arch/arm/include/uapi/asm/ptrace.h +++ b/arch/arm/include/uapi/asm/ptrace.h @@ -92,7 +92,7 @@ * ARMv7 groups of PSR bits */ #define APSR_MASK 0xf80f0000 /* N, Z, C, V, Q and GE flags */ -#define PSR_ISET_MASK 0x01000010 /* ISA state (J, T) mask */ +#define PSR_ISET_MASK 0x01000020 /* ISA state (J, T) mask */ #define PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */ #define PSR_ENDIAN_MASK 0x00000200 /* Endianness state mask */ diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index f89811f..1d110d1 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -58,7 +58,7 @@ EXPORT_SYMBOL(arm_delay_ops); /* networking */ EXPORT_SYMBOL(csum_partial); -EXPORT_SYMBOL(csum_partial_copy_from_user); +EXPORT_SYMBOL(__csum_partial_copy_from_user); EXPORT_SYMBOL(csum_partial_copy_nocheck); EXPORT_SYMBOL(__csum_ipv6_magic); diff --git a/arch/arm/kernel/cpuidle.c b/arch/arm/kernel/cpuidle.c index 318da33..373689f 100644 --- a/arch/arm/kernel/cpuidle.c +++ b/arch/arm/kernel/cpuidle.c @@ -19,7 +19,7 @@ extern struct of_cpuidle_method __cpuidle_method_of_table[]; static const struct of_cpuidle_method __cpuidle_method_of_table_sentinel __used __section(__cpuidle_method_of_table_end); -static struct cpuidle_ops cpuidle_ops[NR_CPUS]; +static struct cpuidle_ops cpuidle_ops[NR_CPUS] __read_only; /** * arm_cpuidle_simple_enter() - a wrapper to cpu_do_idle() diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 3e1c26e..9ea61e6 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -50,6 +50,87 @@ 9997: .endm + .macro pax_enter_kernel +#if defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) + @ make aligned space for saved DACR + sub sp, sp, #8 + @ save regs + stmdb sp!, {r1, r2} + @ read DACR from cpu_domain into r1 + mov r2, sp + @ assume 8K pages, since we have to split the immediate in two + bic r2, r2, #(0x1fc0) + bic r2, r2, #(0x3f) + ldr r1, [r2, #TI_CPU_DOMAIN] + @ store old DACR on stack + str r1, [sp, #8] +#ifdef CONFIG_PAX_KERNEXEC + @ set type of DOMAIN_KERNEL to DOMAIN_KERNELCLIENT + bic r1, r1, #(domain_val(DOMAIN_KERNEL, 3)) + orr r1, r1, #(domain_val(DOMAIN_KERNEL, DOMAIN_KERNELCLIENT)) +#endif +#ifdef CONFIG_PAX_MEMORY_UDEREF + @ set current DOMAIN_USER to DOMAIN_NOACCESS + bic r1, r1, #(domain_val(DOMAIN_USER, 3)) +#endif + @ write r1 to current_thread_info()->cpu_domain + str r1, [r2, #TI_CPU_DOMAIN] + @ write r1 to DACR + mcr p15, 0, r1, c3, c0, 0 + @ instruction sync + instr_sync + @ restore regs + ldmia sp!, {r1, r2} +#endif + .endm + + .macro pax_open_userland +#ifdef CONFIG_PAX_MEMORY_UDEREF + @ save regs + stmdb sp!, {r0, r1} + @ read DACR from cpu_domain into r1 + mov r0, sp + @ assume 8K pages, since we have to split the immediate in two + bic r0, r0, #(0x1fc0) + bic r0, r0, #(0x3f) + ldr r1, [r0, #TI_CPU_DOMAIN] + @ set current DOMAIN_USER to DOMAIN_CLIENT + bic r1, r1, #(domain_val(DOMAIN_USER, 3)) + orr r1, r1, #(domain_val(DOMAIN_USER, DOMAIN_UDEREF)) + @ write r1 to current_thread_info()->cpu_domain + str r1, [r0, #TI_CPU_DOMAIN] + @ write r1 to DACR + mcr p15, 0, r1, c3, c0, 0 + @ instruction sync + instr_sync + @ restore regs + ldmia sp!, {r0, r1} +#endif + .endm + + .macro pax_close_userland +#ifdef CONFIG_PAX_MEMORY_UDEREF + @ save regs + stmdb sp!, {r0, r1} + @ read DACR from cpu_domain into r1 + mov r0, sp + @ assume 8K pages, since we have to split the immediate in two + bic r0, r0, #(0x1fc0) + bic r0, r0, #(0x3f) + ldr r1, [r0, #TI_CPU_DOMAIN] + @ set current DOMAIN_USER to DOMAIN_NOACCESS + bic r1, r1, #(domain_val(DOMAIN_USER, 3)) + @ write r1 to current_thread_info()->cpu_domain + str r1, [r0, #TI_CPU_DOMAIN] + @ write r1 to DACR + mcr p15, 0, r1, c3, c0, 0 + @ instruction sync + instr_sync + @ restore regs + ldmia sp!, {r0, r1} +#endif + .endm + .macro pabt_helper @ PABORT handler takes pt_regs in r2, fault address in r4 and psr in r5 #ifdef MULTI_PABORT @@ -92,11 +173,15 @@ * Invalid mode handlers */ .macro inv_entry, reason + + pax_enter_kernel + sub sp, sp, #S_FRAME_SIZE ARM( stmib sp, {r1 - lr} ) THUMB( stmia sp, {r0 - r12} ) THUMB( str sp, [sp, #S_SP] ) THUMB( str lr, [sp, #S_LR] ) + mov r1, #\reason .endm @@ -152,6 +237,9 @@ ENDPROC(__und_invalid) .macro svc_entry, stack_hole=0, trace=1, uaccess=1 UNWIND(.fnstart ) UNWIND(.save {r0 - pc} ) + + pax_enter_kernel + sub sp, sp, #(S_FRAME_SIZE + 8 + \stack_hole - 4) #ifdef CONFIG_THUMB2_KERNEL SPFIX( str r0, [sp] ) @ temporarily saved @@ -167,7 +255,12 @@ ENDPROC(__und_invalid) ldmia r0, {r3 - r5} add r7, sp, #S_SP - 4 @ here for interlock avoidance mov r6, #-1 @ "" "" "" "" +#if defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) + @ offset sp by 8 as done in pax_enter_kernel + add r2, sp, #(S_FRAME_SIZE + \stack_hole + 4) +#else add r2, sp, #(S_FRAME_SIZE + 8 + \stack_hole - 4) +#endif SPFIX( addeq r2, r2, #4 ) str r3, [sp, #-4]! @ save the "real" r0 copied @ from the exception stack @@ -376,6 +469,9 @@ ENDPROC(__fiq_abt) .macro usr_entry, trace=1, uaccess=1 UNWIND(.fnstart ) UNWIND(.cantunwind ) @ don't unwind the user space + + pax_enter_kernel_user + sub sp, sp, #S_FRAME_SIZE ARM( stmib sp, {r1 - r12} ) THUMB( stmia sp, {r0 - r12} ) @@ -490,7 +586,9 @@ __und_usr: tst r3, #PSR_T_BIT @ Thumb mode? bne __und_usr_thumb sub r4, r2, #4 @ ARM instr at LR - 4 + pax_open_userland 1: ldrt r0, [r4] + pax_close_userland ARM_BE8(rev r0, r0) @ little endian instruction uaccess_disable ip @@ -526,11 +624,15 @@ __und_usr_thumb: */ .arch armv6t2 #endif + pax_open_userland 2: ldrht r5, [r4] + pax_close_userland ARM_BE8(rev16 r5, r5) @ little endian instruction cmp r5, #0xe800 @ 32bit instruction if xx != 0 blo __und_usr_fault_16_pan @ 16bit undefined instruction + pax_open_userland 3: ldrht r0, [r2] + pax_close_userland ARM_BE8(rev16 r0, r0) @ little endian instruction uaccess_disable ip add r2, r2, #2 @ r2 is PC + 2, make it PC + 4 @@ -561,7 +663,8 @@ ENDPROC(__und_usr) */ .pushsection .text.fixup, "ax" .align 2 -4: str r4, [sp, #S_PC] @ retry current instruction +4: pax_close_userland + str r4, [sp, #S_PC] @ retry current instruction ret r9 .popsection .pushsection __ex_table,"a" @@ -783,7 +886,7 @@ ENTRY(__switch_to) THUMB( str lr, [ip], #4 ) ldr r4, [r2, #TI_TP_VALUE] ldr r5, [r2, #TI_TP_VALUE + 4] -#ifdef CONFIG_CPU_USE_DOMAINS +#if defined(CONFIG_CPU_USE_DOMAINS) || defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) mrc p15, 0, r6, c3, c0, 0 @ Get domain register str r6, [r1, #TI_CPU_DOMAIN] @ Save old domain register ldr r6, [r2, #TI_CPU_DOMAIN] @@ -794,7 +897,7 @@ ENTRY(__switch_to) ldr r8, =__stack_chk_guard ldr r7, [r7, #TSK_STACK_CANARY] #endif -#ifdef CONFIG_CPU_USE_DOMAINS +#if defined(CONFIG_CPU_USE_DOMAINS) || defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) mcr p15, 0, r6, c3, c0, 0 @ Set domain register #endif mov r5, r0 diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 30a7228..d071196 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -11,18 +11,46 @@ #include #include #include +#include #include +#include "entry-header.S" + #ifdef CONFIG_NEED_RET_TO_USER #include #else .macro arch_ret_to_user, tmp1, tmp2 +#if defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) + @ save regs + stmdb sp!, {r1, r2} + @ read DACR from cpu_domain into r1 + mov r2, sp + @ assume 8K pages, since we have to split the immediate in two + bic r2, r2, #(0x1fc0) + bic r2, r2, #(0x3f) + ldr r1, [r2, #TI_CPU_DOMAIN] +#ifdef CONFIG_PAX_KERNEXEC + @ set type of DOMAIN_KERNEL to DOMAIN_KERNELCLIENT + bic r1, r1, #(domain_val(DOMAIN_KERNEL, 3)) + orr r1, r1, #(domain_val(DOMAIN_KERNEL, DOMAIN_KERNELCLIENT)) +#endif +#ifdef CONFIG_PAX_MEMORY_UDEREF + @ set current DOMAIN_USER to DOMAIN_UDEREF + bic r1, r1, #(domain_val(DOMAIN_USER, 3)) + orr r1, r1, #(domain_val(DOMAIN_USER, DOMAIN_UDEREF)) +#endif + @ write r1 to current_thread_info()->cpu_domain + str r1, [r2, #TI_CPU_DOMAIN] + @ write r1 to DACR + mcr p15, 0, r1, c3, c0, 0 + @ instruction sync + instr_sync + @ restore regs + ldmia sp!, {r1, r2} +#endif .endm #endif -#include "entry-header.S" - - .align 5 #if !(IS_ENABLED(CONFIG_TRACE_IRQFLAGS) || IS_ENABLED(CONFIG_CONTEXT_TRACKING)) /* @@ -36,7 +64,9 @@ ret_fast_syscall: UNWIND(.cantunwind ) disable_irq_notrace @ disable interrupts ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing - tst r1, #_TIF_SYSCALL_WORK | _TIF_WORK_MASK + tst r1, #_TIF_SYSCALL_WORK + bne fast_work_pending + tst r1, #_TIF_WORK_MASK bne fast_work_pending /* perform architecture specific actions before user return */ @@ -62,7 +92,9 @@ ret_fast_syscall: str r0, [sp, #S_R0 + S_OFF]! @ save returned r0 disable_irq_notrace @ disable interrupts ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing - tst r1, #_TIF_SYSCALL_WORK | _TIF_WORK_MASK + tst r1, #_TIF_SYSCALL_WORK + bne __sys_trace_return_nosave + tst r1, #_TIF_WORK_MASK beq no_work_pending UNWIND(.fnend ) ENDPROC(ret_fast_syscall) @@ -199,6 +231,12 @@ ENTRY(vector_swi) uaccess_disable tbl + /* + * do this here to avoid a performance hit of wrapping the code above + * that directly dereferences userland to parse the SWI instruction + */ + pax_enter_kernel_user + adr tbl, sys_call_table @ load syscall table pointer #if defined(CONFIG_OABI_COMPAT) diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 0d22ad2..d776aa0 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -196,6 +196,59 @@ msr cpsr_c, \rtemp @ switch back to the SVC mode .endm + .macro pax_enter_kernel_user +#if defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) + @ save regs + stmdb sp!, {r0, r1} + @ read DACR from cpu_domain into r1 + mov r0, sp + @ assume 8K pages, since we have to split the immediate in two + bic r0, r0, #(0x1fc0) + bic r0, r0, #(0x3f) + ldr r1, [r0, #TI_CPU_DOMAIN] +#ifdef CONFIG_PAX_MEMORY_UDEREF + @ set current DOMAIN_USER to DOMAIN_NOACCESS + bic r1, r1, #(domain_val(DOMAIN_USER, 3)) +#endif +#ifdef CONFIG_PAX_KERNEXEC + @ set current DOMAIN_KERNEL to DOMAIN_KERNELCLIENT + bic r1, r1, #(domain_val(DOMAIN_KERNEL, 3)) + orr r1, r1, #(domain_val(DOMAIN_KERNEL, DOMAIN_KERNELCLIENT)) +#endif + @ write r1 to current_thread_info()->cpu_domain + str r1, [r0, #TI_CPU_DOMAIN] + @ write r1 to DACR + mcr p15, 0, r1, c3, c0, 0 + @ instruction sync + instr_sync + @ restore regs + ldmia sp!, {r0, r1} +#endif + .endm + + .macro pax_exit_kernel +#if defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) + @ save regs + stmdb sp!, {r0, r1} + @ read old DACR from stack into r1 + ldr r1, [sp, #(8 + S_SP)] + sub r1, r1, #8 + ldr r1, [r1] + + @ write r1 to current_thread_info()->cpu_domain + mov r0, sp + @ assume 8K pages, since we have to split the immediate in two + bic r0, r0, #(0x1fc0) + bic r0, r0, #(0x3f) + str r1, [r0, #TI_CPU_DOMAIN] + @ write r1 to DACR + mcr p15, 0, r1, c3, c0, 0 + @ instruction sync + instr_sync + @ restore regs + ldmia sp!, {r0, r1} +#endif + .endm .macro svc_exit, rpsr, irq = 0 .if \irq != 0 @@ -217,6 +270,8 @@ .endif uaccess_restore + pax_exit_kernel + #ifndef CONFIG_THUMB2_KERNEL @ ARM mode SVC restore msr spsr_cxsf, \rpsr diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c index 059c3da..8e45cfc 100644 --- a/arch/arm/kernel/fiq.c +++ b/arch/arm/kernel/fiq.c @@ -95,7 +95,10 @@ void set_fiq_handler(void *start, unsigned int length) void *base = vectors_page; unsigned offset = FIQ_OFFSET; + pax_open_kernel(); memcpy(base + offset, start, length); + pax_close_kernel(); + if (!cache_is_vipt_nonaliasing()) flush_icache_range((unsigned long)base + offset, offset + length); diff --git a/arch/arm/kernel/module-plts.c b/arch/arm/kernel/module-plts.c index 097e2e2..3927085 100644 --- a/arch/arm/kernel/module-plts.c +++ b/arch/arm/kernel/module-plts.c @@ -30,17 +30,12 @@ struct plt_entries { u32 lit[PLT_ENT_COUNT]; }; -static bool in_init(const struct module *mod, u32 addr) -{ - return addr - (u32)mod->module_init < mod->init_size; -} - u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val) { struct plt_entries *plt, *plt_end; int c, *count; - if (in_init(mod, loc)) { + if (within_module_init(loc, mod)) { plt = (void *)mod->arch.init_plt->sh_addr; plt_end = (void *)plt + mod->arch.init_plt->sh_size; count = &mod->arch.init_plt_count; diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index efdddcb..35e58f6 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c @@ -38,17 +38,47 @@ #endif #ifdef CONFIG_MMU -void *module_alloc(unsigned long size) +static inline void *__module_alloc(unsigned long size, pgprot_t prot) { - void *p = __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, - GFP_KERNEL, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE, + void *p; + + if (!size || (!IS_ENABLED(CONFIG_ARM_MODULE_PLTS) && PAGE_ALIGN(size) > MODULES_END - MODULES_VADDR)) + return NULL; + + p = __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, + GFP_KERNEL, prot, 0, NUMA_NO_NODE, __builtin_return_address(0)); if (!IS_ENABLED(CONFIG_ARM_MODULE_PLTS) || p) return p; return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END, - GFP_KERNEL, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE, + GFP_KERNEL, prot, 0, NUMA_NO_NODE, __builtin_return_address(0)); } + +void *module_alloc(unsigned long size) +{ + +#ifdef CONFIG_PAX_KERNEXEC + return __module_alloc(size, PAGE_KERNEL); +#else + return __module_alloc(size, PAGE_KERNEL_EXEC); +#endif + +} + +#ifdef CONFIG_PAX_KERNEXEC +void module_memfree_exec(void *module_region) +{ + module_memfree(module_region); +} +EXPORT_SYMBOL(module_memfree_exec); + +void *module_alloc_exec(unsigned long size) +{ + return __module_alloc(size, PAGE_KERNEL_EXEC); +} +EXPORT_SYMBOL(module_alloc_exec); +#endif #endif int diff --git a/arch/arm/kernel/patch.c b/arch/arm/kernel/patch.c index 69bda1a..755113a 100644 --- a/arch/arm/kernel/patch.c +++ b/arch/arm/kernel/patch.c @@ -66,6 +66,7 @@ void __kprobes __patch_text_real(void *addr, unsigned int insn, bool remap) else __acquire(&patch_lock); + pax_open_kernel(); if (thumb2 && __opcode_is_thumb16(insn)) { *(u16 *)waddr = __opcode_to_mem_thumb16(insn); size = sizeof(u16); @@ -97,6 +98,7 @@ void __kprobes __patch_text_real(void *addr, unsigned int insn, bool remap) *(u32 *)waddr = insn; size = sizeof(u32); } + pax_close_kernel(); if (waddr != addr) { flush_kernel_vmap_range(waddr, twopage ? size / 2 : size); diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 7a7c4ce..bc91093 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -98,8 +98,8 @@ void __show_regs(struct pt_regs *regs) show_regs_print_info(KERN_DEFAULT); - print_symbol("PC is at %s\n", instruction_pointer(regs)); - print_symbol("LR is at %s\n", regs->ARM_lr); + printk("PC is at %pA\n", (void *)instruction_pointer(regs)); + printk("LR is at %pA\n", (void *)regs->ARM_lr); printk("pc : [<%08lx>] lr : [<%08lx>] psr: %08lx\n" "sp : %08lx ip : %08lx fp : %08lx\n", regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr, @@ -309,12 +309,6 @@ unsigned long get_wchan(struct task_struct *p) return 0; } -unsigned long arch_randomize_brk(struct mm_struct *mm) -{ - unsigned long range_end = mm->brk + 0x02000000; - return randomize_range(mm->brk, range_end, 0) ? : mm->brk; -} - #ifdef CONFIG_MMU #ifdef CONFIG_KUSER_HELPERS /* @@ -330,7 +324,7 @@ static struct vm_area_struct gate_vma = { static int __init gate_vma_init(void) { - gate_vma.vm_page_prot = PAGE_READONLY_EXEC; + gate_vma.vm_page_prot = vm_get_page_prot(gate_vma.vm_flags); return 0; } arch_initcall(gate_vma_init); @@ -359,91 +353,13 @@ const char *arch_vma_name(struct vm_area_struct *vma) return is_gate_vma(vma) ? "[vectors]" : NULL; } -/* If possible, provide a placement hint at a random offset from the - * stack for the sigpage and vdso pages. - */ -static unsigned long sigpage_addr(const struct mm_struct *mm, - unsigned int npages) -{ - unsigned long offset; - unsigned long first; - unsigned long last; - unsigned long addr; - unsigned int slots; - - first = PAGE_ALIGN(mm->start_stack); - - last = TASK_SIZE - (npages << PAGE_SHIFT); - - /* No room after stack? */ - if (first > last) - return 0; - - /* Just enough room? */ - if (first == last) - return first; - - slots = ((last - first) >> PAGE_SHIFT) + 1; - - offset = get_random_int() % slots; - - addr = first + (offset << PAGE_SHIFT); - - return addr; -} - -static struct page *signal_page; -extern struct page *get_signal_page(void); - -static const struct vm_special_mapping sigpage_mapping = { - .name = "[sigpage]", - .pages = &signal_page, -}; - int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - unsigned long npages; - unsigned long addr; - unsigned long hint; - int ret = 0; - - if (!signal_page) - signal_page = get_signal_page(); - if (!signal_page) - return -ENOMEM; - - npages = 1; /* for sigpage */ - npages += vdso_total_pages; down_write(&mm->mmap_sem); - hint = sigpage_addr(mm, npages); - addr = get_unmapped_area(NULL, hint, npages << PAGE_SHIFT, 0, 0); - if (IS_ERR_VALUE(addr)) { - ret = addr; - goto up_fail; - } - - vma = _install_special_mapping(mm, addr, PAGE_SIZE, - VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, - &sigpage_mapping); - - if (IS_ERR(vma)) { - ret = PTR_ERR(vma); - goto up_fail; - } - - mm->context.sigpage = addr; - - /* Unlike the sigpage, failure to install the vdso is unlikely - * to be fatal to the process, so no error check needed - * here. - */ - arm_install_vdso(mm, addr + PAGE_SIZE); - - up_fail: + mm->context.sigpage = (PAGE_OFFSET + (get_random_int() % 0x3FFEFFE0)) & 0xFFFFFFFC; up_write(&mm->mmap_sem); - return ret; + return 0; } #endif diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index ef9119f..31995a3 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -928,10 +928,19 @@ static void tracehook_report_syscall(struct pt_regs *regs, regs->ARM_ip = ip; } +#ifdef CONFIG_GRKERNSEC_SETXID +extern void gr_delayed_cred_worker(void); +#endif + asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno) { current_thread_info()->syscall = scno; +#ifdef CONFIG_GRKERNSEC_SETXID + if (unlikely(test_and_clear_thread_flag(TIF_GRSEC_SETXID))) + gr_delayed_cred_worker(); +#endif + /* Do the secure computing check first; failures should be fast. */ #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER if (secure_computing() == -1) diff --git a/arch/arm/kernel/reboot.c b/arch/arm/kernel/reboot.c index 3826935..8ed63ed 100644 --- a/arch/arm/kernel/reboot.c +++ b/arch/arm/kernel/reboot.c @@ -122,6 +122,7 @@ void machine_power_off(void) if (pm_power_off) pm_power_off(); + while (1); } /* diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 20edd34..e18ac81 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -110,21 +110,23 @@ EXPORT_SYMBOL(elf_hwcap); unsigned int elf_hwcap2 __read_mostly; EXPORT_SYMBOL(elf_hwcap2); +pteval_t __supported_pte_mask __read_only; +pmdval_t __supported_pmd_mask __read_only; #ifdef MULTI_CPU -struct processor processor __read_mostly; +struct processor processor __read_only; #endif #ifdef MULTI_TLB -struct cpu_tlb_fns cpu_tlb __read_mostly; +struct cpu_tlb_fns cpu_tlb __read_only; #endif #ifdef MULTI_USER -struct cpu_user_fns cpu_user __read_mostly; +struct cpu_user_fns cpu_user __read_only; #endif #ifdef MULTI_CACHE -struct cpu_cache_fns cpu_cache __read_mostly; +struct cpu_cache_fns cpu_cache __read_only; #endif #ifdef CONFIG_OUTER_CACHE -struct outer_cache_fns outer_cache __read_mostly; +struct outer_cache_fns outer_cache __read_only; EXPORT_SYMBOL(outer_cache); #endif @@ -255,9 +257,13 @@ static int __get_cpu_architecture(void) * Register 0 and check for VMSAv7 or PMSAv7 */ unsigned int mmfr0 = read_cpuid_ext(CPUID_EXT_MMFR0); if ((mmfr0 & 0x0000000f) >= 0x00000003 || - (mmfr0 & 0x000000f0) >= 0x00000030) + (mmfr0 & 0x000000f0) >= 0x00000030) { cpu_arch = CPU_ARCH_ARMv7; - else if ((mmfr0 & 0x0000000f) == 0x00000002 || + if ((mmfr0 & 0x0000000f) == 0x00000005 || (mmfr0 & 0x0000000f) == 0x00000004) { + __supported_pte_mask |= L_PTE_PXN; + __supported_pmd_mask |= PMD_PXNTABLE; + } + } else if ((mmfr0 & 0x0000000f) == 0x00000002 || (mmfr0 & 0x000000f0) == 0x00000020) cpu_arch = CPU_ARCH_ARMv6; else diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 7b8f214..ece8e28 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -24,8 +24,6 @@ extern const unsigned long sigreturn_codes[7]; -static unsigned long signal_return_offset; - #ifdef CONFIG_CRUNCH static int preserve_crunch_context(struct crunch_sigframe __user *frame) { @@ -388,8 +386,7 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig, * except when the MPU has protected the vectors * page from PL0 */ - retcode = mm->context.sigpage + signal_return_offset + - (idx << 2) + thumb; + retcode = mm->context.sigpage + (idx << 2) + thumb; } else #endif { @@ -601,33 +598,3 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) } while (thread_flags & _TIF_WORK_MASK); return 0; } - -struct page *get_signal_page(void) -{ - unsigned long ptr; - unsigned offset; - struct page *page; - void *addr; - - page = alloc_pages(GFP_KERNEL, 0); - - if (!page) - return NULL; - - addr = page_address(page); - - /* Give the signal return code some randomness */ - offset = 0x200 + (get_random_int() & 0x7fc); - signal_return_offset = offset; - - /* - * Copy signal return handlers into the vector page, and - * set sigreturn to be a pointer to these. - */ - memcpy(addr + offset, sigreturn_codes, sizeof(sigreturn_codes)); - - ptr = (unsigned long)addr + offset; - flush_icache_range(ptr, ptr + sizeof(sigreturn_codes)); - - return page; -} diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 48185a7..426ae3a 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -78,7 +78,7 @@ enum ipi_msg_type { static DECLARE_COMPLETION(cpu_running); -static struct smp_operations smp_ops; +static struct smp_operations smp_ops __read_only; void __init smp_set_ops(struct smp_operations *ops) { diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index b83f3b7..087acb5 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c @@ -193,15 +193,44 @@ struct oabi_flock64 { pid_t l_pid; } __attribute__ ((packed,aligned(4))); -asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd, +static long do_locks(unsigned int fd, unsigned int cmd, unsigned long arg) { - struct oabi_flock64 user; struct flock64 kernel; - mm_segment_t fs = USER_DS; /* initialized to kill a warning */ - unsigned long local_arg = arg; - int ret; + struct oabi_flock64 user; + mm_segment_t fs; + long ret; + if (copy_from_user(&user, (struct oabi_flock64 __user *)arg, + sizeof(user))) + return -EFAULT; + kernel.l_type = user.l_type; + kernel.l_whence = user.l_whence; + kernel.l_start = user.l_start; + kernel.l_len = user.l_len; + kernel.l_pid = user.l_pid; + + fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_fcntl64(fd, cmd, (unsigned long)&kernel); + set_fs(fs); + + if (!ret && (cmd == F_GETLK64 || cmd == F_OFD_GETLK)) { + user.l_type = kernel.l_type; + user.l_whence = kernel.l_whence; + user.l_start = kernel.l_start; + user.l_len = kernel.l_len; + user.l_pid = kernel.l_pid; + if (copy_to_user((struct oabi_flock64 __user *)arg, + &user, sizeof(user))) + ret = -EFAULT; + } + return ret; +} + +asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd, + unsigned long arg) +{ switch (cmd) { case F_OFD_GETLK: case F_OFD_SETLK: @@ -209,39 +238,11 @@ asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd, case F_GETLK64: case F_SETLK64: case F_SETLKW64: - if (copy_from_user(&user, (struct oabi_flock64 __user *)arg, - sizeof(user))) - return -EFAULT; - kernel.l_type = user.l_type; - kernel.l_whence = user.l_whence; - kernel.l_start = user.l_start; - kernel.l_len = user.l_len; - kernel.l_pid = user.l_pid; - local_arg = (unsigned long)&kernel; - fs = get_fs(); - set_fs(KERNEL_DS); - } - - ret = sys_fcntl64(fd, cmd, local_arg); + return do_locks(fd, cmd, arg); - switch (cmd) { - case F_GETLK64: - if (!ret) { - user.l_type = kernel.l_type; - user.l_whence = kernel.l_whence; - user.l_start = kernel.l_start; - user.l_len = kernel.l_len; - user.l_pid = kernel.l_pid; - if (copy_to_user((struct oabi_flock64 __user *)arg, - &user, sizeof(user))) - ret = -EFAULT; - } - case F_SETLK64: - case F_SETLKW64: - set_fs(fs); + default: + return sys_fcntl64(fd, cmd, arg); } - - return ret; } struct oabi_epoll_event { diff --git a/arch/arm/kernel/tcm.c b/arch/arm/kernel/tcm.c index b10e136..cb5edf9 100644 --- a/arch/arm/kernel/tcm.c +++ b/arch/arm/kernel/tcm.c @@ -64,7 +64,7 @@ static struct map_desc itcm_iomap[] __initdata = { .virtual = ITCM_OFFSET, .pfn = __phys_to_pfn(ITCM_OFFSET), .length = 0, - .type = MT_MEMORY_RWX_ITCM, + .type = MT_MEMORY_RX_ITCM, } }; @@ -362,7 +362,9 @@ no_dtcm: start = &__sitcm_text; end = &__eitcm_text; ram = &__itcm_start; + pax_open_kernel(); memcpy(start, ram, itcm_code_sz); + pax_close_kernel(); pr_debug("CPU ITCM: copied code from %p - %p\n", start, end); itcm_present = true; diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 969f9d9..8a96d0d 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -65,7 +65,7 @@ static void dump_mem(const char *, const char *, unsigned long, unsigned long); void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame) { #ifdef CONFIG_KALLSYMS - printk("[<%08lx>] (%ps) from [<%08lx>] (%pS)\n", where, (void *)where, from, (void *)from); + printk("[<%08lx>] (%pA) from [<%08lx>] (%pA)\n", where, (void *)where, from, (void *)from); #else printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from); #endif @@ -267,6 +267,8 @@ static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED; static int die_owner = -1; static unsigned int die_nest_count; +extern void gr_handle_kernel_exploit(void); + static unsigned long oops_begin(void) { int cpu; @@ -309,6 +311,9 @@ static void oops_end(unsigned long flags, struct pt_regs *regs, int signr) panic("Fatal exception in interrupt"); if (panic_on_oops) panic("Fatal exception"); + + gr_handle_kernel_exploit(); + if (signr) do_exit(signr); } diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 8b60fde..8d986dd 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -37,7 +37,7 @@ #endif #if (defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)) || \ - defined(CONFIG_GENERIC_BUG) + defined(CONFIG_GENERIC_BUG) || defined(CONFIG_PAX_REFCOUNT) #define ARM_EXIT_KEEP(x) x #define ARM_EXIT_DISCARD(x) #else @@ -120,6 +120,8 @@ SECTIONS #ifdef CONFIG_DEBUG_RODATA . = ALIGN(1<arch.vmid_gen != atomic64_read(&kvm_vmid_gen)); + return unlikely(kvm->arch.vmid_gen != atomic64_read_unchecked(&kvm_vmid_gen)); } /** @@ -402,7 +402,7 @@ static void update_vttbr(struct kvm *kvm) /* First user of a new VMID generation? */ if (unlikely(kvm_next_vmid == 0)) { - atomic64_inc(&kvm_vmid_gen); + atomic64_inc_unchecked(&kvm_vmid_gen); kvm_next_vmid = 1; /* @@ -419,7 +419,7 @@ static void update_vttbr(struct kvm *kvm) kvm_call_hyp(__kvm_flush_vm_context); } - kvm->arch.vmid_gen = atomic64_read(&kvm_vmid_gen); + kvm->arch.vmid_gen = atomic64_read_unchecked(&kvm_vmid_gen); kvm->arch.vmid = kvm_next_vmid; kvm_next_vmid++; diff --git a/arch/arm/lib/copy_page.S b/arch/arm/lib/copy_page.S index 6ee2f67..d1cce76 100644 --- a/arch/arm/lib/copy_page.S +++ b/arch/arm/lib/copy_page.S @@ -10,6 +10,7 @@ * ASM optimised string functions */ #include +#include #include #include #include diff --git a/arch/arm/lib/csumpartialcopyuser.S b/arch/arm/lib/csumpartialcopyuser.S index 1712f13..a3165dc 100644 --- a/arch/arm/lib/csumpartialcopyuser.S +++ b/arch/arm/lib/csumpartialcopyuser.S @@ -71,8 +71,8 @@ * Returns : r0 = checksum, [[sp, #0], #0] = 0 or -EFAULT */ -#define FN_ENTRY ENTRY(csum_partial_copy_from_user) -#define FN_EXIT ENDPROC(csum_partial_copy_from_user) +#define FN_ENTRY ENTRY(__csum_partial_copy_from_user) +#define FN_EXIT ENDPROC(__csum_partial_copy_from_user) #include "csumpartialcopygeneric.S" diff --git a/arch/arm/lib/delay.c b/arch/arm/lib/delay.c index 8044591..c9b2609 100644 --- a/arch/arm/lib/delay.c +++ b/arch/arm/lib/delay.c @@ -29,7 +29,7 @@ /* * Default to the loop-based delay implementation. */ -struct arm_delay_ops arm_delay_ops = { +struct arm_delay_ops arm_delay_ops __read_only = { .delay = __loop_delay, .const_udelay = __loop_const_udelay, .udelay = __loop_udelay, diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c index d72b909..0521929 100644 --- a/arch/arm/lib/uaccess_with_memcpy.c +++ b/arch/arm/lib/uaccess_with_memcpy.c @@ -85,7 +85,7 @@ pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp) return 1; } -static unsigned long noinline +static unsigned long noinline __size_overflow(3) __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n) { int atomic; @@ -150,7 +150,7 @@ arm_copy_to_user(void __user *to, const void *from, unsigned long n) return __copy_to_user_memcpy(to, from, n); } -static unsigned long noinline +static unsigned long noinline __size_overflow(2) __clear_user_memset(void __user *addr, unsigned long n) { if (unlikely(segment_eq(get_fs(), KERNEL_DS))) { diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c index e00eb39..0f95491 100644 --- a/arch/arm/mach-exynos/suspend.c +++ b/arch/arm/mach-exynos/suspend.c @@ -730,8 +730,10 @@ void __init exynos_pm_init(void) tmp |= pm_data->wake_disable_mask; pmu_raw_writel(tmp, S5P_WAKEUP_MASK); - 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; + pax_close_kernel(); register_syscore_ops(&exynos_pm_syscore_ops); suspend_set_ops(&exynos_suspend_ops); diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index 44eedf3..13a0528 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -105,7 +105,7 @@ static void __init armada_370_coherency_init(struct device_node *np) /* * This ioremap hook is used on Armada 375/38x to ensure that PCIe - * memory areas are mapped as MT_UNCACHED instead of MT_DEVICE. This + * memory areas are mapped as MT_UNCACHED_RW instead of MT_DEVICE. This * is needed as a workaround for a deadlock issue between the PCIe * interface and the cache controller. */ @@ -118,7 +118,7 @@ armada_pcie_wa_ioremap_caller(phys_addr_t phys_addr, size_t size, mvebu_mbus_get_pcie_mem_aperture(&pcie_mem); if (pcie_mem.start <= phys_addr && (phys_addr + size) <= pcie_mem.end) - mtype = MT_UNCACHED; + mtype = MT_UNCACHED_RW; return __arm_ioremap_caller(phys_addr, size, mtype, caller); } diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c index b6443a4..20a0b74 100644 --- a/arch/arm/mach-omap2/board-n8x0.c +++ b/arch/arm/mach-omap2/board-n8x0.c @@ -569,7 +569,7 @@ static int n8x0_menelaus_late_init(struct device *dev) } #endif -struct menelaus_platform_data n8x0_menelaus_platform_data __initdata = { +struct menelaus_platform_data n8x0_menelaus_platform_data __initconst = { .late_init = n8x0_menelaus_late_init, }; diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c index 65024af..70bf184 100644 --- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c @@ -86,7 +86,7 @@ struct cpu_pm_ops { void (*resume)(void); void (*scu_prepare)(unsigned int cpu_id, unsigned int cpu_state); void (*hotplug_restart)(void); -}; +} __no_const; static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info); static struct powerdomain *mpuss_pd; @@ -105,7 +105,7 @@ static void dummy_cpu_resume(void) static void dummy_scu_prepare(unsigned int cpu_id, unsigned int cpu_state) {} -static struct cpu_pm_ops omap_pm_ops = { +static struct cpu_pm_ops omap_pm_ops __read_only = { .finish_suspend = default_finish_suspend, .resume = dummy_cpu_resume, .scu_prepare = dummy_scu_prepare, diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 5305ec7..6d74045 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c index e1d2e99..d9b3177 100644 --- a/arch/arm/mach-omap2/omap-wakeupgen.c +++ b/arch/arm/mach-omap2/omap-wakeupgen.c @@ -330,7 +330,7 @@ static int irq_cpu_hotplug_notify(struct notifier_block *self, return NOTIFY_OK; } -static struct notifier_block __refdata irq_hotplug_notifier = { +static struct notifier_block irq_hotplug_notifier = { .notifier_call = irq_cpu_hotplug_notify, }; diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c index 72ebc4c..18c4406 100644 --- a/arch/arm/mach-omap2/omap_device.c +++ b/arch/arm/mach-omap2/omap_device.c @@ -504,7 +504,7 @@ void omap_device_delete(struct omap_device *od) struct platform_device __init *omap_device_build(const char *pdev_name, int pdev_id, struct omap_hwmod *oh, - void *pdata, int pdata_len) + const void *pdata, int pdata_len) { struct omap_hwmod *ohs[] = { oh }; @@ -532,7 +532,7 @@ struct platform_device __init *omap_device_build(const char *pdev_name, struct platform_device __init *omap_device_build_ss(const char *pdev_name, int pdev_id, struct omap_hwmod **ohs, - int oh_cnt, void *pdata, + int oh_cnt, const void *pdata, int pdata_len) { int ret = -ENOMEM; diff --git a/arch/arm/mach-omap2/omap_device.h b/arch/arm/mach-omap2/omap_device.h index 78c02b3..c94109a 100644 --- a/arch/arm/mach-omap2/omap_device.h +++ b/arch/arm/mach-omap2/omap_device.h @@ -72,12 +72,12 @@ int omap_device_idle(struct platform_device *pdev); /* Core code interface */ struct platform_device *omap_device_build(const char *pdev_name, int pdev_id, - struct omap_hwmod *oh, void *pdata, + struct omap_hwmod *oh, const void *pdata, int pdata_len); struct platform_device *omap_device_build_ss(const char *pdev_name, int pdev_id, struct omap_hwmod **oh, int oh_cnt, - void *pdata, int pdata_len); + const void *pdata, int pdata_len); struct omap_device *omap_device_alloc(struct platform_device *pdev, struct omap_hwmod **ohs, int oh_cnt); diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index cc8a987..dab541b 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -200,10 +200,10 @@ struct omap_hwmod_soc_ops { int (*init_clkdm)(struct omap_hwmod *oh); void (*update_context_lost)(struct omap_hwmod *oh); int (*get_context_lost)(struct omap_hwmod *oh); -}; +} __no_const; /* soc_ops: adapts the omap_hwmod code to the currently-booted SoC */ -static struct omap_hwmod_soc_ops soc_ops; +static struct omap_hwmod_soc_ops soc_ops __read_only; /* 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 --- a/arch/arm/mach-omap2/powerdomains43xx_data.c +++ b/arch/arm/mach-omap2/powerdomains43xx_data.c @@ -10,6 +10,7 @@ #include #include +#include #include "powerdomain.h" @@ -129,7 +130,9 @@ static int am43xx_check_vcvp(void) void __init am43xx_powerdomains_init(void) { - omap4_pwrdm_operations.pwrdm_has_voltdm = am43xx_check_vcvp; + pax_open_kernel(); + *(void **)&omap4_pwrdm_operations.pwrdm_has_voltdm = am43xx_check_vcvp; + pax_close_kernel(); pwrdm_register_platform_funcs(&omap4_pwrdm_operations); pwrdm_register_pwrdms(powerdomains_am43xx); pwrdm_complete_init(); diff --git a/arch/arm/mach-omap2/wd_timer.c b/arch/arm/mach-omap2/wd_timer.c index ff0a68c..b312aa0 100644 --- a/arch/arm/mach-omap2/wd_timer.c +++ b/arch/arm/mach-omap2/wd_timer.c @@ -110,7 +110,9 @@ static int __init omap_init_wdt(void) struct omap_hwmod *oh; char *oh_name = "wd_timer2"; char *dev_name = "omap_wdt"; - struct omap_wd_timer_platform_data pdata; + static struct omap_wd_timer_platform_data pdata = { + .read_reset_sources = prm_read_reset_sources + }; if (!cpu_class_is_omap2() || of_have_populated_dt()) return 0; @@ -121,8 +123,6 @@ static int __init omap_init_wdt(void) return -EINVAL; } - pdata.read_reset_sources = prm_read_reset_sources; - pdev = omap_device_build(dev_name, id, oh, &pdata, 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 4e54512..ed7c349 100644 --- a/arch/arm/mach-shmobile/platsmp-apmu.c +++ b/arch/arm/mach-shmobile/platsmp-apmu.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "common.h" #include "platsmp-apmu.h" @@ -233,6 +234,8 @@ static int shmobile_smp_apmu_enter_suspend(suspend_state_t state) void __init shmobile_smp_apmu_suspend_init(void) { - shmobile_suspend_ops.enter = shmobile_smp_apmu_enter_suspend; + pax_open_kernel(); + *(void **)&shmobile_suspend_ops.enter = shmobile_smp_apmu_enter_suspend; + pax_close_kernel(); } #endif diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c index 7469347..1ecc350 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra20.c +++ b/arch/arm/mach-tegra/cpuidle-tegra20.c @@ -177,7 +177,7 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev, bool entered_lp2 = false; if (tegra_pending_sgi()) - ACCESS_ONCE(abort_flag) = true; + ACCESS_ONCE_RW(abort_flag) = true; cpuidle_coupled_parallel_barrier(dev, &abort_barrier); diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c index 3b9098d..15b390f 100644 --- a/arch/arm/mach-tegra/irq.c +++ b/arch/arm/mach-tegra/irq.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm/mach-ux500/pm.c b/arch/arm/mach-ux500/pm.c index 8538910..2f39bc4 100644 --- a/arch/arm/mach-ux500/pm.c +++ b/arch/arm/mach-ux500/pm.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include diff --git a/arch/arm/mach-zynq/platsmp.c b/arch/arm/mach-zynq/platsmp.c index f66816c..228b951 100644 --- a/arch/arm/mach-zynq/platsmp.c +++ b/arch/arm/mach-zynq/platsmp.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "common.h" diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index df7537f..b931a5f 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -446,6 +446,7 @@ config CPU_32v5 config CPU_32v6 bool + select CPU_USE_DOMAINS if CPU_V6 && MMU && !PAX_KERNEXEC && !PAX_MEMORY_UDEREF select TLS_REG_EMUL if !CPU_32v6K && !MMU config CPU_32v6K @@ -600,6 +601,7 @@ config CPU_CP15_MPU config CPU_USE_DOMAINS bool + depends on !ARM_LPAE && !PAX_KERNEXEC && !PAX_MEMORY_UDEREF help This option enables or disables the use of domain switching via the set_fs() function. @@ -818,7 +820,7 @@ config NEED_KUSER_HELPERS config KUSER_HELPERS bool "Enable kuser helpers in vector page" if !NEED_KUSER_HELPERS - depends on MMU + depends on MMU && (!(CPU_V6 || CPU_V6K || CPU_V7) || GRKERNSEC_OLD_ARM_USERLAND) default y help Warning: disabling this option may break user programs. @@ -832,7 +834,7 @@ config KUSER_HELPERS See Documentation/arm/kernel_user_helpers.txt for details. However, the fixed address nature of these helpers can be used - by ROP (return orientated programming) authors when creating + by ROP (Return Oriented Programming) authors when creating exploits. If all of the binaries and libraries which run on your platform diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index 00b7f7d..6fc28bc 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c @@ -216,10 +216,12 @@ union offset_union { #define __get16_unaligned_check(ins,val,addr) \ do { \ unsigned int err = 0, v, a = addr; \ + pax_open_userland(); \ __get8_unaligned_check(ins,v,a,err); \ val = v << ((BE) ? 8 : 0); \ __get8_unaligned_check(ins,v,a,err); \ val |= v << ((BE) ? 0 : 8); \ + pax_close_userland(); \ if (err) \ goto fault; \ } while (0) @@ -233,6 +235,7 @@ union offset_union { #define __get32_unaligned_check(ins,val,addr) \ do { \ unsigned int err = 0, v, a = addr; \ + pax_open_userland(); \ __get8_unaligned_check(ins,v,a,err); \ val = v << ((BE) ? 24 : 0); \ __get8_unaligned_check(ins,v,a,err); \ @@ -241,6 +244,7 @@ union offset_union { val |= v << ((BE) ? 8 : 16); \ __get8_unaligned_check(ins,v,a,err); \ val |= v << ((BE) ? 0 : 24); \ + pax_close_userland(); \ if (err) \ goto fault; \ } while (0) @@ -254,6 +258,7 @@ union offset_union { #define __put16_unaligned_check(ins,val,addr) \ do { \ unsigned int err = 0, v = val, a = addr; \ + pax_open_userland(); \ __asm__( FIRST_BYTE_16 \ ARM( "1: "ins" %1, [%2], #1\n" ) \ THUMB( "1: "ins" %1, [%2]\n" ) \ @@ -273,6 +278,7 @@ union offset_union { " .popsection\n" \ : "=r" (err), "=&r" (v), "=&r" (a) \ : "0" (err), "1" (v), "2" (a)); \ + pax_close_userland(); \ if (err) \ goto fault; \ } while (0) @@ -286,6 +292,7 @@ union offset_union { #define __put32_unaligned_check(ins,val,addr) \ do { \ unsigned int err = 0, v = val, a = addr; \ + pax_open_userland(); \ __asm__( FIRST_BYTE_32 \ ARM( "1: "ins" %1, [%2], #1\n" ) \ THUMB( "1: "ins" %1, [%2]\n" ) \ @@ -315,6 +322,7 @@ union offset_union { " .popsection\n" \ : "=r" (err), "=&r" (v), "=&r" (a) \ : "0" (err), "1" (v), "2" (a)); \ + pax_close_userland(); \ if (err) \ goto fault; \ } while (0) diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 493692d..42a4504 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -44,7 +44,7 @@ struct l2c_init_data { void (*configure)(void __iomem *); void (*unlock)(void __iomem *, unsigned); struct outer_cache_fns outer_cache; -}; +} __do_const; #define CACHE_LINE_SIZE 32 diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c index 845769e..4278fd7 100644 --- a/arch/arm/mm/context.c +++ b/arch/arm/mm/context.c @@ -43,7 +43,7 @@ #define NUM_USER_ASIDS ASID_FIRST_VERSION static DEFINE_RAW_SPINLOCK(cpu_asid_lock); -static atomic64_t asid_generation = ATOMIC64_INIT(ASID_FIRST_VERSION); +static atomic64_unchecked_t asid_generation = ATOMIC64_INIT(ASID_FIRST_VERSION); static DECLARE_BITMAP(asid_map, NUM_USER_ASIDS); static DEFINE_PER_CPU(atomic64_t, active_asids); @@ -178,7 +178,7 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu) { static u32 cur_idx = 1; u64 asid = atomic64_read(&mm->context.id); - u64 generation = atomic64_read(&asid_generation); + u64 generation = atomic64_read_unchecked(&asid_generation); if (asid != 0) { /* @@ -208,7 +208,7 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu) */ asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, cur_idx); if (asid == NUM_USER_ASIDS) { - generation = atomic64_add_return(ASID_FIRST_VERSION, + generation = atomic64_add_return_unchecked(ASID_FIRST_VERSION, &asid_generation); flush_context(cpu); asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, 1); @@ -240,14 +240,14 @@ void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk) cpu_set_reserved_ttbr0(); asid = atomic64_read(&mm->context.id); - if (!((asid ^ atomic64_read(&asid_generation)) >> ASID_BITS) + if (!((asid ^ atomic64_read_unchecked(&asid_generation)) >> ASID_BITS) && atomic64_xchg(&per_cpu(active_asids, cpu), asid)) goto switch_mm_fastpath; raw_spin_lock_irqsave(&cpu_asid_lock, flags); /* Check that our ASID belongs to the current generation. */ asid = atomic64_read(&mm->context.id); - if ((asid ^ atomic64_read(&asid_generation)) >> ASID_BITS) { + if ((asid ^ atomic64_read_unchecked(&asid_generation)) >> ASID_BITS) { asid = new_context(mm, cpu); atomic64_set(&mm->context.id, asid); } diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 0d629b8..f13ad33 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "fault.h" @@ -138,6 +139,31 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, if (fixup_exception(regs)) return; +#ifdef CONFIG_PAX_MEMORY_UDEREF + if (addr < TASK_SIZE) { + if (current->signal->curr_ip) + printk(KERN_EMERG "PAX: From %pI4: %s:%d, uid/euid: %u/%u, attempted to access userland memory at %08lx\n", ¤t->signal->curr_ip, current->comm, task_pid_nr(current), + from_kuid_munged(&init_user_ns, current_uid()), from_kuid_munged(&init_user_ns, current_euid()), addr); + else + printk(KERN_EMERG "PAX: %s:%d, uid/euid: %u/%u, attempted to access userland memory at %08lx\n", current->comm, task_pid_nr(current), + from_kuid_munged(&init_user_ns, current_uid()), from_kuid_munged(&init_user_ns, current_euid()), addr); + } +#endif + +#ifdef CONFIG_PAX_KERNEXEC + if ((fsr & FSR_WRITE) && + (((unsigned long)_stext <= addr && addr < init_mm.end_code) || + (MODULES_VADDR <= addr && addr < MODULES_END))) + { + if (current->signal->curr_ip) + printk(KERN_EMERG "PAX: From %pI4: %s:%d, uid/euid: %u/%u, attempted to modify kernel code\n", ¤t->signal->curr_ip, current->comm, task_pid_nr(current), + from_kuid_munged(&init_user_ns, current_uid()), from_kuid_munged(&init_user_ns, current_euid())); + else + printk(KERN_EMERG "PAX: %s:%d, uid/euid: %u/%u, attempted to modify kernel code\n", current->comm, task_pid_nr(current), + from_kuid_munged(&init_user_ns, current_uid()), from_kuid_munged(&init_user_ns, current_euid())); + } +#endif + /* * No handler, we'll have to terminate things with extreme prejudice. */ @@ -173,6 +199,13 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr, } #endif +#ifdef CONFIG_PAX_PAGEEXEC + if ((tsk->mm->pax_flags & MF_PAX_PAGEEXEC) && (fsr & FSR_LNX_PF)) { + pax_report_fault(regs, (void *)regs->ARM_pc, (void *)regs->ARM_sp); + do_group_exit(SIGKILL); + } +#endif + tsk->thread.address = addr; tsk->thread.error_code = fsr; tsk->thread.trap_no = 14; @@ -400,6 +433,33 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) } #endif /* CONFIG_MMU */ +#ifdef CONFIG_PAX_PAGEEXEC +void pax_report_insns(struct pt_regs *regs, void *pc, void *sp) +{ + long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 20; i++) { + unsigned char c; + if (get_user(c, (__force unsigned char __user *)pc+i)) + printk(KERN_CONT "?? "); + else + printk(KERN_CONT "%02x ", c); + } + printk("\n"); + + printk(KERN_ERR "PAX: bytes at SP-4: "); + for (i = -1; i < 20; i++) { + unsigned long c; + if (get_user(c, (__force unsigned long __user *)sp+i)) + printk(KERN_CONT "???????? "); + else + printk(KERN_CONT "%08lx ", c); + } + printk("\n"); +} +#endif + /* * First Level Translation Fault Handler * @@ -547,9 +607,22 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) const struct fsr_info *inf = fsr_info + fsr_fs(fsr); struct siginfo info; +#ifdef CONFIG_PAX_MEMORY_UDEREF + if (addr < TASK_SIZE && is_domain_fault(fsr)) { + if (current->signal->curr_ip) + printk(KERN_EMERG "PAX: From %pI4: %s:%d, uid/euid: %u/%u, attempted to access userland memory at %08lx\n", ¤t->signal->curr_ip, current->comm, task_pid_nr(current), + from_kuid_munged(&init_user_ns, current_uid()), from_kuid_munged(&init_user_ns, current_euid()), addr); + else + printk(KERN_EMERG "PAX: %s:%d, uid/euid: %u/%u, attempted to access userland memory at %08lx\n", current->comm, task_pid_nr(current), + from_kuid_munged(&init_user_ns, current_uid()), from_kuid_munged(&init_user_ns, current_euid()), addr); + goto die; + } +#endif + if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs)) return; +die: 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 * ifsr_info[nr].name = name; } +asmlinkage int sys_sigreturn(struct pt_regs *regs); +asmlinkage int sys_rt_sigreturn(struct pt_regs *regs); + asmlinkage void __exception do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs) { const struct fsr_info *inf = ifsr_info + fsr_fs(ifsr); struct siginfo info; + unsigned long pc = instruction_pointer(regs); + + if (user_mode(regs)) { + unsigned long sigpage = current->mm->context.sigpage; + + if (sigpage <= pc && pc < sigpage + 7*4) { + if (pc < sigpage + 3*4) + sys_sigreturn(regs); + else + sys_rt_sigreturn(regs); + return; + } + if (pc == 0xffff0f60UL) { + /* + * PaX: __kuser_cmpxchg64 emulation + */ + // TODO + //regs->ARM_pc = regs->ARM_lr; + //return; + } + if (pc == 0xffff0fa0UL) { + /* + * PaX: __kuser_memory_barrier emulation + */ + // dmb(); implied by the exception + regs->ARM_pc = regs->ARM_lr; + return; + } + if (pc == 0xffff0fc0UL) { + /* + * PaX: __kuser_cmpxchg emulation + */ + // TODO + //long new; + //int op; + + //op = FUTEX_OP_SET << 28; + //new = futex_atomic_op_inuser(op, regs->ARM_r2); + //regs->ARM_r0 = old != new; + //regs->ARM_pc = regs->ARM_lr; + //return; + } + if (pc == 0xffff0fe0UL) { + /* + * PaX: __kuser_get_tls emulation + */ + regs->ARM_r0 = current_thread_info()->tp_value[0]; + regs->ARM_pc = regs->ARM_lr; + return; + } + } + +#if defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) + else if (is_domain_fault(ifsr) || is_xn_fault(ifsr)) { + if (current->signal->curr_ip) + printk(KERN_EMERG "PAX: From %pI4: %s:%d, uid/euid: %u/%u, attempted to execute %s memory at %08lx\n", ¤t->signal->curr_ip, current->comm, task_pid_nr(current), + from_kuid_munged(&init_user_ns, current_uid()), from_kuid_munged(&init_user_ns, current_euid()), + pc >= TASK_SIZE ? "non-executable kernel" : "userland", pc); + else + printk(KERN_EMERG "PAX: %s:%d, uid/euid: %u/%u, attempted to execute %s memory at %08lx\n", current->comm, task_pid_nr(current), + from_kuid_munged(&init_user_ns, current_uid()), from_kuid_munged(&init_user_ns, current_euid()), + pc >= TASK_SIZE ? "non-executable kernel" : "userland", pc); + goto die; + } +#endif + +#ifdef CONFIG_PAX_REFCOUNT + if (fsr_fs(ifsr) == FAULT_CODE_DEBUG) { +#ifdef CONFIG_THUMB2_KERNEL + unsigned short bkpt; + + if (!probe_kernel_address(pc, bkpt) && cpu_to_le16(bkpt) == 0xbef1) { +#else + unsigned int bkpt; + + if (!probe_kernel_address(pc, bkpt) && cpu_to_le32(bkpt) == 0xe12f1073) { +#endif + current->thread.error_code = ifsr; + current->thread.trap_no = 0; + pax_report_refcount_overflow(regs); + fixup_exception(regs); + return; + } + } +#endif if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs)) return; +die: pr_alert("Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n", inf->name, ifsr, addr); diff --git a/arch/arm/mm/fault.h b/arch/arm/mm/fault.h index cf08bdf..772656c 100644 --- a/arch/arm/mm/fault.h +++ b/arch/arm/mm/fault.h @@ -3,6 +3,7 @@ /* * Fault status register encodings. We steal bit 31 for our own purposes. + * Set when the FSR value is from an instruction fault. */ #define FSR_LNX_PF (1 << 31) #define FSR_WRITE (1 << 11) @@ -22,6 +23,17 @@ static inline int fsr_fs(unsigned int fsr) } #endif +/* valid for LPAE and !LPAE */ +static inline int is_xn_fault(unsigned int fsr) +{ + return ((fsr_fs(fsr) & 0x3c) == 0xc); +} + +static inline int is_domain_fault(unsigned int fsr) +{ + return ((fsr_fs(fsr) & 0xD) == 0x9); +} + void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs); unsigned long search_exception_table(unsigned long addr); diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 8a63b4c..6b04370 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -710,7 +710,46 @@ void free_tcmmem(void) { #ifdef CONFIG_HAVE_TCM extern char __tcm_start, __tcm_end; +#endif +#ifdef CONFIG_PAX_KERNEXEC + unsigned long addr; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + int cpu_arch = cpu_architecture(); + unsigned int cr = get_cr(); + + if (cpu_arch >= CPU_ARCH_ARMv6 && (cr & CR_XP)) { + /* make pages tables, etc before .text NX */ + for (addr = PAGE_OFFSET; addr < (unsigned long)_stext; addr += SECTION_SIZE) { + pgd = pgd_offset_k(addr); + pud = pud_offset(pgd, addr); + pmd = pmd_offset(pud, addr); + __section_update(pmd, addr, PMD_SECT_XN); + } + /* make init NX */ + for (addr = (unsigned long)__init_begin; addr < (unsigned long)_sdata; addr += SECTION_SIZE) { + pgd = pgd_offset_k(addr); + pud = pud_offset(pgd, addr); + pmd = pmd_offset(pud, addr); + __section_update(pmd, addr, PMD_SECT_XN); + } + /* make kernel code/rodata RX */ + for (addr = (unsigned long)_stext; addr < (unsigned long)__init_begin; addr += SECTION_SIZE) { + pgd = pgd_offset_k(addr); + pud = pud_offset(pgd, addr); + pmd = pmd_offset(pud, addr); +#ifdef CONFIG_ARM_LPAE + __section_update(pmd, addr, PMD_SECT_RDONLY); +#else + __section_update(pmd, addr, PMD_SECT_APX|PMD_SECT_AP_WRITE); +#endif + } + } +#endif + +#ifdef CONFIG_HAVE_TCM poison_init_mem(&__tcm_start, &__tcm_end - &__tcm_start); free_reserved_area(&__tcm_start, &__tcm_end, -1, "TCM link"); #endif diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 0c81056..97279f7 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -405,9 +405,9 @@ __arm_ioremap_exec(phys_addr_t phys_addr, size_t size, bool cached) unsigned int mtype; if (cached) - mtype = MT_MEMORY_RWX; + mtype = MT_MEMORY_RX; else - mtype = MT_MEMORY_RWX_NONCACHED; + mtype = MT_MEMORY_RX_NONCACHED; return __arm_ioremap_caller(phys_addr, size, mtype, __builtin_return_address(0)); diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c index 407dc78..047ce9d 100644 --- a/arch/arm/mm/mmap.c +++ b/arch/arm/mm/mmap.c @@ -59,6 +59,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, struct vm_area_struct *vma; int do_align = 0; int aliasing = cache_is_vipt_aliasing(); + unsigned long offset = gr_rand_threadstack_offset(mm, filp, flags); struct vm_unmapped_area_info info; /* @@ -81,6 +82,10 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, if (len > TASK_SIZE) return -ENOMEM; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + if (addr) { if (do_align) addr = COLOUR_ALIGN(addr, pgoff); @@ -88,8 +93,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + if (TASK_SIZE - len >= addr && check_heap_stack_gap(vma, addr, len, offset)) return addr; } @@ -99,6 +103,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, info.high_limit = TASK_SIZE; info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0; info.align_offset = pgoff << PAGE_SHIFT; + info.threadstack_offset = offset; return vm_unmapped_area(&info); } @@ -112,6 +117,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, unsigned long addr = addr0; int do_align = 0; int aliasing = cache_is_vipt_aliasing(); + unsigned long offset = gr_rand_threadstack_offset(mm, filp, flags); struct vm_unmapped_area_info info; /* @@ -132,6 +138,10 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, return addr; } +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + /* requesting a specific address */ if (addr) { if (do_align) @@ -139,8 +149,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, else addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + if (TASK_SIZE - len >= addr && check_heap_stack_gap(vma, addr, len, offset)) return addr; } @@ -150,6 +159,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, info.high_limit = mm->mmap_base; info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0; info.align_offset = pgoff << PAGE_SHIFT; + info.threadstack_offset = offset; addr = vm_unmapped_area(&info); /* @@ -183,14 +193,30 @@ void arch_pick_mmap_layout(struct mm_struct *mm) { unsigned long random_factor = 0UL; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + if (current->flags & PF_RANDOMIZE) random_factor = arch_mmap_rnd(); if (mmap_is_legacy()) { mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base += mm->delta_mmap; +#endif + mm->get_unmapped_area = arch_get_unmapped_area; } else { mm->mmap_base = mmap_base(random_factor); + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base -= mm->delta_mmap + mm->delta_stack; +#endif + mm->get_unmapped_area = arch_get_unmapped_area_topdown; } } diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 7cd1514..0307305 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -242,7 +242,15 @@ __setup("noalign", noalign_setup); #define PROT_PTE_S2_DEVICE PROT_PTE_DEVICE #define PROT_SECT_DEVICE PMD_TYPE_SECT|PMD_SECT_AP_WRITE -static struct mem_type mem_types[] = { +#ifdef CONFIG_PAX_KERNEXEC +#define L_PTE_KERNEXEC L_PTE_RDONLY +#define PMD_SECT_KERNEXEC PMD_SECT_RDONLY +#else +#define L_PTE_KERNEXEC L_PTE_DIRTY +#define PMD_SECT_KERNEXEC PMD_SECT_AP_WRITE +#endif + +static struct mem_type mem_types[] __read_only = { [MT_DEVICE] = { /* Strongly ordered / ARMv6 shared device */ .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED | L_PTE_SHARED, @@ -271,19 +279,19 @@ static struct mem_type mem_types[] = { .prot_sect = PROT_SECT_DEVICE, .domain = DOMAIN_IO, }, - [MT_UNCACHED] = { + [MT_UNCACHED_RW] = { .prot_pte = PROT_PTE_DEVICE, .prot_l1 = PMD_TYPE_TABLE, .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN, .domain = DOMAIN_IO, }, - [MT_CACHECLEAN] = { - .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN, + [MT_CACHECLEAN_RO] = { + .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN | PMD_SECT_RDONLY, .domain = DOMAIN_KERNEL, }, #ifndef CONFIG_ARM_LPAE - [MT_MINICLEAN] = { - .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN | PMD_SECT_MINICACHE, + [MT_MINICLEAN_RO] = { + .prot_sect = PMD_TYPE_SECT | PMD_SECT_MINICACHE | PMD_SECT_XN | PMD_SECT_RDONLY, .domain = DOMAIN_KERNEL, }, #endif @@ -299,7 +307,7 @@ static struct mem_type mem_types[] = { .prot_l1 = PMD_TYPE_TABLE, .domain = DOMAIN_VECTORS, }, - [MT_MEMORY_RWX] = { + [__MT_MEMORY_RWX] = { .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY, .prot_l1 = PMD_TYPE_TABLE, .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, @@ -312,17 +320,30 @@ static struct mem_type mem_types[] = { .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, .domain = DOMAIN_KERNEL, }, - [MT_ROM] = { - .prot_sect = PMD_TYPE_SECT, + [MT_MEMORY_RX] = { + .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_KERNEXEC, + .prot_l1 = PMD_TYPE_TABLE, + .prot_sect = PMD_TYPE_SECT | PMD_SECT_KERNEXEC, + .domain = DOMAIN_KERNEL, + }, + [MT_ROM_RX] = { + .prot_sect = PMD_TYPE_SECT | PMD_SECT_RDONLY, .domain = DOMAIN_KERNEL, }, - [MT_MEMORY_RWX_NONCACHED] = { + [MT_MEMORY_RW_NONCACHED] = { .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_MT_BUFFERABLE, .prot_l1 = PMD_TYPE_TABLE, .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, .domain = DOMAIN_KERNEL, }, + [MT_MEMORY_RX_NONCACHED] = { + .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_KERNEXEC | + L_PTE_MT_BUFFERABLE, + .prot_l1 = PMD_TYPE_TABLE, + .prot_sect = PMD_TYPE_SECT | PMD_SECT_KERNEXEC, + .domain = DOMAIN_KERNEL, + }, [MT_MEMORY_RW_DTCM] = { .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_XN, @@ -330,9 +351,10 @@ static struct mem_type mem_types[] = { .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN, .domain = DOMAIN_KERNEL, }, - [MT_MEMORY_RWX_ITCM] = { - .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY, + [MT_MEMORY_RX_ITCM] = { + .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_KERNEXEC, .prot_l1 = PMD_TYPE_TABLE, + .prot_sect = PMD_TYPE_SECT | PMD_SECT_KERNEXEC, .domain = DOMAIN_KERNEL, }, [MT_MEMORY_RW_SO] = { @@ -585,9 +607,14 @@ static void __init build_mem_type_table(void) * Mark cache clean areas and XIP ROM read only * from SVC mode and no access from userspace. */ - mem_types[MT_ROM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; - mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; - mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; + mem_types[MT_ROM_RX].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; +#ifdef CONFIG_PAX_KERNEXEC + mem_types[MT_MEMORY_RX].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; + mem_types[MT_MEMORY_RX_NONCACHED].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; + mem_types[MT_MEMORY_RX_ITCM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; +#endif + mem_types[MT_MINICLEAN_RO].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; + mem_types[MT_CACHECLEAN_RO].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; #endif /* @@ -604,13 +631,17 @@ static void __init build_mem_type_table(void) mem_types[MT_DEVICE_WC].prot_pte |= L_PTE_SHARED; mem_types[MT_DEVICE_CACHED].prot_sect |= PMD_SECT_S; mem_types[MT_DEVICE_CACHED].prot_pte |= L_PTE_SHARED; - mem_types[MT_MEMORY_RWX].prot_sect |= PMD_SECT_S; - mem_types[MT_MEMORY_RWX].prot_pte |= L_PTE_SHARED; + mem_types[__MT_MEMORY_RWX].prot_sect |= PMD_SECT_S; + mem_types[__MT_MEMORY_RWX].prot_pte |= L_PTE_SHARED; mem_types[MT_MEMORY_RW].prot_sect |= PMD_SECT_S; mem_types[MT_MEMORY_RW].prot_pte |= L_PTE_SHARED; + mem_types[MT_MEMORY_RX].prot_sect |= PMD_SECT_S; + mem_types[MT_MEMORY_RX].prot_pte |= L_PTE_SHARED; mem_types[MT_MEMORY_DMA_READY].prot_pte |= L_PTE_SHARED; - mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= PMD_SECT_S; - mem_types[MT_MEMORY_RWX_NONCACHED].prot_pte |= L_PTE_SHARED; + mem_types[MT_MEMORY_RW_NONCACHED].prot_sect |= PMD_SECT_S; + mem_types[MT_MEMORY_RW_NONCACHED].prot_pte |= L_PTE_SHARED; + mem_types[MT_MEMORY_RX_NONCACHED].prot_sect |= PMD_SECT_S; + mem_types[MT_MEMORY_RX_NONCACHED].prot_pte |= L_PTE_SHARED; } } @@ -621,15 +652,20 @@ static void __init build_mem_type_table(void) if (cpu_arch >= CPU_ARCH_ARMv6) { if (cpu_arch >= CPU_ARCH_ARMv7 && (cr & CR_TRE)) { /* Non-cacheable Normal is XCB = 001 */ - mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= + mem_types[MT_MEMORY_RW_NONCACHED].prot_sect |= + PMD_SECT_BUFFERED; + mem_types[MT_MEMORY_RX_NONCACHED].prot_sect |= PMD_SECT_BUFFERED; } else { /* For both ARMv6 and non-TEX-remapping ARMv7 */ - mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= + mem_types[MT_MEMORY_RW_NONCACHED].prot_sect |= + PMD_SECT_TEX(1); + mem_types[MT_MEMORY_RX_NONCACHED].prot_sect |= PMD_SECT_TEX(1); } } else { - mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= PMD_SECT_BUFFERABLE; + mem_types[MT_MEMORY_RW_NONCACHED].prot_sect |= PMD_SECT_BUFFERABLE; + mem_types[MT_MEMORY_RX_NONCACHED].prot_sect |= PMD_SECT_BUFFERABLE; } #ifdef CONFIG_ARM_LPAE @@ -650,6 +686,8 @@ static void __init build_mem_type_table(void) user_pgprot |= PTE_EXT_PXN; #endif + user_pgprot |= __supported_pte_mask; + for (i = 0; i < 16; i++) { pteval_t v = pgprot_val(protection_map[i]); protection_map[i] = __pgprot(v | user_pgprot); @@ -667,21 +705,24 @@ static void __init build_mem_type_table(void) mem_types[MT_LOW_VECTORS].prot_l1 |= ecc_mask; mem_types[MT_HIGH_VECTORS].prot_l1 |= ecc_mask; - mem_types[MT_MEMORY_RWX].prot_sect |= ecc_mask | cp->pmd; - mem_types[MT_MEMORY_RWX].prot_pte |= kern_pgprot; + mem_types[__MT_MEMORY_RWX].prot_sect |= ecc_mask | cp->pmd; + mem_types[__MT_MEMORY_RWX].prot_pte |= kern_pgprot; mem_types[MT_MEMORY_RW].prot_sect |= ecc_mask | cp->pmd; mem_types[MT_MEMORY_RW].prot_pte |= kern_pgprot; + mem_types[MT_MEMORY_RX].prot_sect |= ecc_mask | cp->pmd; + mem_types[MT_MEMORY_RX].prot_pte |= kern_pgprot; mem_types[MT_MEMORY_DMA_READY].prot_pte |= kern_pgprot; - mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= ecc_mask; - mem_types[MT_ROM].prot_sect |= cp->pmd; + mem_types[MT_MEMORY_RW_NONCACHED].prot_sect |= ecc_mask; + mem_types[MT_MEMORY_RX_NONCACHED].prot_sect |= ecc_mask; + mem_types[MT_ROM_RX].prot_sect |= cp->pmd; switch (cp->pmd) { case PMD_SECT_WT: - mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_WT; + mem_types[MT_CACHECLEAN_RO].prot_sect |= PMD_SECT_WT; break; case PMD_SECT_WB: case PMD_SECT_WBWA: - mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_WB; + mem_types[MT_CACHECLEAN_RO].prot_sect |= PMD_SECT_WB; break; } pr_info("Memory policy: %sData cache %s\n", @@ -895,7 +936,7 @@ static void __init create_mapping(struct map_desc *md) return; } - if ((md->type == MT_DEVICE || md->type == MT_ROM) && + if ((md->type == MT_DEVICE || md->type == MT_ROM_RX) && md->virtual >= PAGE_OFFSET && md->virtual < FIXADDR_START && (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) { pr_warn("BUG: mapping for 0x%08llx at 0x%08lx out of vmalloc space\n", @@ -1265,18 +1306,15 @@ void __init arm_mm_memblock_reserve(void) * Any other function or debugging method which may touch any device _will_ * crash the kernel. */ + +static char vectors[PAGE_SIZE * 2] __read_only __aligned(PAGE_SIZE); + static void __init devicemaps_init(const struct machine_desc *mdesc) { struct map_desc map; unsigned long addr; - void *vectors; - /* - * Allocate the vector page early. - */ - vectors = early_alloc(PAGE_SIZE * 2); - - early_trap_init(vectors); + early_trap_init(&vectors); /* * Clear page table except top pmd used by early fixmaps @@ -1292,7 +1330,7 @@ static void __init devicemaps_init(const struct machine_desc *mdesc) map.pfn = __phys_to_pfn(CONFIG_XIP_PHYS_ADDR & SECTION_MASK); map.virtual = MODULES_VADDR; map.length = ((unsigned long)_etext - map.virtual + ~SECTION_MASK) & SECTION_MASK; - map.type = MT_ROM; + map.type = MT_ROM_RX; create_mapping(&map); #endif @@ -1303,14 +1341,14 @@ static void __init devicemaps_init(const struct machine_desc *mdesc) map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS); map.virtual = FLUSH_BASE; map.length = SZ_1M; - map.type = MT_CACHECLEAN; + map.type = MT_CACHECLEAN_RO; create_mapping(&map); #endif #ifdef FLUSH_BASE_MINICACHE map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS + SZ_1M); map.virtual = FLUSH_BASE_MINICACHE; map.length = SZ_1M; - map.type = MT_MINICLEAN; + map.type = MT_MINICLEAN_RO; create_mapping(&map); #endif @@ -1319,7 +1357,7 @@ static void __init devicemaps_init(const struct machine_desc *mdesc) * location (0xffff0000). If we aren't using high-vectors, also * create a mapping at the low-vectors virtual address. */ - map.pfn = __phys_to_pfn(virt_to_phys(vectors)); + map.pfn = __phys_to_pfn(virt_to_phys(&vectors)); map.virtual = 0xffff0000; map.length = PAGE_SIZE; #ifdef CONFIG_KUSER_HELPERS @@ -1379,8 +1417,10 @@ static void __init kmap_init(void) static void __init map_lowmem(void) { struct memblock_region *reg; +#ifndef CONFIG_PAX_KERNEXEC phys_addr_t kernel_x_start = round_down(__pa(_stext), SECTION_SIZE); phys_addr_t kernel_x_end = round_up(__pa(__init_end), SECTION_SIZE); +#endif /* Map all the lowmem memory banks. */ for_each_memblock(memory, reg) { @@ -1393,11 +1433,48 @@ static void __init map_lowmem(void) if (start >= end) break; +#ifdef CONFIG_PAX_KERNEXEC + map.pfn = __phys_to_pfn(start); + map.virtual = __phys_to_virt(start); + map.length = end - start; + + if (map.virtual <= (unsigned long)_stext && ((unsigned long)_end < (map.virtual + map.length))) { + struct map_desc kernel; + struct map_desc initmap; + + /* when freeing initmem we will make this RW */ + initmap.pfn = __phys_to_pfn(__pa(__init_begin)); + initmap.virtual = (unsigned long)__init_begin; + initmap.length = _sdata - __init_begin; + initmap.type = __MT_MEMORY_RWX; + create_mapping(&initmap); + + /* when freeing initmem we will make this RX */ + kernel.pfn = __phys_to_pfn(__pa(_stext)); + kernel.virtual = (unsigned long)_stext; + kernel.length = __init_begin - _stext; + kernel.type = __MT_MEMORY_RWX; + create_mapping(&kernel); + + if (map.virtual < (unsigned long)_stext) { + map.length = (unsigned long)_stext - map.virtual; + map.type = __MT_MEMORY_RWX; + create_mapping(&map); + } + + map.pfn = __phys_to_pfn(__pa(_sdata)); + map.virtual = (unsigned long)_sdata; + map.length = end - __pa(_sdata); + } + + map.type = MT_MEMORY_RW; + create_mapping(&map); +#else if (end < kernel_x_start) { map.pfn = __phys_to_pfn(start); map.virtual = __phys_to_virt(start); map.length = end - start; - map.type = MT_MEMORY_RWX; + map.type = __MT_MEMORY_RWX; create_mapping(&map); } else if (start >= kernel_x_end) { @@ -1421,7 +1498,7 @@ static void __init map_lowmem(void) map.pfn = __phys_to_pfn(kernel_x_start); map.virtual = __phys_to_virt(kernel_x_start); map.length = kernel_x_end - kernel_x_start; - map.type = MT_MEMORY_RWX; + map.type = __MT_MEMORY_RWX; create_mapping(&map); @@ -1434,6 +1511,7 @@ static void __init map_lowmem(void) create_mapping(&map); } } +#endif } } diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index b8efb8c..88fa837 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "bpf_jit_32.h" @@ -72,54 +73,38 @@ struct jit_ctx { #endif }; +#ifdef CONFIG_GRKERNSEC_BPF_HARDEN +int bpf_jit_enable __read_only; +#else int bpf_jit_enable __read_mostly; +#endif -static inline int call_neg_helper(struct sk_buff *skb, int offset, void *ret, - unsigned int size) -{ - void *ptr = bpf_internal_load_pointer_neg_helper(skb, offset, size); - - if (!ptr) - return -EFAULT; - memcpy(ret, ptr, size); - return 0; -} - -static u64 jit_get_skb_b(struct sk_buff *skb, int offset) +static u64 jit_get_skb_b(struct sk_buff *skb, unsigned offset) { u8 ret; int err; - if (offset < 0) - err = call_neg_helper(skb, offset, &ret, 1); - else - err = skb_copy_bits(skb, offset, &ret, 1); + err = skb_copy_bits(skb, offset, &ret, 1); return (u64)err << 32 | ret; } -static u64 jit_get_skb_h(struct sk_buff *skb, int offset) +static u64 jit_get_skb_h(struct sk_buff *skb, unsigned offset) { u16 ret; int err; - if (offset < 0) - err = call_neg_helper(skb, offset, &ret, 2); - else - err = skb_copy_bits(skb, offset, &ret, 2); + err = skb_copy_bits(skb, offset, &ret, 2); return (u64)err << 32 | ntohs(ret); } -static u64 jit_get_skb_w(struct sk_buff *skb, int offset) +static u64 jit_get_skb_w(struct sk_buff *skb, unsigned offset) { u32 ret; int err; - if (offset < 0) - err = call_neg_helper(skb, offset, &ret, 4); - else - err = skb_copy_bits(skb, offset, &ret, 4); + err = skb_copy_bits(skb, offset, &ret, 4); return (u64)err << 32 | ntohl(ret); } @@ -199,8 +184,10 @@ static void jit_fill_hole(void *area, unsigned int size) { u32 *ptr; /* We are guaranteed to have aligned memory. */ + pax_open_kernel(); for (ptr = area; size >= sizeof(u32); size -= sizeof(u32)) *ptr++ = __opcode_to_mem_arm(ARM_INST_UDF); + pax_close_kernel(); } static void build_prologue(struct jit_ctx *ctx) @@ -556,6 +543,9 @@ static int build_body(struct jit_ctx *ctx) case BPF_LD | BPF_B | BPF_ABS: load_order = 0; load: + /* the interpreter will deal with the negative K */ + if ((int)k < 0) + return -ENOTSUPP; emit_mov_i(r_off, k, ctx); load_common: ctx->seen |= SEEN_DATA | SEEN_CALL; @@ -570,18 +560,6 @@ load_common: condt = ARM_COND_HI; } - /* - * test for negative offset, only if we are - * currently scheduled to take the fast - * path. this will update the flags so that - * the slowpath instruction are ignored if the - * offset is negative. - * - * for loard_order == 0 the HI condition will - * make loads at offset 0 take the slow path too. - */ - _emit(condt, ARM_CMP_I(r_off, 0), ctx); - _emit(condt, ARM_ADD_R(r_scratch, r_off, r_skb_data), ctx); diff --git a/arch/arm/plat-iop/setup.c b/arch/arm/plat-iop/setup.c index 5b217f4..c23f40e 100644 --- a/arch/arm/plat-iop/setup.c +++ b/arch/arm/plat-iop/setup.c @@ -24,7 +24,7 @@ static struct map_desc iop3xx_std_desc[] __initdata = { .virtual = IOP3XX_PERIPHERAL_VIRT_BASE, .pfn = __phys_to_pfn(IOP3XX_PERIPHERAL_PHYS_BASE), .length = IOP3XX_PERIPHERAL_SIZE, - .type = MT_UNCACHED, + .type = MT_UNCACHED_RW, }, }; diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index a5bc92d..0bb4730 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c @@ -93,6 +93,8 @@ void __init omap_map_sram(unsigned long start, unsigned long size, * Looks like we need to preserve some bootloader code at the * beginning of SRAM for jumping to flash for reboot to work... */ + pax_open_kernel(); memset_io(omap_sram_base + omap_sram_skip, 0, omap_sram_size - omap_sram_skip); + pax_close_kernel(); } diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug index d6285ef..b684dac 100644 --- a/arch/arm64/Kconfig.debug +++ b/arch/arm64/Kconfig.debug @@ -10,6 +10,7 @@ config ARM64_PTDUMP bool "Export kernel pagetable layout to userspace via debugfs" depends on DEBUG_KERNEL select DEBUG_FS + depends on !GRKERNSEC_KMEM 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/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index 35a6778..caabbd36 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h @@ -91,5 +91,15 @@ #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) +#define atomic64_read_unchecked(v) atomic64_read(v) +#define atomic64_set_unchecked(v, i) atomic64_set((v), (i)) +#define atomic64_add_unchecked(a, v) atomic64_add((a), (v)) +#define atomic64_add_return_unchecked(a, v) atomic64_add_return((a), (v)) +#define atomic64_sub_unchecked(a, v) atomic64_sub((a), (v)) +#define atomic64_inc_unchecked(v) atomic64_inc(v) +#define atomic64_inc_return_unchecked(v) atomic64_inc_return(v) +#define atomic64_dec_unchecked(v) atomic64_dec(v) +#define atomic64_cmpxchg_unchecked(v, o, n) atomic64_cmpxchg((v), (o), (n)) + #endif #endif diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h index 0a456be..7799ff5 100644 --- a/arch/arm64/include/asm/percpu.h +++ b/arch/arm64/include/asm/percpu.h @@ -127,16 +127,16 @@ static inline void __percpu_write(void *ptr, unsigned long val, int size) { switch (size) { case 1: - ACCESS_ONCE(*(u8 *)ptr) = (u8)val; + ACCESS_ONCE_RW(*(u8 *)ptr) = (u8)val; break; case 2: - ACCESS_ONCE(*(u16 *)ptr) = (u16)val; + ACCESS_ONCE_RW(*(u16 *)ptr) = (u16)val; break; case 4: - ACCESS_ONCE(*(u32 *)ptr) = (u32)val; + ACCESS_ONCE_RW(*(u32 *)ptr) = (u32)val; break; case 8: - ACCESS_ONCE(*(u64 *)ptr) = (u64)val; + ACCESS_ONCE_RW(*(u64 *)ptr) = (u64)val; break; default: BUILD_BUG(); diff --git a/arch/arm64/include/asm/pgalloc.h b/arch/arm64/include/asm/pgalloc.h index 7642056..bffc904 100644 --- a/arch/arm64/include/asm/pgalloc.h +++ b/arch/arm64/include/asm/pgalloc.h @@ -46,6 +46,11 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) set_pud(pud, __pud(__pa(pmd) | PMD_TYPE_TABLE)); } +static inline void pud_populate_kernel(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) +{ + pud_populate(mm, pud, pmd); +} + #endif /* CONFIG_PGTABLE_LEVELS > 2 */ #if CONFIG_PGTABLE_LEVELS > 3 diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index b2ede967..865eed5 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -102,6 +102,7 @@ static inline void set_fs(mm_segment_t fs) flag; \ }) +#define access_ok_noprefault(type, addr, size) access_ok((type), (addr), (size)) #define access_ok(type, addr, size) __range_ok(addr, size) #define user_addr_max get_fs diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 99224dc..148dfb7 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -134,7 +134,7 @@ static void __dma_free_coherent(struct device *dev, size_t size, phys_to_page(paddr), size >> PAGE_SHIFT); if (!freed) - swiotlb_free_coherent(dev, size, vaddr, dma_handle); + swiotlb_free_coherent(dev, size, vaddr, dma_handle, attrs); } static void *__dma_alloc(struct device *dev, size_t size, diff --git a/arch/avr32/include/asm/cache.h b/arch/avr32/include/asm/cache.h index c3a58a1..78fbf54 100644 --- a/arch/avr32/include/asm/cache.h +++ b/arch/avr32/include/asm/cache.h @@ -1,8 +1,10 @@ #ifndef __ASM_AVR32_CACHE_H #define __ASM_AVR32_CACHE_H +#include + #define L1_CACHE_SHIFT 5 -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) /* * Memory returned by kmalloc() may be used for DMA, so we must make diff --git a/arch/avr32/include/asm/elf.h b/arch/avr32/include/asm/elf.h index 0388ece..87c8df1 100644 --- a/arch/avr32/include/asm/elf.h +++ b/arch/avr32/include/asm/elf.h @@ -84,8 +84,14 @@ typedef struct user_fpu_struct elf_fpregset_t; the loader. We need to make sure that it is out of the way of the program that it will "exec", and that there is sufficient room for the brk. */ -#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) +#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE 0x00001000UL + +#define PAX_DELTA_MMAP_LEN 15 +#define PAX_DELTA_STACK_LEN 15 +#endif /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. This could be done in user space, diff --git a/arch/avr32/include/asm/kmap_types.h b/arch/avr32/include/asm/kmap_types.h index 479330b..53717a8 100644 --- a/arch/avr32/include/asm/kmap_types.h +++ b/arch/avr32/include/asm/kmap_types.h @@ -2,9 +2,9 @@ #define __ASM_AVR32_KMAP_TYPES_H #ifdef CONFIG_DEBUG_HIGHMEM -# define KM_TYPE_NR 29 +# define KM_TYPE_NR 30 #else -# define KM_TYPE_NR 14 +# define KM_TYPE_NR 15 #endif #endif /* __ASM_AVR32_KMAP_TYPES_H */ diff --git a/arch/avr32/mm/fault.c b/arch/avr32/mm/fault.c index c035339..e1fa594 100644 --- a/arch/avr32/mm/fault.c +++ b/arch/avr32/mm/fault.c @@ -41,6 +41,23 @@ static inline int notify_page_fault(struct pt_regs *regs, int trap) int exception_trace = 1; +#ifdef CONFIG_PAX_PAGEEXEC +void pax_report_insns(struct pt_regs *regs, void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 20; i++) { + unsigned char c; + if (get_user(c, (unsigned char *)pc+i)) + printk(KERN_CONT "???????? "); + else + printk(KERN_CONT "%02x ", c); + } + printk("\n"); +} +#endif + /* * This routine handles page faults. It determines the address and the * problem, and then passes it off to one of the appropriate routines. @@ -178,6 +195,16 @@ bad_area: up_read(&mm->mmap_sem); if (user_mode(regs)) { + +#ifdef CONFIG_PAX_PAGEEXEC + if (mm->pax_flags & MF_PAX_PAGEEXEC) { + if (ecr == ECR_PROTECTION_X || ecr == ECR_TLB_MISS_X) { + pax_report_fault(regs, (void *)regs->pc, (void *)regs->sp); + do_group_exit(SIGKILL); + } + } +#endif + if (exception_trace && printk_ratelimit()) printk("%s%s[%d]: segfault at %08lx pc %08lx " "sp %08lx ecr %lu\n", diff --git a/arch/blackfin/Kconfig.debug b/arch/blackfin/Kconfig.debug index f3337ee..15b6f8d 100644 --- a/arch/blackfin/Kconfig.debug +++ b/arch/blackfin/Kconfig.debug @@ -18,6 +18,7 @@ config DEBUG_VERBOSE config DEBUG_MMRS tristate "Generate Blackfin MMR tree" select DEBUG_FS + depends on !GRKERNSEC_KMEM help Create a tree of Blackfin MMRs via the debugfs tree. If you enable this, you will find all MMRs laid out in the diff --git a/arch/blackfin/include/asm/cache.h b/arch/blackfin/include/asm/cache.h index 568885a..f8008df 100644 --- a/arch/blackfin/include/asm/cache.h +++ b/arch/blackfin/include/asm/cache.h @@ -7,6 +7,7 @@ #ifndef __ARCH_BLACKFIN_CACHE_H #define __ARCH_BLACKFIN_CACHE_H +#include #include /* for asmlinkage */ /* @@ -14,7 +15,7 @@ * Blackfin loads 32 bytes for cache */ #define L1_CACHE_SHIFT 5 -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #define SMP_CACHE_BYTES L1_CACHE_BYTES #define ARCH_DMA_MINALIGN L1_CACHE_BYTES diff --git a/arch/cris/include/arch-v10/arch/cache.h b/arch/cris/include/arch-v10/arch/cache.h index aea2718..3639a60 100644 --- a/arch/cris/include/arch-v10/arch/cache.h +++ b/arch/cris/include/arch-v10/arch/cache.h @@ -1,8 +1,9 @@ #ifndef _ASM_ARCH_CACHE_H #define _ASM_ARCH_CACHE_H +#include /* Etrax 100LX have 32-byte cache-lines. */ -#define L1_CACHE_BYTES 32 #define L1_CACHE_SHIFT 5 +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #endif /* _ASM_ARCH_CACHE_H */ diff --git a/arch/cris/include/arch-v32/arch/cache.h b/arch/cris/include/arch-v32/arch/cache.h index 7caf25d..ee65ac5 100644 --- a/arch/cris/include/arch-v32/arch/cache.h +++ b/arch/cris/include/arch-v32/arch/cache.h @@ -1,11 +1,12 @@ #ifndef _ASM_CRIS_ARCH_CACHE_H #define _ASM_CRIS_ARCH_CACHE_H +#include #include /* A cache-line is 32 bytes. */ -#define L1_CACHE_BYTES 32 #define L1_CACHE_SHIFT 5 +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #define __read_mostly __attribute__((__section__(".data..read_mostly"))) diff --git a/arch/frv/include/asm/atomic.h b/arch/frv/include/asm/atomic.h index 0da689d..3aad5fb 100644 --- a/arch/frv/include/asm/atomic.h +++ b/arch/frv/include/asm/atomic.h @@ -166,6 +166,16 @@ static inline void atomic64_dec(atomic64_t *v) #define atomic64_cmpxchg(v, old, new) (__cmpxchg_64(old, new, &(v)->counter)) #define atomic64_xchg(v, new) (__xchg_64(new, &(v)->counter)) +#define atomic64_read_unchecked(v) atomic64_read(v) +#define atomic64_set_unchecked(v, i) atomic64_set((v), (i)) +#define atomic64_add_unchecked(a, v) atomic64_add((a), (v)) +#define atomic64_add_return_unchecked(a, v) atomic64_add_return((a), (v)) +#define atomic64_sub_unchecked(a, v) atomic64_sub((a), (v)) +#define atomic64_inc_unchecked(v) atomic64_inc(v) +#define atomic64_inc_return_unchecked(v) atomic64_inc_return(v) +#define atomic64_dec_unchecked(v) atomic64_dec(v) +#define atomic64_cmpxchg_unchecked(v, o, n) atomic64_cmpxchg((v), (o), (n)) + static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) { int c, old; diff --git a/arch/frv/include/asm/cache.h b/arch/frv/include/asm/cache.h index 2797163..c2a401df9 100644 --- a/arch/frv/include/asm/cache.h +++ b/arch/frv/include/asm/cache.h @@ -12,10 +12,11 @@ #ifndef __ASM_CACHE_H #define __ASM_CACHE_H +#include /* bytes per L1 cache line */ #define L1_CACHE_SHIFT (CONFIG_FRV_L1_CACHE_SHIFT) -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #define __cacheline_aligned __attribute__((aligned(L1_CACHE_BYTES))) #define ____cacheline_aligned __attribute__((aligned(L1_CACHE_BYTES))) diff --git a/arch/frv/include/asm/kmap_types.h b/arch/frv/include/asm/kmap_types.h index 43901f2..0d8b865 100644 --- a/arch/frv/include/asm/kmap_types.h +++ b/arch/frv/include/asm/kmap_types.h @@ -2,6 +2,6 @@ #ifndef _ASM_KMAP_TYPES_H #define _ASM_KMAP_TYPES_H -#define KM_TYPE_NR 17 +#define KM_TYPE_NR 18 #endif diff --git a/arch/frv/mm/elf-fdpic.c b/arch/frv/mm/elf-fdpic.c index 836f147..4cf23f5 100644 --- a/arch/frv/mm/elf-fdpic.c +++ b/arch/frv/mm/elf-fdpic.c @@ -61,6 +61,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi { struct vm_area_struct *vma; struct vm_unmapped_area_info info; + unsigned long offset = gr_rand_threadstack_offset(current->mm, filp, flags); if (len > TASK_SIZE) return -ENOMEM; @@ -73,8 +74,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi if (addr) { addr = PAGE_ALIGN(addr); vma = find_vma(current->mm, addr); - if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + if (TASK_SIZE - len >= addr && check_heap_stack_gap(vma, addr, len, offset)) goto success; } @@ -85,6 +85,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi info.high_limit = (current->mm->start_stack - 0x00200000); info.align_mask = 0; info.align_offset = 0; + info.threadstack_offset = offset; addr = vm_unmapped_area(&info); if (!(addr & ~PAGE_MASK)) goto success; diff --git a/arch/hexagon/include/asm/cache.h b/arch/hexagon/include/asm/cache.h index 69952c18..4fa2908 100644 --- a/arch/hexagon/include/asm/cache.h +++ b/arch/hexagon/include/asm/cache.h @@ -21,9 +21,11 @@ #ifndef __ASM_CACHE_H #define __ASM_CACHE_H +#include + /* Bytes per L1 cache line */ -#define L1_CACHE_SHIFT (5) -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_SHIFT 5 +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #define ARCH_DMA_MINALIGN L1_CACHE_BYTES diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index eb0249e..388ff32 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -519,6 +519,7 @@ config KEXEC bool "kexec system call" depends on !IA64_HP_SIM && (!SMP || HOTPLUG_CPU) select KEXEC_CORE + depends on !GRKERNSEC_KMEM 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 diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index 970d0bd..e750b9b 100644 --- a/arch/ia64/Makefile +++ b/arch/ia64/Makefile @@ -98,5 +98,6 @@ endef archprepare: make_nr_irqs_h FORCE PHONY += make_nr_irqs_h FORCE +make_nr_irqs_h: KBUILD_CFLAGS := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS)) make_nr_irqs_h: FORCE $(Q)$(MAKE) $(build)=arch/ia64/kernel include/generated/nr-irqs.h diff --git a/arch/ia64/include/asm/atomic.h b/arch/ia64/include/asm/atomic.h index be4beeb..c0ec564 100644 --- a/arch/ia64/include/asm/atomic.h +++ b/arch/ia64/include/asm/atomic.h @@ -209,4 +209,14 @@ atomic64_add_negative (__s64 i, atomic64_t *v) #define atomic64_inc(v) atomic64_add(1, (v)) #define atomic64_dec(v) atomic64_sub(1, (v)) +#define atomic64_read_unchecked(v) atomic64_read(v) +#define atomic64_set_unchecked(v, i) atomic64_set((v), (i)) +#define atomic64_add_unchecked(a, v) atomic64_add((a), (v)) +#define atomic64_add_return_unchecked(a, v) atomic64_add_return((a), (v)) +#define atomic64_sub_unchecked(a, v) atomic64_sub((a), (v)) +#define atomic64_inc_unchecked(v) atomic64_inc(v) +#define atomic64_inc_return_unchecked(v) atomic64_inc_return(v) +#define atomic64_dec_unchecked(v) atomic64_dec(v) +#define atomic64_cmpxchg_unchecked(v, o, n) atomic64_cmpxchg((v), (o), (n)) + #endif /* _ASM_IA64_ATOMIC_H */ diff --git a/arch/ia64/include/asm/cache.h b/arch/ia64/include/asm/cache.h index 988254a..e1ee885 100644 --- a/arch/ia64/include/asm/cache.h +++ b/arch/ia64/include/asm/cache.h @@ -1,6 +1,7 @@ #ifndef _ASM_IA64_CACHE_H #define _ASM_IA64_CACHE_H +#include /* * Copyright (C) 1998-2000 Hewlett-Packard Co @@ -9,7 +10,7 @@ /* Bytes per L1 (data) cache line. */ #define L1_CACHE_SHIFT CONFIG_IA64_L1_CACHE_SHIFT -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #ifdef CONFIG_SMP # define SMP_CACHE_SHIFT L1_CACHE_SHIFT diff --git a/arch/ia64/include/asm/elf.h b/arch/ia64/include/asm/elf.h index 5a83c5c..4d7f553 100644 --- a/arch/ia64/include/asm/elf.h +++ b/arch/ia64/include/asm/elf.h @@ -42,6 +42,13 @@ */ #define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x800000000UL) +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE (current->personality == PER_LINUX32 ? 0x08048000UL : 0x4000000000000000UL) + +#define PAX_DELTA_MMAP_LEN (current->personality == PER_LINUX32 ? 16 : 3*PAGE_SHIFT - 13) +#define PAX_DELTA_STACK_LEN (current->personality == PER_LINUX32 ? 16 : 3*PAGE_SHIFT - 13) +#endif + #define PT_IA_64_UNWIND 0x70000001 /* IA-64 relocations: */ diff --git a/arch/ia64/include/asm/pgalloc.h b/arch/ia64/include/asm/pgalloc.h index f5e70e9..624fad5 100644 --- a/arch/ia64/include/asm/pgalloc.h +++ b/arch/ia64/include/asm/pgalloc.h @@ -39,6 +39,12 @@ pgd_populate(struct mm_struct *mm, pgd_t * pgd_entry, pud_t * pud) pgd_val(*pgd_entry) = __pa(pud); } +static inline void +pgd_populate_kernel(struct mm_struct *mm, pgd_t * pgd_entry, pud_t * pud) +{ + pgd_populate(mm, pgd_entry, pud); +} + static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) { return quicklist_alloc(0, GFP_KERNEL, NULL); @@ -57,6 +63,12 @@ pud_populate(struct mm_struct *mm, pud_t * pud_entry, pmd_t * pmd) pud_val(*pud_entry) = __pa(pmd); } +static inline void +pud_populate_kernel(struct mm_struct *mm, pud_t * pud_entry, pmd_t * pmd) +{ + pud_populate(mm, pud_entry, pmd); +} + static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) { return quicklist_alloc(0, GFP_KERNEL, NULL); diff --git a/arch/ia64/include/asm/pgtable.h b/arch/ia64/include/asm/pgtable.h index 9f3ed9e..c99b418 100644 --- a/arch/ia64/include/asm/pgtable.h +++ b/arch/ia64/include/asm/pgtable.h @@ -12,7 +12,7 @@ * David Mosberger-Tang */ - +#include #include #include #include @@ -139,6 +139,17 @@ #define PAGE_READONLY __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_R) #define PAGE_COPY __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_R) #define PAGE_COPY_EXEC __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RX) + +#ifdef CONFIG_PAX_PAGEEXEC +# define PAGE_SHARED_NOEXEC __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RW) +# define PAGE_READONLY_NOEXEC __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_R) +# define PAGE_COPY_NOEXEC __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_R) +#else +# define PAGE_SHARED_NOEXEC PAGE_SHARED +# define PAGE_READONLY_NOEXEC PAGE_READONLY +# define PAGE_COPY_NOEXEC PAGE_COPY +#endif + #define PAGE_GATE __pgprot(__ACCESS_BITS | _PAGE_PL_0 | _PAGE_AR_X_RX) #define PAGE_KERNEL __pgprot(__DIRTY_BITS | _PAGE_PL_0 | _PAGE_AR_RWX) #define PAGE_KERNELRX __pgprot(__ACCESS_BITS | _PAGE_PL_0 | _PAGE_AR_RX) diff --git a/arch/ia64/include/asm/spinlock.h b/arch/ia64/include/asm/spinlock.h index 45698cd..e8e2dbc 100644 --- a/arch/ia64/include/asm/spinlock.h +++ b/arch/ia64/include/asm/spinlock.h @@ -71,7 +71,7 @@ static __always_inline void __ticket_spin_unlock(arch_spinlock_t *lock) unsigned short *p = (unsigned short *)&lock->lock + 1, tmp; asm volatile ("ld2.bias %0=[%1]" : "=r"(tmp) : "r"(p)); - ACCESS_ONCE(*p) = (tmp + 2) & ~1; + ACCESS_ONCE_RW(*p) = (tmp + 2) & ~1; } static __always_inline void __ticket_spin_unlock_wait(arch_spinlock_t *lock) diff --git a/arch/ia64/include/asm/uaccess.h b/arch/ia64/include/asm/uaccess.h index 4f3fb6cc..254055e 100644 --- a/arch/ia64/include/asm/uaccess.h +++ b/arch/ia64/include/asm/uaccess.h @@ -70,6 +70,7 @@ && ((segment).seg == KERNEL_DS.seg \ || likely(REGION_OFFSET((unsigned long) (addr)) < RGN_MAP_LIMIT))); \ }) +#define access_ok_noprefault(type, addr, size) access_ok((type), (addr), (size)) #define access_ok(type, addr, size) __access_ok((addr), (size), get_fs()) /* @@ -241,12 +242,24 @@ extern unsigned long __must_check __copy_user (void __user *to, const void __use static inline unsigned long __copy_to_user (void __user *to, const void *from, unsigned long count) { + if (count > INT_MAX) + return count; + + if (!__builtin_constant_p(count)) + check_object_size(from, count, true); + return __copy_user(to, (__force void __user *) from, count); } static inline unsigned long __copy_from_user (void *to, const void __user *from, unsigned long count) { + if (count > INT_MAX) + return count; + + if (!__builtin_constant_p(count)) + check_object_size(to, count, false); + return __copy_user((__force void __user *) to, from, count); } @@ -256,10 +269,13 @@ __copy_from_user (void *to, const void __user *from, unsigned long count) ({ \ void __user *__cu_to = (to); \ const void *__cu_from = (from); \ - long __cu_len = (n); \ + unsigned long __cu_len = (n); \ \ - if (__access_ok(__cu_to, __cu_len, get_fs())) \ + if (__cu_len <= INT_MAX && __access_ok(__cu_to, __cu_len, get_fs())) { \ + if (!__builtin_constant_p(n)) \ + check_object_size(__cu_from, __cu_len, true); \ __cu_len = __copy_user(__cu_to, (__force void __user *) __cu_from, __cu_len); \ + } \ __cu_len; \ }) @@ -267,11 +283,14 @@ __copy_from_user (void *to, const void __user *from, unsigned long count) ({ \ void *__cu_to = (to); \ const void __user *__cu_from = (from); \ - long __cu_len = (n); \ + unsigned long __cu_len = (n); \ \ __chk_user_ptr(__cu_from); \ - if (__access_ok(__cu_from, __cu_len, get_fs())) \ + if (__cu_len <= INT_MAX && __access_ok(__cu_from, __cu_len, get_fs())) { \ + if (!__builtin_constant_p(n)) \ + check_object_size(__cu_to, __cu_len, false); \ __cu_len = __copy_user((__force void __user *) __cu_to, __cu_from, __cu_len); \ + } \ __cu_len; \ }) diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c index b15933c..098b1c8 100644 --- a/arch/ia64/kernel/module.c +++ b/arch/ia64/kernel/module.c @@ -484,15 +484,39 @@ module_frob_arch_sections (Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings, } static inline int +in_init_rx (const struct module *mod, uint64_t addr) +{ + return addr - (uint64_t) mod->module_init_rx < mod->init_size_rx; +} + +static inline int +in_init_rw (const struct module *mod, uint64_t addr) +{ + return addr - (uint64_t) mod->module_init_rw < mod->init_size_rw; +} + +static inline int in_init (const struct module *mod, uint64_t addr) { - return addr - (uint64_t) mod->module_init < mod->init_size; + return in_init_rx(mod, addr) || in_init_rw(mod, addr); +} + +static inline int +in_core_rx (const struct module *mod, uint64_t addr) +{ + return addr - (uint64_t) mod->module_core_rx < mod->core_size_rx; +} + +static inline int +in_core_rw (const struct module *mod, uint64_t addr) +{ + return addr - (uint64_t) mod->module_core_rw < mod->core_size_rw; } static inline int in_core (const struct module *mod, uint64_t addr) { - return addr - (uint64_t) mod->module_core < mod->core_size; + return in_core_rx(mod, addr) || in_core_rw(mod, addr); } static inline int @@ -675,7 +699,14 @@ do_reloc (struct module *mod, uint8_t r_type, Elf64_Sym *sym, uint64_t addend, break; case RV_BDREL: - val -= (uint64_t) (in_init(mod, val) ? mod->module_init : mod->module_core); + if (in_init_rx(mod, val)) + val -= (uint64_t) mod->module_init_rx; + else if (in_init_rw(mod, val)) + val -= (uint64_t) mod->module_init_rw; + else if (in_core_rx(mod, val)) + val -= (uint64_t) mod->module_core_rx; + else if (in_core_rw(mod, val)) + val -= (uint64_t) mod->module_core_rw; break; case RV_LTV: @@ -810,15 +841,15 @@ apply_relocate_add (Elf64_Shdr *sechdrs, const char *strtab, unsigned int symind * addresses have been selected... */ uint64_t gp; - if (mod->core_size > MAX_LTOFF) + if (mod->core_size_rx + mod->core_size_rw > MAX_LTOFF) /* * This takes advantage of fact that SHF_ARCH_SMALL gets allocated * at the end of the module. */ - gp = mod->core_size - MAX_LTOFF / 2; + gp = mod->core_size_rx + mod->core_size_rw - MAX_LTOFF / 2; else - gp = mod->core_size / 2; - gp = (uint64_t) mod->module_core + ((gp + 7) & -8); + gp = (mod->core_size_rx + mod->core_size_rw) / 2; + gp = (uint64_t) mod->module_core_rx + ((gp + 7) & -8); mod->arch.gp = gp; DEBUGP("%s: placing gp at 0x%lx\n", __func__, gp); } diff --git a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c index c39c3cd..3c77738 100644 --- a/arch/ia64/kernel/palinfo.c +++ b/arch/ia64/kernel/palinfo.c @@ -980,7 +980,7 @@ static int palinfo_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -static struct notifier_block __refdata palinfo_cpu_notifier = +static struct notifier_block palinfo_cpu_notifier = { .notifier_call = palinfo_cpu_callback, .priority = 0, diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c index 41e33f8..65180b2a 100644 --- a/arch/ia64/kernel/sys_ia64.c +++ b/arch/ia64/kernel/sys_ia64.c @@ -28,6 +28,7 @@ arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len unsigned long align_mask = 0; struct mm_struct *mm = current->mm; struct vm_unmapped_area_info info; + unsigned long offset = gr_rand_threadstack_offset(mm, filp, flags); if (len > RGN_MAP_LIMIT) return -ENOMEM; @@ -43,6 +44,13 @@ arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len if (REGION_NUMBER(addr) == RGN_HPAGE) addr = 0; #endif + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + addr = mm->free_area_cache; + else +#endif + if (!addr) addr = TASK_UNMAPPED_BASE; @@ -61,6 +69,7 @@ arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len info.high_limit = TASK_SIZE; info.align_mask = align_mask; info.align_offset = 0; + info.threadstack_offset = offset; return vm_unmapped_area(&info); } diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index dc506b0..39baade 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S @@ -171,7 +171,7 @@ SECTIONS { /* Per-cpu data: */ . = ALIGN(PERCPU_PAGE_SIZE); PERCPU_VADDR(SMP_CACHE_BYTES, PERCPU_ADDR, :percpu) - __phys_per_cpu_start = __per_cpu_load; + __phys_per_cpu_start = per_cpu_load; /* * ensure percpu data fits * into percpu page size diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c index 70b40d1..01a9a28 100644 --- a/arch/ia64/mm/fault.c +++ b/arch/ia64/mm/fault.c @@ -72,6 +72,23 @@ mapped_kernel_page_is_present (unsigned long address) return pte_present(pte); } +#ifdef CONFIG_PAX_PAGEEXEC +void pax_report_insns(struct pt_regs *regs, void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 8; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk(KERN_CONT "???????? "); + else + printk(KERN_CONT "%08x ", c); + } + printk("\n"); +} +#endif + # define VM_READ_BIT 0 # define VM_WRITE_BIT 1 # define VM_EXEC_BIT 2 @@ -151,8 +168,21 @@ retry: if (((isr >> IA64_ISR_R_BIT) & 1UL) && (!(vma->vm_flags & (VM_READ | VM_WRITE)))) goto bad_area; - if ((vma->vm_flags & mask) != mask) + if ((vma->vm_flags & mask) != mask) { + +#ifdef CONFIG_PAX_PAGEEXEC + if (!(vma->vm_flags & VM_EXEC) && (mask & VM_EXEC)) { + if (!(mm->pax_flags & MF_PAX_PAGEEXEC) || address != regs->cr_iip) + goto bad_area; + + up_read(&mm->mmap_sem); + pax_report_fault(regs, (void *)regs->cr_iip, (void *)regs->r12); + do_group_exit(SIGKILL); + } +#endif + goto bad_area; + } /* * If for any reason at all we couldn't handle the fault, make diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c index f50d4b3..c7975ee 100644 --- a/arch/ia64/mm/hugetlbpage.c +++ b/arch/ia64/mm/hugetlbpage.c @@ -138,6 +138,7 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, u unsigned long pgoff, unsigned long flags) { struct vm_unmapped_area_info info; + unsigned long offset = gr_rand_threadstack_offset(current->mm, file, flags); if (len > RGN_MAP_LIMIT) return -ENOMEM; @@ -161,6 +162,7 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, u info.high_limit = HPAGE_REGION_BASE + RGN_MAP_LIMIT; info.align_mask = PAGE_MASK & (HPAGE_SIZE - 1); info.align_offset = 0; + info.threadstack_offset = offset; return vm_unmapped_area(&info); } diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 1841ef6..74d8330 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -119,6 +119,19 @@ ia64_init_addr_space (void) vma->vm_start = current->thread.rbs_bot & PAGE_MASK; vma->vm_end = vma->vm_start + PAGE_SIZE; vma->vm_flags = VM_DATA_DEFAULT_FLAGS|VM_GROWSUP|VM_ACCOUNT; + +#ifdef CONFIG_PAX_PAGEEXEC + if (current->mm->pax_flags & MF_PAX_PAGEEXEC) { + vma->vm_flags &= ~VM_EXEC; + +#ifdef CONFIG_PAX_MPROTECT + if (current->mm->pax_flags & MF_PAX_MPROTECT) + vma->vm_flags &= ~VM_MAYEXEC; +#endif + + } +#endif + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); down_write(¤t->mm->mmap_sem); if (insert_vm_struct(current->mm, vma)) { @@ -279,7 +292,7 @@ static int __init gate_vma_init(void) gate_vma.vm_start = FIXADDR_USER_START; gate_vma.vm_end = FIXADDR_USER_END; gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC; - gate_vma.vm_page_prot = __P101; + gate_vma.vm_page_prot = vm_get_page_prot(gate_vma.vm_flags); return 0; } diff --git a/arch/m32r/include/asm/cache.h b/arch/m32r/include/asm/cache.h index 40b3ee98..8c2c112 100644 --- a/arch/m32r/include/asm/cache.h +++ b/arch/m32r/include/asm/cache.h @@ -1,8 +1,10 @@ #ifndef _ASM_M32R_CACHE_H #define _ASM_M32R_CACHE_H +#include + /* L1 cache line size */ #define L1_CACHE_SHIFT 4 -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #endif /* _ASM_M32R_CACHE_H */ diff --git a/arch/m32r/lib/usercopy.c b/arch/m32r/lib/usercopy.c index 82abd15..d95ae5d 100644 --- a/arch/m32r/lib/usercopy.c +++ b/arch/m32r/lib/usercopy.c @@ -14,6 +14,9 @@ unsigned long __generic_copy_to_user(void __user *to, const void *from, unsigned long n) { + if ((long)n < 0) + return n; + prefetch(from); if (access_ok(VERIFY_WRITE, to, n)) __copy_user(to,from,n); @@ -23,6 +26,9 @@ __generic_copy_to_user(void __user *to, const void *from, unsigned long n) unsigned long __generic_copy_from_user(void *to, const void __user *from, unsigned long n) { + if ((long)n < 0) + return n; + prefetchw(to); if (access_ok(VERIFY_READ, from, n)) __copy_user_zeroing(to,from,n); diff --git a/arch/m68k/include/asm/cache.h b/arch/m68k/include/asm/cache.h index 0395c51..5f26031 100644 --- a/arch/m68k/include/asm/cache.h +++ b/arch/m68k/include/asm/cache.h @@ -4,9 +4,11 @@ #ifndef __ARCH_M68K_CACHE_H #define __ARCH_M68K_CACHE_H +#include + /* bytes per L1 cache line */ #define L1_CACHE_SHIFT 4 -#define L1_CACHE_BYTES (1<< L1_CACHE_SHIFT) +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #define ARCH_DMA_MINALIGN L1_CACHE_BYTES diff --git a/arch/metag/mm/hugetlbpage.c b/arch/metag/mm/hugetlbpage.c index 53f0f6c..2dc07fd 100644 --- a/arch/metag/mm/hugetlbpage.c +++ b/arch/metag/mm/hugetlbpage.c @@ -189,6 +189,7 @@ hugetlb_get_unmapped_area_new_pmd(unsigned long len) info.high_limit = TASK_SIZE; info.align_mask = PAGE_MASK & HUGEPT_MASK; info.align_offset = 0; + info.threadstack_offset = 0; return vm_unmapped_area(&info); } diff --git a/arch/microblaze/include/asm/cache.h b/arch/microblaze/include/asm/cache.h index 4efe96a..60e8699 100644 --- a/arch/microblaze/include/asm/cache.h +++ b/arch/microblaze/include/asm/cache.h @@ -13,11 +13,12 @@ #ifndef _ASM_MICROBLAZE_CACHE_H #define _ASM_MICROBLAZE_CACHE_H +#include #include #define L1_CACHE_SHIFT 5 /* word-granular cache in microblaze */ -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #define SMP_CACHE_BYTES L1_CACHE_BYTES diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index e3aa5b0..2ed7912 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2598,6 +2598,7 @@ source "kernel/Kconfig.preempt" config KEXEC bool "Kexec system call" select KEXEC_CORE + depends on !GRKERNSEC_KMEM 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 diff --git a/arch/mips/cavium-octeon/dma-octeon.c b/arch/mips/cavium-octeon/dma-octeon.c index 2cd45f5..d0f4900 100644 --- a/arch/mips/cavium-octeon/dma-octeon.c +++ b/arch/mips/cavium-octeon/dma-octeon.c @@ -191,7 +191,7 @@ static void *octeon_dma_alloc_coherent(struct device *dev, size_t size, static void octeon_dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle, struct dma_attrs *attrs) { - swiotlb_free_coherent(dev, size, vaddr, dma_handle); + swiotlb_free_coherent(dev, size, vaddr, dma_handle, attrs); } static dma_addr_t octeon_unity_phys_to_dma(struct device *dev, phys_addr_t paddr) diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h index 4c42fd9..fc7a48e 100644 --- a/arch/mips/include/asm/atomic.h +++ b/arch/mips/include/asm/atomic.h @@ -22,15 +22,39 @@ #include #include +#ifdef CONFIG_GENERIC_ATOMIC64 +#include +#endif + #define ATOMIC_INIT(i) { (i) } +#ifdef CONFIG_64BIT +#define _ASM_EXTABLE(from, to) \ +" .section __ex_table,\"a\"\n" \ +" .dword " #from ", " #to"\n" \ +" .previous\n" +#else +#define _ASM_EXTABLE(from, to) \ +" .section __ex_table,\"a\"\n" \ +" .word " #from ", " #to"\n" \ +" .previous\n" +#endif + /* * atomic_read - read atomic variable * @v: pointer of type atomic_t * * Atomically reads the value of @v. */ -#define atomic_read(v) ACCESS_ONCE((v)->counter) +static inline int atomic_read(const atomic_t *v) +{ + return ACCESS_ONCE(v->counter); +} + +static inline int atomic_read_unchecked(const atomic_unchecked_t *v) +{ + return ACCESS_ONCE(v->counter); +} /* * atomic_set - set atomic variable @@ -39,47 +63,77 @@ * * Atomically sets the value of @v to @i. */ -#define atomic_set(v, i) ((v)->counter = (i)) +static inline void atomic_set(atomic_t *v, int i) +{ + v->counter = i; +} -#define ATOMIC_OP(op, c_op, asm_op) \ -static __inline__ void atomic_##op(int i, atomic_t * v) \ +static inline void atomic_set_unchecked(atomic_unchecked_t *v, int i) +{ + v->counter = i; +} + +#ifdef CONFIG_PAX_REFCOUNT +#define __OVERFLOW_POST \ + " b 4f \n" \ + " .set noreorder \n" \ + "3: b 5f \n" \ + " move %0, %1 \n" \ + " .set reorder \n" +#define __OVERFLOW_EXTABLE \ + "3:\n" \ + _ASM_EXTABLE(2b, 3b) +#else +#define __OVERFLOW_POST +#define __OVERFLOW_EXTABLE +#endif + +#define __ATOMIC_OP(op, suffix, asm_op, extable) \ +static inline void atomic_##op##suffix(int i, atomic##suffix##_t * v) \ { \ if (kernel_uses_llsc && R10000_LLSC_WAR) { \ int temp; \ \ __asm__ __volatile__( \ - " .set arch=r4000 \n" \ - "1: ll %0, %1 # atomic_" #op " \n" \ - " " #asm_op " %0, %2 \n" \ + " .set mips3 \n" \ + "1: ll %0, %1 # atomic_" #op #suffix "\n" \ + "2: " #asm_op " %0, %2 \n" \ " sc %0, %1 \n" \ " beqzl %0, 1b \n" \ + extable \ " .set mips0 \n" \ : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter) \ : "Ir" (i)); \ } else if (kernel_uses_llsc) { \ int temp; \ \ - do { \ - __asm__ __volatile__( \ - " .set "MIPS_ISA_LEVEL" \n" \ - " ll %0, %1 # atomic_" #op "\n" \ - " " #asm_op " %0, %2 \n" \ - " sc %0, %1 \n" \ - " .set mips0 \n" \ - : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter) \ - : "Ir" (i)); \ - } while (unlikely(!temp)); \ + __asm__ __volatile__( \ + " .set "MIPS_ISA_LEVEL" \n" \ + "1: ll %0, %1 # atomic_" #op #suffix "\n" \ + "2: " #asm_op " %0, %2 \n" \ + " sc %0, %1 \n" \ + " beqz %0, 1b \n" \ + extable \ + " .set mips0 \n" \ + : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter) \ + : "Ir" (i)); \ } else { \ unsigned long flags; \ \ raw_local_irq_save(flags); \ - v->counter c_op i; \ + __asm__ __volatile__( \ + "2: " #asm_op " %0, %1 \n" \ + extable \ + : "+r" (v->counter) : "Ir" (i)); \ raw_local_irq_restore(flags); \ } \ } -#define ATOMIC_OP_RETURN(op, c_op, asm_op) \ -static __inline__ int atomic_##op##_return(int i, atomic_t * v) \ +#define ATOMIC_OP(op, asm_op) __ATOMIC_OP(op, _unchecked, asm_op##u, ) \ + __ATOMIC_OP(op, , asm_op, __OVERFLOW_EXTABLE) + +#define __ATOMIC_OP_RETURN(op, suffix, asm_op, post_op, extable) \ +static inline int atomic_##op##_return##suffix(int i, atomic##suffix##_t * v) \ { \ int result; \ \ @@ -89,12 +143,15 @@ static __inline__ int atomic_##op##_return(int i, atomic_t * v) \ int temp; \ \ __asm__ __volatile__( \ - " .set arch=r4000 \n" \ - "1: ll %1, %2 # atomic_" #op "_return \n" \ - " " #asm_op " %0, %1, %3 \n" \ + " .set mips3 \n" \ + "1: ll %1, %2 # atomic_" #op "_return" #suffix"\n" \ + "2: " #asm_op " %0, %1, %3 \n" \ " sc %0, %2 \n" \ " beqzl %0, 1b \n" \ - " " #asm_op " %0, %1, %3 \n" \ + post_op \ + extable \ + "4: " #asm_op " %0, %1, %3 \n" \ + "5: \n" \ " .set mips0 \n" \ : "=&r" (result), "=&r" (temp), \ "+" GCC_OFF_SMALL_ASM() (v->counter) \ @@ -102,26 +159,33 @@ static __inline__ int atomic_##op##_return(int i, atomic_t * v) \ } else if (kernel_uses_llsc) { \ int temp; \ \ - do { \ - __asm__ __volatile__( \ - " .set "MIPS_ISA_LEVEL" \n" \ - " ll %1, %2 # atomic_" #op "_return \n" \ - " " #asm_op " %0, %1, %3 \n" \ - " sc %0, %2 \n" \ - " .set mips0 \n" \ - : "=&r" (result), "=&r" (temp), \ - "+" GCC_OFF_SMALL_ASM() (v->counter) \ - : "Ir" (i)); \ - } while (unlikely(!result)); \ + __asm__ __volatile__( \ + " .set "MIPS_ISA_LEVEL" \n" \ + "1: ll %1, %2 # atomic_" #op "_return" #suffix "\n" \ + "2: " #asm_op " %0, %1, %3 \n" \ + " sc %0, %2 \n" \ + post_op \ + extable \ + "4: " #asm_op " %0, %1, %3 \n" \ + "5: \n" \ + " .set mips0 \n" \ + : "=&r" (result), "=&r" (temp), \ + "+" GCC_OFF_SMALL_ASM() (v->counter) \ + : "Ir" (i)); \ \ result = temp; result c_op i; \ } else { \ unsigned long flags; \ \ raw_local_irq_save(flags); \ - result = v->counter; \ - result c_op i; \ - v->counter = result; \ + __asm__ __volatile__( \ + " lw %0, %1 \n" \ + "2: " #asm_op " %0, %1, %2 \n" \ + " sw %0, %1 \n" \ + "3: \n" \ + extable \ + : "=&r" (result), "+" GCC_OFF_SMALL_ASM() (v->counter) \ + : "Ir" (i)); \ raw_local_irq_restore(flags); \ } \ \ @@ -130,20 +194,25 @@ static __inline__ int atomic_##op##_return(int i, atomic_t * v) \ return result; \ } -#define ATOMIC_OPS(op, c_op, asm_op) \ - ATOMIC_OP(op, c_op, asm_op) \ - ATOMIC_OP_RETURN(op, c_op, asm_op) +#define ATOMIC_OP_RETURN(op, asm_op) __ATOMIC_OP_RETURN(op, _unchecked, asm_op##u, , ) \ + __ATOMIC_OP_RETURN(op, , asm_op, __OVERFLOW_POST, __OVERFLOW_EXTABLE) -ATOMIC_OPS(add, +=, addu) -ATOMIC_OPS(sub, -=, subu) +#define ATOMIC_OPS(op, asm_op) \ + ATOMIC_OP(op, asm_op) \ + ATOMIC_OP_RETURN(op, asm_op) -ATOMIC_OP(and, &=, and) -ATOMIC_OP(or, |=, or) -ATOMIC_OP(xor, ^=, xor) +ATOMIC_OPS(add, add) +ATOMIC_OPS(sub, sub) + +ATOMIC_OP(and, and) +ATOMIC_OP(or, or) +ATOMIC_OP(xor, xor) #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN +#undef __ATOMIC_OP_RETURN #undef ATOMIC_OP +#undef __ATOMIC_OP /* * atomic_sub_if_positive - conditionally subtract integer from atomic variable @@ -153,7 +222,7 @@ ATOMIC_OP(xor, ^=, xor) * Atomically test @v and subtract @i if @v is greater or equal than @i. * The function returns the old value of @v minus @i. */ -static __inline__ int atomic_sub_if_positive(int i, atomic_t * v) +static __inline__ int atomic_sub_if_positive(int i, atomic_t *v) { int result; @@ -163,7 +232,7 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v) int temp; __asm__ __volatile__( - " .set arch=r4000 \n" + " .set "MIPS_ISA_LEVEL" \n" "1: ll %1, %2 # atomic_sub_if_positive\n" " subu %0, %1, %3 \n" " bltz %0, 1f \n" @@ -212,8 +281,26 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v) return result; } -#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) -#define atomic_xchg(v, new) (xchg(&((v)->counter), (new))) +static inline int atomic_cmpxchg(atomic_t *v, int old, int new) +{ + return cmpxchg(&v->counter, old, new); +} + +static inline int atomic_cmpxchg_unchecked(atomic_unchecked_t *v, int old, + int new) +{ + return cmpxchg(&(v->counter), old, new); +} + +static inline int atomic_xchg(atomic_t *v, int new) +{ + return xchg(&v->counter, new); +} + +static inline int atomic_xchg_unchecked(atomic_unchecked_t *v, int new) +{ + return xchg(&(v->counter), new); +} /** * __atomic_add_unless - add unless the number is a given value @@ -241,6 +328,10 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) #define atomic_dec_return(v) atomic_sub_return(1, (v)) #define atomic_inc_return(v) atomic_add_return(1, (v)) +static __inline__ int atomic_inc_return_unchecked(atomic_unchecked_t *v) +{ + return atomic_add_return_unchecked(1, v); +} /* * atomic_sub_and_test - subtract value from variable and test result @@ -262,6 +353,10 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) * other cases. */ #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) +static __inline__ int atomic_inc_and_test_unchecked(atomic_unchecked_t *v) +{ + return atomic_add_return_unchecked(1, v) == 0; +} /* * atomic_dec_and_test - decrement by 1 and test @@ -286,6 +381,10 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) * Atomically increments @v by 1. */ #define atomic_inc(v) atomic_add(1, (v)) +static __inline__ void atomic_inc_unchecked(atomic_unchecked_t *v) +{ + atomic_add_unchecked(1, v); +} /* * atomic_dec - decrement and test @@ -294,6 +393,10 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) * Atomically decrements @v by 1. */ #define atomic_dec(v) atomic_sub(1, (v)) +static __inline__ void atomic_dec_unchecked(atomic_unchecked_t *v) +{ + atomic_sub_unchecked(1, v); +} /* * atomic_add_negative - add and test if negative @@ -315,54 +418,77 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) * @v: pointer of type atomic64_t * */ -#define atomic64_read(v) ACCESS_ONCE((v)->counter) +static inline long atomic64_read(const atomic64_t *v) +{ + return ACCESS_ONCE(v->counter); +} + +static inline long atomic64_read_unchecked(const atomic64_unchecked_t *v) +{ + return ACCESS_ONCE(v->counter); +} /* * atomic64_set - set atomic variable * @v: pointer of type atomic64_t * @i: required value */ -#define atomic64_set(v, i) ((v)->counter = (i)) +static inline void atomic64_set(atomic64_t *v, long i) +{ + v->counter = i; +} -#define ATOMIC64_OP(op, c_op, asm_op) \ -static __inline__ void atomic64_##op(long i, atomic64_t * v) \ +static inline void atomic64_set_unchecked(atomic64_unchecked_t *v, long i) +{ + v->counter = i; +} + +#define __ATOMIC64_OP(op, suffix, asm_op, extable) \ +static inline void atomic64_##op##suffix(long i, atomic64##suffix##_t * v) \ { \ if (kernel_uses_llsc && R10000_LLSC_WAR) { \ long temp; \ \ __asm__ __volatile__( \ - " .set arch=r4000 \n" \ - "1: lld %0, %1 # atomic64_" #op " \n" \ - " " #asm_op " %0, %2 \n" \ + " .set "MIPS_ISA_LEVEL" \n" \ + "1: lld %0, %1 # atomic64_" #op #suffix "\n" \ + "2: " #asm_op " %0, %2 \n" \ " scd %0, %1 \n" \ " beqzl %0, 1b \n" \ + extable \ " .set mips0 \n" \ : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter) \ : "Ir" (i)); \ } else if (kernel_uses_llsc) { \ long temp; \ \ - do { \ - __asm__ __volatile__( \ - " .set "MIPS_ISA_LEVEL" \n" \ - " lld %0, %1 # atomic64_" #op "\n" \ - " " #asm_op " %0, %2 \n" \ - " scd %0, %1 \n" \ - " .set mips0 \n" \ - : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter) \ - : "Ir" (i)); \ - } while (unlikely(!temp)); \ + __asm__ __volatile__( \ + " .set "MIPS_ISA_LEVEL" \n" \ + "1: lld %0, %1 # atomic64_" #op #suffix "\n" \ + "2: " #asm_op " %0, %2 \n" \ + " scd %0, %1 \n" \ + " beqz %0, 1b \n" \ + extable \ + " .set mips0 \n" \ + : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter) \ + : "Ir" (i)); \ } else { \ unsigned long flags; \ \ raw_local_irq_save(flags); \ - v->counter c_op i; \ + __asm__ __volatile__( \ + "2: " #asm_op " %0, %1 \n" \ + extable \ + : "+" GCC_OFF_SMALL_ASM() (v->counter) : "Ir" (i)); \ raw_local_irq_restore(flags); \ } \ } -#define ATOMIC64_OP_RETURN(op, c_op, asm_op) \ -static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ +#define ATOMIC64_OP(op, asm_op) __ATOMIC64_OP(op, _unchecked, asm_op##u, ) \ + __ATOMIC64_OP(op, , asm_op, __OVERFLOW_EXTABLE) + +#define __ATOMIC64_OP_RETURN(op, suffix, asm_op, post_op, extable) \ +static inline long atomic64_##op##_return##suffix(long i, atomic64##suffix##_t * v)\ { \ long result; \ \ @@ -372,12 +498,15 @@ static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ long temp; \ \ __asm__ __volatile__( \ - " .set arch=r4000 \n" \ + " .set mips3 \n" \ "1: lld %1, %2 # atomic64_" #op "_return\n" \ - " " #asm_op " %0, %1, %3 \n" \ + "2: " #asm_op " %0, %1, %3 \n" \ " scd %0, %2 \n" \ " beqzl %0, 1b \n" \ - " " #asm_op " %0, %1, %3 \n" \ + post_op \ + extable \ + "4: " #asm_op " %0, %1, %3 \n" \ + "5: \n" \ " .set mips0 \n" \ : "=&r" (result), "=&r" (temp), \ "+" GCC_OFF_SMALL_ASM() (v->counter) \ @@ -385,27 +514,35 @@ static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ } else if (kernel_uses_llsc) { \ long temp; \ \ - do { \ - __asm__ __volatile__( \ - " .set "MIPS_ISA_LEVEL" \n" \ - " lld %1, %2 # atomic64_" #op "_return\n" \ - " " #asm_op " %0, %1, %3 \n" \ - " scd %0, %2 \n" \ - " .set mips0 \n" \ - : "=&r" (result), "=&r" (temp), \ - "=" GCC_OFF_SMALL_ASM() (v->counter) \ - : "Ir" (i), GCC_OFF_SMALL_ASM() (v->counter) \ - : "memory"); \ - } while (unlikely(!result)); \ + __asm__ __volatile__( \ + " .set "MIPS_ISA_LEVEL" \n" \ + "1: lld %1, %2 # atomic64_" #op "_return" #suffix "\n"\ + "2: " #asm_op " %0, %1, %3 \n" \ + " scd %0, %2 \n" \ + " beqz %0, 1b \n" \ + post_op \ + extable \ + "4: " #asm_op " %0, %1, %3 \n" \ + "5: \n" \ + " .set mips0 \n" \ + : "=&r" (result), "=&r" (temp), \ + "=" GCC_OFF_SMALL_ASM() (v->counter) \ + : "Ir" (i), GCC_OFF_SMALL_ASM() (v->counter) \ + : "memory"); \ \ result = temp; result c_op i; \ } else { \ unsigned long flags; \ \ raw_local_irq_save(flags); \ - result = v->counter; \ - result c_op i; \ - v->counter = result; \ + __asm__ __volatile__( \ + " ld %0, %1 \n" \ + "2: " #asm_op " %0, %1, %2 \n" \ + " sd %0, %1 \n" \ + "3: \n" \ + extable \ + : "=&r" (result), "+" GCC_OFF_SMALL_ASM() (v->counter) \ + : "Ir" (i)); \ raw_local_irq_restore(flags); \ } \ \ @@ -414,19 +551,27 @@ static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ return result; \ } -#define ATOMIC64_OPS(op, c_op, asm_op) \ - ATOMIC64_OP(op, c_op, asm_op) \ - ATOMIC64_OP_RETURN(op, c_op, asm_op) +#define ATOMIC64_OP_RETURN(op, asm_op) __ATOMIC64_OP_RETURN(op, _unchecked, asm_op##u, , ) \ + __ATOMIC64_OP_RETURN(op, , asm_op, __OVERFLOW_POST, __OVERFLOW_EXTABLE) -ATOMIC64_OPS(add, +=, daddu) -ATOMIC64_OPS(sub, -=, dsubu) -ATOMIC64_OP(and, &=, and) -ATOMIC64_OP(or, |=, or) -ATOMIC64_OP(xor, ^=, xor) +#define ATOMIC64_OPS(op, asm_op) \ + ATOMIC64_OP(op, asm_op) \ + ATOMIC64_OP_RETURN(op, asm_op) + +ATOMIC64_OPS(add, dadd) +ATOMIC64_OPS(sub, dsub) + +ATOMIC64_OP(and, and) +ATOMIC64_OP(or, or) +ATOMIC64_OP(xor, xor) #undef ATOMIC64_OPS #undef ATOMIC64_OP_RETURN +#undef __ATOMIC64_OP_RETURN #undef ATOMIC64_OP +#undef __ATOMIC64_OP +#undef __OVERFLOW_EXTABLE +#undef __OVERFLOW_POST /* * atomic64_sub_if_positive - conditionally subtract integer from atomic @@ -437,7 +582,7 @@ ATOMIC64_OP(xor, ^=, xor) * Atomically test @v and subtract @i if @v is greater or equal than @i. * The function returns the old value of @v minus @i. */ -static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v) +static __inline__ long atomic64_sub_if_positive(long i, atomic64_t *v) { long result; @@ -447,7 +592,7 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v) long temp; __asm__ __volatile__( - " .set arch=r4000 \n" + " .set "MIPS_ISA_LEVEL" \n" "1: lld %1, %2 # atomic64_sub_if_positive\n" " dsubu %0, %1, %3 \n" " bltz %0, 1f \n" @@ -496,9 +641,26 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v) return result; } -#define atomic64_cmpxchg(v, o, n) \ - ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n))) -#define atomic64_xchg(v, new) (xchg(&((v)->counter), (new))) +static inline long atomic64_cmpxchg(atomic64_t *v, long old, long new) +{ + return cmpxchg(&v->counter, old, new); +} + +static inline long atomic64_cmpxchg_unchecked(atomic64_unchecked_t *v, long old, + long new) +{ + return cmpxchg(&(v->counter), old, new); +} + +static inline long atomic64_xchg(atomic64_t *v, long new) +{ + return xchg(&v->counter, new); +} + +static inline long atomic64_xchg_unchecked(atomic64_unchecked_t *v, long new) +{ + return xchg(&(v->counter), new); +} /** * atomic64_add_unless - add unless the number is a given value @@ -528,6 +690,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) #define atomic64_dec_return(v) atomic64_sub_return(1, (v)) #define atomic64_inc_return(v) atomic64_add_return(1, (v)) +#define atomic64_inc_return_unchecked(v) atomic64_add_return_unchecked(1, (v)) /* * atomic64_sub_and_test - subtract value from variable and test result @@ -549,6 +712,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) * other cases. */ #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) +#define atomic64_inc_and_test_unchecked(v) atomic64_add_return_unchecked(1, (v)) == 0) /* * atomic64_dec_and_test - decrement by 1 and test @@ -573,6 +737,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) * Atomically increments @v by 1. */ #define atomic64_inc(v) atomic64_add(1, (v)) +#define atomic64_inc_unchecked(v) atomic64_add_unchecked(1, (v)) /* * atomic64_dec - decrement and test @@ -581,6 +746,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) * Atomically decrements @v by 1. */ #define atomic64_dec(v) atomic64_sub(1, (v)) +#define atomic64_dec_unchecked(v) atomic64_sub_unchecked(1, (v)) /* * atomic64_add_negative - add and test if negative diff --git a/arch/mips/include/asm/cache.h b/arch/mips/include/asm/cache.h index b4db69f..8f3b093 100644 --- a/arch/mips/include/asm/cache.h +++ b/arch/mips/include/asm/cache.h @@ -9,10 +9,11 @@ #ifndef _ASM_CACHE_H #define _ASM_CACHE_H +#include #include #define L1_CACHE_SHIFT CONFIG_MIPS_L1_CACHE_SHIFT -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #define SMP_CACHE_SHIFT L1_CACHE_SHIFT #define SMP_CACHE_BYTES L1_CACHE_BYTES diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index 53b2693..13803b9 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -419,6 +419,13 @@ extern const char *__elf_platform; #define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) #endif +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE (TASK_IS_32BIT_ADDR ? 0x00400000UL : 0x00400000UL) + +#define PAX_DELTA_MMAP_LEN (TASK_IS_32BIT_ADDR ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#define PAX_DELTA_STACK_LEN (TASK_IS_32BIT_ADDR ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#endif + #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 struct linux_binprm; extern int arch_setup_additional_pages(struct linux_binprm *bprm, diff --git a/arch/mips/include/asm/exec.h b/arch/mips/include/asm/exec.h index c1f6afa..38cc6e9 100644 --- a/arch/mips/include/asm/exec.h +++ b/arch/mips/include/asm/exec.h @@ -12,6 +12,6 @@ #ifndef _ASM_EXEC_H #define _ASM_EXEC_H -extern unsigned long arch_align_stack(unsigned long sp); +#define arch_align_stack(x) ((x) & ~0xfUL) #endif /* _ASM_EXEC_H */ diff --git a/arch/mips/include/asm/hw_irq.h b/arch/mips/include/asm/hw_irq.h index 9e8ef59..1139d6b 100644 --- a/arch/mips/include/asm/hw_irq.h +++ b/arch/mips/include/asm/hw_irq.h @@ -10,7 +10,7 @@ #include -extern atomic_t irq_err_count; +extern atomic_unchecked_t irq_err_count; /* * interrupt-retrigger: NOP for now. This may not be appropriate for all diff --git a/arch/mips/include/asm/local.h b/arch/mips/include/asm/local.h index 8feaed6..1bd8a64 100644 --- a/arch/mips/include/asm/local.h +++ b/arch/mips/include/asm/local.h @@ -13,15 +13,25 @@ typedef struct atomic_long_t a; } local_t; +typedef struct { + atomic_long_unchecked_t a; +} local_unchecked_t; + #define LOCAL_INIT(i) { ATOMIC_LONG_INIT(i) } #define local_read(l) atomic_long_read(&(l)->a) +#define local_read_unchecked(l) atomic_long_read_unchecked(&(l)->a) #define local_set(l, i) atomic_long_set(&(l)->a, (i)) +#define local_set_unchecked(l, i) atomic_long_set_unchecked(&(l)->a, (i)) #define local_add(i, l) atomic_long_add((i), (&(l)->a)) +#define local_add_unchecked(i, l) atomic_long_add_unchecked((i), (&(l)->a)) #define local_sub(i, l) atomic_long_sub((i), (&(l)->a)) +#define local_sub_unchecked(i, l) atomic_long_sub_unchecked((i), (&(l)->a)) #define local_inc(l) atomic_long_inc(&(l)->a) +#define local_inc_unchecked(l) atomic_long_inc_unchecked(&(l)->a) #define local_dec(l) atomic_long_dec(&(l)->a) +#define local_dec_unchecked(l) atomic_long_dec_unchecked(&(l)->a) /* * Same as above, but return the result value @@ -71,6 +81,51 @@ static __inline__ long local_add_return(long i, local_t * l) return result; } +static __inline__ long local_add_return_unchecked(long i, local_unchecked_t * l) +{ + unsigned long result; + + if (kernel_uses_llsc && R10000_LLSC_WAR) { + unsigned long temp; + + __asm__ __volatile__( + " .set mips3 \n" + "1:" __LL "%1, %2 # local_add_return \n" + " addu %0, %1, %3 \n" + __SC "%0, %2 \n" + " beqzl %0, 1b \n" + " addu %0, %1, %3 \n" + " .set mips0 \n" + : "=&r" (result), "=&r" (temp), "=m" (l->a.counter) + : "Ir" (i), "m" (l->a.counter) + : "memory"); + } else if (kernel_uses_llsc) { + unsigned long temp; + + __asm__ __volatile__( + " .set mips3 \n" + "1:" __LL "%1, %2 # local_add_return \n" + " addu %0, %1, %3 \n" + __SC "%0, %2 \n" + " beqz %0, 1b \n" + " addu %0, %1, %3 \n" + " .set mips0 \n" + : "=&r" (result), "=&r" (temp), "=m" (l->a.counter) + : "Ir" (i), "m" (l->a.counter) + : "memory"); + } else { + unsigned long flags; + + local_irq_save(flags); + result = l->a.counter; + result += i; + l->a.counter = result; + local_irq_restore(flags); + } + + return result; +} + static __inline__ long local_sub_return(long i, local_t * l) { unsigned long result; @@ -118,6 +173,8 @@ static __inline__ long local_sub_return(long i, local_t * l) #define local_cmpxchg(l, o, n) \ ((long)cmpxchg_local(&((l)->a.counter), (o), (n))) +#define local_cmpxchg_unchecked(l, o, n) \ + ((long)cmpxchg_local(&((l)->a.counter), (o), (n))) #define local_xchg(l, n) (atomic_long_xchg((&(l)->a), (n))) /** diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h index 89dd7fe..a123c97 100644 --- a/arch/mips/include/asm/page.h +++ b/arch/mips/include/asm/page.h @@ -118,7 +118,7 @@ extern void copy_user_highpage(struct page *to, struct page *from, #ifdef CONFIG_CPU_MIPS32 typedef struct { unsigned long pte_low, pte_high; } pte_t; #define pte_val(x) ((x).pte_low | ((unsigned long long)(x).pte_high << 32)) - #define __pte(x) ({ pte_t __pte = {(x), ((unsigned long long)(x)) >> 32}; __pte; }) + #define __pte(x) ({ pte_t __pte = {(x), (x) >> 32}; __pte; }) #else typedef struct { unsigned long long pte; } pte_t; #define pte_val(x) ((x).pte) diff --git a/arch/mips/include/asm/pgalloc.h b/arch/mips/include/asm/pgalloc.h index b336037..5b874cc 100644 --- a/arch/mips/include/asm/pgalloc.h +++ b/arch/mips/include/asm/pgalloc.h @@ -37,6 +37,11 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) { set_pud(pud, __pud((unsigned long)pmd)); } + +static inline void pud_populate_kernel(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) +{ + pud_populate(mm, pud, pmd); +} #endif /* diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index 8957f15..c5b802e 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -20,6 +20,9 @@ #include #include +#define ktla_ktva(addr) (addr) +#define ktva_ktla(addr) (addr) + struct mm_struct; struct vm_area_struct; diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h index e309d8f..20eefec 100644 --- a/arch/mips/include/asm/thread_info.h +++ b/arch/mips/include/asm/thread_info.h @@ -101,6 +101,9 @@ static inline struct thread_info *current_thread_info(void) #define TIF_NOTIFY_RESUME 5 /* callback before returning to user */ #define TIF_UPROBE 6 /* breakpointed or singlestepping */ #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ +/* li takes a 32bit immediate */ +#define TIF_GRSEC_SETXID 10 /* update credentials on syscall entry/exit */ + #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ #define TIF_NOHZ 19 /* in adaptive nohz mode */ @@ -137,14 +140,16 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_USEDMSA (1< #include #include diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c index 9287678..f870e47 100644 --- a/arch/mips/kernel/binfmt_elfo32.c +++ b/arch/mips/kernel/binfmt_elfo32.c @@ -70,6 +70,13 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #undef ELF_ET_DYN_BASE #define ELF_ET_DYN_BASE (TASK32_SIZE / 3 * 2) +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE (TASK_IS_32BIT_ADDR ? 0x00400000UL : 0x00400000UL) + +#define PAX_DELTA_MMAP_LEN (TASK_IS_32BIT_ADDR ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#define PAX_DELTA_STACK_LEN (TASK_IS_32BIT_ADDR ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#endif + #include #include diff --git a/arch/mips/kernel/irq-gt641xx.c b/arch/mips/kernel/irq-gt641xx.c index 44a1f79..2bd6aa3 100644 --- a/arch/mips/kernel/irq-gt641xx.c +++ b/arch/mips/kernel/irq-gt641xx.c @@ -110,7 +110,7 @@ void gt641xx_irq_dispatch(void) } } - atomic_inc(&irq_err_count); + atomic_inc_unchecked(&irq_err_count); } void __init gt641xx_irq_init(void) diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index 8eb5af8..2baf465 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -34,17 +34,17 @@ void ack_bad_irq(unsigned int irq) printk("unexpected IRQ # %d\n", irq); } -atomic_t irq_err_count; +atomic_unchecked_t irq_err_count; int arch_show_interrupts(struct seq_file *p, int prec) { - seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count)); + seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read_unchecked(&irq_err_count)); return 0; } asmlinkage void spurious_interrupt(void) { - atomic_inc(&irq_err_count); + atomic_inc_unchecked(&irq_err_count); } void __init init_IRQ(void) @@ -58,6 +58,8 @@ void __init init_IRQ(void) } #ifdef CONFIG_DEBUG_STACKOVERFLOW + +extern void gr_handle_kernel_exploit(void); static inline void check_stack_overflow(void) { unsigned long sp; @@ -73,6 +75,7 @@ static inline void check_stack_overflow(void) printk("do_IRQ: stack overflow: %ld\n", sp - sizeof(struct thread_info)); dump_stack(); + gr_handle_kernel_exploit(); } } #else diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index f63a289..53037c22 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -172,7 +172,7 @@ int cps_pm_enter_state(enum cps_pm_state state) nc_core_ready_count = nc_addr; /* Ensure ready_count is zero-initialised before the assembly runs */ - ACCESS_ONCE(*nc_core_ready_count) = 0; + ACCESS_ONCE_RW(*nc_core_ready_count) = 0; coupled_barrier(&per_cpu(pm_barrier, core), online); /* Run the generated entry code */ diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index f2975d4..f61d355 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -541,18 +541,6 @@ out: return pc; } -/* - * Don't forget that the stack pointer must be aligned on a 8 bytes - * boundary for 32-bits ABI and 16 bytes for 64-bits ABI. - */ -unsigned long arch_align_stack(unsigned long sp) -{ - if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) - sp -= get_random_int() & ~PAGE_MASK; - - return sp & ALMASK; -} - static void arch_dump_stack(void *info) { struct pt_regs *regs; diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 4f0ac78..491124a 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -873,6 +873,10 @@ long arch_ptrace(struct task_struct *child, long request, return ret; } +#ifdef CONFIG_GRKERNSEC_SETXID +extern void gr_delayed_cred_worker(void); +#endif + /* * Notification of system call entry/exit * - triggered by current->work.syscall_trace @@ -891,6 +895,11 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall) tracehook_report_syscall_entry(regs)) ret = -1; +#ifdef CONFIG_GRKERNSEC_SETXID + if (unlikely(test_and_clear_thread_flag(TIF_GRSEC_SETXID))) + gr_delayed_cred_worker(); +#endif + if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_enter(regs, regs->regs[2]); diff --git a/arch/mips/kernel/sync-r4k.c b/arch/mips/kernel/sync-r4k.c index 2242bdd..b284048 100644 --- a/arch/mips/kernel/sync-r4k.c +++ b/arch/mips/kernel/sync-r4k.c @@ -18,8 +18,8 @@ #include static atomic_t count_start_flag = ATOMIC_INIT(0); -static atomic_t count_count_start = ATOMIC_INIT(0); -static atomic_t count_count_stop = ATOMIC_INIT(0); +static atomic_unchecked_t count_count_start = ATOMIC_INIT(0); +static atomic_unchecked_t count_count_stop = ATOMIC_INIT(0); static atomic_t count_reference = ATOMIC_INIT(0); #define COUNTON 100 @@ -58,13 +58,13 @@ void synchronise_count_master(int cpu) for (i = 0; i < NR_LOOPS; i++) { /* slaves loop on '!= 2' */ - while (atomic_read(&count_count_start) != 1) + while (atomic_read_unchecked(&count_count_start) != 1) mb(); - atomic_set(&count_count_stop, 0); + atomic_set_unchecked(&count_count_stop, 0); smp_wmb(); /* this lets the slaves write their count register */ - atomic_inc(&count_count_start); + atomic_inc_unchecked(&count_count_start); /* * Everyone initialises count in the last loop: @@ -75,11 +75,11 @@ void synchronise_count_master(int cpu) /* * Wait for all slaves to leave the synchronization point: */ - while (atomic_read(&count_count_stop) != 1) + while (atomic_read_unchecked(&count_count_stop) != 1) mb(); - atomic_set(&count_count_start, 0); + atomic_set_unchecked(&count_count_start, 0); smp_wmb(); - atomic_inc(&count_count_stop); + atomic_inc_unchecked(&count_count_stop); } /* Arrange for an interrupt in a short while */ write_c0_compare(read_c0_count() + COUNTON); @@ -112,8 +112,8 @@ void synchronise_count_slave(int cpu) initcount = atomic_read(&count_reference); for (i = 0; i < NR_LOOPS; i++) { - atomic_inc(&count_count_start); - while (atomic_read(&count_count_start) != 2) + atomic_inc_unchecked(&count_count_start); + while (atomic_read_unchecked(&count_count_start) != 2) mb(); /* @@ -122,8 +122,8 @@ void synchronise_count_slave(int cpu) if (i == NR_LOOPS-1) write_c0_count(initcount); - atomic_inc(&count_count_stop); - while (atomic_read(&count_count_stop) != 2) + atomic_inc_unchecked(&count_count_stop); + while (atomic_read_unchecked(&count_count_stop) != 2) mb(); } /* Arrange for an interrupt in a short while */ diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index fdb392b..c5cf284 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -692,7 +692,18 @@ asmlinkage void do_ov(struct pt_regs *regs) siginfo_t info; prev_state = exception_enter(); - die_if_kernel("Integer overflow", regs); + if (unlikely(!user_mode(regs))) { + +#ifdef CONFIG_PAX_REFCOUNT + if (fixup_exception(regs)) { + pax_report_refcount_overflow(regs); + exception_exit(prev_state); + return; + } +#endif + + die("Integer overflow", regs); + } info.si_code = FPE_INTOVF; info.si_signo = SIGFPE; diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index 4b88fa0..b16bc17 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -31,6 +31,23 @@ int show_unhandled_signals = 1; +#ifdef CONFIG_PAX_PAGEEXEC +void pax_report_insns(struct pt_regs *regs, void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk(KERN_CONT "???????? "); + else + printk(KERN_CONT "%08x ", c); + } + printk("\n"); +} +#endif + /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -205,6 +222,14 @@ bad_area: bad_area_nosemaphore: /* User mode accesses just cause a SIGSEGV */ if (user_mode(regs)) { + +#ifdef CONFIG_PAX_PAGEEXEC + if (cpu_has_rixi && (mm->pax_flags & MF_PAX_PAGEEXEC) && !write && address == instruction_pointer(regs)) { + pax_report_fault(regs, (void *)address, (void *)user_stack_pointer(regs)); + do_group_exit(SIGKILL); + } +#endif + tsk->thread.cp0_badvaddr = address; tsk->thread.error_code = write; if (show_unhandled_signals && diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c index 5c81fdd..db158d3 100644 --- a/arch/mips/mm/mmap.c +++ b/arch/mips/mm/mmap.c @@ -59,6 +59,7 @@ static unsigned long arch_get_unmapped_area_common(struct file *filp, struct vm_area_struct *vma; unsigned long addr = addr0; int do_color_align; + unsigned long offset = gr_rand_threadstack_offset(mm, filp, flags); struct vm_unmapped_area_info info; if (unlikely(len > TASK_SIZE)) @@ -84,6 +85,11 @@ static unsigned long arch_get_unmapped_area_common(struct file *filp, do_color_align = 1; /* requesting a specific address */ + +#ifdef CONFIG_PAX_RANDMMAP + if (!(current->mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + if (addr) { if (do_color_align) addr = COLOUR_ALIGN(addr, pgoff); @@ -91,14 +97,14 @@ static unsigned long arch_get_unmapped_area_common(struct file *filp, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + if (TASK_SIZE - len >= addr && check_heap_stack_gap(vma, addr, len, offset)) return addr; } info.length = len; info.align_mask = do_color_align ? (PAGE_MASK & shm_align_mask) : 0; info.align_offset = pgoff << PAGE_SHIFT; + info.threadstack_offset = offset; if (dir == DOWN) { info.flags = VM_UNMAPPED_AREA_TOPDOWN; @@ -160,45 +166,34 @@ void arch_pick_mmap_layout(struct mm_struct *mm) { unsigned long random_factor = 0UL; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + if (current->flags & PF_RANDOMIZE) random_factor = arch_mmap_rnd(); if (mmap_is_legacy()) { mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base += mm->delta_mmap; +#endif + mm->get_unmapped_area = arch_get_unmapped_area; } else { mm->mmap_base = mmap_base(random_factor); + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base -= mm->delta_mmap + mm->delta_stack; +#endif + mm->get_unmapped_area = arch_get_unmapped_area_topdown; } } -static inline unsigned long brk_rnd(void) -{ - unsigned long rnd = get_random_int(); - - rnd = rnd << PAGE_SHIFT; - /* 8MB for 32bit, 256MB for 64bit */ - if (TASK_IS_32BIT_ADDR) - rnd = rnd & 0x7ffffful; - else - rnd = rnd & 0xffffffful; - - return rnd; -} - -unsigned long arch_randomize_brk(struct mm_struct *mm) -{ - unsigned long base = mm->brk; - unsigned long ret; - - ret = PAGE_ALIGN(base + brk_rnd()); - - if (ret < mm->brk) - return mm->brk; - - return ret; -} - int __virt_addr_valid(const volatile void *kaddr) { return pfn_valid(PFN_DOWN(virt_to_phys(kaddr))); diff --git a/arch/mips/sgi-ip27/ip27-nmi.c b/arch/mips/sgi-ip27/ip27-nmi.c index a2358b4..7cead4f 100644 --- a/arch/mips/sgi-ip27/ip27-nmi.c +++ b/arch/mips/sgi-ip27/ip27-nmi.c @@ -187,9 +187,9 @@ void cont_nmi_dump(void) { #ifndef REAL_NMI_SIGNAL - static atomic_t nmied_cpus = ATOMIC_INIT(0); + static atomic_unchecked_t nmied_cpus = ATOMIC_INIT(0); - atomic_inc(&nmied_cpus); + atomic_inc_unchecked(&nmied_cpus); #endif /* * Only allow 1 cpu to proceed @@ -233,7 +233,7 @@ cont_nmi_dump(void) udelay(10000); } #else - while (atomic_read(&nmied_cpus) != num_online_cpus()); + while (atomic_read_unchecked(&nmied_cpus) != num_online_cpus()); #endif /* diff --git a/arch/mips/sni/rm200.c b/arch/mips/sni/rm200.c index a046b30..6799527 100644 --- a/arch/mips/sni/rm200.c +++ b/arch/mips/sni/rm200.c @@ -270,7 +270,7 @@ spurious_8259A_irq: "spurious RM200 8259A interrupt: IRQ%d.\n", irq); spurious_irq_mask |= irqmask; } - atomic_inc(&irq_err_count); + atomic_inc_unchecked(&irq_err_count); /* * Theoretically we do not have to handle this IRQ, * but in Linux this does not cause problems and is diff --git a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c index 41e873b..34d33a7 100644 --- a/arch/mips/vr41xx/common/icu.c +++ b/arch/mips/vr41xx/common/icu.c @@ -653,7 +653,7 @@ static int icu_get_irq(unsigned int irq) printk(KERN_ERR "spurious ICU interrupt: %04x,%04x\n", pend1, pend2); - atomic_inc(&irq_err_count); + atomic_inc_unchecked(&irq_err_count); return -1; } diff --git a/arch/mips/vr41xx/common/irq.c b/arch/mips/vr41xx/common/irq.c index ae0e4ee..e8f0692 100644 --- a/arch/mips/vr41xx/common/irq.c +++ b/arch/mips/vr41xx/common/irq.c @@ -64,7 +64,7 @@ static void irq_dispatch(unsigned int irq) irq_cascade_t *cascade; if (irq >= NR_IRQS) { - atomic_inc(&irq_err_count); + atomic_inc_unchecked(&irq_err_count); return; } @@ -84,7 +84,7 @@ static void irq_dispatch(unsigned int irq) ret = cascade->get_irq(irq); irq = ret; if (ret < 0) - atomic_inc(&irq_err_count); + atomic_inc_unchecked(&irq_err_count); else irq_dispatch(irq); if (!irqd_irq_disabled(idata) && chip->irq_unmask) diff --git a/arch/mn10300/proc-mn103e010/include/proc/cache.h b/arch/mn10300/proc-mn103e010/include/proc/cache.h index 967d144..db12197 100644 --- a/arch/mn10300/proc-mn103e010/include/proc/cache.h +++ b/arch/mn10300/proc-mn103e010/include/proc/cache.h @@ -11,12 +11,14 @@ #ifndef _ASM_PROC_CACHE_H #define _ASM_PROC_CACHE_H +#include + /* L1 cache */ #define L1_CACHE_NWAYS 4 /* number of ways in caches */ #define L1_CACHE_NENTRIES 256 /* number of entries in each way */ -#define L1_CACHE_BYTES 16 /* bytes per entry */ #define L1_CACHE_SHIFT 4 /* shift for bytes per entry */ +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) /* bytes per entry */ #define L1_CACHE_WAYDISP 0x1000 /* displacement of one way from the next */ #define L1_CACHE_TAG_VALID 0x00000001 /* cache tag valid bit */ diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/cache.h b/arch/mn10300/proc-mn2ws0050/include/proc/cache.h index bcb5df2..84fabd2 100644 --- a/arch/mn10300/proc-mn2ws0050/include/proc/cache.h +++ b/arch/mn10300/proc-mn2ws0050/include/proc/cache.h @@ -16,13 +16,15 @@ #ifndef _ASM_PROC_CACHE_H #define _ASM_PROC_CACHE_H +#include + /* * L1 cache */ #define L1_CACHE_NWAYS 4 /* number of ways in caches */ #define L1_CACHE_NENTRIES 128 /* number of entries in each way */ -#define L1_CACHE_BYTES 32 /* bytes per entry */ #define L1_CACHE_SHIFT 5 /* shift for bytes per entry */ +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) /* bytes per entry */ #define L1_CACHE_WAYDISP 0x1000 /* distance from one way to the next */ #define L1_CACHE_TAG_VALID 0x00000001 /* cache tag valid bit */ diff --git a/arch/openrisc/include/asm/cache.h b/arch/openrisc/include/asm/cache.h index 4ce7a01..449202a 100644 --- a/arch/openrisc/include/asm/cache.h +++ b/arch/openrisc/include/asm/cache.h @@ -19,11 +19,13 @@ #ifndef __ASM_OPENRISC_CACHE_H #define __ASM_OPENRISC_CACHE_H +#include + /* FIXME: How can we replace these with values from the CPU... * they shouldn't be hard-coded! */ -#define L1_CACHE_BYTES 16 #define L1_CACHE_SHIFT 4 +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #endif /* __ASM_OPENRISC_CACHE_H */ diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h index 2536965..5d3e884 100644 --- a/arch/parisc/include/asm/atomic.h +++ b/arch/parisc/include/asm/atomic.h @@ -280,6 +280,16 @@ static inline long atomic64_dec_if_positive(atomic64_t *v) return dec; } +#define atomic64_read_unchecked(v) atomic64_read(v) +#define atomic64_set_unchecked(v, i) atomic64_set((v), (i)) +#define atomic64_add_unchecked(a, v) atomic64_add((a), (v)) +#define atomic64_add_return_unchecked(a, v) atomic64_add_return((a), (v)) +#define atomic64_sub_unchecked(a, v) atomic64_sub((a), (v)) +#define atomic64_inc_unchecked(v) atomic64_inc(v) +#define atomic64_inc_return_unchecked(v) atomic64_inc_return(v) +#define atomic64_dec_unchecked(v) atomic64_dec(v) +#define atomic64_cmpxchg_unchecked(v, o, n) atomic64_cmpxchg((v), (o), (n)) + #endif /* !CONFIG_64BIT */ diff --git a/arch/parisc/include/asm/cache.h b/arch/parisc/include/asm/cache.h index 47f11c7..3420df2 100644 --- a/arch/parisc/include/asm/cache.h +++ b/arch/parisc/include/asm/cache.h @@ -5,6 +5,7 @@ #ifndef __ARCH_PARISC_CACHE_H #define __ARCH_PARISC_CACHE_H +#include /* * PA 2.0 processors have 64-byte cachelines; PA 1.1 processors have @@ -15,13 +16,13 @@ * just ruin performance. */ #ifdef CONFIG_PA20 -#define L1_CACHE_BYTES 64 #define L1_CACHE_SHIFT 6 #else -#define L1_CACHE_BYTES 32 #define L1_CACHE_SHIFT 5 #endif +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) + #ifndef __ASSEMBLY__ #define SMP_CACHE_BYTES L1_CACHE_BYTES diff --git a/arch/parisc/include/asm/elf.h b/arch/parisc/include/asm/elf.h index 78c9fd3..42fa66a 100644 --- a/arch/parisc/include/asm/elf.h +++ b/arch/parisc/include/asm/elf.h @@ -342,6 +342,13 @@ struct pt_regs; /* forward declaration... */ #define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x01000000) +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE 0x10000UL + +#define PAX_DELTA_MMAP_LEN 16 +#define PAX_DELTA_STACK_LEN 16 +#endif + /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. This could be done in user space, but it's not easy, and we've already done it here. */ diff --git a/arch/parisc/include/asm/pgalloc.h b/arch/parisc/include/asm/pgalloc.h index 3edbb9f..08fef28 100644 --- a/arch/parisc/include/asm/pgalloc.h +++ b/arch/parisc/include/asm/pgalloc.h @@ -61,6 +61,11 @@ static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd) (__u32)(__pa((unsigned long)pmd) >> PxD_VALUE_SHIFT)); } +static inline void pgd_populate_kernel(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd) +{ + pgd_populate(mm, pgd, pmd); +} + static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) { pmd_t *pmd = (pmd_t *)__get_free_pages(GFP_KERNEL|__GFP_REPEAT, @@ -97,6 +102,7 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) #define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); }) #define pmd_free(mm, x) do { } while (0) #define pgd_populate(mm, pmd, pte) BUG() +#define pgd_populate_kernel(mm, pmd, pte) BUG() #endif diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h index f93c4a4..cfd5663 100644 --- a/arch/parisc/include/asm/pgtable.h +++ b/arch/parisc/include/asm/pgtable.h @@ -231,6 +231,17 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr) #define PAGE_EXECREAD __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_EXEC |_PAGE_ACCESSED) #define PAGE_COPY PAGE_EXECREAD #define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE | _PAGE_EXEC |_PAGE_ACCESSED) + +#ifdef CONFIG_PAX_PAGEEXEC +# define PAGE_SHARED_NOEXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE | _PAGE_ACCESSED) +# define PAGE_COPY_NOEXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_ACCESSED) +# define PAGE_READONLY_NOEXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_ACCESSED) +#else +# define PAGE_SHARED_NOEXEC PAGE_SHARED +# define PAGE_COPY_NOEXEC PAGE_COPY +# define PAGE_READONLY_NOEXEC PAGE_READONLY +#endif + #define PAGE_KERNEL __pgprot(_PAGE_KERNEL) #define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL_EXEC) #define PAGE_KERNEL_RWX __pgprot(_PAGE_KERNEL_RWX) diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h index 0abdd4c..1af92f0 100644 --- a/arch/parisc/include/asm/uaccess.h +++ b/arch/parisc/include/asm/uaccess.h @@ -243,10 +243,10 @@ static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) { - int sz = __compiletime_object_size(to); + size_t sz = __compiletime_object_size(to); int ret = -EFAULT; - if (likely(sz == -1 || !__builtin_constant_p(n) || sz >= n)) + if (likely(sz == (size_t)-1 || !__builtin_constant_p(n) || sz >= n)) ret = __copy_from_user(to, from, n); else copy_from_user_overflow(); diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c index 3c63a82..b1d6ee9 100644 --- a/arch/parisc/kernel/module.c +++ b/arch/parisc/kernel/module.c @@ -98,16 +98,38 @@ /* three functions to determine where in the module core * or init pieces the location is */ +static inline int in_init_rx(struct module *me, void *loc) +{ + return (loc >= me->module_init_rx && + loc < (me->module_init_rx + me->init_size_rx)); +} + +static inline int in_init_rw(struct module *me, void *loc) +{ + return (loc >= me->module_init_rw && + loc < (me->module_init_rw + me->init_size_rw)); +} + static inline int in_init(struct module *me, void *loc) { - return (loc >= me->module_init && - loc <= (me->module_init + me->init_size)); + return in_init_rx(me, loc) || in_init_rw(me, loc); +} + +static inline int in_core_rx(struct module *me, void *loc) +{ + return (loc >= me->module_core_rx && + loc < (me->module_core_rx + me->core_size_rx)); +} + +static inline int in_core_rw(struct module *me, void *loc) +{ + return (loc >= me->module_core_rw && + loc < (me->module_core_rw + me->core_size_rw)); } static inline int in_core(struct module *me, void *loc) { - return (loc >= me->module_core && - loc <= (me->module_core + me->core_size)); + return in_core_rx(me, loc) || in_core_rw(me, loc); } static inline int in_local(struct module *me, void *loc) @@ -367,13 +389,13 @@ int module_frob_arch_sections(CONST Elf_Ehdr *hdr, } /* align things a bit */ - me->core_size = ALIGN(me->core_size, 16); - me->arch.got_offset = me->core_size; - me->core_size += gots * sizeof(struct got_entry); + me->core_size_rw = ALIGN(me->core_size_rw, 16); + me->arch.got_offset = me->core_size_rw; + me->core_size_rw += gots * sizeof(struct got_entry); - me->core_size = ALIGN(me->core_size, 16); - me->arch.fdesc_offset = me->core_size; - me->core_size += fdescs * sizeof(Elf_Fdesc); + me->core_size_rw = ALIGN(me->core_size_rw, 16); + me->arch.fdesc_offset = me->core_size_rw; + me->core_size_rw += fdescs * sizeof(Elf_Fdesc); me->arch.got_max = gots; me->arch.fdesc_max = fdescs; @@ -391,7 +413,7 @@ static Elf64_Word get_got(struct module *me, unsigned long value, long addend) BUG_ON(value == 0); - got = me->module_core + me->arch.got_offset; + got = me->module_core_rw + me->arch.got_offset; for (i = 0; got[i].addr; i++) if (got[i].addr == value) goto out; @@ -409,7 +431,7 @@ static Elf64_Word get_got(struct module *me, unsigned long value, long addend) #ifdef CONFIG_64BIT static Elf_Addr get_fdesc(struct module *me, unsigned long value) { - Elf_Fdesc *fdesc = me->module_core + me->arch.fdesc_offset; + Elf_Fdesc *fdesc = me->module_core_rw + me->arch.fdesc_offset; if (!value) { printk(KERN_ERR "%s: zero OPD requested!\n", me->name); @@ -427,7 +449,7 @@ static Elf_Addr get_fdesc(struct module *me, unsigned long value) /* Create new one */ fdesc->addr = value; - fdesc->gp = (Elf_Addr)me->module_core + me->arch.got_offset; + fdesc->gp = (Elf_Addr)me->module_core_rw + me->arch.got_offset; return (Elf_Addr)fdesc; } #endif /* CONFIG_64BIT */ @@ -839,7 +861,7 @@ register_unwind_table(struct module *me, table = (unsigned char *)sechdrs[me->arch.unwind_section].sh_addr; end = table + sechdrs[me->arch.unwind_section].sh_size; - gp = (Elf_Addr)me->module_core + me->arch.got_offset; + gp = (Elf_Addr)me->module_core_rw + me->arch.got_offset; DEBUGP("register_unwind_table(), sect = %d at 0x%p - 0x%p (gp=0x%lx)\n", me->arch.unwind_section, table, end, gp); diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index 5aba01a..47cdd5a 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -92,6 +92,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long task_size = TASK_SIZE; int do_color_align, last_mmap; struct vm_unmapped_area_info info; + unsigned long offset = gr_rand_threadstack_offset(current->mm, filp, flags); if (len > task_size) return -ENOMEM; @@ -109,6 +110,10 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, goto found_addr; } +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + if (addr) { if (do_color_align && last_mmap) addr = COLOR_ALIGN(addr, last_mmap, pgoff); @@ -127,6 +132,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, info.high_limit = mmap_upper_limit(); info.align_mask = last_mmap ? (PAGE_MASK & (SHM_COLOUR - 1)) : 0; info.align_offset = shared_align_offset(last_mmap, pgoff); + info.threadstack_offset = offset; addr = vm_unmapped_area(&info); found_addr: @@ -146,6 +152,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, unsigned long addr = addr0; int do_color_align, last_mmap; struct vm_unmapped_area_info info; + unsigned long offset = gr_rand_threadstack_offset(current->mm, filp, flags); #ifdef CONFIG_64BIT /* This should only ever run for 32-bit processes. */ @@ -170,6 +177,10 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, } /* requesting a specific address */ +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + if (addr) { if (do_color_align && last_mmap) addr = COLOR_ALIGN(addr, last_mmap, pgoff); @@ -187,6 +198,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, info.high_limit = mm->mmap_base; info.align_mask = last_mmap ? (PAGE_MASK & (SHM_COLOUR - 1)) : 0; info.align_offset = shared_align_offset(last_mmap, pgoff); + info.threadstack_offset = offset; addr = vm_unmapped_area(&info); if (!(addr & ~PAGE_MASK)) goto found_addr; @@ -252,6 +264,13 @@ void arch_pick_mmap_layout(struct mm_struct *mm) mm->mmap_legacy_base = mmap_legacy_base(); mm->mmap_base = mmap_upper_limit(); +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) { + mm->mmap_legacy_base += mm->delta_mmap; + mm->mmap_base -= mm->delta_mmap + mm->delta_stack; + } +#endif + if (mmap_is_legacy()) { mm->mmap_base = mm->mmap_legacy_base; mm->get_unmapped_area = arch_get_unmapped_area; diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index b99b39f..e3915ae 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -722,9 +722,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs) down_read(¤t->mm->mmap_sem); vma = find_vma(current->mm,regs->iaoq[0]); - if (vma && (regs->iaoq[0] >= vma->vm_start) - && (vma->vm_flags & VM_EXEC)) { - + if (vma && (regs->iaoq[0] >= vma->vm_start)) { fault_address = regs->iaoq[0]; fault_space = regs->iasq[0]; diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index a762864..664087f 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -50,7 +51,7 @@ int show_unhandled_signals = 1; static unsigned long parisc_acctyp(unsigned long code, unsigned int inst) { - if (code == 6 || code == 16) + if (code == 6 || code == 7 || code == 16) return VM_EXEC; switch (inst & 0xf0000000) { @@ -136,6 +137,116 @@ parisc_acctyp(unsigned long code, unsigned int inst) } #endif +#ifdef CONFIG_PAX_PAGEEXEC +/* + * PaX: decide what to do with offenders (instruction_pointer(regs) = fault address) + * + * returns 1 when task should be killed + * 2 when rt_sigreturn trampoline was detected + * 3 when unpatched PLT trampoline was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + +#ifdef CONFIG_PAX_EMUPLT + int err; + + do { /* PaX: unpatched PLT emulation */ + unsigned int bl, depwi; + + err = get_user(bl, (unsigned int *)instruction_pointer(regs)); + err |= get_user(depwi, (unsigned int *)(instruction_pointer(regs)+4)); + + if (err) + break; + + if (bl == 0xEA9F1FDDU && depwi == 0xD6801C1EU) { + unsigned int ldw, bv, ldw2, addr = instruction_pointer(regs)-12; + + err = get_user(ldw, (unsigned int *)addr); + err |= get_user(bv, (unsigned int *)(addr+4)); + err |= get_user(ldw2, (unsigned int *)(addr+8)); + + if (err) + break; + + if (ldw == 0x0E801096U && + bv == 0xEAC0C000U && + ldw2 == 0x0E881095U) + { + unsigned int resolver, map; + + err = get_user(resolver, (unsigned int *)(instruction_pointer(regs)+8)); + err |= get_user(map, (unsigned int *)(instruction_pointer(regs)+12)); + if (err) + break; + + regs->gr[20] = instruction_pointer(regs)+8; + regs->gr[21] = map; + regs->gr[22] = resolver; + regs->iaoq[0] = resolver | 3UL; + regs->iaoq[1] = regs->iaoq[0] + 4; + return 3; + } + } + } while (0); +#endif + +#ifdef CONFIG_PAX_EMUTRAMP + +#ifndef CONFIG_PAX_EMUSIGRT + if (!(current->mm->pax_flags & MF_PAX_EMUTRAMP)) + return 1; +#endif + + do { /* PaX: rt_sigreturn emulation */ + unsigned int ldi1, ldi2, bel, nop; + + err = get_user(ldi1, (unsigned int *)instruction_pointer(regs)); + err |= get_user(ldi2, (unsigned int *)(instruction_pointer(regs)+4)); + err |= get_user(bel, (unsigned int *)(instruction_pointer(regs)+8)); + err |= get_user(nop, (unsigned int *)(instruction_pointer(regs)+12)); + + if (err) + break; + + if ((ldi1 == 0x34190000U || ldi1 == 0x34190002U) && + ldi2 == 0x3414015AU && + bel == 0xE4008200U && + nop == 0x08000240U) + { + regs->gr[25] = (ldi1 & 2) >> 1; + regs->gr[20] = __NR_rt_sigreturn; + regs->gr[31] = regs->iaoq[1] + 16; + regs->sr[0] = regs->iasq[1]; + regs->iaoq[0] = 0x100UL; + regs->iaoq[1] = regs->iaoq[0] + 4; + regs->iasq[0] = regs->sr[2]; + regs->iasq[1] = regs->sr[2]; + return 2; + } + } while (0); +#endif + + return 1; +} + +void pax_report_insns(struct pt_regs *regs, void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk(KERN_CONT "???????? "); + else + printk(KERN_CONT "%08x ", c); + } + printk("\n"); +} +#endif + int fixup_exception(struct pt_regs *regs) { const struct exception_table_entry *fix; @@ -234,8 +345,33 @@ retry: good_area: - if ((vma->vm_flags & acc_type) != acc_type) + if ((vma->vm_flags & acc_type) != acc_type) { + +#ifdef CONFIG_PAX_PAGEEXEC + if ((mm->pax_flags & MF_PAX_PAGEEXEC) && (acc_type & VM_EXEC) && + (address & ~3UL) == instruction_pointer(regs)) + { + up_read(&mm->mmap_sem); + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_PAX_EMUPLT + case 3: + return; +#endif + +#ifdef CONFIG_PAX_EMUTRAMP + case 2: + return; +#endif + + } + pax_report_fault(regs, (void *)instruction_pointer(regs), (void *)regs->gr[30]); + do_group_exit(SIGKILL); + } +#endif + goto bad_area; + } /* * If for any reason at all we couldn't handle the fault, make diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 9a7057e..5691c0b 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -421,6 +421,7 @@ config KEXEC bool "kexec system call" depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP)) select KEXEC_CORE + depends on !GRKERNSEC_KMEM 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 diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h index 55f106e..70cc82a 100644 --- a/arch/powerpc/include/asm/atomic.h +++ b/arch/powerpc/include/asm/atomic.h @@ -12,6 +12,11 @@ #define ATOMIC_INIT(i) { (i) } +#define _ASM_EXTABLE(from, to) \ +" .section __ex_table,\"a\"\n" \ + PPC_LONG" " #from ", " #to"\n" \ +" .previous\n" + static __inline__ int atomic_read(const atomic_t *v) { int t; @@ -21,39 +26,80 @@ static __inline__ int atomic_read(const atomic_t *v) return t; } +static __inline__ int atomic_read_unchecked(const atomic_unchecked_t *v) +{ + int t; + + __asm__ __volatile__("lwz%U1%X1 %0,%1" : "=r"(t) : "m"(v->counter)); + + return t; +} + static __inline__ void atomic_set(atomic_t *v, int i) { __asm__ __volatile__("stw%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i)); } -#define ATOMIC_OP(op, asm_op) \ -static __inline__ void atomic_##op(int a, atomic_t *v) \ +static __inline__ void atomic_set_unchecked(atomic_unchecked_t *v, int i) +{ + __asm__ __volatile__("stw%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i)); +} + +#ifdef CONFIG_PAX_REFCOUNT +#define __REFCOUNT_OP(op) op##o. +#define __OVERFLOW_PRE \ + " mcrxr cr0\n" +#define __OVERFLOW_POST \ + " bf 4*cr0+so, 3f\n" \ + "2: .long 0x00c00b00\n" \ + "3:\n" +#define __OVERFLOW_EXTABLE \ + "\n4:\n" + _ASM_EXTABLE(2b, 4b) +#else +#define __REFCOUNT_OP(op) op +#define __OVERFLOW_PRE +#define __OVERFLOW_POST +#define __OVERFLOW_EXTABLE +#endif + +#define __ATOMIC_OP(op, suffix, pre_op, asm_op, post_op, extable) \ +static inline void atomic_##op##suffix(int a, atomic##suffix##_t *v) \ { \ int t; \ \ __asm__ __volatile__( \ -"1: lwarx %0,0,%3 # atomic_" #op "\n" \ +"1: lwarx %0,0,%3 # atomic_" #op #suffix "\n" \ + pre_op \ #asm_op " %0,%2,%0\n" \ + post_op \ PPC405_ERR77(0,%3) \ " stwcx. %0,0,%3 \n" \ " bne- 1b\n" \ + extable \ : "=&r" (t), "+m" (v->counter) \ : "r" (a), "r" (&v->counter) \ : "cc"); \ } \ -#define ATOMIC_OP_RETURN(op, asm_op) \ -static __inline__ int atomic_##op##_return(int a, atomic_t *v) \ +#define ATOMIC_OP(op, asm_op) __ATOMIC_OP(op, , , asm_op, , ) \ + __ATOMIC_OP(op, _unchecked, __OVERFLOW_PRE, __REFCOUNT_OP(asm_op), __OVERFLOW_POST, __OVERFLOW_EXTABLE) + +#define __ATOMIC_OP_RETURN(op, suffix, pre_op, asm_op, post_op, extable)\ +static inline int atomic_##op##_return##suffix(int a, atomic##suffix##_t *v)\ { \ int t; \ \ __asm__ __volatile__( \ PPC_ATOMIC_ENTRY_BARRIER \ -"1: lwarx %0,0,%2 # atomic_" #op "_return\n" \ +"1: lwarx %0,0,%2 # atomic_" #op "_return" #suffix "\n" \ + pre_op \ #asm_op " %0,%1,%0\n" \ + post_op \ PPC405_ERR77(0,%2) \ " stwcx. %0,0,%2 \n" \ " bne- 1b\n" \ + extable \ PPC_ATOMIC_EXIT_BARRIER \ : "=&r" (t) \ : "r" (a), "r" (&v->counter) \ @@ -62,6 +108,9 @@ static __inline__ int atomic_##op##_return(int a, atomic_t *v) \ return t; \ } +#define ATOMIC_OP_RETURN(op, asm_op) __ATOMIC_OP_RETURN(op, , , asm_op, , )\ + __ATOMIC_OP_RETURN(op, _unchecked, __OVERFLOW_PRE, __REFCOUNT_OP(asm_op), __OVERFLOW_POST, __OVERFLOW_EXTABLE) + #define ATOMIC_OPS(op, asm_op) ATOMIC_OP(op, asm_op) ATOMIC_OP_RETURN(op, asm_op) ATOMIC_OPS(add, add) @@ -73,42 +122,29 @@ ATOMIC_OP(xor, xor) #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN +#undef __ATOMIC_OP_RETURN #undef ATOMIC_OP +#undef __ATOMIC_OP #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) -static __inline__ void atomic_inc(atomic_t *v) -{ - int t; +/* + * atomic_inc - increment atomic variable + * @v: pointer of type atomic_t + * + * Automatically increments @v by 1 + */ +#define atomic_inc(v) atomic_add(1, (v)) +#define atomic_inc_return(v) atomic_add_return(1, (v)) - __asm__ __volatile__( -"1: lwarx %0,0,%2 # atomic_inc\n\ - addic %0,%0,1\n" - PPC405_ERR77(0,%2) -" stwcx. %0,0,%2 \n\ - bne- 1b" - : "=&r" (t), "+m" (v->counter) - : "r" (&v->counter) - : "cc", "xer"); +static inline void atomic_inc_unchecked(atomic_unchecked_t *v) +{ + atomic_add_unchecked(1, v); } -static __inline__ int atomic_inc_return(atomic_t *v) +static inline int atomic_inc_return_unchecked(atomic_unchecked_t *v) { - int t; - - __asm__ __volatile__( - PPC_ATOMIC_ENTRY_BARRIER -"1: lwarx %0,0,%1 # atomic_inc_return\n\ - addic %0,%0,1\n" - PPC405_ERR77(0,%1) -" stwcx. %0,0,%1 \n\ - bne- 1b" - PPC_ATOMIC_EXIT_BARRIER - : "=&r" (t) - : "r" (&v->counter) - : "cc", "xer", "memory"); - - return t; + return atomic_add_return_unchecked(1, v); } /* @@ -121,43 +157,38 @@ static __inline__ int atomic_inc_return(atomic_t *v) */ #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) -static __inline__ void atomic_dec(atomic_t *v) +static __inline__ int atomic_inc_and_test_unchecked(atomic_unchecked_t *v) { - int t; - - __asm__ __volatile__( -"1: lwarx %0,0,%2 # atomic_dec\n\ - addic %0,%0,-1\n" - PPC405_ERR77(0,%2)\ -" stwcx. %0,0,%2\n\ - bne- 1b" - : "=&r" (t), "+m" (v->counter) - : "r" (&v->counter) - : "cc", "xer"); + return atomic_add_return_unchecked(1, v) == 0; } -static __inline__ int atomic_dec_return(atomic_t *v) +/* + * atomic_dec - decrement atomic variable + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1 + */ +#define atomic_dec(v) atomic_sub(1, (v)) +#define atomic_dec_return(v) atomic_sub_return(1, (v)) + +static __inline__ void atomic_dec_unchecked(atomic_unchecked_t *v) { - int t; - - __asm__ __volatile__( - PPC_ATOMIC_ENTRY_BARRIER -"1: lwarx %0,0,%1 # atomic_dec_return\n\ - addic %0,%0,-1\n" - PPC405_ERR77(0,%1) -" stwcx. %0,0,%1\n\ - bne- 1b" - PPC_ATOMIC_EXIT_BARRIER - : "=&r" (t) - : "r" (&v->counter) - : "cc", "xer", "memory"); - - return t; + atomic_sub_unchecked(1, v); } #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) +static inline int atomic_cmpxchg_unchecked(atomic_unchecked_t *v, int old, int new) +{ + return cmpxchg(&(v->counter), old, new); +} + +static inline int atomic_xchg_unchecked(atomic_unchecked_t *v, int new) +{ + return xchg(&(v->counter), new); +} + /** * __atomic_add_unless - add unless the number is a given value * @v: pointer of type atomic_t @@ -175,11 +206,27 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) PPC_ATOMIC_ENTRY_BARRIER "1: lwarx %0,0,%1 # __atomic_add_unless\n\ cmpw 0,%0,%3 \n\ - beq- 2f \n\ - add %0,%2,%0 \n" + beq- 2f \n" + +#ifdef CONFIG_PAX_REFCOUNT +" mcrxr cr0\n" +" addo. %0,%2,%0\n" +" bf 4*cr0+so, 4f\n" +"3:.long " "0x00c00b00""\n" +"4:\n" +#else + "add %0,%2,%0 \n" +#endif + PPC405_ERR77(0,%2) " stwcx. %0,0,%1 \n\ bne- 1b \n" +"5:" + +#ifdef CONFIG_PAX_REFCOUNT + _ASM_EXTABLE(3b, 5b) +#endif + 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) return t; } +static __inline__ long atomic64_read_unchecked(const atomic64_unchecked_t *v) +{ + long t; + + __asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : "m"(v->counter)); + + return t; +} + static __inline__ void atomic64_set(atomic64_t *v, long i) { __asm__ __volatile__("std%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i)); } -#define ATOMIC64_OP(op, asm_op) \ -static __inline__ void atomic64_##op(long a, atomic64_t *v) \ +static __inline__ void atomic64_set_unchecked(atomic64_unchecked_t *v, long i) +{ + __asm__ __volatile__("std%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i)); +} + +#define __ATOMIC64_OP(op, suffix, pre_op, asm_op, post_op, extable) \ +static inline void atomic64_##op##suffix(long a, atomic64##suffix##_t *v)\ { \ long t; \ \ __asm__ __volatile__( \ "1: ldarx %0,0,%3 # atomic64_" #op "\n" \ + pre_op \ #asm_op " %0,%2,%0\n" \ + post_op \ " stdcx. %0,0,%3 \n" \ " bne- 1b\n" \ + extable \ : "=&r" (t), "+m" (v->counter) \ : "r" (a), "r" (&v->counter) \ : "cc"); \ } -#define ATOMIC64_OP_RETURN(op, asm_op) \ -static __inline__ long atomic64_##op##_return(long a, atomic64_t *v) \ +#define ATOMIC64_OP(op, asm_op) __ATOMIC64_OP(op, , , asm_op, , ) \ + __ATOMIC64_OP(op, _unchecked, __OVERFLOW_PRE, __REFCOUNT_OP(asm_op), __OVERFLOW_POST, __OVERFLOW_EXTABLE) + +#define __ATOMIC64_OP_RETURN(op, suffix, pre_op, asm_op, post_op, extable)\ +static inline long atomic64_##op##_return##suffix(long a, atomic64##suffix##_t *v)\ { \ long t; \ \ __asm__ __volatile__( \ PPC_ATOMIC_ENTRY_BARRIER \ "1: ldarx %0,0,%2 # atomic64_" #op "_return\n" \ + pre_op \ #asm_op " %0,%1,%0\n" \ + post_op \ " stdcx. %0,0,%2 \n" \ " bne- 1b\n" \ + extable \ 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) \ return t; \ } +#define ATOMIC64_OP_RETURN(op, asm_op) __ATOMIC64_OP_RETURN(op, , , asm_op, , )\ + __ATOMIC64_OP_RETURN(op, _unchecked, __OVERFLOW_PRE, __REFCOUNT_OP(asm_op), __OVERFLOW_POST, __OVERFLOW_EXTABLE) + #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) #undef ATOMIC64_OPS #undef ATOMIC64_OP_RETURN +#undef __ATOMIC64_OP_RETURN #undef ATOMIC64_OP +#undef __ATOMIC64_OP +#undef __OVERFLOW_EXTABLE +#undef __OVERFLOW_POST +#undef __OVERFLOW_PRE +#undef __REFCOUNT_OP #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) -static __inline__ void atomic64_inc(atomic64_t *v) -{ - long t; +/* + * atomic64_inc - increment atomic variable + * @v: pointer of type atomic64_t + * + * Automatically increments @v by 1 + */ +#define atomic64_inc(v) atomic64_add(1, (v)) +#define atomic64_inc_return(v) atomic64_add_return(1, (v)) - __asm__ __volatile__( -"1: ldarx %0,0,%2 # atomic64_inc\n\ - addic %0,%0,1\n\ - stdcx. %0,0,%2 \n\ - bne- 1b" - : "=&r" (t), "+m" (v->counter) - : "r" (&v->counter) - : "cc", "xer"); +static inline void atomic64_inc_unchecked(atomic64_unchecked_t *v) +{ + atomic64_add_unchecked(1, v); } -static __inline__ long atomic64_inc_return(atomic64_t *v) +static inline long atomic64_inc_return_unchecked(atomic64_unchecked_t *v) { - long t; - - __asm__ __volatile__( - PPC_ATOMIC_ENTRY_BARRIER -"1: ldarx %0,0,%1 # atomic64_inc_return\n\ - addic %0,%0,1\n\ - stdcx. %0,0,%1 \n\ - bne- 1b" - PPC_ATOMIC_EXIT_BARRIER - : "=&r" (t) - : "r" (&v->counter) - : "cc", "xer", "memory"); - - return t; + return atomic64_add_return_unchecked(1, v); } /* @@ -360,36 +431,18 @@ static __inline__ long atomic64_inc_return(atomic64_t *v) */ #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) -static __inline__ void atomic64_dec(atomic64_t *v) +/* + * atomic64_dec - decrement atomic variable + * @v: pointer of type atomic64_t + * + * Atomically decrements @v by 1 + */ +#define atomic64_dec(v) atomic64_sub(1, (v)) +#define atomic64_dec_return(v) atomic64_sub_return(1, (v)) + +static __inline__ void atomic64_dec_unchecked(atomic64_unchecked_t *v) { - long t; - - __asm__ __volatile__( -"1: ldarx %0,0,%2 # atomic64_dec\n\ - addic %0,%0,-1\n\ - stdcx. %0,0,%2\n\ - bne- 1b" - : "=&r" (t), "+m" (v->counter) - : "r" (&v->counter) - : "cc", "xer"); -} - -static __inline__ long atomic64_dec_return(atomic64_t *v) -{ - long t; - - __asm__ __volatile__( - PPC_ATOMIC_ENTRY_BARRIER -"1: ldarx %0,0,%1 # atomic64_dec_return\n\ - addic %0,%0,-1\n\ - stdcx. %0,0,%1\n\ - bne- 1b" - PPC_ATOMIC_EXIT_BARRIER - : "=&r" (t) - : "r" (&v->counter) - : "cc", "xer", "memory"); - - return t; + atomic64_sub_unchecked(1, v); } #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) #define atomic64_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) #define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) +static inline long atomic64_cmpxchg_unchecked(atomic64_unchecked_t *v, long old, long new) +{ + return cmpxchg(&(v->counter), old, new); +} + +static inline long atomic64_xchg_unchecked(atomic64_unchecked_t *v, long new) +{ + return xchg(&(v->counter), new); +} + /** * 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) __asm__ __volatile__ ( PPC_ATOMIC_ENTRY_BARRIER -"1: ldarx %0,0,%1 # __atomic_add_unless\n\ +"1: ldarx %0,0,%1 # atomic64_add_unless\n\ cmpd 0,%0,%3 \n\ - beq- 2f \n\ - add %0,%2,%0 \n" + beq- 2f \n" + +#ifdef CONFIG_PAX_REFCOUNT +" mcrxr cr0\n" +" addo. %0,%2,%0\n" +" bf 4*cr0+so, 4f\n" +"3:.long " "0x00c00b00""\n" +"4:\n" +#else + "add %0,%2,%0 \n" +#endif + " stdcx. %0,0,%1 \n\ bne- 1b \n" PPC_ATOMIC_EXIT_BARRIER +"5:" + +#ifdef CONFIG_PAX_REFCOUNT + _ASM_EXTABLE(3b, 5b) +#endif + " subf %0,%2,%0 \n\ 2:" : "=&r" (t) diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h index 5f8229e..385d90b 100644 --- a/arch/powerpc/include/asm/cache.h +++ b/arch/powerpc/include/asm/cache.h @@ -3,6 +3,8 @@ #ifdef __KERNEL__ +#include +#include /* bytes per L1 cache line */ #if defined(CONFIG_8xx) || defined(CONFIG_403GCX) @@ -22,7 +24,7 @@ #define L1_CACHE_SHIFT 7 #endif -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #define SMP_CACHE_BYTES L1_CACHE_BYTES diff --git a/arch/powerpc/include/asm/elf.h b/arch/powerpc/include/asm/elf.h index ee46ffe..b36c98c 100644 --- a/arch/powerpc/include/asm/elf.h +++ b/arch/powerpc/include/asm/elf.h @@ -30,6 +30,18 @@ #define ELF_ET_DYN_BASE 0x20000000 +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE (0x10000000UL) + +#ifdef __powerpc64__ +#define PAX_DELTA_MMAP_LEN (is_32bit_task() ? 16 : 28) +#define PAX_DELTA_STACK_LEN (is_32bit_task() ? 16 : 28) +#else +#define PAX_DELTA_MMAP_LEN 15 +#define PAX_DELTA_STACK_LEN 15 +#endif +#endif + #define ELF_CORE_EFLAGS (is_elf2_task() ? 2 : 0) /* diff --git a/arch/powerpc/include/asm/exec.h b/arch/powerpc/include/asm/exec.h index 8196e9c..d83a9f3 100644 --- a/arch/powerpc/include/asm/exec.h +++ b/arch/powerpc/include/asm/exec.h @@ -4,6 +4,6 @@ #ifndef _ASM_POWERPC_EXEC_H #define _ASM_POWERPC_EXEC_H -extern unsigned long arch_align_stack(unsigned long sp); +#define arch_align_stack(x) ((x) & ~0xfUL) #endif /* _ASM_POWERPC_EXEC_H */ diff --git a/arch/powerpc/include/asm/kmap_types.h b/arch/powerpc/include/asm/kmap_types.h index 5acabbd..7ea14fa 100644 --- a/arch/powerpc/include/asm/kmap_types.h +++ b/arch/powerpc/include/asm/kmap_types.h @@ -10,7 +10,7 @@ * 2 of the License, or (at your option) any later version. */ -#define KM_TYPE_NR 16 +#define KM_TYPE_NR 17 #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_KMAP_TYPES_H */ diff --git a/arch/powerpc/include/asm/local.h b/arch/powerpc/include/asm/local.h index b8da913..c02b593 100644 --- a/arch/powerpc/include/asm/local.h +++ b/arch/powerpc/include/asm/local.h @@ -9,21 +9,65 @@ typedef struct atomic_long_t a; } local_t; +typedef struct +{ + atomic_long_unchecked_t a; +} local_unchecked_t; + #define LOCAL_INIT(i) { ATOMIC_LONG_INIT(i) } #define local_read(l) atomic_long_read(&(l)->a) +#define local_read_unchecked(l) atomic_long_read_unchecked(&(l)->a) #define local_set(l,i) atomic_long_set(&(l)->a, (i)) +#define local_set_unchecked(l,i) atomic_long_set_unchecked(&(l)->a, (i)) #define local_add(i,l) atomic_long_add((i),(&(l)->a)) +#define local_add_unchecked(i,l) atomic_long_add_unchecked((i),(&(l)->a)) #define local_sub(i,l) atomic_long_sub((i),(&(l)->a)) +#define local_sub_unchecked(i,l) atomic_long_sub_unchecked((i),(&(l)->a)) #define local_inc(l) atomic_long_inc(&(l)->a) +#define local_inc_unchecked(l) atomic_long_inc_unchecked(&(l)->a) #define local_dec(l) atomic_long_dec(&(l)->a) +#define local_dec_unchecked(l) atomic_long_dec_unchecked(&(l)->a) static __inline__ long local_add_return(long a, local_t *l) { long t; __asm__ __volatile__( +"1:" PPC_LLARX(%0,0,%2,0) " # local_add_return\n" + +#ifdef CONFIG_PAX_REFCOUNT +" mcrxr cr0\n" +" addo. %0,%1,%0\n" +" bf 4*cr0+so, 3f\n" +"2:.long " "0x00c00b00""\n" +#else +" add %0,%1,%0\n" +#endif + +"3:\n" + PPC405_ERR77(0,%2) + PPC_STLCX "%0,0,%2 \n\ + bne- 1b" + +#ifdef CONFIG_PAX_REFCOUNT +"\n4:\n" + _ASM_EXTABLE(2b, 4b) +#endif + + : "=&r" (t) + : "r" (a), "r" (&(l->a.counter)) + : "cc", "memory"); + + return t; +} + +static __inline__ long local_add_return_unchecked(long a, local_unchecked_t *l) +{ + long t; + + __asm__ __volatile__( "1:" PPC_LLARX(%0,0,%2,0) " # local_add_return\n\ add %0,%1,%0\n" PPC405_ERR77(0,%2) @@ -101,6 +145,8 @@ static __inline__ long local_dec_return(local_t *l) #define local_cmpxchg(l, o, n) \ (cmpxchg_local(&((l)->a.counter), (o), (n))) +#define local_cmpxchg_unchecked(l, o, n) \ + (cmpxchg_local(&((l)->a.counter), (o), (n))) #define local_xchg(l, n) (xchg_local(&((l)->a.counter), (n))) /** diff --git a/arch/powerpc/include/asm/mman.h b/arch/powerpc/include/asm/mman.h index 8565c25..2865190 100644 --- a/arch/powerpc/include/asm/mman.h +++ b/arch/powerpc/include/asm/mman.h @@ -24,7 +24,7 @@ static inline unsigned long arch_calc_vm_prot_bits(unsigned long prot) } #define arch_calc_vm_prot_bits(prot) arch_calc_vm_prot_bits(prot) -static inline pgprot_t arch_vm_get_page_prot(unsigned long vm_flags) +static inline pgprot_t arch_vm_get_page_prot(vm_flags_t vm_flags) { return (vm_flags & VM_SAO) ? __pgprot(_PAGE_SAO) : __pgprot(0); } diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h index 71294a6..9e40aca 100644 --- a/arch/powerpc/include/asm/page.h +++ b/arch/powerpc/include/asm/page.h @@ -227,8 +227,9 @@ extern long long virt_phys_offset; * and needs to be executable. This means the whole heap ends * up being executable. */ -#define VM_DATA_DEFAULT_FLAGS32 (VM_READ | VM_WRITE | VM_EXEC | \ - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) +#define VM_DATA_DEFAULT_FLAGS32 \ + (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \ + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) #define VM_DATA_DEFAULT_FLAGS64 (VM_READ | VM_WRITE | \ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) @@ -256,6 +257,9 @@ extern long long virt_phys_offset; #define is_kernel_addr(x) ((x) >= PAGE_OFFSET) #endif +#define ktla_ktva(addr) (addr) +#define ktva_ktla(addr) (addr) + #ifndef CONFIG_PPC_BOOK3S_64 /* * Use the top bit of the higher-level page table entries to indicate whether diff --git a/arch/powerpc/include/asm/page_64.h b/arch/powerpc/include/asm/page_64.h index d908a46..3753f71 100644 --- a/arch/powerpc/include/asm/page_64.h +++ b/arch/powerpc/include/asm/page_64.h @@ -172,15 +172,18 @@ do { \ * stack by default, so in the absence of a PT_GNU_STACK program header * we turn execute permission off. */ -#define VM_STACK_DEFAULT_FLAGS32 (VM_READ | VM_WRITE | VM_EXEC | \ - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) +#define VM_STACK_DEFAULT_FLAGS32 \ + (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \ + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) #define VM_STACK_DEFAULT_FLAGS64 (VM_READ | VM_WRITE | \ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) +#ifndef CONFIG_PAX_PAGEEXEC #define VM_STACK_DEFAULT_FLAGS \ (is_32bit_task() ? \ VM_STACK_DEFAULT_FLAGS32 : VM_STACK_DEFAULT_FLAGS64) +#endif #include diff --git a/arch/powerpc/include/asm/pgalloc-64.h b/arch/powerpc/include/asm/pgalloc-64.h index 4b0be20..c15a27d 100644 --- a/arch/powerpc/include/asm/pgalloc-64.h +++ b/arch/powerpc/include/asm/pgalloc-64.h @@ -54,6 +54,7 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) #ifndef CONFIG_PPC_64K_PAGES #define pgd_populate(MM, PGD, PUD) pgd_set(PGD, PUD) +#define pgd_populate_kernel(MM, PGD, PUD) pgd_populate((MM), (PGD), (PUD)) static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) { @@ -71,6 +72,11 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) pud_set(pud, (unsigned long)pmd); } +static inline void pud_populate_kernel(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) +{ + pud_populate(mm, pud, pmd); +} + #define pmd_populate(mm, pmd, pte_page) \ pmd_populate_kernel(mm, pmd, page_address(pte_page)) #define pmd_populate_kernel(mm, pmd, pte) pmd_set(pmd, (unsigned long)(pte)) @@ -173,6 +179,7 @@ extern void __tlb_remove_table(void *_table); #endif #define pud_populate(mm, pud, pmd) pud_set(pud, (unsigned long)pmd) +#define pud_populate_kernel(mm, pud, pmd) pud_populate((mm), (pud), (pmd)) static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h index 0717693..6a1f488 100644 --- a/arch/powerpc/include/asm/pgtable.h +++ b/arch/powerpc/include/asm/pgtable.h @@ -2,6 +2,7 @@ #define _ASM_POWERPC_PGTABLE_H #ifdef __KERNEL__ +#include #ifndef __ASSEMBLY__ #include #include diff --git a/arch/powerpc/include/asm/pte-hash32.h b/arch/powerpc/include/asm/pte-hash32.h index 62cfb0c..50c6402 100644 --- a/arch/powerpc/include/asm/pte-hash32.h +++ b/arch/powerpc/include/asm/pte-hash32.h @@ -20,6 +20,7 @@ #define _PAGE_HASHPTE 0x002 /* hash_page has made an HPTE for this pte */ #define _PAGE_USER 0x004 /* usermode access allowed */ #define _PAGE_GUARDED 0x008 /* G: prohibit speculative access */ +#define _PAGE_EXEC _PAGE_GUARDED #define _PAGE_COHERENT 0x010 /* M: enforce memory coherence (SMP systems) */ #define _PAGE_NO_CACHE 0x020 /* I: cache inhibit */ #define _PAGE_WRITETHRU 0x040 /* W: cache write-through */ diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index a908ada..f3c8966 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -252,6 +252,7 @@ #define SPRN_DBCR 0x136 /* e300 Data Breakpoint Control Reg */ #define SPRN_DSISR 0x012 /* Data Storage Interrupt Status Register */ #define DSISR_NOHPTE 0x40000000 /* no translation found */ +#define DSISR_GUARDED 0x10000000 /* fetch from guarded storage */ #define DSISR_PROTFAULT 0x08000000 /* protection fault */ #define DSISR_ISSTORE 0x02000000 /* access was a store */ #define DSISR_DABRMATCH 0x00400000 /* hit data breakpoint */ diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 825663c..f9e9134 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -51,7 +51,7 @@ struct smp_ops_t { int (*cpu_disable)(void); void (*cpu_die)(unsigned int nr); int (*cpu_bootable)(unsigned int nr); -}; +} __no_const; extern void smp_send_debugger_break(void); extern void start_secondary_resume(void); diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h index 523673d..4aeef3b 100644 --- a/arch/powerpc/include/asm/spinlock.h +++ b/arch/powerpc/include/asm/spinlock.h @@ -202,13 +202,29 @@ static inline long __arch_read_trylock(arch_rwlock_t *rw) __asm__ __volatile__( "1: " PPC_LWARX(%0,0,%1,1) "\n" __DO_SIGN_EXTEND -" addic. %0,%0,1\n\ - ble- 2f\n" + +#ifdef CONFIG_PAX_REFCOUNT +" mcrxr cr0\n" +" addico. %0,%0,1\n" +" bf 4*cr0+so, 3f\n" +"2:.long " "0x00c00b00""\n" +#else +" addic. %0,%0,1\n" +#endif + +"3:\n" + "ble- 4f\n" PPC405_ERR77(0,%1) " stwcx. %0,0,%1\n\ bne- 1b\n" PPC_ACQUIRE_BARRIER -"2:" : "=&r" (tmp) +"4:" + +#ifdef CONFIG_PAX_REFCOUNT + _ASM_EXTABLE(2b,4b) +#endif + + : "=&r" (tmp) : "r" (&rw->lock) : "cr0", "xer", "memory"); @@ -284,11 +300,27 @@ static inline void arch_read_unlock(arch_rwlock_t *rw) __asm__ __volatile__( "# read_unlock\n\t" PPC_RELEASE_BARRIER -"1: lwarx %0,0,%1\n\ - addic %0,%0,-1\n" +"1: lwarx %0,0,%1\n" + +#ifdef CONFIG_PAX_REFCOUNT +" mcrxr cr0\n" +" addico. %0,%0,-1\n" +" bf 4*cr0+so, 3f\n" +"2:.long " "0x00c00b00""\n" +#else +" addic. %0,%0,-1\n" +#endif + +"3:\n" PPC405_ERR77(0,%1) " stwcx. %0,0,%1\n\ bne- 1b" + +#ifdef CONFIG_PAX_REFCOUNT +"\n4:\n" + _ASM_EXTABLE(2b, 4b) +#endif + : "=&r"(tmp) : "r"(&rw->lock) : "cr0", "xer", "memory"); diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index 7efee4a..48d47cc 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -101,6 +101,8 @@ static inline struct thread_info *current_thread_info(void) #if defined(CONFIG_PPC64) #define TIF_ELF2ABI 18 /* function descriptors must die! */ #endif +/* mask must be expressable within 16 bits to satisfy 'andi' instruction reqs */ +#define TIF_GRSEC_SETXID 6 /* update credentials on syscall entry/exit */ /* as above, but as bit values */ #define _TIF_SYSCALL_TRACE (1< INT_MAX) + return n; + + if (!__builtin_constant_p(n)) + check_object_size(to, n, false); + + if (likely(access_ok(VERIFY_READ, from, n))) + n = __copy_from_user(to, from, n); + else + memset(to, 0, n); + return n; +} + +static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) +{ + if ((long)n < 0 || n > INT_MAX) + return n; + + if (likely(access_ok(VERIFY_WRITE, to, n))) { + if (!__builtin_constant_p(n)) + check_object_size(from, n, true); + n = __copy_to_user(to, from, n); + } + return n; +} + +extern unsigned long copy_in_user(void __user *to, const void __user *from, + unsigned long n); + +#endif /* __powerpc64__ */ + extern unsigned long __clear_user(void __user *addr, unsigned long size); 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 ba33693..d8db875 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) + ifdef CONFIG_FUNCTION_TRACER # Do not trace early boot code CFLAGS_REMOVE_cputable.o = -pg -mno-sched-epilog @@ -26,6 +31,8 @@ CFLAGS_REMOVE_ftrace.o = -pg -mno-sched-epilog CFLAGS_REMOVE_time.o = -pg -mno-sched-epilog endif +CFLAGS_REMOVE_prom_init.o += $(LATENT_ENTROPY_PLUGIN_CFLAGS) + obj-y := cputable.o ptrace.o syscalls.o \ irq.o align.o signal_32.o pmc.o vdso.o \ process.o systbl.o idle.o \ diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index f3bd5e7..50040455 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -1010,6 +1010,7 @@ storage_fault_common: std r14,_DAR(r1) std r15,_DSISR(r1) addi r3,r1,STACK_FRAME_OVERHEAD + bl save_nvgprs mr r4,r14 mr r5,r15 ld r14,PACA_EXGEN+EX_R14(r13) @@ -1018,8 +1019,7 @@ storage_fault_common: cmpdi r3,0 bne- 1f b ret_from_except_lite -1: bl save_nvgprs - mr r5,r3 +1: mr r5,r3 addi r3,r1,STACK_FRAME_OVERHEAD ld r4,_DAR(r1) bl bad_page_fault diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 0a0399c2..262a2e6 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -1591,10 +1591,10 @@ handle_page_fault: 11: ld r4,_DAR(r1) ld r5,_DSISR(r1) addi r3,r1,STACK_FRAME_OVERHEAD + bl save_nvgprs bl do_page_fault cmpdi r3,0 beq+ 12f - bl save_nvgprs mr r5,r3 addi r3,r1,STACK_FRAME_OVERHEAD lwz r4,_DAR(r1) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 290559d..0094ddb 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -460,6 +460,8 @@ void migrate_irqs(void) } #endif +extern void gr_handle_kernel_exploit(void); + static inline void check_stack_overflow(void) { #ifdef CONFIG_DEBUG_STACKOVERFLOW @@ -472,6 +474,7 @@ static inline void check_stack_overflow(void) pr_err("do_IRQ: stack overflow: %ld\n", sp - sizeof(struct thread_info)); dump_stack(); + gr_handle_kernel_exploit(); } #endif } diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c index c94d2e0..992a9ce 100644 --- a/arch/powerpc/kernel/module_32.c +++ b/arch/powerpc/kernel/module_32.c @@ -158,7 +158,7 @@ int module_frob_arch_sections(Elf32_Ehdr *hdr, me->arch.core_plt_section = i; } if (!me->arch.core_plt_section || !me->arch.init_plt_section) { - pr_err("Module doesn't contain .plt or .init.plt sections.\n"); + pr_err("Module $s doesn't contain .plt or .init.plt sections.\n", me->name); return -ENOEXEC; } @@ -188,11 +188,16 @@ static uint32_t do_plt_call(void *location, pr_debug("Doing plt for call to 0x%x at 0x%x\n", val, (unsigned int)location); /* Init, or core PLT? */ - if (location >= mod->module_core - && location < mod->module_core + mod->core_size) + if ((location >= mod->module_core_rx && location < mod->module_core_rx + mod->core_size_rx) || + (location >= mod->module_core_rw && location < mod->module_core_rw + mod->core_size_rw)) entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr; - else + else if ((location >= mod->module_init_rx && location < mod->module_init_rx + mod->init_size_rx) || + (location >= mod->module_init_rw && location < mod->module_init_rw + mod->init_size_rw)) entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr; + else { + printk(KERN_ERR "%s: invalid R_PPC_REL24 entry found\n", mod->name); + return ~0UL; + } /* Find this entry, or if that fails, the next avail. entry */ while (entry->jump[0]) { @@ -296,7 +301,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, } #ifdef CONFIG_DYNAMIC_FTRACE module->arch.tramp = - do_plt_call(module->module_core, + do_plt_call(module->module_core_rx, (unsigned long)ftrace_caller, sechdrs, module); #endif diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 75b6676..41c72b5 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1033,8 +1033,8 @@ void show_regs(struct pt_regs * regs) * Lookup NIP late so we have the best change of getting the * above info out without failing */ - printk("NIP ["REG"] %pS\n", regs->nip, (void *)regs->nip); - printk("LR ["REG"] %pS\n", regs->link, (void *)regs->link); + printk("NIP ["REG"] %pA\n", regs->nip, (void *)regs->nip); + printk("LR ["REG"] %pA\n", regs->link, (void *)regs->link); #endif show_stack(current, (unsigned long *) regs->gpr[1]); if (!user_mode(regs)) @@ -1550,10 +1550,10 @@ void show_stack(struct task_struct *tsk, unsigned long *stack) newsp = stack[0]; ip = stack[STACK_FRAME_LR_SAVE]; if (!firstframe || ip != lr) { - printk("["REG"] ["REG"] %pS", sp, ip, (void *)ip); + printk("["REG"] ["REG"] %pA", sp, ip, (void *)ip); #ifdef CONFIG_FUNCTION_GRAPH_TRACER if ((ip == rth) && curr_frame >= 0) { - printk(" (%pS)", + printk(" (%pA)", (void *)current->ret_stack[curr_frame].ret); curr_frame--; } @@ -1573,7 +1573,7 @@ void show_stack(struct task_struct *tsk, unsigned long *stack) struct pt_regs *regs = (struct pt_regs *) (sp + STACK_FRAME_OVERHEAD); lr = regs->link; - printk("--- interrupt: %lx at %pS\n LR = %pS\n", + printk("--- interrupt: %lx at %pA\n LR = %pA\n", regs->trap, (void *)regs->nip, (void *)lr); firstframe = 1; } @@ -1609,49 +1609,3 @@ void notrace __ppc64_runlatch_off(void) mtspr(SPRN_CTRLT, ctrl); } #endif /* CONFIG_PPC64 */ - -unsigned long arch_align_stack(unsigned long sp) -{ - if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) - sp -= get_random_int() & ~PAGE_MASK; - return sp & ~0xf; -} - -static inline unsigned long brk_rnd(void) -{ - unsigned long rnd = 0; - - /* 8MB for 32bit, 1GB for 64bit */ - if (is_32bit_task()) - rnd = (long)(get_random_int() % (1<<(23-PAGE_SHIFT))); - else - rnd = (long)(get_random_int() % (1<<(30-PAGE_SHIFT))); - - return rnd << PAGE_SHIFT; -} - -unsigned long arch_randomize_brk(struct mm_struct *mm) -{ - unsigned long base = mm->brk; - unsigned long ret; - -#ifdef CONFIG_PPC_STD_MMU_64 - /* - * If we are using 1TB segments and we are allowed to randomise - * the heap, we can put it above 1TB so it is backed by a 1TB - * segment. Otherwise the heap will be in the bottom 1TB - * which always uses 256MB segments and this may result in a - * performance penalty. - */ - if (!is_32bit_task() && (mmu_highuser_ssize == MMU_SEGSIZE_1T)) - base = max_t(unsigned long, mm->brk, 1UL << SID_SHIFT_1T); -#endif - - ret = PAGE_ALIGN(base + brk_rnd()); - - if (ret < mm->brk) - return mm->brk; - - return ret; -} - diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 737c0d0..59c7417 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -1800,6 +1800,10 @@ static int do_seccomp(struct pt_regs *regs) static inline int do_seccomp(struct pt_regs *regs) { return 0; } #endif /* CONFIG_SECCOMP */ +#ifdef CONFIG_GRKERNSEC_SETXID +extern void gr_delayed_cred_worker(void); +#endif + /** * do_syscall_trace_enter() - Do syscall tracing on kernel entry. * @regs: the pt_regs of the task to trace (current) @@ -1828,6 +1832,11 @@ long do_syscall_trace_enter(struct pt_regs *regs) if (do_seccomp(regs)) return -1; +#ifdef CONFIG_GRKERNSEC_SETXID + if (unlikely(test_and_clear_thread_flag(TIF_GRSEC_SETXID))) + gr_delayed_cred_worker(); +#endif + if (test_thread_flag(TIF_SYSCALL_TRACE)) { /* * The tracer may decide to abort the syscall, if so tracehook @@ -1870,6 +1879,11 @@ void do_syscall_trace_leave(struct pt_regs *regs) { int step; +#ifdef CONFIG_GRKERNSEC_SETXID + if (unlikely(test_and_clear_thread_flag(TIF_GRSEC_SETXID))) + gr_delayed_cred_worker(); +#endif + audit_syscall_exit(regs); if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 0dbee46..97b77b9 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -1014,7 +1014,7 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset, /* Save user registers on the stack */ frame = &rt_sf->uc.uc_mcontext; addr = frame; - if (vdso32_rt_sigtramp && current->mm->context.vdso_base) { + if (vdso32_rt_sigtramp && current->mm->context.vdso_base != ~0UL) { sigret = 0; tramp = current->mm->context.vdso_base + vdso32_rt_sigtramp; } else { diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 20756df..300e2a4 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -765,7 +765,7 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs current->thread.fp_state.fpscr = 0; /* Set up to return from userspace. */ - if (vdso64_rt_sigtramp && current->mm->context.vdso_base) { + if (vdso64_rt_sigtramp && current->mm->context.vdso_base != ~0UL) { regs->link = current->mm->context.vdso_base + vdso64_rt_sigtramp; } else { err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]); diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 37de90f..12472ac 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -142,6 +143,8 @@ static unsigned __kprobes long oops_begin(struct pt_regs *regs) return flags; } +extern void gr_handle_kernel_exploit(void); + static void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) { @@ -191,6 +194,9 @@ static void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, panic("Fatal exception in interrupt"); if (panic_on_oops) panic("Fatal exception"); + + gr_handle_kernel_exploit(); + do_exit(signr); } @@ -1139,6 +1145,26 @@ void __kprobes program_check_exception(struct pt_regs *regs) enum ctx_state prev_state = exception_enter(); unsigned int reason = get_reason(regs); +#ifdef CONFIG_PAX_REFCOUNT + unsigned int bkpt; + const struct exception_table_entry *entry; + + if (reason & REASON_ILLEGAL) { + /* Check if PaX bad instruction */ + if (!probe_kernel_address(regs->nip, bkpt) && bkpt == 0xc00b00) { + current->thread.trap_nr = 0; + pax_report_refcount_overflow(regs); + /* fixup_exception() for PowerPC does not exist, simulate its job */ + if ((entry = search_exception_tables(regs->nip)) != NULL) { + regs->nip = entry->fixup; + return; + } + /* fixup_exception() could not handle */ + goto bail; + } + } +#endif + /* We can now get here via a FP Unavailable exception if the core * has no FPU, in that case the reason flags will be 0 */ diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index b457bfa..9018cde 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c @@ -34,6 +34,7 @@ #include #include #include +#include #undef DEBUG @@ -179,7 +180,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) vdso_base = VDSO32_MBASE; #endif - current->mm->context.vdso_base = 0; + current->mm->context.vdso_base = ~0UL; /* vDSO has a problem and was disabled, just don't "enable" it for the * process @@ -199,7 +200,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) vdso_base = get_unmapped_area(NULL, vdso_base, (vdso_pages << PAGE_SHIFT) + ((VDSO_ALIGNMENT - 1) & PAGE_MASK), - 0, 0); + 0, MAP_PRIVATE | MAP_EXECUTABLE); if (IS_ERR_VALUE(vdso_base)) { rc = vdso_base; goto fail_mmapsem; diff --git a/arch/powerpc/lib/usercopy_64.c b/arch/powerpc/lib/usercopy_64.c index 5eea6f3..5d10396 100644 --- a/arch/powerpc/lib/usercopy_64.c +++ b/arch/powerpc/lib/usercopy_64.c @@ -9,22 +9,6 @@ #include #include -unsigned long copy_from_user(void *to, const void __user *from, unsigned long n) -{ - if (likely(access_ok(VERIFY_READ, from, n))) - n = __copy_from_user(to, from, n); - else - memset(to, 0, n); - return n; -} - -unsigned long copy_to_user(void __user *to, const void *from, unsigned long n) -{ - if (likely(access_ok(VERIFY_WRITE, to, n))) - n = __copy_to_user(to, from, n); - return n; -} - unsigned long copy_in_user(void __user *to, const void __user *from, unsigned long n) { @@ -35,7 +19,5 @@ unsigned long copy_in_user(void __user *to, const void __user *from, return n; } -EXPORT_SYMBOL(copy_from_user); -EXPORT_SYMBOL(copy_to_user); EXPORT_SYMBOL(copy_in_user); diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index a67c6d7..a662e6d 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -34,6 +34,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -68,6 +72,33 @@ static inline int notify_page_fault(struct pt_regs *regs) } #endif +#ifdef CONFIG_PAX_PAGEEXEC +/* + * PaX: decide what to do with offenders (regs->nip = fault address) + * + * returns 1 when task should be killed + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + return 1; +} + +void pax_report_insns(struct pt_regs *regs, void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int __user *)pc+i)) + printk(KERN_CONT "???????? "); + else + printk(KERN_CONT "%08x ", c); + } + printk("\n"); +} +#endif + /* * Check whether the instruction at regs->nip is a store using * an update addressing form which will update r1. @@ -227,7 +258,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, * indicate errors in DSISR but can validly be set in SRR1. */ if (trap == 0x400) - error_code &= 0x48200000; + error_code &= 0x58200000; else is_write = error_code & DSISR_ISSTORE; #else @@ -384,12 +415,16 @@ good_area: * "undefined". Of those that can be set, this is the only * one which seems bad. */ - if (error_code & 0x10000000) + if (error_code & DSISR_GUARDED) /* Guarded storage error. */ goto bad_area; #endif /* CONFIG_8xx */ if (is_exec) { +#ifdef CONFIG_PPC_STD_MMU + if (error_code & DSISR_GUARDED) + goto bad_area; +#endif /* * Allow execution from readable areas if the MMU does not * provide separate controls over reading and executing. @@ -484,6 +519,23 @@ bad_area: bad_area_nosemaphore: /* User mode accesses cause a SIGSEGV */ if (user_mode(regs)) { + +#ifdef CONFIG_PAX_PAGEEXEC + if (mm->pax_flags & MF_PAX_PAGEEXEC) { +#ifdef CONFIG_PPC_STD_MMU + if (is_exec && (error_code & (DSISR_PROTFAULT | DSISR_GUARDED))) { +#else + if (is_exec && regs->nip == address) { +#endif + switch (pax_handle_fetch_fault(regs)) { + } + + pax_report_fault(regs, (void *)regs->nip, (void *)regs->gpr[PT_R1]); + do_group_exit(SIGKILL); + } + } +#endif + _exception(SIGSEGV, regs, code, address); goto bail; } diff --git a/arch/powerpc/mm/mmap.c b/arch/powerpc/mm/mmap.c index 0f0502e..bc3e7a3 100644 --- a/arch/powerpc/mm/mmap.c +++ b/arch/powerpc/mm/mmap.c @@ -86,6 +86,10 @@ void arch_pick_mmap_layout(struct mm_struct *mm) { unsigned long random_factor = 0UL; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + if (current->flags & PF_RANDOMIZE) random_factor = arch_mmap_rnd(); @@ -95,9 +99,21 @@ void arch_pick_mmap_layout(struct mm_struct *mm) */ if (mmap_is_legacy()) { mm->mmap_base = TASK_UNMAPPED_BASE; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base += mm->delta_mmap; +#endif + mm->get_unmapped_area = arch_get_unmapped_area; } else { mm->mmap_base = mmap_base(random_factor); + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base -= mm->delta_mmap + mm->delta_stack; +#endif + mm->get_unmapped_area = arch_get_unmapped_area_topdown; } } diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index 0f432a7..abfe841 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c @@ -105,7 +105,7 @@ static int slice_area_is_free(struct mm_struct *mm, unsigned long addr, if ((mm->task_size - len) < addr) return 0; vma = find_vma(mm, addr); - return (!vma || (addr + len) <= vma->vm_start); + return check_heap_stack_gap(vma, addr, len, 0); } static int slice_low_has_vma(struct mm_struct *mm, unsigned long slice) @@ -277,6 +277,12 @@ static unsigned long slice_find_area_bottomup(struct mm_struct *mm, info.align_offset = 0; addr = TASK_UNMAPPED_BASE; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + addr += mm->delta_mmap; +#endif + while (addr < TASK_SIZE) { info.low_limit = addr; if (!slice_scan_available(addr, available, 1, &addr)) @@ -410,6 +416,11 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len, if (fixed && addr > (mm->task_size - len)) return -ENOMEM; +#ifdef CONFIG_PAX_RANDMMAP + if (!fixed && (mm->pax_flags & MF_PAX_RANDMMAP)) + addr = 0; +#endif + /* If hint, make sure it matches our alignment restrictions */ if (!fixed && addr) { addr = _ALIGN_UP(addr, 1ul << pshift); diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 5038fd5..87a2033 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -263,9 +263,9 @@ spufs_mem_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return VM_FAULT_NOPAGE; } -static int spufs_mem_mmap_access(struct vm_area_struct *vma, +static ssize_t spufs_mem_mmap_access(struct vm_area_struct *vma, unsigned long address, - void *buf, int len, int write) + void *buf, size_t len, int write) { struct spu_context *ctx = vma->vm_file->private_data; unsigned long offset = address - vma->vm_start; diff --git a/arch/s390/Kconfig.debug b/arch/s390/Kconfig.debug index c56878e..073d04e 100644 --- a/arch/s390/Kconfig.debug +++ b/arch/s390/Kconfig.debug @@ -21,6 +21,7 @@ config S390_PTDUMP bool "Export kernel pagetable layout to userspace via debugfs" depends on DEBUG_KERNEL select DEBUG_FS + depends on !GRKERNSEC_KMEM ---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/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h index 117fa5c..e2f6e51 100644 --- a/arch/s390/include/asm/atomic.h +++ b/arch/s390/include/asm/atomic.h @@ -324,4 +324,14 @@ static inline long long atomic64_dec_if_positive(atomic64_t *v) #define atomic64_dec_and_test(_v) (atomic64_sub_return(1, _v) == 0) #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) +#define atomic64_read_unchecked(v) atomic64_read(v) +#define atomic64_set_unchecked(v, i) atomic64_set((v), (i)) +#define atomic64_add_unchecked(a, v) atomic64_add((a), (v)) +#define atomic64_add_return_unchecked(a, v) atomic64_add_return((a), (v)) +#define atomic64_sub_unchecked(a, v) atomic64_sub((a), (v)) +#define atomic64_inc_unchecked(v) atomic64_inc(v) +#define atomic64_inc_return_unchecked(v) atomic64_inc_return(v) +#define atomic64_dec_unchecked(v) atomic64_dec(v) +#define atomic64_cmpxchg_unchecked(v, o, n) atomic64_cmpxchg((v), (o), (n)) + #endif /* __ARCH_S390_ATOMIC__ */ diff --git a/arch/s390/include/asm/cache.h b/arch/s390/include/asm/cache.h index 4d7ccac..d03d0ad 100644 --- a/arch/s390/include/asm/cache.h +++ b/arch/s390/include/asm/cache.h @@ -9,8 +9,10 @@ #ifndef __ARCH_S390_CACHE_H #define __ARCH_S390_CACHE_H -#define L1_CACHE_BYTES 256 +#include + #define L1_CACHE_SHIFT 8 +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #define NET_SKB_PAD 32 #define __read_mostly __attribute__((__section__(".data..read_mostly"))) diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index 3ad48f2..64cc6f3 100644 --- a/arch/s390/include/asm/elf.h +++ b/arch/s390/include/asm/elf.h @@ -163,6 +163,13 @@ extern unsigned int vdso_enabled; (STACK_TOP / 3 * 2) : \ (STACK_TOP / 3 * 2) & ~((1UL << 32) - 1)) +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE (test_thread_flag(TIF_31BIT) ? 0x10000UL : 0x80000000UL) + +#define PAX_DELTA_MMAP_LEN (test_thread_flag(TIF_31BIT) ? 15 : 26) +#define PAX_DELTA_STACK_LEN (test_thread_flag(TIF_31BIT) ? 15 : 26) +#endif + /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. */ diff --git a/arch/s390/include/asm/exec.h b/arch/s390/include/asm/exec.h index c4a93d6..4d2a9b4 100644 --- a/arch/s390/include/asm/exec.h +++ b/arch/s390/include/asm/exec.h @@ -7,6 +7,6 @@ #ifndef __ASM_EXEC_H #define __ASM_EXEC_H -extern unsigned long arch_align_stack(unsigned long sp); +#define arch_align_stack(x) ((x) & ~0xfUL) #endif /* __ASM_EXEC_H */ diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h index 9dd4cc4..36f4b84 100644 --- a/arch/s390/include/asm/uaccess.h +++ b/arch/s390/include/asm/uaccess.h @@ -59,6 +59,7 @@ static inline int __range_ok(unsigned long addr, unsigned long size) __range_ok((unsigned long)(addr), (size)); \ }) +#define access_ok_noprefault(type, addr, size) access_ok((type), (addr), (size)) #define access_ok(type, addr, size) __access_ok(addr, size) /* @@ -278,6 +279,10 @@ static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) { might_fault(); + + if ((long)n < 0) + return n; + return __copy_to_user(to, from, n); } @@ -307,10 +312,14 @@ __compiletime_warning("copy_from_user() buffer size is not provably correct") static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) { - unsigned int sz = __compiletime_object_size(to); + size_t sz = __compiletime_object_size(to); might_fault(); - if (unlikely(sz != -1 && sz < n)) { + + if ((long)n < 0) + return n; + + if (unlikely(sz != (size_t)-1 && sz < n)) { copy_from_user_overflow(); return n; } diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 0c1a679..e1df357 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -159,11 +159,11 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, /* Increase core size by size of got & plt and set start offsets for got and plt. */ - me->core_size = ALIGN(me->core_size, 4); - me->arch.got_offset = me->core_size; - me->core_size += me->arch.got_size; - me->arch.plt_offset = me->core_size; - me->core_size += me->arch.plt_size; + me->core_size_rw = ALIGN(me->core_size_rw, 4); + me->arch.got_offset = me->core_size_rw; + me->core_size_rw += me->arch.got_size; + me->arch.plt_offset = me->core_size_rx; + me->core_size_rx += me->arch.plt_size; return 0; } @@ -279,7 +279,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, if (info->got_initialized == 0) { Elf_Addr *gotent; - gotent = me->module_core + me->arch.got_offset + + gotent = me->module_core_rw + me->arch.got_offset + info->got_offset; *gotent = val; info->got_initialized = 1; @@ -302,7 +302,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, rc = apply_rela_bits(loc, val, 0, 64, 0); else if (r_type == R_390_GOTENT || r_type == R_390_GOTPLTENT) { - val += (Elf_Addr) me->module_core - loc; + val += (Elf_Addr) me->module_core_rw - loc; rc = apply_rela_bits(loc, val, 1, 32, 1); } break; @@ -315,7 +315,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */ if (info->plt_initialized == 0) { unsigned int *ip; - ip = me->module_core + me->arch.plt_offset + + ip = me->module_core_rx + me->arch.plt_offset + info->plt_offset; ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */ ip[1] = 0x100a0004; @@ -334,7 +334,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, val - loc + 0xffffUL < 0x1ffffeUL) || (r_type == R_390_PLT32DBL && val - loc + 0xffffffffULL < 0x1fffffffeULL))) - val = (Elf_Addr) me->module_core + + val = (Elf_Addr) me->module_core_rx + me->arch.plt_offset + info->plt_offset; val += rela->r_addend - loc; @@ -356,7 +356,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, case R_390_GOTOFF32: /* 32 bit offset to GOT. */ case R_390_GOTOFF64: /* 64 bit offset to GOT. */ val = val + rela->r_addend - - ((Elf_Addr) me->module_core + me->arch.got_offset); + ((Elf_Addr) me->module_core_rw + me->arch.got_offset); if (r_type == R_390_GOTOFF16) rc = apply_rela_bits(loc, val, 0, 16, 0); else if (r_type == R_390_GOTOFF32) @@ -366,7 +366,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, break; case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */ case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */ - val = (Elf_Addr) me->module_core + me->arch.got_offset + + val = (Elf_Addr) me->module_core_rw + me->arch.got_offset + rela->r_addend - loc; if (r_type == R_390_GOTPC) rc = apply_rela_bits(loc, val, 1, 32, 0); diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index f2dac9f..936c8c2 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -232,27 +232,3 @@ unsigned long get_wchan(struct task_struct *p) } return 0; } - -unsigned long arch_align_stack(unsigned long sp) -{ - if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) - sp -= get_random_int() & ~PAGE_MASK; - return sp & ~0xf; -} - -static inline unsigned long brk_rnd(void) -{ - /* 8MB for 32bit, 1GB for 64bit */ - if (is_32bit_task()) - return (get_random_int() & 0x7ffUL) << PAGE_SHIFT; - else - return (get_random_int() & 0x3ffffUL) << PAGE_SHIFT; -} - -unsigned long arch_randomize_brk(struct mm_struct *mm) -{ - unsigned long ret; - - ret = PAGE_ALIGN(mm->brk + brk_rnd()); - return (ret > mm->brk) ? ret : mm->brk; -} diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c index 6e552af..3e608a1 100644 --- a/arch/s390/mm/mmap.c +++ b/arch/s390/mm/mmap.c @@ -239,6 +239,10 @@ void arch_pick_mmap_layout(struct mm_struct *mm) { unsigned long random_factor = 0UL; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + if (current->flags & PF_RANDOMIZE) random_factor = arch_mmap_rnd(); @@ -248,9 +252,21 @@ void arch_pick_mmap_layout(struct mm_struct *mm) */ if (mmap_is_legacy()) { mm->mmap_base = mmap_base_legacy(random_factor); + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base += mm->delta_mmap; +#endif + mm->get_unmapped_area = s390_get_unmapped_area; } else { mm->mmap_base = mmap_base(random_factor); + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base -= mm->delta_mmap + mm->delta_stack; +#endif + mm->get_unmapped_area = s390_get_unmapped_area_topdown; } } diff --git a/arch/score/include/asm/cache.h b/arch/score/include/asm/cache.h index ae3d59f..f65f075 100644 --- a/arch/score/include/asm/cache.h +++ b/arch/score/include/asm/cache.h @@ -1,7 +1,9 @@ #ifndef _ASM_SCORE_CACHE_H #define _ASM_SCORE_CACHE_H +#include + #define L1_CACHE_SHIFT 4 -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #endif /* _ASM_SCORE_CACHE_H */ diff --git a/arch/score/include/asm/exec.h b/arch/score/include/asm/exec.h index f9f3cd5..58ff438 100644 --- a/arch/score/include/asm/exec.h +++ b/arch/score/include/asm/exec.h @@ -1,6 +1,6 @@ #ifndef _ASM_SCORE_EXEC_H #define _ASM_SCORE_EXEC_H -extern unsigned long arch_align_stack(unsigned long sp); +#define arch_align_stack(x) (x) #endif /* _ASM_SCORE_EXEC_H */ diff --git a/arch/score/kernel/process.c b/arch/score/kernel/process.c index a1519ad3..e8ac1ff 100644 --- a/arch/score/kernel/process.c +++ b/arch/score/kernel/process.c @@ -116,8 +116,3 @@ unsigned long get_wchan(struct task_struct *task) return task_pt_regs(task)->cp0_epc; } - -unsigned long arch_align_stack(unsigned long sp) -{ - return sp; -} diff --git a/arch/sh/include/asm/cache.h b/arch/sh/include/asm/cache.h index ef9e555..331bd29 100644 --- a/arch/sh/include/asm/cache.h +++ b/arch/sh/include/asm/cache.h @@ -9,10 +9,11 @@ #define __ASM_SH_CACHE_H #ifdef __KERNEL__ +#include #include #include -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #define __read_mostly __attribute__((__section__(".data..read_mostly"))) diff --git a/arch/sh/mm/mmap.c b/arch/sh/mm/mmap.c index 6777177..cb5e44f 100644 --- a/arch/sh/mm/mmap.c +++ b/arch/sh/mm/mmap.c @@ -36,6 +36,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, struct mm_struct *mm = current->mm; struct vm_area_struct *vma; int do_colour_align; + unsigned long offset = gr_rand_threadstack_offset(mm, filp, flags); struct vm_unmapped_area_info info; if (flags & MAP_FIXED) { @@ -55,6 +56,10 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, if (filp || (flags & MAP_SHARED)) do_colour_align = 1; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + if (addr) { if (do_colour_align) addr = COLOUR_ALIGN(addr, pgoff); @@ -62,14 +67,13 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + if (TASK_SIZE - len >= addr && check_heap_stack_gap(vma, addr, len, offset)) return addr; } info.flags = 0; info.length = len; - info.low_limit = TASK_UNMAPPED_BASE; + info.low_limit = mm->mmap_base; info.high_limit = TASK_SIZE; info.align_mask = do_colour_align ? (PAGE_MASK & shm_align_mask) : 0; info.align_offset = pgoff << PAGE_SHIFT; @@ -85,6 +89,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, struct mm_struct *mm = current->mm; unsigned long addr = addr0; int do_colour_align; + unsigned long offset = gr_rand_threadstack_offset(mm, filp, flags); struct vm_unmapped_area_info info; if (flags & MAP_FIXED) { @@ -104,6 +109,10 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, if (filp || (flags & MAP_SHARED)) do_colour_align = 1; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + /* requesting a specific address */ if (addr) { if (do_colour_align) @@ -112,8 +121,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + if (TASK_SIZE - len >= addr && check_heap_stack_gap(vma, addr, len, offset)) return addr; } @@ -135,6 +143,12 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, VM_BUG_ON(addr != -ENOMEM); info.flags = 0; info.low_limit = TASK_UNMAPPED_BASE; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + info.low_limit += mm->delta_mmap; +#endif + info.high_limit = TASK_SIZE; addr = vm_unmapped_area(&info); } diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index 917084a..4ff965d 100644 --- a/arch/sparc/include/asm/atomic_64.h +++ b/arch/sparc/include/asm/atomic_64.h @@ -15,18 +15,38 @@ #define ATOMIC64_INIT(i) { (i) } #define atomic_read(v) ACCESS_ONCE((v)->counter) +static inline int atomic_read_unchecked(const atomic_unchecked_t *v) +{ + return ACCESS_ONCE(v->counter); +} #define atomic64_read(v) ACCESS_ONCE((v)->counter) +static inline long atomic64_read_unchecked(const atomic64_unchecked_t *v) +{ + return ACCESS_ONCE(v->counter); +} #define atomic_set(v, i) (((v)->counter) = i) +static inline void atomic_set_unchecked(atomic_unchecked_t *v, int i) +{ + v->counter = i; +} #define atomic64_set(v, i) (((v)->counter) = i) +static inline void atomic64_set_unchecked(atomic64_unchecked_t *v, long i) +{ + v->counter = i; +} -#define ATOMIC_OP(op) \ -void atomic_##op(int, atomic_t *); \ -void atomic64_##op(long, atomic64_t *); +#define __ATOMIC_OP(op, suffix) \ +void atomic_##op##suffix(int, atomic##suffix##_t *); \ +void atomic64_##op##suffix(long, atomic64##suffix##_t *); -#define ATOMIC_OP_RETURN(op) \ -int atomic_##op##_return(int, atomic_t *); \ -long atomic64_##op##_return(long, atomic64_t *); +#define ATOMIC_OP(op) __ATOMIC_OP(op, ) __ATOMIC_OP(op, _unchecked) + +#define __ATOMIC_OP_RETURN(op, suffix) \ +int atomic_##op##_return##suffix(int, atomic##suffix##_t *); \ +long atomic64_##op##_return##suffix(long, atomic64##suffix##_t *); + +#define ATOMIC_OP_RETURN(op) __ATOMIC_OP_RETURN(op, ) __ATOMIC_OP_RETURN(op, _unchecked) #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) @@ -39,13 +59,23 @@ ATOMIC_OP(xor) #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN +#undef __ATOMIC_OP_RETURN #undef ATOMIC_OP +#undef __ATOMIC_OP #define atomic_dec_return(v) atomic_sub_return(1, v) #define atomic64_dec_return(v) atomic64_sub_return(1, v) #define atomic_inc_return(v) atomic_add_return(1, v) +static inline int atomic_inc_return_unchecked(atomic_unchecked_t *v) +{ + return atomic_add_return_unchecked(1, v); +} #define atomic64_inc_return(v) atomic64_add_return(1, v) +static inline long atomic64_inc_return_unchecked(atomic64_unchecked_t *v) +{ + return atomic64_add_return_unchecked(1, v); +} /* * atomic_inc_and_test - increment and test @@ -56,6 +86,10 @@ ATOMIC_OP(xor) * other cases. */ #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) +static inline int atomic_inc_and_test_unchecked(atomic_unchecked_t *v) +{ + return atomic_inc_return_unchecked(v) == 0; +} #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) #define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) @@ -65,25 +99,60 @@ ATOMIC_OP(xor) #define atomic64_dec_and_test(v) (atomic64_sub_return(1, v) == 0) #define atomic_inc(v) atomic_add(1, v) +static inline void atomic_inc_unchecked(atomic_unchecked_t *v) +{ + atomic_add_unchecked(1, v); +} #define atomic64_inc(v) atomic64_add(1, v) +static inline void atomic64_inc_unchecked(atomic64_unchecked_t *v) +{ + atomic64_add_unchecked(1, v); +} #define atomic_dec(v) atomic_sub(1, v) +static inline void atomic_dec_unchecked(atomic_unchecked_t *v) +{ + atomic_sub_unchecked(1, v); +} #define atomic64_dec(v) atomic64_sub(1, v) +static inline void atomic64_dec_unchecked(atomic64_unchecked_t *v) +{ + atomic64_sub_unchecked(1, v); +} #define atomic_add_negative(i, v) (atomic_add_return(i, v) < 0) #define atomic64_add_negative(i, v) (atomic64_add_return(i, v) < 0) #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) +static inline int atomic_cmpxchg_unchecked(atomic_unchecked_t *v, int old, int new) +{ + return cmpxchg(&v->counter, old, new); +} #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) +static inline int atomic_xchg_unchecked(atomic_unchecked_t *v, int new) +{ + return xchg(&v->counter, new); +} static inline int __atomic_add_unless(atomic_t *v, int a, int u) { - int c, old; + int c, old, new; c = atomic_read(v); for (;;) { - if (unlikely(c == (u))) + if (unlikely(c == u)) break; - old = atomic_cmpxchg((v), c, c + (a)); + + asm volatile("addcc %2, %0, %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "tvs %%icc, 6\n" +#endif + + : "=r" (new) + : "0" (c), "ir" (a) + : "cc"); + + old = atomic_cmpxchg(v, c, new); if (likely(old == c)) break; c = old; @@ -94,20 +163,35 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) #define atomic64_cmpxchg(v, o, n) \ ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n))) #define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) +static inline long atomic64_xchg_unchecked(atomic64_unchecked_t *v, long new) +{ + return xchg(&v->counter, new); +} static inline long atomic64_add_unless(atomic64_t *v, long a, long u) { - long c, old; + long c, old, new; c = atomic64_read(v); for (;;) { - if (unlikely(c == (u))) + if (unlikely(c == u)) break; - old = atomic64_cmpxchg((v), c, c + (a)); + + asm volatile("addcc %2, %0, %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "tvs %%xcc, 6\n" +#endif + + : "=r" (new) + : "0" (c), "ir" (a) + : "cc"); + + old = atomic64_cmpxchg(v, c, new); if (likely(old == c)) break; c = old; } - return c != (u); + return c != u; } #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) diff --git a/arch/sparc/include/asm/cache.h b/arch/sparc/include/asm/cache.h index 5bb6991..5c2132e 100644 --- a/arch/sparc/include/asm/cache.h +++ b/arch/sparc/include/asm/cache.h @@ -7,10 +7,12 @@ #ifndef _SPARC_CACHE_H #define _SPARC_CACHE_H +#include + #define ARCH_SLAB_MINALIGN __alignof__(unsigned long long) #define L1_CACHE_SHIFT 5 -#define L1_CACHE_BYTES 32 +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #ifdef CONFIG_SPARC32 #define SMP_CACHE_BYTES_SHIFT 5 diff --git a/arch/sparc/include/asm/elf_32.h b/arch/sparc/include/asm/elf_32.h index a24e41f..47677ff 100644 --- a/arch/sparc/include/asm/elf_32.h +++ b/arch/sparc/include/asm/elf_32.h @@ -114,6 +114,13 @@ typedef struct { #define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE) +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE 0x10000UL + +#define PAX_DELTA_MMAP_LEN 16 +#define PAX_DELTA_STACK_LEN 16 +#endif + /* This yields a mask that user programs can use to figure out what instruction set this cpu supports. This can NOT be done in userspace on Sparc. */ diff --git a/arch/sparc/include/asm/elf_64.h b/arch/sparc/include/asm/elf_64.h index 370ca1e..d4f4a98 100644 --- a/arch/sparc/include/asm/elf_64.h +++ b/arch/sparc/include/asm/elf_64.h @@ -189,6 +189,13 @@ typedef struct { #define ELF_ET_DYN_BASE 0x0000010000000000UL #define COMPAT_ELF_ET_DYN_BASE 0x0000000070000000UL +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE (test_thread_flag(TIF_32BIT) ? 0x10000UL : 0x100000UL) + +#define PAX_DELTA_MMAP_LEN (test_thread_flag(TIF_32BIT) ? 14 : 28) +#define PAX_DELTA_STACK_LEN (test_thread_flag(TIF_32BIT) ? 15 : 29) +#endif + extern unsigned long sparc64_elf_hwcap; #define ELF_HWCAP sparc64_elf_hwcap diff --git a/arch/sparc/include/asm/pgalloc_32.h b/arch/sparc/include/asm/pgalloc_32.h index a3890da..f6a408e 100644 --- a/arch/sparc/include/asm/pgalloc_32.h +++ b/arch/sparc/include/asm/pgalloc_32.h @@ -35,6 +35,7 @@ static inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp) } #define pgd_populate(MM, PGD, PMD) pgd_set(PGD, PMD) +#define pgd_populate_kernel(MM, PGD, PMD) pgd_populate((MM), (PGD), (PMD)) static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) diff --git a/arch/sparc/include/asm/pgalloc_64.h b/arch/sparc/include/asm/pgalloc_64.h index 5e31871..13469c6 100644 --- a/arch/sparc/include/asm/pgalloc_64.h +++ b/arch/sparc/include/asm/pgalloc_64.h @@ -21,6 +21,7 @@ static inline void __pgd_populate(pgd_t *pgd, pud_t *pud) } #define pgd_populate(MM, PGD, PUD) __pgd_populate(PGD, PUD) +#define pgd_populate_kernel(MM, PGD, PMD) pgd_populate((MM), (PGD), (PMD)) static inline pgd_t *pgd_alloc(struct mm_struct *mm) { @@ -38,6 +39,7 @@ static inline void __pud_populate(pud_t *pud, pmd_t *pmd) } #define pud_populate(MM, PUD, PMD) __pud_populate(PUD, PMD) +#define pud_populate_kernel(MM, PUD, PMD) pud_populate((MM), (PUD), (PMD)) static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) { diff --git a/arch/sparc/include/asm/pgtable.h b/arch/sparc/include/asm/pgtable.h index 59ba6f6..4518128 100644 --- a/arch/sparc/include/asm/pgtable.h +++ b/arch/sparc/include/asm/pgtable.h @@ -5,4 +5,8 @@ #else #include #endif + +#define ktla_ktva(addr) (addr) +#define ktva_ktla(addr) (addr) + #endif diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h index 91b963a..9a806c1 100644 --- a/arch/sparc/include/asm/pgtable_32.h +++ b/arch/sparc/include/asm/pgtable_32.h @@ -51,6 +51,9 @@ unsigned long __init bootmem_init(unsigned long *pages_avail); #define PAGE_SHARED SRMMU_PAGE_SHARED #define PAGE_COPY SRMMU_PAGE_COPY #define PAGE_READONLY SRMMU_PAGE_RDONLY +#define PAGE_SHARED_NOEXEC SRMMU_PAGE_SHARED_NOEXEC +#define PAGE_COPY_NOEXEC SRMMU_PAGE_COPY_NOEXEC +#define PAGE_READONLY_NOEXEC SRMMU_PAGE_RDONLY_NOEXEC #define PAGE_KERNEL SRMMU_PAGE_KERNEL /* Top-level page directory - dummy used by init-mm. @@ -63,18 +66,18 @@ extern unsigned long ptr_in_current_pgd; /* xwr */ #define __P000 PAGE_NONE -#define __P001 PAGE_READONLY -#define __P010 PAGE_COPY -#define __P011 PAGE_COPY +#define __P001 PAGE_READONLY_NOEXEC +#define __P010 PAGE_COPY_NOEXEC +#define __P011 PAGE_COPY_NOEXEC #define __P100 PAGE_READONLY #define __P101 PAGE_READONLY #define __P110 PAGE_COPY #define __P111 PAGE_COPY #define __S000 PAGE_NONE -#define __S001 PAGE_READONLY -#define __S010 PAGE_SHARED -#define __S011 PAGE_SHARED +#define __S001 PAGE_READONLY_NOEXEC +#define __S010 PAGE_SHARED_NOEXEC +#define __S011 PAGE_SHARED_NOEXEC #define __S100 PAGE_READONLY #define __S101 PAGE_READONLY #define __S110 PAGE_SHARED diff --git a/arch/sparc/include/asm/pgtsrmmu.h b/arch/sparc/include/asm/pgtsrmmu.h index ae51a11..eadfd03 100644 --- a/arch/sparc/include/asm/pgtsrmmu.h +++ b/arch/sparc/include/asm/pgtsrmmu.h @@ -111,6 +111,11 @@ SRMMU_EXEC | SRMMU_REF) #define SRMMU_PAGE_RDONLY __pgprot(SRMMU_VALID | SRMMU_CACHE | \ SRMMU_EXEC | SRMMU_REF) + +#define SRMMU_PAGE_SHARED_NOEXEC __pgprot(SRMMU_VALID | SRMMU_CACHE | SRMMU_WRITE | SRMMU_REF) +#define SRMMU_PAGE_COPY_NOEXEC __pgprot(SRMMU_VALID | SRMMU_CACHE | SRMMU_REF) +#define SRMMU_PAGE_RDONLY_NOEXEC __pgprot(SRMMU_VALID | SRMMU_CACHE | SRMMU_REF) + #define SRMMU_PAGE_KERNEL __pgprot(SRMMU_VALID | SRMMU_CACHE | SRMMU_PRIV | \ SRMMU_DIRTY | SRMMU_REF) diff --git a/arch/sparc/include/asm/setup.h b/arch/sparc/include/asm/setup.h index 29d64b1..4272fe8 100644 --- a/arch/sparc/include/asm/setup.h +++ b/arch/sparc/include/asm/setup.h @@ -55,8 +55,8 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs); void handle_ld_nf(u32 insn, struct pt_regs *regs); /* init_64.c */ -extern atomic_t dcpage_flushes; -extern atomic_t dcpage_flushes_xcall; +extern atomic_unchecked_t dcpage_flushes; +extern atomic_unchecked_t dcpage_flushes_xcall; extern int sysctl_tsb_ratio; #endif diff --git a/arch/sparc/include/asm/spinlock_64.h b/arch/sparc/include/asm/spinlock_64.h index 9689176..63c18ea 100644 --- a/arch/sparc/include/asm/spinlock_64.h +++ b/arch/sparc/include/asm/spinlock_64.h @@ -92,14 +92,19 @@ static inline void arch_spin_lock_flags(arch_spinlock_t *lock, unsigned long fla /* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */ -static void inline arch_read_lock(arch_rwlock_t *lock) +static inline void arch_read_lock(arch_rwlock_t *lock) { unsigned long tmp1, tmp2; __asm__ __volatile__ ( "1: ldsw [%2], %0\n" " brlz,pn %0, 2f\n" -"4: add %0, 1, %1\n" +"4: addcc %0, 1, %1\n" + +#ifdef CONFIG_PAX_REFCOUNT +" tvs %%icc, 6\n" +#endif + " cas [%2], %0, %1\n" " cmp %0, %1\n" " bne,pn %%icc, 1b\n" @@ -112,10 +117,10 @@ static void inline arch_read_lock(arch_rwlock_t *lock) " .previous" : "=&r" (tmp1), "=&r" (tmp2) : "r" (lock) - : "memory"); + : "memory", "cc"); } -static int inline arch_read_trylock(arch_rwlock_t *lock) +static inline int arch_read_trylock(arch_rwlock_t *lock) { int tmp1, tmp2; @@ -123,7 +128,12 @@ static int inline arch_read_trylock(arch_rwlock_t *lock) "1: ldsw [%2], %0\n" " brlz,a,pn %0, 2f\n" " mov 0, %0\n" -" add %0, 1, %1\n" +" addcc %0, 1, %1\n" + +#ifdef CONFIG_PAX_REFCOUNT +" tvs %%icc, 6\n" +#endif + " cas [%2], %0, %1\n" " cmp %0, %1\n" " bne,pn %%icc, 1b\n" @@ -136,13 +146,18 @@ static int inline arch_read_trylock(arch_rwlock_t *lock) return tmp1; } -static void inline arch_read_unlock(arch_rwlock_t *lock) +static inline void arch_read_unlock(arch_rwlock_t *lock) { unsigned long tmp1, tmp2; __asm__ __volatile__( "1: lduw [%2], %0\n" -" sub %0, 1, %1\n" +" subcc %0, 1, %1\n" + +#ifdef CONFIG_PAX_REFCOUNT +" tvs %%icc, 6\n" +#endif + " cas [%2], %0, %1\n" " cmp %0, %1\n" " bne,pn %%xcc, 1b\n" @@ -152,7 +167,7 @@ static void inline arch_read_unlock(arch_rwlock_t *lock) : "memory"); } -static void inline arch_write_lock(arch_rwlock_t *lock) +static inline void arch_write_lock(arch_rwlock_t *lock) { unsigned long mask, tmp1, tmp2; @@ -177,7 +192,7 @@ static void inline arch_write_lock(arch_rwlock_t *lock) : "memory"); } -static void inline arch_write_unlock(arch_rwlock_t *lock) +static inline void arch_write_unlock(arch_rwlock_t *lock) { __asm__ __volatile__( " stw %%g0, [%0]" @@ -186,7 +201,7 @@ static void inline arch_write_unlock(arch_rwlock_t *lock) : "memory"); } -static int inline arch_write_trylock(arch_rwlock_t *lock) +static inline int arch_write_trylock(arch_rwlock_t *lock) { unsigned long mask, tmp1, tmp2, result; diff --git a/arch/sparc/include/asm/thread_info_32.h b/arch/sparc/include/asm/thread_info_32.h index 229475f..2fca9163 100644 --- a/arch/sparc/include/asm/thread_info_32.h +++ b/arch/sparc/include/asm/thread_info_32.h @@ -48,6 +48,7 @@ struct thread_info { struct reg_window32 reg_window[NSWINS]; /* align for ldd! */ unsigned long rwbuf_stkptrs[NSWINS]; unsigned long w_saved; + unsigned long lowest_stack; }; /* diff --git a/arch/sparc/include/asm/thread_info_64.h b/arch/sparc/include/asm/thread_info_64.h index bde5982..9cbb56d 100644 --- a/arch/sparc/include/asm/thread_info_64.h +++ b/arch/sparc/include/asm/thread_info_64.h @@ -59,6 +59,8 @@ struct thread_info { struct pt_regs *kern_una_regs; unsigned int kern_una_insn; + unsigned long lowest_stack; + unsigned long fpregs[(7 * 256) / sizeof(unsigned long)] __attribute__ ((aligned(64))); }; @@ -180,12 +182,13 @@ register struct thread_info *current_thread_info_reg asm("g6"); #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ /* flag bit 4 is available */ #define TIF_UNALIGNED 5 /* allowed to do unaligned accesses */ -/* flag bit 6 is available */ +#define TIF_GRSEC_SETXID 6 /* update credentials on syscall entry/exit */ #define TIF_32BIT 7 /* 32-bit binary */ #define TIF_NOHZ 8 /* in adaptive nohz mode */ #define TIF_SECCOMP 9 /* secure computing */ #define TIF_SYSCALL_AUDIT 10 /* syscall auditing active */ #define TIF_SYSCALL_TRACEPOINT 11 /* syscall tracepoint instrumentation */ + /* NOTE: Thread flags >= 12 should be ones we have no interest * in using in assembly, else we can't use the mask as * an immediate value in instructions such as andcc. @@ -205,12 +208,17 @@ register struct thread_info *current_thread_info_reg asm("g6"); #define _TIF_SYSCALL_AUDIT (1< #else diff --git a/arch/sparc/include/asm/uaccess_32.h b/arch/sparc/include/asm/uaccess_32.h index 64ee103..388aef0 100644 --- a/arch/sparc/include/asm/uaccess_32.h +++ b/arch/sparc/include/asm/uaccess_32.h @@ -47,6 +47,7 @@ #define __user_ok(addr, size) ({ (void)(size); (addr) < STACK_TOP; }) #define __kernel_ok (segment_eq(get_fs(), KERNEL_DS)) #define __access_ok(addr, size) (__user_ok((addr) & get_fs().seg, (size))) +#define access_ok_noprefault(type, addr, size) access_ok((type), (addr), (size)) #define access_ok(type, addr, size) \ ({ (void)(type); __access_ok((unsigned long)(addr), size); }) @@ -313,27 +314,46 @@ unsigned long __copy_user(void __user *to, const void __user *from, unsigned lon static inline unsigned long copy_to_user(void __user *to, const void *from, unsigned long n) { - if (n && __access_ok((unsigned long) to, n)) + if ((long)n < 0) + return n; + + if (n && __access_ok((unsigned long) to, n)) { + if (!__builtin_constant_p(n)) + check_object_size(from, n, true); return __copy_user(to, (__force void __user *) from, n); - else + } else return n; } static inline unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n) { + if ((long)n < 0) + return n; + + if (!__builtin_constant_p(n)) + check_object_size(from, n, true); + return __copy_user(to, (__force void __user *) from, n); } static inline unsigned long copy_from_user(void *to, const void __user *from, unsigned long n) { - if (n && __access_ok((unsigned long) from, n)) + if ((long)n < 0) + return n; + + if (n && __access_ok((unsigned long) from, n)) { + if (!__builtin_constant_p(n)) + check_object_size(to, n, false); return __copy_user((__force void __user *) to, from, n); - else + } else return n; } static inline unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n) { + if ((long)n < 0) + return n; + return __copy_user((__force void __user *) to, from, n); } diff --git a/arch/sparc/include/asm/uaccess_64.h b/arch/sparc/include/asm/uaccess_64.h index ea6e9a2..5703598 100644 --- a/arch/sparc/include/asm/uaccess_64.h +++ b/arch/sparc/include/asm/uaccess_64.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -76,6 +77,11 @@ static inline int __access_ok(const void __user * addr, unsigned long size) return 1; } +static inline int access_ok_noprefault(int type, const void __user * addr, unsigned long size) +{ + return 1; +} + static inline int access_ok(int type, const void __user * addr, unsigned long size) { return 1; @@ -250,8 +256,15 @@ unsigned long copy_from_user_fixup(void *to, const void __user *from, static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long size) { - unsigned long ret = ___copy_from_user(to, from, size); + unsigned long ret; + if ((long)size < 0 || size > INT_MAX) + return size; + + if (!__builtin_constant_p(size)) + check_object_size(to, size, false); + + ret = ___copy_from_user(to, from, size); if (unlikely(ret)) ret = copy_from_user_fixup(to, from, size); @@ -267,8 +280,15 @@ unsigned long copy_to_user_fixup(void __user *to, const void *from, static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long size) { - unsigned long ret = ___copy_to_user(to, from, size); + unsigned long ret; + if ((long)size < 0 || size > INT_MAX) + return size; + + if (!__builtin_constant_p(size)) + check_object_size(from, size, true); + + ret = ___copy_to_user(to, from, size); if (unlikely(ret)) ret = copy_to_user_fixup(to, from, size); return ret; diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 7cf9c6e..6206648 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -4,7 +4,7 @@ # asflags-y := -ansi -ccflags-y := -Werror +#ccflags-y := -Werror extra-y := head_$(BITS).o diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index c5113c7..52322e4 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -123,14 +123,14 @@ void show_regs(struct pt_regs *r) printk("PSR: %08lx PC: %08lx NPC: %08lx Y: %08lx %s\n", r->psr, r->pc, r->npc, r->y, print_tainted()); - printk("PC: <%pS>\n", (void *) r->pc); + printk("PC: <%pA>\n", (void *) r->pc); printk("%%G: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", r->u_regs[0], r->u_regs[1], r->u_regs[2], r->u_regs[3], r->u_regs[4], r->u_regs[5], r->u_regs[6], r->u_regs[7]); printk("%%O: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", r->u_regs[8], r->u_regs[9], r->u_regs[10], r->u_regs[11], r->u_regs[12], r->u_regs[13], r->u_regs[14], r->u_regs[15]); - printk("RPC: <%pS>\n", (void *) r->u_regs[15]); + printk("RPC: <%pA>\n", (void *) r->u_regs[15]); printk("%%L: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3], @@ -167,7 +167,7 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp) rw = (struct reg_window32 *) fp; pc = rw->ins[7]; printk("[%08lx : ", pc); - printk("%pS ] ", (void *) pc); + printk("%pA ] ", (void *) pc); fp = rw->ins[6]; } while (++count < 16); printk("\n"); diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index 46a5964..a35c62c 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -161,7 +161,7 @@ static void show_regwindow(struct pt_regs *regs) printk("i4: %016lx i5: %016lx i6: %016lx i7: %016lx\n", rwk->ins[4], rwk->ins[5], rwk->ins[6], rwk->ins[7]); if (regs->tstate & TSTATE_PRIV) - printk("I7: <%pS>\n", (void *) rwk->ins[7]); + printk("I7: <%pA>\n", (void *) rwk->ins[7]); } void show_regs(struct pt_regs *regs) @@ -170,7 +170,7 @@ void show_regs(struct pt_regs *regs) printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x %s\n", regs->tstate, regs->tpc, regs->tnpc, regs->y, print_tainted()); - printk("TPC: <%pS>\n", (void *) regs->tpc); + printk("TPC: <%pA>\n", (void *) regs->tpc); printk("g0: %016lx g1: %016lx g2: %016lx g3: %016lx\n", regs->u_regs[0], regs->u_regs[1], regs->u_regs[2], regs->u_regs[3]); @@ -183,7 +183,7 @@ void show_regs(struct pt_regs *regs) printk("o4: %016lx o5: %016lx sp: %016lx ret_pc: %016lx\n", regs->u_regs[12], regs->u_regs[13], regs->u_regs[14], regs->u_regs[15]); - printk("RPC: <%pS>\n", (void *) regs->u_regs[15]); + printk("RPC: <%pA>\n", (void *) regs->u_regs[15]); show_regwindow(regs); show_stack(current, (unsigned long *) regs->u_regs[UREG_FP]); } @@ -278,7 +278,7 @@ void arch_trigger_all_cpu_backtrace(bool include_self) ((tp && tp->task) ? tp->task->pid : -1)); if (gp->tstate & TSTATE_PRIV) { - printk(" TPC[%pS] O7[%pS] I7[%pS] RPC[%pS]\n", + printk(" TPC[%pA] O7[%pA] I7[%pA] RPC[%pA]\n", (void *) gp->tpc, (void *) gp->o7, (void *) gp->i7, diff --git a/arch/sparc/kernel/prom_common.c b/arch/sparc/kernel/prom_common.c index 79cc0d1..ec62734 100644 --- a/arch/sparc/kernel/prom_common.c +++ b/arch/sparc/kernel/prom_common.c @@ -144,7 +144,7 @@ static int __init prom_common_nextprop(phandle node, char *prev, char *buf) unsigned int prom_early_allocated __initdata; -static struct of_pdt_ops prom_sparc_ops __initdata = { +static struct of_pdt_ops prom_sparc_ops __initconst = { .nextprop = prom_common_nextprop, .getproplen = prom_getproplen, .getproperty = prom_getproperty, diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c index 9ddc492..27a5619 100644 --- a/arch/sparc/kernel/ptrace_64.c +++ b/arch/sparc/kernel/ptrace_64.c @@ -1060,6 +1060,10 @@ long arch_ptrace(struct task_struct *child, long request, return ret; } +#ifdef CONFIG_GRKERNSEC_SETXID +extern void gr_delayed_cred_worker(void); +#endif + asmlinkage int syscall_trace_enter(struct pt_regs *regs) { int ret = 0; @@ -1070,6 +1074,11 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs) if (test_thread_flag(TIF_NOHZ)) user_exit(); +#ifdef CONFIG_GRKERNSEC_SETXID + if (unlikely(test_and_clear_thread_flag(TIF_GRSEC_SETXID))) + gr_delayed_cred_worker(); +#endif + if (test_thread_flag(TIF_SYSCALL_TRACE)) ret = tracehook_report_syscall_entry(regs); @@ -1088,6 +1097,11 @@ asmlinkage void syscall_trace_leave(struct pt_regs *regs) if (test_thread_flag(TIF_NOHZ)) user_exit(); +#ifdef CONFIG_GRKERNSEC_SETXID + if (unlikely(test_and_clear_thread_flag(TIF_GRSEC_SETXID))) + gr_delayed_cred_worker(); +#endif + audit_syscall_exit(regs); if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 19cd08d..ff21e99 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -891,7 +891,7 @@ void smp_flush_dcache_page_impl(struct page *page, int cpu) return; #ifdef CONFIG_DEBUG_DCFLUSH - atomic_inc(&dcpage_flushes); + atomic_inc_unchecked(&dcpage_flushes); #endif this_cpu = get_cpu(); @@ -915,7 +915,7 @@ void smp_flush_dcache_page_impl(struct page *page, int cpu) xcall_deliver(data0, __pa(pg_addr), (u64) pg_addr, cpumask_of(cpu)); #ifdef CONFIG_DEBUG_DCFLUSH - atomic_inc(&dcpage_flushes_xcall); + atomic_inc_unchecked(&dcpage_flushes_xcall); #endif } } @@ -934,7 +934,7 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page) preempt_disable(); #ifdef CONFIG_DEBUG_DCFLUSH - atomic_inc(&dcpage_flushes); + atomic_inc_unchecked(&dcpage_flushes); #endif data0 = 0; pg_addr = page_address(page); @@ -951,7 +951,7 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page) xcall_deliver(data0, __pa(pg_addr), (u64) pg_addr, cpu_online_mask); #ifdef CONFIG_DEBUG_DCFLUSH - atomic_inc(&dcpage_flushes_xcall); + atomic_inc_unchecked(&dcpage_flushes_xcall); #endif } __local_flush_dcache_page(page); diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c index 646988d..b88905f 100644 --- a/arch/sparc/kernel/sys_sparc_32.c +++ b/arch/sparc/kernel/sys_sparc_32.c @@ -54,7 +54,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi if (len > TASK_SIZE - PAGE_SIZE) return -ENOMEM; if (!addr) - addr = TASK_UNMAPPED_BASE; + addr = current->mm->mmap_base; info.flags = 0; info.length = len; diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index 30e7ddb..266a3b0 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -89,13 +89,14 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi struct vm_area_struct * vma; unsigned long task_size = TASK_SIZE; int do_color_align; + unsigned long offset = gr_rand_threadstack_offset(mm, filp, flags); struct vm_unmapped_area_info info; if (flags & MAP_FIXED) { /* We do not accept a shared mapping if it would violate * cache aliasing constraints. */ - if ((flags & MAP_SHARED) && + if ((filp || (flags & MAP_SHARED)) && ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))) return -EINVAL; return addr; @@ -110,6 +111,10 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi if (filp || (flags & MAP_SHARED)) do_color_align = 1; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + if (addr) { if (do_color_align) addr = COLOR_ALIGN(addr, pgoff); @@ -117,22 +122,28 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (task_size - len >= addr && - (!vma || addr + len <= vma->vm_start)) + if (task_size - len >= addr && check_heap_stack_gap(vma, addr, len, offset)) return addr; } info.flags = 0; info.length = len; - info.low_limit = TASK_UNMAPPED_BASE; + info.low_limit = mm->mmap_base; info.high_limit = min(task_size, VA_EXCLUDE_START); info.align_mask = do_color_align ? (PAGE_MASK & (SHMLBA - 1)) : 0; info.align_offset = pgoff << PAGE_SHIFT; + info.threadstack_offset = offset; addr = vm_unmapped_area(&info); if ((addr & ~PAGE_MASK) && task_size > VA_EXCLUDE_END) { VM_BUG_ON(addr != -ENOMEM); info.low_limit = VA_EXCLUDE_END; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + info.low_limit += mm->delta_mmap; +#endif + info.high_limit = task_size; addr = vm_unmapped_area(&info); } @@ -150,6 +161,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, unsigned long task_size = STACK_TOP32; unsigned long addr = addr0; int do_color_align; + unsigned long offset = gr_rand_threadstack_offset(mm, filp, flags); struct vm_unmapped_area_info info; /* This should only ever run for 32-bit processes. */ @@ -159,7 +171,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, /* We do not accept a shared mapping if it would violate * cache aliasing constraints. */ - if ((flags & MAP_SHARED) && + if ((filp || (flags & MAP_SHARED)) && ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))) return -EINVAL; return addr; @@ -172,6 +184,10 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, if (filp || (flags & MAP_SHARED)) do_color_align = 1; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + /* requesting a specific address */ if (addr) { if (do_color_align) @@ -180,8 +196,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (task_size - len >= addr && - (!vma || addr + len <= vma->vm_start)) + if (task_size - len >= addr && check_heap_stack_gap(vma, addr, len, offset)) return addr; } @@ -191,6 +206,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, info.high_limit = mm->mmap_base; info.align_mask = do_color_align ? (PAGE_MASK & (SHMLBA - 1)) : 0; info.align_offset = pgoff << PAGE_SHIFT; + info.threadstack_offset = offset; addr = vm_unmapped_area(&info); /* @@ -203,6 +219,12 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, VM_BUG_ON(addr != -ENOMEM); info.flags = 0; info.low_limit = TASK_UNMAPPED_BASE; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + info.low_limit += mm->delta_mmap; +#endif + info.high_limit = STACK_TOP32; addr = vm_unmapped_area(&info); } @@ -259,10 +281,14 @@ unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, u EXPORT_SYMBOL(get_fb_unmapped_area); /* Essentially the same as PowerPC. */ -static unsigned long mmap_rnd(void) +static unsigned long mmap_rnd(struct mm_struct *mm) { unsigned long rnd = 0UL; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + if (current->flags & PF_RANDOMIZE) { unsigned long val = get_random_int(); if (test_thread_flag(TIF_32BIT)) @@ -275,7 +301,7 @@ static unsigned long mmap_rnd(void) void arch_pick_mmap_layout(struct mm_struct *mm) { - unsigned long random_factor = mmap_rnd(); + unsigned long random_factor = mmap_rnd(mm); unsigned long gap; /* @@ -288,6 +314,12 @@ void arch_pick_mmap_layout(struct mm_struct *mm) gap == RLIM_INFINITY || sysctl_legacy_va_layout) { mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base += mm->delta_mmap; +#endif + mm->get_unmapped_area = arch_get_unmapped_area; } else { /* We know it's 32-bit */ @@ -299,6 +331,12 @@ void arch_pick_mmap_layout(struct mm_struct *mm) gap = (task_size / 6 * 5); mm->mmap_base = PAGE_ALIGN(task_size - gap - random_factor); + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base -= mm->delta_mmap + mm->delta_stack; +#endif + mm->get_unmapped_area = arch_get_unmapped_area_topdown; } } diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S index bb00089..e0ea580 100644 --- a/arch/sparc/kernel/syscalls.S +++ b/arch/sparc/kernel/syscalls.S @@ -62,7 +62,7 @@ sys32_rt_sigreturn: #endif .align 32 1: ldx [%g6 + TI_FLAGS], %l5 - andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT|_TIF_NOHZ), %g0 + andcc %l5, _TIF_WORK_SYSCALL, %g0 be,pt %icc, rtrap nop call syscall_trace_leave @@ -194,7 +194,7 @@ linux_sparc_syscall32: srl %i3, 0, %o3 ! IEU0 srl %i2, 0, %o2 ! IEU0 Group - andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT|_TIF_NOHZ), %g0 + andcc %l0, _TIF_WORK_SYSCALL, %g0 bne,pn %icc, linux_syscall_trace32 ! CTI mov %i0, %l5 ! IEU1 5: call %l7 ! CTI Group brk forced @@ -218,7 +218,7 @@ linux_sparc_syscall: mov %i3, %o3 ! IEU1 mov %i4, %o4 ! IEU0 Group - andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT|_TIF_NOHZ), %g0 + andcc %l0, _TIF_WORK_SYSCALL, %g0 bne,pn %icc, linux_syscall_trace ! CTI Group mov %i0, %l5 ! IEU0 2: call %l7 ! CTI Group brk forced @@ -233,7 +233,7 @@ ret_sys_call: cmp %o0, -ERESTART_RESTARTBLOCK bgeu,pn %xcc, 1f - andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT|_TIF_NOHZ), %g0 + andcc %l0, _TIF_WORK_SYSCALL, %g0 ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc 2: diff --git a/arch/sparc/kernel/traps_32.c b/arch/sparc/kernel/traps_32.c index 4f21df7..0a374da 100644 --- a/arch/sparc/kernel/traps_32.c +++ b/arch/sparc/kernel/traps_32.c @@ -44,6 +44,8 @@ static void instruction_dump(unsigned long *pc) #define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t") #define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t") +extern void gr_handle_kernel_exploit(void); + void __noreturn die_if_kernel(char *str, struct pt_regs *regs) { static int die_counter; @@ -76,15 +78,17 @@ void __noreturn die_if_kernel(char *str, struct pt_regs *regs) count++ < 30 && (((unsigned long) rw) >= PAGE_OFFSET) && !(((unsigned long) rw) & 0x7)) { - printk("Caller[%08lx]: %pS\n", rw->ins[7], + printk("Caller[%08lx]: %pA\n", rw->ins[7], (void *) rw->ins[7]); rw = (struct reg_window32 *)rw->ins[6]; } } printk("Instruction DUMP:"); instruction_dump ((unsigned long *) regs->pc); - if(regs->psr & PSR_PS) + if(regs->psr & PSR_PS) { + gr_handle_kernel_exploit(); do_exit(SIGKILL); + } do_exit(SIGSEGV); } diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c index d21cd62..00a4a17 100644 --- a/arch/sparc/kernel/traps_64.c +++ b/arch/sparc/kernel/traps_64.c @@ -79,7 +79,7 @@ static void dump_tl1_traplog(struct tl1_traplog *p) i + 1, p->trapstack[i].tstate, p->trapstack[i].tpc, p->trapstack[i].tnpc, p->trapstack[i].tt); - printk("TRAPLOG: TPC<%pS>\n", (void *) p->trapstack[i].tpc); + printk("TRAPLOG: TPC<%pA>\n", (void *) p->trapstack[i].tpc); } } @@ -99,6 +99,12 @@ void bad_trap(struct pt_regs *regs, long lvl) lvl -= 0x100; if (regs->tstate & TSTATE_PRIV) { + +#ifdef CONFIG_PAX_REFCOUNT + if (lvl == 6) + pax_report_refcount_overflow(regs); +#endif + sprintf(buffer, "Kernel bad sw trap %lx", lvl); die_if_kernel(buffer, regs); } @@ -117,11 +123,16 @@ void bad_trap(struct pt_regs *regs, long lvl) void bad_trap_tl1(struct pt_regs *regs, long lvl) { char buffer[32]; - + if (notify_die(DIE_TRAP_TL1, "bad trap tl1", regs, 0, lvl, SIGTRAP) == NOTIFY_STOP) return; +#ifdef CONFIG_PAX_REFCOUNT + if (lvl == 6) + pax_report_refcount_overflow(regs); +#endif + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); sprintf (buffer, "Bad trap %lx at tl>0", lvl); @@ -1151,7 +1162,7 @@ static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *in regs->tpc, regs->tnpc, regs->u_regs[UREG_I7], regs->tstate); printk("%s" "ERROR(%d): ", (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id()); - printk("TPC<%pS>\n", (void *) regs->tpc); + printk("TPC<%pA>\n", (void *) regs->tpc); printk("%s" "ERROR(%d): M_SYND(%lx), E_SYND(%lx)%s%s\n", (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT, @@ -1758,7 +1769,7 @@ void cheetah_plus_parity_error(int type, struct pt_regs *regs) smp_processor_id(), (type & 0x1) ? 'I' : 'D', regs->tpc); - printk(KERN_EMERG "TPC<%pS>\n", (void *) regs->tpc); + printk(KERN_EMERG "TPC<%pA>\n", (void *) regs->tpc); panic("Irrecoverable Cheetah+ parity error."); } @@ -1766,7 +1777,7 @@ void cheetah_plus_parity_error(int type, struct pt_regs *regs) smp_processor_id(), (type & 0x1) ? 'I' : 'D', regs->tpc); - printk(KERN_WARNING "TPC<%pS>\n", (void *) regs->tpc); + printk(KERN_WARNING "TPC<%pA>\n", (void *) regs->tpc); } struct sun4v_error_entry { @@ -1839,8 +1850,8 @@ struct sun4v_error_entry { /*0x38*/u64 reserved_5; }; -static atomic_t sun4v_resum_oflow_cnt = ATOMIC_INIT(0); -static atomic_t sun4v_nonresum_oflow_cnt = ATOMIC_INIT(0); +static atomic_unchecked_t sun4v_resum_oflow_cnt = ATOMIC_INIT(0); +static atomic_unchecked_t sun4v_nonresum_oflow_cnt = ATOMIC_INIT(0); static const char *sun4v_err_type_to_str(u8 type) { @@ -1932,7 +1943,7 @@ static void sun4v_report_real_raddr(const char *pfx, struct pt_regs *regs) } static void sun4v_log_error(struct pt_regs *regs, struct sun4v_error_entry *ent, - int cpu, const char *pfx, atomic_t *ocnt) + int cpu, const char *pfx, atomic_unchecked_t *ocnt) { u64 *raw_ptr = (u64 *) ent; u32 attrs; @@ -1990,8 +2001,8 @@ static void sun4v_log_error(struct pt_regs *regs, struct sun4v_error_entry *ent, show_regs(regs); - if ((cnt = atomic_read(ocnt)) != 0) { - atomic_set(ocnt, 0); + if ((cnt = atomic_read_unchecked(ocnt)) != 0) { + atomic_set_unchecked(ocnt, 0); wmb(); printk("%s: Queue overflowed %d times.\n", pfx, cnt); @@ -2048,7 +2059,7 @@ out: */ void sun4v_resum_overflow(struct pt_regs *regs) { - atomic_inc(&sun4v_resum_oflow_cnt); + atomic_inc_unchecked(&sun4v_resum_oflow_cnt); } /* We run with %pil set to PIL_NORMAL_MAX and PSTATE_IE enabled in %pstate. @@ -2101,7 +2112,7 @@ void sun4v_nonresum_overflow(struct pt_regs *regs) /* XXX Actually even this can make not that much sense. Perhaps * XXX we should just pull the plug and panic directly from here? */ - atomic_inc(&sun4v_nonresum_oflow_cnt); + atomic_inc_unchecked(&sun4v_nonresum_oflow_cnt); } static void sun4v_tlb_error(struct pt_regs *regs) @@ -2120,9 +2131,9 @@ void sun4v_itlb_error_report(struct pt_regs *regs, int tl) printk(KERN_EMERG "SUN4V-ITLB: Error at TPC[%lx], tl %d\n", regs->tpc, tl); - printk(KERN_EMERG "SUN4V-ITLB: TPC<%pS>\n", (void *) regs->tpc); + printk(KERN_EMERG "SUN4V-ITLB: TPC<%pA>\n", (void *) regs->tpc); printk(KERN_EMERG "SUN4V-ITLB: O7[%lx]\n", regs->u_regs[UREG_I7]); - printk(KERN_EMERG "SUN4V-ITLB: O7<%pS>\n", + printk(KERN_EMERG "SUN4V-ITLB: O7<%pA>\n", (void *) regs->u_regs[UREG_I7]); printk(KERN_EMERG "SUN4V-ITLB: vaddr[%lx] ctx[%lx] " "pte[%lx] error[%lx]\n", @@ -2143,9 +2154,9 @@ void sun4v_dtlb_error_report(struct pt_regs *regs, int tl) printk(KERN_EMERG "SUN4V-DTLB: Error at TPC[%lx], tl %d\n", regs->tpc, tl); - printk(KERN_EMERG "SUN4V-DTLB: TPC<%pS>\n", (void *) regs->tpc); + printk(KERN_EMERG "SUN4V-DTLB: TPC<%pA>\n", (void *) regs->tpc); printk(KERN_EMERG "SUN4V-DTLB: O7[%lx]\n", regs->u_regs[UREG_I7]); - printk(KERN_EMERG "SUN4V-DTLB: O7<%pS>\n", + printk(KERN_EMERG "SUN4V-DTLB: O7<%pA>\n", (void *) regs->u_regs[UREG_I7]); printk(KERN_EMERG "SUN4V-DTLB: vaddr[%lx] ctx[%lx] " "pte[%lx] error[%lx]\n", @@ -2362,13 +2373,13 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp) fp = (unsigned long)sf->fp + STACK_BIAS; } - printk(" [%016lx] %pS\n", pc, (void *) pc); + printk(" [%016lx] %pA\n", pc, (void *) pc); #ifdef CONFIG_FUNCTION_GRAPH_TRACER if ((pc + 8UL) == (unsigned long) &return_to_handler) { int index = tsk->curr_ret_stack; if (tsk->ret_stack && index >= graph) { pc = tsk->ret_stack[index - graph].ret; - printk(" [%016lx] %pS\n", pc, (void *) pc); + printk(" [%016lx] %pA\n", pc, (void *) pc); graph++; } } @@ -2386,6 +2397,8 @@ static inline struct reg_window *kernel_stack_up(struct reg_window *rw) return (struct reg_window *) (fp + STACK_BIAS); } +extern void gr_handle_kernel_exploit(void); + void __noreturn die_if_kernel(char *str, struct pt_regs *regs) { static int die_counter; @@ -2414,7 +2427,7 @@ void __noreturn die_if_kernel(char *str, struct pt_regs *regs) while (rw && count++ < 30 && kstack_valid(tp, (unsigned long) rw)) { - printk("Caller[%016lx]: %pS\n", rw->ins[7], + printk("Caller[%016lx]: %pA\n", rw->ins[7], (void *) rw->ins[7]); rw = kernel_stack_up(rw); @@ -2429,8 +2442,10 @@ void __noreturn die_if_kernel(char *str, struct pt_regs *regs) } if (panic_on_oops) panic("Fatal exception"); - if (regs->tstate & TSTATE_PRIV) + if (regs->tstate & TSTATE_PRIV) { + gr_handle_kernel_exploit(); do_exit(SIGKILL); + } do_exit(SIGSEGV); } EXPORT_SYMBOL(die_if_kernel); diff --git a/arch/sparc/kernel/unaligned_64.c b/arch/sparc/kernel/unaligned_64.c index 62098a8..547ab2c 100644 --- a/arch/sparc/kernel/unaligned_64.c +++ b/arch/sparc/kernel/unaligned_64.c @@ -297,7 +297,7 @@ static void log_unaligned(struct pt_regs *regs) static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 5); if (__ratelimit(&ratelimit)) { - printk("Kernel unaligned access at TPC[%lx] %pS\n", + printk("Kernel unaligned access at TPC[%lx] %pA\n", regs->tpc, (void *) regs->tpc); } } diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index 3269b02..64f5231 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -2,7 +2,7 @@ # asflags-y := -ansi -DST_DIV0=0x02 -ccflags-y := -Werror +#ccflags-y := -Werror lib-$(CONFIG_SPARC32) += ashrdi3.o lib-$(CONFIG_SPARC32) += memcpy.o memset.o diff --git a/arch/sparc/lib/atomic_64.S b/arch/sparc/lib/atomic_64.S index d6b0363..552bcbb6 100644 --- a/arch/sparc/lib/atomic_64.S +++ b/arch/sparc/lib/atomic_64.S @@ -15,11 +15,22 @@ * a value and does the barriers. */ -#define ATOMIC_OP(op) \ -ENTRY(atomic_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ +#ifdef CONFIG_PAX_REFCOUNT +#define __REFCOUNT_OP(op) op##cc +#define __OVERFLOW_IOP tvs %icc, 6; +#define __OVERFLOW_XOP tvs %xcc, 6; +#else +#define __REFCOUNT_OP(op) op +#define __OVERFLOW_IOP +#define __OVERFLOW_XOP +#endif + +#define __ATOMIC_OP(op, suffix, asm_op, post_op) \ +ENTRY(atomic_##op##suffix) /* %o0 = increment, %o1 = atomic_ptr */ \ BACKOFF_SETUP(%o2); \ 1: lduw [%o1], %g1; \ - op %g1, %o0, %g7; \ + asm_op %g1, %o0, %g7; \ + post_op \ cas [%o1], %g1, %g7; \ cmp %g1, %g7; \ bne,pn %icc, BACKOFF_LABEL(2f, 1b); \ @@ -29,11 +40,15 @@ ENTRY(atomic_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ 2: BACKOFF_SPIN(%o2, %o3, 1b); \ ENDPROC(atomic_##op); \ -#define ATOMIC_OP_RETURN(op) \ -ENTRY(atomic_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \ +#define ATOMIC_OP(op) __ATOMIC_OP(op, , op, ) \ + __ATOMIC_OP(op, _unchecked, __REFCOUNT_OP(op), __OVERFLOW_IOP) + +#define __ATOMIC_OP_RETURN(op, suffix, asm_op, post_op) \ +ENTRY(atomic_##op##_return##suffix) /* %o0 = increment, %o1 = atomic_ptr */\ BACKOFF_SETUP(%o2); \ 1: lduw [%o1], %g1; \ - op %g1, %o0, %g7; \ + asm_op %g1, %o0, %g7; \ + post_op \ cas [%o1], %g1, %g7; \ cmp %g1, %g7; \ bne,pn %icc, BACKOFF_LABEL(2f, 1b); \ @@ -43,6 +58,9 @@ ENTRY(atomic_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \ 2: BACKOFF_SPIN(%o2, %o3, 1b); \ ENDPROC(atomic_##op##_return); +#define ATOMIC_OP_RETURN(op) __ATOMIC_OP_RETURN(op, , op, ) \ + __ATOMIC_OP_RETURN(op, _unchecked, __REFCOUNT_OP(op), __OVERFLOW_IOP) + #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_OPS(add) @@ -53,13 +71,16 @@ ATOMIC_OP(xor) #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN +#undef __ATOMIC_OP_RETURN #undef ATOMIC_OP +#undef __ATOMIC_OP -#define ATOMIC64_OP(op) \ -ENTRY(atomic64_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ +#define __ATOMIC64_OP(op, suffix, asm_op, post_op) \ +ENTRY(atomic64_##op##suffix) /* %o0 = increment, %o1 = atomic_ptr */ \ BACKOFF_SETUP(%o2); \ 1: ldx [%o1], %g1; \ - op %g1, %o0, %g7; \ + asm_op %g1, %o0, %g7; \ + post_op \ casx [%o1], %g1, %g7; \ cmp %g1, %g7; \ bne,pn %xcc, BACKOFF_LABEL(2f, 1b); \ @@ -69,11 +90,15 @@ ENTRY(atomic64_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ 2: BACKOFF_SPIN(%o2, %o3, 1b); \ ENDPROC(atomic64_##op); \ -#define ATOMIC64_OP_RETURN(op) \ -ENTRY(atomic64_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \ +#define ATOMIC64_OP(op) __ATOMIC64_OP(op, , op, ) \ + __ATOMIC64_OP(op, _unchecked, __REFCOUNT_OP(op), __OVERFLOW_XOP) + +#define __ATOMIC64_OP_RETURN(op, suffix, asm_op, post_op) \ +ENTRY(atomic64_##op##_return##suffix) /* %o0 = increment, %o1 = atomic_ptr */\ BACKOFF_SETUP(%o2); \ 1: ldx [%o1], %g1; \ - op %g1, %o0, %g7; \ + asm_op %g1, %o0, %g7; \ + post_op \ casx [%o1], %g1, %g7; \ cmp %g1, %g7; \ bne,pn %xcc, BACKOFF_LABEL(2f, 1b); \ @@ -83,6 +108,9 @@ ENTRY(atomic64_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \ 2: BACKOFF_SPIN(%o2, %o3, 1b); \ ENDPROC(atomic64_##op##_return); +#define ATOMIC64_OP_RETURN(op) __ATOMIC64_OP_RETURN(op, , op, ) \ +i __ATOMIC64_OP_RETURN(op, _unchecked, __REFCOUNT_OP(op), __OVERFLOW_XOP) + #define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op) ATOMIC64_OPS(add) @@ -93,7 +121,12 @@ ATOMIC64_OP(xor) #undef ATOMIC64_OPS #undef ATOMIC64_OP_RETURN +#undef __ATOMIC64_OP_RETURN #undef ATOMIC64_OP +#undef __ATOMIC64_OP +#undef __OVERFLOW_XOP +#undef __OVERFLOW_IOP +#undef __REFCOUNT_OP ENTRY(atomic64_dec_if_positive) /* %o0 = atomic_ptr */ BACKOFF_SETUP(%o2) diff --git a/arch/sparc/lib/ksyms.c b/arch/sparc/lib/ksyms.c index 8eb454c..9f95c5b 100644 --- a/arch/sparc/lib/ksyms.c +++ b/arch/sparc/lib/ksyms.c @@ -101,7 +101,9 @@ EXPORT_SYMBOL(__clear_user); /* Atomic counter implementation. */ #define ATOMIC_OP(op) \ EXPORT_SYMBOL(atomic_##op); \ -EXPORT_SYMBOL(atomic64_##op); +EXPORT_SYMBOL(atomic_##op##_unchecked); \ +EXPORT_SYMBOL(atomic64_##op); \ +EXPORT_SYMBOL(atomic64_##op##_unchecked); #define ATOMIC_OP_RETURN(op) \ EXPORT_SYMBOL(atomic_##op##_return); \ @@ -110,6 +112,8 @@ EXPORT_SYMBOL(atomic64_##op##_return); #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_OPS(add) +EXPORT_SYMBOL(atomic_add_ret_unchecked); +EXPORT_SYMBOL(atomic64_add_ret_unchecked); ATOMIC_OPS(sub) ATOMIC_OP(and) ATOMIC_OP(or) diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile index 30c3ecc..736f015 100644 --- a/arch/sparc/mm/Makefile +++ b/arch/sparc/mm/Makefile @@ -2,7 +2,7 @@ # asflags-y := -ansi -ccflags-y := -Werror +#ccflags-y := -Werror obj-$(CONFIG_SPARC64) += ultra.o tlb.o tsb.o gup.o obj-y += fault_$(BITS).o diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c index c399e7b..2387414 100644 --- a/arch/sparc/mm/fault_32.c +++ b/arch/sparc/mm/fault_32.c @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include #include #include @@ -156,6 +159,277 @@ static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault) return safe_compute_effective_address(regs, insn); } +#ifdef CONFIG_PAX_PAGEEXEC +#ifdef CONFIG_PAX_DLRESOLVE +static void pax_emuplt_close(struct vm_area_struct *vma) +{ + vma->vm_mm->call_dl_resolve = 0UL; +} + +static int pax_emuplt_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + unsigned int *kaddr; + + vmf->page = alloc_page(GFP_HIGHUSER); + if (!vmf->page) + return VM_FAULT_OOM; + + kaddr = kmap(vmf->page); + memset(kaddr, 0, PAGE_SIZE); + kaddr[0] = 0x9DE3BFA8U; /* save */ + flush_dcache_page(vmf->page); + kunmap(vmf->page); + return VM_FAULT_MAJOR; +} + +static const struct vm_operations_struct pax_vm_ops = { + .close = pax_emuplt_close, + .fault = pax_emuplt_fault +}; + +static int pax_insert_vma(struct vm_area_struct *vma, unsigned long addr) +{ + int ret; + + INIT_LIST_HEAD(&vma->anon_vma_chain); + vma->vm_mm = current->mm; + vma->vm_start = addr; + vma->vm_end = addr + PAGE_SIZE; + vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC; + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + vma->vm_ops = &pax_vm_ops; + + ret = insert_vm_struct(current->mm, vma); + if (ret) + return ret; + + ++current->mm->total_vm; + return 0; +} +#endif + +/* + * PaX: decide what to do with offenders (regs->pc = fault address) + * + * returns 1 when task should be killed + * 2 when patched PLT trampoline was detected + * 3 when unpatched PLT trampoline was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + +#ifdef CONFIG_PAX_EMUPLT + int err; + + do { /* PaX: patched PLT emulation #1 */ + unsigned int sethi1, sethi2, jmpl; + + err = get_user(sethi1, (unsigned int *)regs->pc); + err |= get_user(sethi2, (unsigned int *)(regs->pc+4)); + err |= get_user(jmpl, (unsigned int *)(regs->pc+8)); + + if (err) + break; + + if ((sethi1 & 0xFFC00000U) == 0x03000000U && + (sethi2 & 0xFFC00000U) == 0x03000000U && + (jmpl & 0xFFFFE000U) == 0x81C06000U) + { + unsigned int addr; + + regs->u_regs[UREG_G1] = (sethi2 & 0x003FFFFFU) << 10; + addr = regs->u_regs[UREG_G1]; + addr += (((jmpl | 0xFFFFE000U) ^ 0x00001000U) + 0x00001000U); + regs->pc = addr; + regs->npc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #2 */ + unsigned int ba; + + err = get_user(ba, (unsigned int *)regs->pc); + + if (err) + break; + + if ((ba & 0xFFC00000U) == 0x30800000U || (ba & 0xFFF80000U) == 0x30480000U) { + unsigned int addr; + + if ((ba & 0xFFC00000U) == 0x30800000U) + addr = regs->pc + ((((ba | 0xFFC00000U) ^ 0x00200000U) + 0x00200000U) << 2); + else + addr = regs->pc + ((((ba | 0xFFF80000U) ^ 0x00040000U) + 0x00040000U) << 2); + regs->pc = addr; + regs->npc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #3 */ + unsigned int sethi, bajmpl, nop; + + err = get_user(sethi, (unsigned int *)regs->pc); + err |= get_user(bajmpl, (unsigned int *)(regs->pc+4)); + err |= get_user(nop, (unsigned int *)(regs->pc+8)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + ((bajmpl & 0xFFFFE000U) == 0x81C06000U || (bajmpl & 0xFFF80000U) == 0x30480000U) && + nop == 0x01000000U) + { + unsigned int addr; + + addr = (sethi & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G1] = addr; + if ((bajmpl & 0xFFFFE000U) == 0x81C06000U) + addr += (((bajmpl | 0xFFFFE000U) ^ 0x00001000U) + 0x00001000U); + else + addr = regs->pc + ((((bajmpl | 0xFFF80000U) ^ 0x00040000U) + 0x00040000U) << 2); + regs->pc = addr; + regs->npc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: unpatched PLT emulation step 1 */ + unsigned int sethi, ba, nop; + + err = get_user(sethi, (unsigned int *)regs->pc); + err |= get_user(ba, (unsigned int *)(regs->pc+4)); + err |= get_user(nop, (unsigned int *)(regs->pc+8)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + ((ba & 0xFFC00000U) == 0x30800000U || (ba & 0xFFF80000U) == 0x30680000U) && + nop == 0x01000000U) + { + unsigned int addr, save, call; + + if ((ba & 0xFFC00000U) == 0x30800000U) + addr = regs->pc + 4 + ((((ba | 0xFFC00000U) ^ 0x00200000U) + 0x00200000U) << 2); + else + addr = regs->pc + 4 + ((((ba | 0xFFF80000U) ^ 0x00040000U) + 0x00040000U) << 2); + + err = get_user(save, (unsigned int *)addr); + err |= get_user(call, (unsigned int *)(addr+4)); + err |= get_user(nop, (unsigned int *)(addr+8)); + if (err) + break; + +#ifdef CONFIG_PAX_DLRESOLVE + if (save == 0x9DE3BFA8U && + (call & 0xC0000000U) == 0x40000000U && + nop == 0x01000000U) + { + struct vm_area_struct *vma; + unsigned long call_dl_resolve; + + down_read(¤t->mm->mmap_sem); + call_dl_resolve = current->mm->call_dl_resolve; + up_read(¤t->mm->mmap_sem); + if (likely(call_dl_resolve)) + goto emulate; + + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); + + down_write(¤t->mm->mmap_sem); + if (current->mm->call_dl_resolve) { + call_dl_resolve = current->mm->call_dl_resolve; + up_write(¤t->mm->mmap_sem); + if (vma) + kmem_cache_free(vm_area_cachep, vma); + goto emulate; + } + + call_dl_resolve = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE); + if (!vma || (call_dl_resolve & ~PAGE_MASK)) { + up_write(¤t->mm->mmap_sem); + if (vma) + kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + if (pax_insert_vma(vma, call_dl_resolve)) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + current->mm->call_dl_resolve = call_dl_resolve; + up_write(¤t->mm->mmap_sem); + +emulate: + regs->u_regs[UREG_G1] = (sethi & 0x003FFFFFU) << 10; + regs->pc = call_dl_resolve; + regs->npc = addr+4; + return 3; + } +#endif + + /* PaX: glibc 2.4+ generates sethi/jmpl instead of save/call */ + if ((save & 0xFFC00000U) == 0x05000000U && + (call & 0xFFFFE000U) == 0x85C0A000U && + nop == 0x01000000U) + { + regs->u_regs[UREG_G1] = (sethi & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G2] = addr + 4; + addr = (save & 0x003FFFFFU) << 10; + addr += (((call | 0xFFFFE000U) ^ 0x00001000U) + 0x00001000U); + regs->pc = addr; + regs->npc = addr+4; + return 3; + } + } + } while (0); + + do { /* PaX: unpatched PLT emulation step 2 */ + unsigned int save, call, nop; + + err = get_user(save, (unsigned int *)(regs->pc-4)); + err |= get_user(call, (unsigned int *)regs->pc); + err |= get_user(nop, (unsigned int *)(regs->pc+4)); + if (err) + break; + + if (save == 0x9DE3BFA8U && + (call & 0xC0000000U) == 0x40000000U && + nop == 0x01000000U) + { + unsigned int dl_resolve = regs->pc + ((((call | 0xC0000000U) ^ 0x20000000U) + 0x20000000U) << 2); + + regs->u_regs[UREG_RETPC] = regs->pc; + regs->pc = dl_resolve; + regs->npc = dl_resolve+4; + return 3; + } + } while (0); +#endif + + return 1; +} + +void pax_report_insns(struct pt_regs *regs, void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 8; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk(KERN_CONT "???????? "); + else + printk(KERN_CONT "%08x ", c); + } + printk("\n"); +} +#endif + static noinline void do_fault_siginfo(int code, int sig, struct pt_regs *regs, int text_fault) { @@ -226,6 +500,24 @@ good_area: if (!(vma->vm_flags & VM_WRITE)) goto bad_area; } else { + +#ifdef CONFIG_PAX_PAGEEXEC + if ((mm->pax_flags & MF_PAX_PAGEEXEC) && text_fault && !(vma->vm_flags & VM_EXEC)) { + up_read(&mm->mmap_sem); + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_PAX_EMUPLT + case 2: + case 3: + return; +#endif + + } + pax_report_fault(regs, (void *)regs->pc, (void *)regs->u_regs[UREG_FP]); + do_group_exit(SIGKILL); + } +#endif + /* Allow reads even for write-only mappings */ if (!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c index dbabe57..d34d315 100644 --- a/arch/sparc/mm/fault_64.c +++ b/arch/sparc/mm/fault_64.c @@ -23,6 +23,9 @@ #include #include #include +#include +#include +#include #include #include @@ -76,7 +79,7 @@ static void __kprobes bad_kernel_pc(struct pt_regs *regs, unsigned long vaddr) printk(KERN_CRIT "OOPS: Bogus kernel PC [%016lx] in fault handler\n", regs->tpc); printk(KERN_CRIT "OOPS: RPC [%016lx]\n", regs->u_regs[15]); - printk("OOPS: RPC <%pS>\n", (void *) regs->u_regs[15]); + printk("OOPS: RPC <%pA>\n", (void *) regs->u_regs[15]); printk(KERN_CRIT "OOPS: Fault was to vaddr[%lx]\n", vaddr); dump_stack(); unhandled_fault(regs->tpc, current, regs); @@ -279,6 +282,466 @@ static void noinline __kprobes bogus_32bit_fault_tpc(struct pt_regs *regs) show_regs(regs); } +#ifdef CONFIG_PAX_PAGEEXEC +#ifdef CONFIG_PAX_DLRESOLVE +static void pax_emuplt_close(struct vm_area_struct *vma) +{ + vma->vm_mm->call_dl_resolve = 0UL; +} + +static int pax_emuplt_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + unsigned int *kaddr; + + vmf->page = alloc_page(GFP_HIGHUSER); + if (!vmf->page) + return VM_FAULT_OOM; + + kaddr = kmap(vmf->page); + memset(kaddr, 0, PAGE_SIZE); + kaddr[0] = 0x9DE3BFA8U; /* save */ + flush_dcache_page(vmf->page); + kunmap(vmf->page); + return VM_FAULT_MAJOR; +} + +static const struct vm_operations_struct pax_vm_ops = { + .close = pax_emuplt_close, + .fault = pax_emuplt_fault +}; + +static int pax_insert_vma(struct vm_area_struct *vma, unsigned long addr) +{ + int ret; + + INIT_LIST_HEAD(&vma->anon_vma_chain); + vma->vm_mm = current->mm; + vma->vm_start = addr; + vma->vm_end = addr + PAGE_SIZE; + vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC; + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + vma->vm_ops = &pax_vm_ops; + + ret = insert_vm_struct(current->mm, vma); + if (ret) + return ret; + + ++current->mm->total_vm; + return 0; +} +#endif + +/* + * PaX: decide what to do with offenders (regs->tpc = fault address) + * + * returns 1 when task should be killed + * 2 when patched PLT trampoline was detected + * 3 when unpatched PLT trampoline was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + +#ifdef CONFIG_PAX_EMUPLT + int err; + + do { /* PaX: patched PLT emulation #1 */ + unsigned int sethi1, sethi2, jmpl; + + err = get_user(sethi1, (unsigned int *)regs->tpc); + err |= get_user(sethi2, (unsigned int *)(regs->tpc+4)); + err |= get_user(jmpl, (unsigned int *)(regs->tpc+8)); + + if (err) + break; + + if ((sethi1 & 0xFFC00000U) == 0x03000000U && + (sethi2 & 0xFFC00000U) == 0x03000000U && + (jmpl & 0xFFFFE000U) == 0x81C06000U) + { + unsigned long addr; + + regs->u_regs[UREG_G1] = (sethi2 & 0x003FFFFFU) << 10; + addr = regs->u_regs[UREG_G1]; + addr += (((jmpl | 0xFFFFFFFFFFFFE000UL) ^ 0x00001000UL) + 0x00001000UL); + + if (test_thread_flag(TIF_32BIT)) + addr &= 0xFFFFFFFFUL; + + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #2 */ + unsigned int ba; + + err = get_user(ba, (unsigned int *)regs->tpc); + + if (err) + break; + + if ((ba & 0xFFC00000U) == 0x30800000U || (ba & 0xFFF80000U) == 0x30480000U) { + unsigned long addr; + + if ((ba & 0xFFC00000U) == 0x30800000U) + addr = regs->tpc + ((((ba | 0xFFFFFFFFFFC00000UL) ^ 0x00200000UL) + 0x00200000UL) << 2); + else + addr = regs->tpc + ((((ba | 0xFFFFFFFFFFF80000UL) ^ 0x00040000UL) + 0x00040000UL) << 2); + + if (test_thread_flag(TIF_32BIT)) + addr &= 0xFFFFFFFFUL; + + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #3 */ + unsigned int sethi, bajmpl, nop; + + err = get_user(sethi, (unsigned int *)regs->tpc); + err |= get_user(bajmpl, (unsigned int *)(regs->tpc+4)); + err |= get_user(nop, (unsigned int *)(regs->tpc+8)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + ((bajmpl & 0xFFFFE000U) == 0x81C06000U || (bajmpl & 0xFFF80000U) == 0x30480000U) && + nop == 0x01000000U) + { + unsigned long addr; + + addr = (sethi & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G1] = addr; + if ((bajmpl & 0xFFFFE000U) == 0x81C06000U) + addr += (((bajmpl | 0xFFFFFFFFFFFFE000UL) ^ 0x00001000UL) + 0x00001000UL); + else + addr = regs->tpc + ((((bajmpl | 0xFFFFFFFFFFF80000UL) ^ 0x00040000UL) + 0x00040000UL) << 2); + + if (test_thread_flag(TIF_32BIT)) + addr &= 0xFFFFFFFFUL; + + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #4 */ + unsigned int sethi, mov1, call, mov2; + + err = get_user(sethi, (unsigned int *)regs->tpc); + err |= get_user(mov1, (unsigned int *)(regs->tpc+4)); + err |= get_user(call, (unsigned int *)(regs->tpc+8)); + err |= get_user(mov2, (unsigned int *)(regs->tpc+12)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + mov1 == 0x8210000FU && + (call & 0xC0000000U) == 0x40000000U && + mov2 == 0x9E100001U) + { + unsigned long addr; + + regs->u_regs[UREG_G1] = regs->u_regs[UREG_RETPC]; + addr = regs->tpc + 4 + ((((call | 0xFFFFFFFFC0000000UL) ^ 0x20000000UL) + 0x20000000UL) << 2); + + if (test_thread_flag(TIF_32BIT)) + addr &= 0xFFFFFFFFUL; + + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #5 */ + unsigned int sethi, sethi1, sethi2, or1, or2, sllx, jmpl, nop; + + err = get_user(sethi, (unsigned int *)regs->tpc); + err |= get_user(sethi1, (unsigned int *)(regs->tpc+4)); + err |= get_user(sethi2, (unsigned int *)(regs->tpc+8)); + err |= get_user(or1, (unsigned int *)(regs->tpc+12)); + err |= get_user(or2, (unsigned int *)(regs->tpc+16)); + err |= get_user(sllx, (unsigned int *)(regs->tpc+20)); + err |= get_user(jmpl, (unsigned int *)(regs->tpc+24)); + err |= get_user(nop, (unsigned int *)(regs->tpc+28)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + (sethi1 & 0xFFC00000U) == 0x03000000U && + (sethi2 & 0xFFC00000U) == 0x0B000000U && + (or1 & 0xFFFFE000U) == 0x82106000U && + (or2 & 0xFFFFE000U) == 0x8A116000U && + sllx == 0x83287020U && + jmpl == 0x81C04005U && + nop == 0x01000000U) + { + unsigned long addr; + + regs->u_regs[UREG_G1] = ((sethi1 & 0x003FFFFFU) << 10) | (or1 & 0x000003FFU); + regs->u_regs[UREG_G1] <<= 32; + regs->u_regs[UREG_G5] = ((sethi2 & 0x003FFFFFU) << 10) | (or2 & 0x000003FFU); + addr = regs->u_regs[UREG_G1] + regs->u_regs[UREG_G5]; + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #6 */ + unsigned int sethi, sethi1, sethi2, sllx, or, jmpl, nop; + + err = get_user(sethi, (unsigned int *)regs->tpc); + err |= get_user(sethi1, (unsigned int *)(regs->tpc+4)); + err |= get_user(sethi2, (unsigned int *)(regs->tpc+8)); + err |= get_user(sllx, (unsigned int *)(regs->tpc+12)); + err |= get_user(or, (unsigned int *)(regs->tpc+16)); + err |= get_user(jmpl, (unsigned int *)(regs->tpc+20)); + err |= get_user(nop, (unsigned int *)(regs->tpc+24)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + (sethi1 & 0xFFC00000U) == 0x03000000U && + (sethi2 & 0xFFC00000U) == 0x0B000000U && + sllx == 0x83287020U && + (or & 0xFFFFE000U) == 0x8A116000U && + jmpl == 0x81C04005U && + nop == 0x01000000U) + { + unsigned long addr; + + regs->u_regs[UREG_G1] = (sethi1 & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G1] <<= 32; + regs->u_regs[UREG_G5] = ((sethi2 & 0x003FFFFFU) << 10) | (or & 0x3FFU); + addr = regs->u_regs[UREG_G1] + regs->u_regs[UREG_G5]; + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: unpatched PLT emulation step 1 */ + unsigned int sethi, ba, nop; + + err = get_user(sethi, (unsigned int *)regs->tpc); + err |= get_user(ba, (unsigned int *)(regs->tpc+4)); + err |= get_user(nop, (unsigned int *)(regs->tpc+8)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + ((ba & 0xFFC00000U) == 0x30800000U || (ba & 0xFFF80000U) == 0x30680000U) && + nop == 0x01000000U) + { + unsigned long addr; + unsigned int save, call; + unsigned int sethi1, sethi2, or1, or2, sllx, add, jmpl; + + if ((ba & 0xFFC00000U) == 0x30800000U) + addr = regs->tpc + 4 + ((((ba | 0xFFFFFFFFFFC00000UL) ^ 0x00200000UL) + 0x00200000UL) << 2); + else + addr = regs->tpc + 4 + ((((ba | 0xFFFFFFFFFFF80000UL) ^ 0x00040000UL) + 0x00040000UL) << 2); + + if (test_thread_flag(TIF_32BIT)) + addr &= 0xFFFFFFFFUL; + + err = get_user(save, (unsigned int *)addr); + err |= get_user(call, (unsigned int *)(addr+4)); + err |= get_user(nop, (unsigned int *)(addr+8)); + if (err) + break; + +#ifdef CONFIG_PAX_DLRESOLVE + if (save == 0x9DE3BFA8U && + (call & 0xC0000000U) == 0x40000000U && + nop == 0x01000000U) + { + struct vm_area_struct *vma; + unsigned long call_dl_resolve; + + down_read(¤t->mm->mmap_sem); + call_dl_resolve = current->mm->call_dl_resolve; + up_read(¤t->mm->mmap_sem); + if (likely(call_dl_resolve)) + goto emulate; + + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); + + down_write(¤t->mm->mmap_sem); + if (current->mm->call_dl_resolve) { + call_dl_resolve = current->mm->call_dl_resolve; + up_write(¤t->mm->mmap_sem); + if (vma) + kmem_cache_free(vm_area_cachep, vma); + goto emulate; + } + + call_dl_resolve = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE); + if (!vma || (call_dl_resolve & ~PAGE_MASK)) { + up_write(¤t->mm->mmap_sem); + if (vma) + kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + if (pax_insert_vma(vma, call_dl_resolve)) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + current->mm->call_dl_resolve = call_dl_resolve; + up_write(¤t->mm->mmap_sem); + +emulate: + regs->u_regs[UREG_G1] = (sethi & 0x003FFFFFU) << 10; + regs->tpc = call_dl_resolve; + regs->tnpc = addr+4; + return 3; + } +#endif + + /* PaX: glibc 2.4+ generates sethi/jmpl instead of save/call */ + if ((save & 0xFFC00000U) == 0x05000000U && + (call & 0xFFFFE000U) == 0x85C0A000U && + nop == 0x01000000U) + { + regs->u_regs[UREG_G1] = (sethi & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G2] = addr + 4; + addr = (save & 0x003FFFFFU) << 10; + addr += (((call | 0xFFFFFFFFFFFFE000UL) ^ 0x00001000UL) + 0x00001000UL); + + if (test_thread_flag(TIF_32BIT)) + addr &= 0xFFFFFFFFUL; + + regs->tpc = addr; + regs->tnpc = addr+4; + return 3; + } + + /* PaX: 64-bit PLT stub */ + err = get_user(sethi1, (unsigned int *)addr); + err |= get_user(sethi2, (unsigned int *)(addr+4)); + err |= get_user(or1, (unsigned int *)(addr+8)); + err |= get_user(or2, (unsigned int *)(addr+12)); + err |= get_user(sllx, (unsigned int *)(addr+16)); + err |= get_user(add, (unsigned int *)(addr+20)); + err |= get_user(jmpl, (unsigned int *)(addr+24)); + err |= get_user(nop, (unsigned int *)(addr+28)); + if (err) + break; + + if ((sethi1 & 0xFFC00000U) == 0x09000000U && + (sethi2 & 0xFFC00000U) == 0x0B000000U && + (or1 & 0xFFFFE000U) == 0x88112000U && + (or2 & 0xFFFFE000U) == 0x8A116000U && + sllx == 0x89293020U && + add == 0x8A010005U && + jmpl == 0x89C14000U && + nop == 0x01000000U) + { + regs->u_regs[UREG_G1] = (sethi & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G4] = ((sethi1 & 0x003FFFFFU) << 10) | (or1 & 0x000003FFU); + regs->u_regs[UREG_G4] <<= 32; + regs->u_regs[UREG_G5] = ((sethi2 & 0x003FFFFFU) << 10) | (or2 & 0x000003FFU); + regs->u_regs[UREG_G5] += regs->u_regs[UREG_G4]; + regs->u_regs[UREG_G4] = addr + 24; + addr = regs->u_regs[UREG_G5]; + regs->tpc = addr; + regs->tnpc = addr+4; + return 3; + } + } + } while (0); + +#ifdef CONFIG_PAX_DLRESOLVE + do { /* PaX: unpatched PLT emulation step 2 */ + unsigned int save, call, nop; + + err = get_user(save, (unsigned int *)(regs->tpc-4)); + err |= get_user(call, (unsigned int *)regs->tpc); + err |= get_user(nop, (unsigned int *)(regs->tpc+4)); + if (err) + break; + + if (save == 0x9DE3BFA8U && + (call & 0xC0000000U) == 0x40000000U && + nop == 0x01000000U) + { + unsigned long dl_resolve = regs->tpc + ((((call | 0xFFFFFFFFC0000000UL) ^ 0x20000000UL) + 0x20000000UL) << 2); + + if (test_thread_flag(TIF_32BIT)) + dl_resolve &= 0xFFFFFFFFUL; + + regs->u_regs[UREG_RETPC] = regs->tpc; + regs->tpc = dl_resolve; + regs->tnpc = dl_resolve+4; + return 3; + } + } while (0); +#endif + + do { /* PaX: patched PLT emulation #7, must be AFTER the unpatched PLT emulation */ + unsigned int sethi, ba, nop; + + err = get_user(sethi, (unsigned int *)regs->tpc); + err |= get_user(ba, (unsigned int *)(regs->tpc+4)); + err |= get_user(nop, (unsigned int *)(regs->tpc+8)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + (ba & 0xFFF00000U) == 0x30600000U && + nop == 0x01000000U) + { + unsigned long addr; + + addr = (sethi & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G1] = addr; + addr = regs->tpc + ((((ba | 0xFFFFFFFFFFF80000UL) ^ 0x00040000UL) + 0x00040000UL) << 2); + + if (test_thread_flag(TIF_32BIT)) + addr &= 0xFFFFFFFFUL; + + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + +#endif + + return 1; +} + +void pax_report_insns(struct pt_regs *regs, void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 8; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk(KERN_CONT "???????? "); + else + printk(KERN_CONT "%08x ", c); + } + printk("\n"); +} +#endif + asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) { enum ctx_state prev_state = exception_enter(); @@ -353,6 +816,29 @@ retry: if (!vma) goto bad_area; +#ifdef CONFIG_PAX_PAGEEXEC + /* PaX: detect ITLB misses on non-exec pages */ + if ((mm->pax_flags & MF_PAX_PAGEEXEC) && vma->vm_start <= address && + !(vma->vm_flags & VM_EXEC) && (fault_code & FAULT_CODE_ITLB)) + { + if (address != regs->tpc) + goto good_area; + + up_read(&mm->mmap_sem); + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_PAX_EMUPLT + case 2: + case 3: + return; +#endif + + } + pax_report_fault(regs, (void *)regs->tpc, (void *)(regs->u_regs[UREG_FP] + STACK_BIAS)); + do_group_exit(SIGKILL); + } +#endif + /* Pure DTLB misses do not tell us whether the fault causing * load/store/atomic was a write or not, it only says that there * was no match. So in such a case we (carefully) read the diff --git a/arch/sparc/mm/hugetlbpage.c b/arch/sparc/mm/hugetlbpage.c index 131eaf4..285ea31 100644 --- a/arch/sparc/mm/hugetlbpage.c +++ b/arch/sparc/mm/hugetlbpage.c @@ -25,8 +25,10 @@ static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, - unsigned long flags) + unsigned long flags, + unsigned long offset) { + struct mm_struct *mm = current->mm; unsigned long task_size = TASK_SIZE; struct vm_unmapped_area_info info; @@ -35,15 +37,22 @@ static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *filp, info.flags = 0; info.length = len; - info.low_limit = TASK_UNMAPPED_BASE; + info.low_limit = mm->mmap_base; info.high_limit = min(task_size, VA_EXCLUDE_START); info.align_mask = PAGE_MASK & ~HPAGE_MASK; info.align_offset = 0; + info.threadstack_offset = offset; addr = vm_unmapped_area(&info); if ((addr & ~PAGE_MASK) && task_size > VA_EXCLUDE_END) { VM_BUG_ON(addr != -ENOMEM); info.low_limit = VA_EXCLUDE_END; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + info.low_limit += mm->delta_mmap; +#endif + info.high_limit = task_size; addr = vm_unmapped_area(&info); } @@ -55,7 +64,8 @@ static unsigned long hugetlb_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, const unsigned long len, const unsigned long pgoff, - const unsigned long flags) + const unsigned long flags, + const unsigned long offset) { struct mm_struct *mm = current->mm; unsigned long addr = addr0; @@ -70,6 +80,7 @@ hugetlb_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, info.high_limit = mm->mmap_base; info.align_mask = PAGE_MASK & ~HPAGE_MASK; info.align_offset = 0; + info.threadstack_offset = offset; addr = vm_unmapped_area(&info); /* @@ -82,6 +93,12 @@ hugetlb_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, VM_BUG_ON(addr != -ENOMEM); info.flags = 0; info.low_limit = TASK_UNMAPPED_BASE; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + info.low_limit += mm->delta_mmap; +#endif + info.high_limit = STACK_TOP32; addr = vm_unmapped_area(&info); } @@ -96,6 +113,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, struct mm_struct *mm = current->mm; struct vm_area_struct *vma; unsigned long task_size = TASK_SIZE; + unsigned long offset = gr_rand_threadstack_offset(mm, file, flags); if (test_thread_flag(TIF_32BIT)) task_size = STACK_TOP32; @@ -111,19 +129,22 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, return addr; } +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + if (addr) { addr = ALIGN(addr, HPAGE_SIZE); vma = find_vma(mm, addr); - if (task_size - len >= addr && - (!vma || addr + len <= vma->vm_start)) + if (task_size - len >= addr && check_heap_stack_gap(vma, addr, len, offset)) return addr; } if (mm->get_unmapped_area == arch_get_unmapped_area) return hugetlb_get_unmapped_area_bottomup(file, addr, len, - pgoff, flags); + pgoff, flags, offset); else return hugetlb_get_unmapped_area_topdown(file, addr, len, - pgoff, flags); + pgoff, flags, offset); } pte_t *huge_pte_alloc(struct mm_struct *mm, diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 4ac88b7..bac6cb2 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -187,9 +187,9 @@ unsigned long sparc64_kern_sec_context __read_mostly; int num_kernel_image_mappings; #ifdef CONFIG_DEBUG_DCFLUSH -atomic_t dcpage_flushes = ATOMIC_INIT(0); +atomic_unchecked_t dcpage_flushes = ATOMIC_INIT(0); #ifdef CONFIG_SMP -atomic_t dcpage_flushes_xcall = ATOMIC_INIT(0); +atomic_unchecked_t dcpage_flushes_xcall = ATOMIC_INIT(0); #endif #endif @@ -197,7 +197,7 @@ inline void flush_dcache_page_impl(struct page *page) { BUG_ON(tlb_type == hypervisor); #ifdef CONFIG_DEBUG_DCFLUSH - atomic_inc(&dcpage_flushes); + atomic_inc_unchecked(&dcpage_flushes); #endif #ifdef DCACHE_ALIASING_POSSIBLE @@ -469,10 +469,10 @@ void mmu_info(struct seq_file *m) #ifdef CONFIG_DEBUG_DCFLUSH seq_printf(m, "DCPageFlushes\t: %d\n", - atomic_read(&dcpage_flushes)); + atomic_read_unchecked(&dcpage_flushes)); #ifdef CONFIG_SMP seq_printf(m, "DCPageFlushesXC\t: %d\n", - atomic_read(&dcpage_flushes_xcall)); + atomic_read_unchecked(&dcpage_flushes_xcall)); #endif /* CONFIG_SMP */ #endif /* CONFIG_DEBUG_DCFLUSH */ } diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index 106c21b..185bf0f 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig @@ -206,6 +206,7 @@ source "kernel/Kconfig.hz" config KEXEC bool "kexec system call" select KEXEC_CORE + depends on !GRKERNSEC_KMEM ---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 diff --git a/arch/tile/include/asm/atomic_64.h b/arch/tile/include/asm/atomic_64.h index 096a56d..bffafc0 100644 --- a/arch/tile/include/asm/atomic_64.h +++ b/arch/tile/include/asm/atomic_64.h @@ -145,6 +145,16 @@ static inline void atomic64_xor(long i, atomic64_t *v) #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) +#define atomic64_read_unchecked(v) atomic64_read(v) +#define atomic64_set_unchecked(v, i) atomic64_set((v), (i)) +#define atomic64_add_unchecked(a, v) atomic64_add((a), (v)) +#define atomic64_add_return_unchecked(a, v) atomic64_add_return((a), (v)) +#define atomic64_sub_unchecked(a, v) atomic64_sub((a), (v)) +#define atomic64_inc_unchecked(v) atomic64_inc(v) +#define atomic64_inc_return_unchecked(v) atomic64_inc_return(v) +#define atomic64_dec_unchecked(v) atomic64_dec(v) +#define atomic64_cmpxchg_unchecked(v, o, n) atomic64_cmpxchg((v), (o), (n)) + #endif /* !__ASSEMBLY__ */ #endif /* _ASM_TILE_ATOMIC_64_H */ diff --git a/arch/tile/include/asm/cache.h b/arch/tile/include/asm/cache.h index 6160761..00cac88 100644 --- a/arch/tile/include/asm/cache.h +++ b/arch/tile/include/asm/cache.h @@ -15,11 +15,12 @@ #ifndef _ASM_TILE_CACHE_H #define _ASM_TILE_CACHE_H +#include #include /* bytes per L1 data cache line */ #define L1_CACHE_SHIFT CHIP_L1D_LOG_LINE_SIZE() -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) /* bytes per L2 cache line */ #define L2_CACHE_SHIFT CHIP_L2_LOG_LINE_SIZE() diff --git a/arch/tile/include/asm/uaccess.h b/arch/tile/include/asm/uaccess.h index 0a9c4265..bfb62d1 100644 --- a/arch/tile/include/asm/uaccess.h +++ b/arch/tile/include/asm/uaccess.h @@ -429,9 +429,9 @@ static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) { - int sz = __compiletime_object_size(to); + size_t sz = __compiletime_object_size(to); - if (likely(sz == -1 || sz >= n)) + if (likely(sz == (size_t)-1 || sz >= n)) n = _copy_from_user(to, from, n); else copy_from_user_overflow(); diff --git a/arch/tile/mm/hugetlbpage.c b/arch/tile/mm/hugetlbpage.c index c034dc3..cf1cc96 100644 --- a/arch/tile/mm/hugetlbpage.c +++ b/arch/tile/mm/hugetlbpage.c @@ -174,6 +174,7 @@ static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *file, info.high_limit = TASK_SIZE; info.align_mask = PAGE_MASK & ~huge_page_mask(h); info.align_offset = 0; + info.threadstack_offset = 0; return vm_unmapped_area(&info); } @@ -191,6 +192,7 @@ static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file, info.high_limit = current->mm->mmap_base; info.align_mask = PAGE_MASK & ~huge_page_mask(h); info.align_offset = 0; + info.threadstack_offset = 0; addr = vm_unmapped_area(&info); /* diff --git a/arch/um/Makefile b/arch/um/Makefile index e3abe6f..ae224ef 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -73,6 +73,10 @@ 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 + #This will adjust *FLAGS accordingly to the platform. include $(ARCH_DIR)/Makefile-os-$(OS) diff --git a/arch/um/include/asm/cache.h b/arch/um/include/asm/cache.h index 19e1bdd..3665b77 100644 --- a/arch/um/include/asm/cache.h +++ b/arch/um/include/asm/cache.h @@ -1,6 +1,7 @@ #ifndef __UM_CACHE_H #define __UM_CACHE_H +#include #if defined(CONFIG_UML_X86) && !defined(CONFIG_64BIT) # define L1_CACHE_SHIFT (CONFIG_X86_L1_CACHE_SHIFT) @@ -12,6 +13,6 @@ # define L1_CACHE_SHIFT 5 #endif -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #endif diff --git a/arch/um/include/asm/kmap_types.h b/arch/um/include/asm/kmap_types.h index 2e0a6b1..a64d0f5 100644 --- a/arch/um/include/asm/kmap_types.h +++ b/arch/um/include/asm/kmap_types.h @@ -8,6 +8,6 @@ /* No more #include "asm/arch/kmap_types.h" ! */ -#define KM_TYPE_NR 14 +#define KM_TYPE_NR 15 #endif diff --git a/arch/um/include/asm/page.h b/arch/um/include/asm/page.h index 71c5d13..4c7b9f1 100644 --- a/arch/um/include/asm/page.h +++ b/arch/um/include/asm/page.h @@ -14,6 +14,9 @@ #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) +#define ktla_ktva(addr) (addr) +#define ktva_ktla(addr) (addr) + #ifndef __ASSEMBLY__ struct page; diff --git a/arch/um/include/asm/pgtable-3level.h b/arch/um/include/asm/pgtable-3level.h index 2b4274e..754fe06 100644 --- a/arch/um/include/asm/pgtable-3level.h +++ b/arch/um/include/asm/pgtable-3level.h @@ -58,6 +58,7 @@ #define pud_present(x) (pud_val(x) & _PAGE_PRESENT) #define pud_populate(mm, pud, pmd) \ set_pud(pud, __pud(_PAGE_TABLE + __pa(pmd))) +#define pud_populate_kernel(mm, pud, pmd) pud_populate((mm), (pud), (pmd)) #ifdef CONFIG_64BIT #define set_pud(pudptr, pudval) set_64bit((u64 *) (pudptr), pud_val(pudval)) diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index a6d9226..d243e1e 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -347,22 +347,6 @@ int singlestepping(void * t) return 2; } -/* - * Only x86 and x86_64 have an arch_align_stack(). - * All other arches have "#define arch_align_stack(x) (x)" - * in their asm/exec.h - * As this is included in UML from asm-um/system-generic.h, - * we can use it to behave as the subarch does. - */ -#ifndef arch_align_stack -unsigned long arch_align_stack(unsigned long sp) -{ - if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) - sp -= get_random_int() % 8192; - return sp & ~0xf; -} -#endif - unsigned long get_wchan(struct task_struct *p) { unsigned long stack_page, sp, ip; diff --git a/arch/unicore32/include/asm/cache.h b/arch/unicore32/include/asm/cache.h index ad8f795..2c7eec6 100644 --- a/arch/unicore32/include/asm/cache.h +++ b/arch/unicore32/include/asm/cache.h @@ -12,8 +12,10 @@ #ifndef __UNICORE_CACHE_H__ #define __UNICORE_CACHE_H__ -#define L1_CACHE_SHIFT (5) -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#include + +#define L1_CACHE_SHIFT 5 +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) /* * Memory returned by kmalloc() may be used for DMA, so we must make diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 96d058a..b581500 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -36,14 +36,13 @@ config X86 select ARCH_MIGHT_HAVE_PC_SERIO select ARCH_SUPPORTS_ATOMIC_RMW select ARCH_SUPPORTS_DEFERRED_STRUCT_PAGE_INIT - select ARCH_SUPPORTS_INT128 if X86_64 + select ARCH_SUPPORTS_INT128 if X86_64 && !PAX_SIZE_OVERFLOW select ARCH_SUPPORTS_NUMA_BALANCING if X86_64 select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_CMPXCHG_LOCKREF if X86_64 select ARCH_USE_QUEUED_RWLOCKS select ARCH_USE_QUEUED_SPINLOCKS select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH if SMP - select ARCH_WANTS_DYNAMIC_TASK_STRUCT select ARCH_WANT_FRAME_POINTERS select ARCH_WANT_IPC_PARSE_VERSION if X86_32 select ARCH_WANT_OPTIONAL_GPIOLIB @@ -87,7 +86,7 @@ config X86 select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_TRANSPARENT_HUGEPAGE select HAVE_BPF_JIT if X86_64 - select HAVE_CC_STACKPROTECTOR + select HAVE_CC_STACKPROTECTOR if X86_64 || !PAX_MEMORY_UDEREF select HAVE_CMPXCHG_DOUBLE select HAVE_CMPXCHG_LOCAL select HAVE_CONTEXT_TRACKING if X86_64 @@ -276,7 +275,7 @@ config X86_64_SMP config X86_32_LAZY_GS def_bool y - depends on X86_32 && !CC_STACKPROTECTOR + depends on X86_32 && !CC_STACKPROTECTOR && !PAX_MEMORY_UDEREF config ARCH_HWEIGHT_CFLAGS string @@ -648,6 +647,7 @@ config SCHED_OMIT_FRAME_POINTER menuconfig HYPERVISOR_GUEST bool "Linux guest support" + depends on !GRKERNSEC_CONFIG_AUTO || GRKERNSEC_CONFIG_VIRT_GUEST || (GRKERNSEC_CONFIG_VIRT_HOST && GRKERNSEC_CONFIG_VIRT_XEN) ---help--- Say Y here to enable options for running Linux under various hyper- visors. This option enables basic hypervisor detection and platform @@ -1039,6 +1039,7 @@ config VM86 config X86_16BIT bool "Enable support for 16-bit segments" if EXPERT + depends on !GRKERNSEC default y depends on MODIFY_LDT_SYSCALL ---help--- @@ -1208,6 +1209,7 @@ choice config NOHIGHMEM bool "off" + depends on !(PAX_PAGEEXEC && PAX_ENABLE_PAE) ---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 @@ -1244,6 +1246,7 @@ config NOHIGHMEM config HIGHMEM4G bool "4GB" + depends on !(PAX_PAGEEXEC && PAX_ENABLE_PAE) ---help--- Select this if you have a 32-bit processor and between 1 and 4 gigabytes of physical RAM. @@ -1296,7 +1299,7 @@ config PAGE_OFFSET hex default 0xB0000000 if VMSPLIT_3G_OPT default 0x80000000 if VMSPLIT_2G - default 0x78000000 if VMSPLIT_2G_OPT + default 0x70000000 if VMSPLIT_2G_OPT default 0x40000000 if VMSPLIT_1G default 0xC0000000 depends on X86_32 @@ -1317,7 +1320,6 @@ config X86_PAE config ARCH_PHYS_ADDR_T_64BIT def_bool y - depends on X86_64 || X86_PAE config ARCH_DMA_ADDR_T_64BIT def_bool y @@ -1757,6 +1759,7 @@ source kernel/Kconfig.hz config KEXEC bool "kexec system call" select KEXEC_CORE + depends on !GRKERNSEC_KMEM ---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 @@ -1939,7 +1942,9 @@ config X86_NEED_RELOCS config PHYSICAL_ALIGN hex "Alignment value to which kernel should be aligned" - default "0x200000" + default "0x1000000" + range 0x200000 0x1000000 if PAX_KERNEXEC && X86_PAE + range 0x400000 0x1000000 if PAX_KERNEXEC && !X86_PAE range 0x2000 0x1000000 if X86_32 range 0x200000 0x1000000 if X86_64 ---help--- @@ -2022,6 +2027,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 + depends on !PAX_PAGEEXEC && !PAX_SEGMEXEC && !PAX_KERNEXEC && !PAX_MEMORY_UDEREF ---help--- Certain buggy versions of glibc will crash if they are presented with a 32-bit vDSO that is not mapped at the address @@ -2102,6 +2108,22 @@ config MODIFY_LDT_SYSCALL Saying 'N' here may make sense for embedded or server kernels. +config DEFAULT_MODIFY_LDT_SYSCALL + bool "Allow userspace to modify the LDT by default" + default y + + ---help--- + Modifying the LDT (Local Descriptor Table) may be needed to run a + 16-bit or segmented code such as Dosemu or Wine. This is done via + a system call which is not needed to run portable applications, + and which can sometimes be abused to exploit some weaknesses of + the architecture, opening new vulnerabilities. + + For this reason this option allows one to enable or disable the + feature at runtime. It is recommended to say 'N' here to leave + the system protected, and to enable it at runtime only if needed + by setting the sys.kernel.modify_ldt sysctl. + source "kernel/livepatch/Kconfig" endmenu diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index 6983314..54ad7e8 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -319,7 +319,7 @@ config X86_PPRO_FENCE config X86_F00F_BUG def_bool y - depends on M586MMX || M586TSC || M586 || M486 + depends on (M586MMX || M586TSC || M586 || M486) && !PAX_KERNEXEC config X86_INVD_BUG def_bool y @@ -327,7 +327,7 @@ config X86_INVD_BUG config X86_ALIGNMENT_16 def_bool y - depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1 + depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK8 || MK7 || MK6 || MCORE2 || MPENTIUM4 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1 config X86_INTEL_USERCOPY def_bool y @@ -369,7 +369,7 @@ config X86_CMPXCHG64 # generates cmov. config X86_CMOV def_bool y - depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MATOM || MGEODE_LX) + depends on (MK8 || MK7 || MCORE2 || MPSC || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MATOM || MGEODE_LX) config X86_MINIMUM_CPU_FAMILY int diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index d8c0d32..28e3117 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -69,6 +69,7 @@ config X86_PTDUMP bool "Export kernel pagetable layout to userspace via debugfs" depends on DEBUG_KERNEL select DEBUG_FS + depends on !GRKERNSEC_KMEM ---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 @@ -89,7 +90,7 @@ config EFI_PGT_DUMP config DEBUG_RODATA bool "Write protect kernel read-only data structures" default y - depends on DEBUG_KERNEL + depends on DEBUG_KERNEL && BROKEN ---help--- Mark the kernel read-only data as write-protected in the pagetables, in order to catch accidental (and incorrect) writes to such const @@ -107,7 +108,7 @@ config DEBUG_RODATA_TEST config DEBUG_SET_MODULE_RONX bool "Set loadable kernel module data as NX and text as RO" - depends on MODULES + depends on MODULES && BROKEN ---help--- This option helps catch unintended modifications to loadable kernel module's text and read-only data. It also prevents execution @@ -359,6 +360,7 @@ config X86_DEBUG_FPU config PUNIT_ATOM_DEBUG tristate "ATOM Punit debug driver" select DEBUG_FS + depends on !GRKERNSEC_KMEM select IOSF_MBI ---help--- This is a debug driver, which gets the power states diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 747860c..0374d1e 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -75,9 +75,6 @@ ifeq ($(CONFIG_X86_32),y) # CPU-specific tuning. Anything which can be shared with UML should go here. include arch/x86/Makefile_32.cpu KBUILD_CFLAGS += $(cflags-y) - - # temporary until string.h is fixed - KBUILD_CFLAGS += -ffreestanding else BITS := 64 UTS_MACHINE := x86_64 @@ -126,6 +123,9 @@ else KBUILD_CFLAGS += $(call cc-option,-maccumulate-outgoing-args) endif +# temporary until string.h is fixed +KBUILD_CFLAGS += -ffreestanding + # Make sure compiler does not have buggy stack-protector support. ifdef CONFIG_CC_STACKPROTECTOR cc_has_sp := $(srctree)/scripts/gcc-x86_$(BITS)-has-stack-protector.sh @@ -191,6 +191,7 @@ archheaders: $(Q)$(MAKE) $(build)=arch/x86/entry/syscalls all archprepare: + $(if $(LDFLAGS_BUILD_ID),,$(error $(OLD_LD))) ifeq ($(CONFIG_KEXEC_FILE),y) $(Q)$(MAKE) $(build)=arch/x86/purgatory arch/x86/purgatory/kexec-purgatory.c endif @@ -276,3 +277,9 @@ define archhelp echo ' FDARGS="..." arguments for the booted kernel' echo ' FDINITRD=file initrd for the booted kernel' endef + +define OLD_LD + +*** ${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 0d553e5..cecccf9 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 diff --git a/arch/x86/boot/bitops.h b/arch/x86/boot/bitops.h index 878e4b9..20537ab 100644 --- a/arch/x86/boot/bitops.h +++ b/arch/x86/boot/bitops.h @@ -26,7 +26,7 @@ static inline int variable_test_bit(int nr, const void *addr) u8 v; const u32 *p = (const u32 *)addr; - asm("btl %2,%1; setc %0" : "=qm" (v) : "m" (*p), "Ir" (nr)); + asm volatile("btl %2,%1; setc %0" : "=qm" (v) : "m" (*p), "Ir" (nr)); return v; } @@ -37,7 +37,7 @@ static inline int variable_test_bit(int nr, const void *addr) static inline void set_bit(int nr, void *addr) { - asm("btsl %1,%0" : "+m" (*(u32 *)addr) : "Ir" (nr)); + asm volatile("btsl %1,%0" : "+m" (*(u32 *)addr) : "Ir" (nr)); } #endif /* BOOT_BITOPS_H */ diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index 0033e96..b3179b9 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h @@ -84,7 +84,7 @@ static inline void io_delay(void) static inline u16 ds(void) { u16 seg; - asm("movw %%ds,%0" : "=rm" (seg)); + asm volatile("movw %%ds,%0" : "=rm" (seg)); return seg; } diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 0a291cd..9686efc 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -30,6 +30,9 @@ KBUILD_CFLAGS += $(cflags-y) 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 KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ GCOV_PROFILE := 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 +++ b/arch/x86/boot/compressed/efi_stub_32.S @@ -46,16 +46,13 @@ ENTRY(efi_call_phys) * parameter 2, ..., param n. To make things easy, we save the return * address of efi_call_phys in a global variable. */ - popl %ecx - movl %ecx, saved_return_addr(%edx) - /* get the function pointer into ECX*/ - popl %ecx - movl %ecx, efi_rt_function_ptr(%edx) + popl saved_return_addr(%edx) + popl efi_rt_function_ptr(%edx) /* * 3. Call the physical function. */ - call *%ecx + call *efi_rt_function_ptr(%edx) /* * 4. Balance the stack. And because EAX contain the return value, @@ -67,15 +64,12 @@ ENTRY(efi_call_phys) 1: popl %edx subl $1b, %edx - movl efi_rt_function_ptr(%edx), %ecx - pushl %ecx + pushl efi_rt_function_ptr(%edx) /* * 10. Push the saved return address onto the stack and return. */ - movl saved_return_addr(%edx), %ecx - pushl %ecx - ret + jmpl *saved_return_addr(%edx) ENDPROC(efi_call_phys) .previous diff --git a/arch/x86/boot/compressed/efi_thunk_64.S b/arch/x86/boot/compressed/efi_thunk_64.S index 630384a..278e788 100644 --- a/arch/x86/boot/compressed/efi_thunk_64.S +++ b/arch/x86/boot/compressed/efi_thunk_64.S @@ -189,8 +189,8 @@ efi_gdt64: .long 0 /* Filled out by user */ .word 0 .quad 0x0000000000000000 /* NULL descriptor */ - .quad 0x00af9a000000ffff /* __KERNEL_CS */ - .quad 0x00cf92000000ffff /* __KERNEL_DS */ + .quad 0x00af9b000000ffff /* __KERNEL_CS */ + .quad 0x00cf93000000ffff /* __KERNEL_DS */ .quad 0x0080890000000000 /* TS descriptor */ .quad 0x0000000000000000 /* TS continued */ efi_gdt64_end: diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S index 8ef964d..fcfb8aa 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S @@ -141,10 +141,10 @@ preferred_addr: addl %eax, %ebx notl %eax andl %eax, %ebx - cmpl $LOAD_PHYSICAL_ADDR, %ebx + cmpl $____LOAD_PHYSICAL_ADDR, %ebx jge 1f #endif - movl $LOAD_PHYSICAL_ADDR, %ebx + movl $____LOAD_PHYSICAL_ADDR, %ebx 1: /* Target address to relocate to for decompression */ diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index b0c0d16..3b44ff8 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -95,10 +95,10 @@ ENTRY(startup_32) addl %eax, %ebx notl %eax andl %eax, %ebx - cmpl $LOAD_PHYSICAL_ADDR, %ebx + cmpl $____LOAD_PHYSICAL_ADDR, %ebx jge 1f #endif - movl $LOAD_PHYSICAL_ADDR, %ebx + movl $____LOAD_PHYSICAL_ADDR, %ebx 1: /* Target address to relocate to for decompression */ @@ -323,10 +323,10 @@ preferred_addr: addq %rax, %rbp notq %rax andq %rax, %rbp - cmpq $LOAD_PHYSICAL_ADDR, %rbp + cmpq $____LOAD_PHYSICAL_ADDR, %rbp jge 1f #endif - movq $LOAD_PHYSICAL_ADDR, %rbp + movq $____LOAD_PHYSICAL_ADDR, %rbp 1: /* Target address to relocate to for decompression */ @@ -435,8 +435,8 @@ gdt: .long gdt .word 0 .quad 0x0000000000000000 /* NULL descriptor */ - .quad 0x00af9a000000ffff /* __KERNEL_CS */ - .quad 0x00cf92000000ffff /* __KERNEL_DS */ + .quad 0x00af9b000000ffff /* __KERNEL_CS */ + .quad 0x00cf93000000ffff /* __KERNEL_DS */ .quad 0x0080890000000000 /* TS descriptor */ .quad 0x0000000000000000 /* TS continued */ gdt_end: diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index 79dac17..1549446 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -259,7 +259,7 @@ static void handle_relocations(void *output, unsigned long output_len) * Calculate the delta between where vmlinux was linked to load * and where it was actually loaded. */ - delta = min_addr - LOAD_PHYSICAL_ADDR; + delta = min_addr - ____LOAD_PHYSICAL_ADDR; if (!delta) { debug_putstr("No relocation needed... "); return; @@ -341,7 +341,7 @@ static void parse_elf(void *output) Elf32_Ehdr ehdr; Elf32_Phdr *phdrs, *phdr; #endif - void *dest; + void *dest, *prev; int i; memcpy(&ehdr, output, sizeof(ehdr)); @@ -368,13 +368,16 @@ static void parse_elf(void *output) case PT_LOAD: #ifdef CONFIG_RELOCATABLE dest = output; - dest += (phdr->p_paddr - LOAD_PHYSICAL_ADDR); + dest += (phdr->p_paddr - ____LOAD_PHYSICAL_ADDR); #else dest = (void *)(phdr->p_paddr); #endif memcpy(dest, output + phdr->p_offset, phdr->p_filesz); + if (i) + memset(prev, 0xff, dest - prev); + prev = dest + phdr->p_filesz; break; default: /* Ignore other PT_* */ break; } @@ -443,7 +446,7 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap, error("Destination address too large"); #endif #ifndef CONFIG_RELOCATABLE - if ((unsigned long)output != LOAD_PHYSICAL_ADDR) + if ((unsigned long)output != ____LOAD_PHYSICAL_ADDR) error("Wrong destination address"); #endif diff --git a/arch/x86/boot/cpucheck.c b/arch/x86/boot/cpucheck.c index 1fd7d57..0f7d096 100644 --- a/arch/x86/boot/cpucheck.c +++ b/arch/x86/boot/cpucheck.c @@ -125,9 +125,9 @@ int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr) u32 ecx = MSR_K7_HWCR; u32 eax, edx; - asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); + asm volatile("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); eax &= ~(1 << 15); - asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); + asm volatile("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); get_cpuflags(); /* Make sure it really did something */ err = check_cpuflags(); @@ -140,9 +140,9 @@ int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr) u32 ecx = MSR_VIA_FCR; u32 eax, edx; - asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); + asm volatile("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); eax |= (1<<1)|(1<<7); - asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); + asm volatile("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); set_bit(X86_FEATURE_CX8, cpu.flags); err = check_cpuflags(); @@ -153,12 +153,12 @@ int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr) u32 eax, edx; u32 level = 1; - asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); - asm("wrmsr" : : "a" (~0), "d" (edx), "c" (ecx)); - asm("cpuid" + asm volatile("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); + asm volatile("wrmsr" : : "a" (~0), "d" (edx), "c" (ecx)); + asm volatile("cpuid" : "+a" (level), "=d" (cpu.flags[0]) : : "ecx", "ebx"); - asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); + asm volatile("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); err = check_cpuflags(); } else if (err == 0x01 && diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S index 2d6b309..65defa1 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -438,10 +438,14 @@ setup_data: .quad 0 # 64-bit physical pointer to # single linked list of # struct setup_data -pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr +pref_address: .quad ____LOAD_PHYSICAL_ADDR # preferred load addr #define ZO_INIT_SIZE (ZO__end - ZO_startup_32 + ZO_z_extract_offset) +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) +#define VO_INIT_SIZE (VO__end - VO__text - __PAGE_OFFSET - ____LOAD_PHYSICAL_ADDR) +#else #define VO_INIT_SIZE (VO__end - VO__text) +#endif #if ZO_INIT_SIZE > VO_INIT_SIZE #define INIT_SIZE ZO_INIT_SIZE #else diff --git a/arch/x86/boot/memory.c b/arch/x86/boot/memory.c index db75d07..8e6d0af 100644 --- a/arch/x86/boot/memory.c +++ b/arch/x86/boot/memory.c @@ -19,7 +19,7 @@ static int detect_memory_e820(void) { - int count = 0; + unsigned int count = 0; struct biosregs ireg, oreg; struct e820entry *desc = boot_params.e820_map; static struct e820entry buf; /* static so it is zeroed */ diff --git a/arch/x86/boot/video-vesa.c b/arch/x86/boot/video-vesa.c index ba3e100..6501b8f 100644 --- a/arch/x86/boot/video-vesa.c +++ b/arch/x86/boot/video-vesa.c @@ -201,6 +201,7 @@ static void vesa_store_pm_info(void) boot_params.screen_info.vesapm_seg = oreg.es; boot_params.screen_info.vesapm_off = oreg.di; + boot_params.screen_info.vesapm_size = oreg.cx; } /* diff --git a/arch/x86/boot/video.c b/arch/x86/boot/video.c index 05111bb..a1ae1f0 100644 --- a/arch/x86/boot/video.c +++ b/arch/x86/boot/video.c @@ -98,7 +98,7 @@ static void store_mode_params(void) static unsigned int get_entry(void) { char entry_buf[4]; - int i, len = 0; + unsigned int i, len = 0; int key; unsigned int v; diff --git a/arch/x86/crypto/aes-x86_64-asm_64.S b/arch/x86/crypto/aes-x86_64-asm_64.S index 9105655..41779c1 100644 --- a/arch/x86/crypto/aes-x86_64-asm_64.S +++ b/arch/x86/crypto/aes-x86_64-asm_64.S @@ -8,6 +8,8 @@ * including this sentence is retained in full. */ +#include + .extern crypto_ft_tab .extern crypto_it_tab .extern crypto_fl_tab @@ -70,6 +72,8 @@ je B192; \ leaq 32(r9),r9; +#define ret pax_force_retaddr; ret + #define epilogue(FUNC,r1,r2,r3,r4,r5,r6,r7,r8,r9) \ movq r1,r2; \ movq r3,r4; \ diff --git a/arch/x86/crypto/aesni-intel_asm.S b/arch/x86/crypto/aesni-intel_asm.S index 6bd2c6c..368c93e 100644 --- a/arch/x86/crypto/aesni-intel_asm.S +++ b/arch/x86/crypto/aesni-intel_asm.S @@ -31,6 +31,7 @@ #include #include +#include /* * The following macros are used to move an (un)aligned 16 byte value to/from @@ -217,7 +218,7 @@ enc: .octa 0x2 * num_initial_blocks = b mod 4 * encrypt the initial num_initial_blocks blocks and apply ghash on * the ciphertext -* %r10, %r11, %r12, %rax, %xmm5, %xmm6, %xmm7, %xmm8, %xmm9 registers +* %r10, %r11, %r15, %rax, %xmm5, %xmm6, %xmm7, %xmm8, %xmm9 registers * are clobbered * arg1, %arg2, %arg3, %r14 are used as a pointer only, not modified */ @@ -227,8 +228,8 @@ enc: .octa 0x2 XMM2 XMM3 XMM4 XMMDst TMP6 TMP7 i i_seq operation MOVADQ SHUF_MASK(%rip), %xmm14 mov arg7, %r10 # %r10 = AAD - mov arg8, %r12 # %r12 = aadLen - mov %r12, %r11 + mov arg8, %r15 # %r15 = aadLen + mov %r15, %r11 pxor %xmm\i, %xmm\i _get_AAD_loop\num_initial_blocks\operation: @@ -237,17 +238,17 @@ _get_AAD_loop\num_initial_blocks\operation: psrldq $4, %xmm\i pxor \TMP1, %xmm\i add $4, %r10 - sub $4, %r12 + sub $4, %r15 jne _get_AAD_loop\num_initial_blocks\operation cmp $16, %r11 je _get_AAD_loop2_done\num_initial_blocks\operation - mov $16, %r12 + mov $16, %r15 _get_AAD_loop2\num_initial_blocks\operation: psrldq $4, %xmm\i - sub $4, %r12 - cmp %r11, %r12 + sub $4, %r15 + cmp %r11, %r15 jne _get_AAD_loop2\num_initial_blocks\operation _get_AAD_loop2_done\num_initial_blocks\operation: @@ -442,7 +443,7 @@ _initial_blocks_done\num_initial_blocks\operation: * num_initial_blocks = b mod 4 * encrypt the initial num_initial_blocks blocks and apply ghash on * the ciphertext -* %r10, %r11, %r12, %rax, %xmm5, %xmm6, %xmm7, %xmm8, %xmm9 registers +* %r10, %r11, %r15, %rax, %xmm5, %xmm6, %xmm7, %xmm8, %xmm9 registers * are clobbered * arg1, %arg2, %arg3, %r14 are used as a pointer only, not modified */ @@ -452,8 +453,8 @@ _initial_blocks_done\num_initial_blocks\operation: XMM2 XMM3 XMM4 XMMDst TMP6 TMP7 i i_seq operation MOVADQ SHUF_MASK(%rip), %xmm14 mov arg7, %r10 # %r10 = AAD - mov arg8, %r12 # %r12 = aadLen - mov %r12, %r11 + mov arg8, %r15 # %r15 = aadLen + mov %r15, %r11 pxor %xmm\i, %xmm\i _get_AAD_loop\num_initial_blocks\operation: movd (%r10), \TMP1 @@ -461,15 +462,15 @@ _get_AAD_loop\num_initial_blocks\operation: psrldq $4, %xmm\i pxor \TMP1, %xmm\i add $4, %r10 - sub $4, %r12 + sub $4, %r15 jne _get_AAD_loop\num_initial_blocks\operation cmp $16, %r11 je _get_AAD_loop2_done\num_initial_blocks\operation - mov $16, %r12 + mov $16, %r15 _get_AAD_loop2\num_initial_blocks\operation: psrldq $4, %xmm\i - sub $4, %r12 - cmp %r11, %r12 + sub $4, %r15 + cmp %r11, %r15 jne _get_AAD_loop2\num_initial_blocks\operation _get_AAD_loop2_done\num_initial_blocks\operation: PSHUFB_XMM %xmm14, %xmm\i # byte-reflect the AAD data @@ -1280,7 +1281,7 @@ _esb_loop_\@: * *****************************************************************************/ ENTRY(aesni_gcm_dec) - push %r12 + push %r15 push %r13 push %r14 mov %rsp, %r14 @@ -1290,8 +1291,8 @@ ENTRY(aesni_gcm_dec) */ sub $VARIABLE_OFFSET, %rsp and $~63, %rsp # align rsp to 64 bytes - mov %arg6, %r12 - movdqu (%r12), %xmm13 # %xmm13 = HashKey + mov %arg6, %r15 + movdqu (%r15), %xmm13 # %xmm13 = HashKey movdqa SHUF_MASK(%rip), %xmm2 PSHUFB_XMM %xmm2, %xmm13 @@ -1319,10 +1320,10 @@ ENTRY(aesni_gcm_dec) movdqa %xmm13, HashKey(%rsp) # store HashKey<<1 (mod poly) mov %arg4, %r13 # save the number of bytes of plaintext/ciphertext and $-16, %r13 # %r13 = %r13 - (%r13 mod 16) - mov %r13, %r12 - and $(3<<4), %r12 + mov %r13, %r15 + and $(3<<4), %r15 jz _initial_num_blocks_is_0_decrypt - cmp $(2<<4), %r12 + cmp $(2<<4), %r15 jb _initial_num_blocks_is_1_decrypt je _initial_num_blocks_is_2_decrypt _initial_num_blocks_is_3_decrypt: @@ -1372,16 +1373,16 @@ _zero_cipher_left_decrypt: sub $16, %r11 add %r13, %r11 movdqu (%arg3,%r11,1), %xmm1 # receive the last <16 byte block - lea SHIFT_MASK+16(%rip), %r12 - sub %r13, %r12 + lea SHIFT_MASK+16(%rip), %r15 + sub %r13, %r15 # adjust the shuffle mask pointer to be able to shift 16-%r13 bytes # (%r13 is the number of bytes in plaintext mod 16) - movdqu (%r12), %xmm2 # get the appropriate shuffle mask + movdqu (%r15), %xmm2 # get the appropriate shuffle mask PSHUFB_XMM %xmm2, %xmm1 # right shift 16-%r13 butes movdqa %xmm1, %xmm2 pxor %xmm1, %xmm0 # Ciphertext XOR E(K, Yn) - movdqu ALL_F-SHIFT_MASK(%r12), %xmm1 + movdqu ALL_F-SHIFT_MASK(%r15), %xmm1 # get the appropriate mask to mask out top 16-%r13 bytes of %xmm0 pand %xmm1, %xmm0 # mask out top 16-%r13 bytes of %xmm0 pand %xmm1, %xmm2 @@ -1410,9 +1411,9 @@ _less_than_8_bytes_left_decrypt: sub $1, %r13 jne _less_than_8_bytes_left_decrypt _multiple_of_16_bytes_decrypt: - mov arg8, %r12 # %r13 = aadLen (number of bytes) - shl $3, %r12 # convert into number of bits - movd %r12d, %xmm15 # len(A) in %xmm15 + mov arg8, %r15 # %r13 = aadLen (number of bytes) + shl $3, %r15 # convert into number of bits + movd %r15d, %xmm15 # len(A) in %xmm15 shl $3, %arg4 # len(C) in bits (*128) MOVQ_R64_XMM %arg4, %xmm1 pslldq $8, %xmm15 # %xmm15 = len(A)||0x0000000000000000 @@ -1451,7 +1452,8 @@ _return_T_done_decrypt: mov %r14, %rsp pop %r14 pop %r13 - pop %r12 + pop %r15 + pax_force_retaddr ret ENDPROC(aesni_gcm_dec) @@ -1540,7 +1542,7 @@ ENDPROC(aesni_gcm_dec) * poly = x^128 + x^127 + x^126 + x^121 + 1 ***************************************************************************/ ENTRY(aesni_gcm_enc) - push %r12 + push %r15 push %r13 push %r14 mov %rsp, %r14 @@ -1550,8 +1552,8 @@ ENTRY(aesni_gcm_enc) # sub $VARIABLE_OFFSET, %rsp and $~63, %rsp - mov %arg6, %r12 - movdqu (%r12), %xmm13 + mov %arg6, %r15 + movdqu (%r15), %xmm13 movdqa SHUF_MASK(%rip), %xmm2 PSHUFB_XMM %xmm2, %xmm13 @@ -1575,13 +1577,13 @@ ENTRY(aesni_gcm_enc) movdqa %xmm13, HashKey(%rsp) mov %arg4, %r13 # %xmm13 holds HashKey<<1 (mod poly) and $-16, %r13 - mov %r13, %r12 + mov %r13, %r15 # Encrypt first few blocks - and $(3<<4), %r12 + and $(3<<4), %r15 jz _initial_num_blocks_is_0_encrypt - cmp $(2<<4), %r12 + cmp $(2<<4), %r15 jb _initial_num_blocks_is_1_encrypt je _initial_num_blocks_is_2_encrypt _initial_num_blocks_is_3_encrypt: @@ -1634,14 +1636,14 @@ _zero_cipher_left_encrypt: sub $16, %r11 add %r13, %r11 movdqu (%arg3,%r11,1), %xmm1 # receive the last <16 byte blocks - lea SHIFT_MASK+16(%rip), %r12 - sub %r13, %r12 + lea SHIFT_MASK+16(%rip), %r15 + sub %r13, %r15 # adjust the shuffle mask pointer to be able to shift 16-r13 bytes # (%r13 is the number of bytes in plaintext mod 16) - movdqu (%r12), %xmm2 # get the appropriate shuffle mask + movdqu (%r15), %xmm2 # get the appropriate shuffle mask PSHUFB_XMM %xmm2, %xmm1 # shift right 16-r13 byte pxor %xmm1, %xmm0 # Plaintext XOR Encrypt(K, Yn) - movdqu ALL_F-SHIFT_MASK(%r12), %xmm1 + movdqu ALL_F-SHIFT_MASK(%r15), %xmm1 # get the appropriate mask to mask out top 16-r13 bytes of xmm0 pand %xmm1, %xmm0 # mask out top 16-r13 bytes of xmm0 movdqa SHUF_MASK(%rip), %xmm10 @@ -1674,9 +1676,9 @@ _less_than_8_bytes_left_encrypt: sub $1, %r13 jne _less_than_8_bytes_left_encrypt _multiple_of_16_bytes_encrypt: - mov arg8, %r12 # %r12 = addLen (number of bytes) - shl $3, %r12 - movd %r12d, %xmm15 # len(A) in %xmm15 + mov arg8, %r15 # %r15 = addLen (number of bytes) + shl $3, %r15 + movd %r15d, %xmm15 # len(A) in %xmm15 shl $3, %arg4 # len(C) in bits (*128) MOVQ_R64_XMM %arg4, %xmm1 pslldq $8, %xmm15 # %xmm15 = len(A)||0x0000000000000000 @@ -1715,7 +1717,8 @@ _return_T_done_encrypt: mov %r14, %rsp pop %r14 pop %r13 - pop %r12 + pop %r15 + pax_force_retaddr ret ENDPROC(aesni_gcm_enc) @@ -1733,6 +1736,7 @@ _key_expansion_256a: pxor %xmm1, %xmm0 movaps %xmm0, (TKEYP) add $0x10, TKEYP + pax_force_retaddr ret ENDPROC(_key_expansion_128) ENDPROC(_key_expansion_256a) @@ -1759,6 +1763,7 @@ _key_expansion_192a: shufps $0b01001110, %xmm2, %xmm1 movaps %xmm1, 0x10(TKEYP) add $0x20, TKEYP + pax_force_retaddr ret ENDPROC(_key_expansion_192a) @@ -1779,6 +1784,7 @@ _key_expansion_192b: movaps %xmm0, (TKEYP) add $0x10, TKEYP + pax_force_retaddr ret ENDPROC(_key_expansion_192b) @@ -1792,6 +1798,7 @@ _key_expansion_256b: pxor %xmm1, %xmm2 movaps %xmm2, (TKEYP) add $0x10, TKEYP + pax_force_retaddr ret ENDPROC(_key_expansion_256b) @@ -1905,6 +1912,7 @@ ENTRY(aesni_set_key) #ifndef __x86_64__ popl KEYP #endif + pax_force_retaddr ret ENDPROC(aesni_set_key) @@ -1927,6 +1935,7 @@ ENTRY(aesni_enc) popl KLEN popl KEYP #endif + pax_force_retaddr ret ENDPROC(aesni_enc) @@ -1985,6 +1994,7 @@ _aesni_enc1: AESENC KEY STATE movaps 0x70(TKEYP), KEY AESENCLAST KEY STATE + pax_force_retaddr ret ENDPROC(_aesni_enc1) @@ -2094,6 +2104,7 @@ _aesni_enc4: AESENCLAST KEY STATE2 AESENCLAST KEY STATE3 AESENCLAST KEY STATE4 + pax_force_retaddr ret ENDPROC(_aesni_enc4) @@ -2117,6 +2128,7 @@ ENTRY(aesni_dec) popl KLEN popl KEYP #endif + pax_force_retaddr ret ENDPROC(aesni_dec) @@ -2175,6 +2187,7 @@ _aesni_dec1: AESDEC KEY STATE movaps 0x70(TKEYP), KEY AESDECLAST KEY STATE + pax_force_retaddr ret ENDPROC(_aesni_dec1) @@ -2284,6 +2297,7 @@ _aesni_dec4: AESDECLAST KEY STATE2 AESDECLAST KEY STATE3 AESDECLAST KEY STATE4 + pax_force_retaddr ret ENDPROC(_aesni_dec4) @@ -2342,6 +2356,7 @@ ENTRY(aesni_ecb_enc) popl KEYP popl LEN #endif + pax_force_retaddr ret ENDPROC(aesni_ecb_enc) @@ -2401,6 +2416,7 @@ ENTRY(aesni_ecb_dec) popl KEYP popl LEN #endif + pax_force_retaddr ret ENDPROC(aesni_ecb_dec) @@ -2443,6 +2459,7 @@ ENTRY(aesni_cbc_enc) popl LEN popl IVP #endif + pax_force_retaddr ret ENDPROC(aesni_cbc_enc) @@ -2534,6 +2551,7 @@ ENTRY(aesni_cbc_dec) popl LEN popl IVP #endif + pax_force_retaddr ret ENDPROC(aesni_cbc_dec) @@ -2561,6 +2579,7 @@ _aesni_inc_init: mov $1, TCTR_LOW MOVQ_R64_XMM TCTR_LOW INC MOVQ_R64_XMM CTR TCTR_LOW + pax_force_retaddr ret ENDPROC(_aesni_inc_init) @@ -2590,6 +2609,7 @@ _aesni_inc: .Linc_low: movaps CTR, IV PSHUFB_XMM BSWAP_MASK IV + pax_force_retaddr ret ENDPROC(_aesni_inc) @@ -2651,6 +2671,7 @@ ENTRY(aesni_ctr_enc) .Lctr_enc_ret: movups IV, (IVP) .Lctr_enc_just_ret: + pax_force_retaddr ret ENDPROC(aesni_ctr_enc) @@ -2777,6 +2798,7 @@ ENTRY(aesni_xts_crypt8) pxor INC, STATE4 movdqu STATE4, 0x70(OUTP) + pax_force_retaddr ret ENDPROC(aesni_xts_crypt8) diff --git a/arch/x86/crypto/blowfish-x86_64-asm_64.S b/arch/x86/crypto/blowfish-x86_64-asm_64.S index 246c670..466e2d6 100644 --- a/arch/x86/crypto/blowfish-x86_64-asm_64.S +++ b/arch/x86/crypto/blowfish-x86_64-asm_64.S @@ -21,6 +21,7 @@ */ #include +#include .file "blowfish-x86_64-asm.S" .text @@ -149,9 +150,11 @@ ENTRY(__blowfish_enc_blk) jnz .L__enc_xor; write_block(); + pax_force_retaddr ret; .L__enc_xor: xor_block(); + pax_force_retaddr ret; ENDPROC(__blowfish_enc_blk) @@ -183,6 +186,7 @@ ENTRY(blowfish_dec_blk) movq %r11, %rbp; + pax_force_retaddr ret; ENDPROC(blowfish_dec_blk) @@ -334,6 +338,7 @@ ENTRY(__blowfish_enc_blk_4way) popq %rbx; popq %rbp; + pax_force_retaddr ret; .L__enc_xor4: @@ -341,6 +346,7 @@ ENTRY(__blowfish_enc_blk_4way) popq %rbx; popq %rbp; + pax_force_retaddr ret; ENDPROC(__blowfish_enc_blk_4way) @@ -375,5 +381,6 @@ ENTRY(blowfish_dec_blk_4way) popq %rbx; popq %rbp; + pax_force_retaddr ret; ENDPROC(blowfish_dec_blk_4way) diff --git a/arch/x86/crypto/camellia-aesni-avx-asm_64.S b/arch/x86/crypto/camellia-aesni-avx-asm_64.S index ce71f92..1dce7ec 100644 --- a/arch/x86/crypto/camellia-aesni-avx-asm_64.S +++ b/arch/x86/crypto/camellia-aesni-avx-asm_64.S @@ -16,6 +16,7 @@ */ #include +#include #define CAMELLIA_TABLE_BYTE_LEN 272 @@ -191,6 +192,7 @@ roundsm16_x0_x1_x2_x3_x4_x5_x6_x7_y0_y1_y2_y3_y4_y5_y6_y7_cd: roundsm16(%xmm0, %xmm1, %xmm2, %xmm3, %xmm4, %xmm5, %xmm6, %xmm7, %xmm8, %xmm9, %xmm10, %xmm11, %xmm12, %xmm13, %xmm14, %xmm15, %rcx, (%r9)); + pax_force_retaddr ret; ENDPROC(roundsm16_x0_x1_x2_x3_x4_x5_x6_x7_y0_y1_y2_y3_y4_y5_y6_y7_cd) @@ -199,6 +201,7 @@ roundsm16_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab: roundsm16(%xmm4, %xmm5, %xmm6, %xmm7, %xmm0, %xmm1, %xmm2, %xmm3, %xmm12, %xmm13, %xmm14, %xmm15, %xmm8, %xmm9, %xmm10, %xmm11, %rax, (%r9)); + pax_force_retaddr ret; ENDPROC(roundsm16_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab) @@ -780,6 +783,7 @@ __camellia_enc_blk16: %xmm8, %xmm9, %xmm10, %xmm11, %xmm12, %xmm13, %xmm14, %xmm15, (key_table)(CTX, %r8, 8), (%rax), 1 * 16(%rax)); + pax_force_retaddr ret; .align 8 @@ -865,6 +869,7 @@ __camellia_dec_blk16: %xmm8, %xmm9, %xmm10, %xmm11, %xmm12, %xmm13, %xmm14, %xmm15, (key_table)(CTX), (%rax), 1 * 16(%rax)); + pax_force_retaddr ret; .align 8 @@ -904,6 +909,7 @@ ENTRY(camellia_ecb_enc_16way) %xmm15, %xmm14, %xmm13, %xmm12, %xmm11, %xmm10, %xmm9, %xmm8, %rsi); + pax_force_retaddr ret; ENDPROC(camellia_ecb_enc_16way) @@ -932,6 +938,7 @@ ENTRY(camellia_ecb_dec_16way) %xmm15, %xmm14, %xmm13, %xmm12, %xmm11, %xmm10, %xmm9, %xmm8, %rsi); + pax_force_retaddr ret; ENDPROC(camellia_ecb_dec_16way) @@ -981,6 +988,7 @@ ENTRY(camellia_cbc_dec_16way) %xmm15, %xmm14, %xmm13, %xmm12, %xmm11, %xmm10, %xmm9, %xmm8, %rsi); + pax_force_retaddr ret; ENDPROC(camellia_cbc_dec_16way) @@ -1092,6 +1100,7 @@ ENTRY(camellia_ctr_16way) %xmm15, %xmm14, %xmm13, %xmm12, %xmm11, %xmm10, %xmm9, %xmm8, %rsi); + pax_force_retaddr ret; ENDPROC(camellia_ctr_16way) @@ -1234,6 +1243,7 @@ camellia_xts_crypt_16way: %xmm15, %xmm14, %xmm13, %xmm12, %xmm11, %xmm10, %xmm9, %xmm8, %rsi); + pax_force_retaddr ret; ENDPROC(camellia_xts_crypt_16way) diff --git a/arch/x86/crypto/camellia-aesni-avx2-asm_64.S b/arch/x86/crypto/camellia-aesni-avx2-asm_64.S index 0e0b886..5a3123c 100644 --- a/arch/x86/crypto/camellia-aesni-avx2-asm_64.S +++ b/arch/x86/crypto/camellia-aesni-avx2-asm_64.S @@ -11,6 +11,7 @@ */ #include +#include #define CAMELLIA_TABLE_BYTE_LEN 272 @@ -230,6 +231,7 @@ roundsm32_x0_x1_x2_x3_x4_x5_x6_x7_y0_y1_y2_y3_y4_y5_y6_y7_cd: roundsm32(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7, %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, %ymm15, %rcx, (%r9)); + pax_force_retaddr ret; ENDPROC(roundsm32_x0_x1_x2_x3_x4_x5_x6_x7_y0_y1_y2_y3_y4_y5_y6_y7_cd) @@ -238,6 +240,7 @@ roundsm32_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab: roundsm32(%ymm4, %ymm5, %ymm6, %ymm7, %ymm0, %ymm1, %ymm2, %ymm3, %ymm12, %ymm13, %ymm14, %ymm15, %ymm8, %ymm9, %ymm10, %ymm11, %rax, (%r9)); + pax_force_retaddr ret; ENDPROC(roundsm32_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab) @@ -820,6 +823,7 @@ __camellia_enc_blk32: %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, %ymm15, (key_table)(CTX, %r8, 8), (%rax), 1 * 32(%rax)); + pax_force_retaddr ret; .align 8 @@ -905,6 +909,7 @@ __camellia_dec_blk32: %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, %ymm15, (key_table)(CTX), (%rax), 1 * 32(%rax)); + pax_force_retaddr ret; .align 8 @@ -948,6 +953,7 @@ ENTRY(camellia_ecb_enc_32way) vzeroupper; + pax_force_retaddr ret; ENDPROC(camellia_ecb_enc_32way) @@ -980,6 +986,7 @@ ENTRY(camellia_ecb_dec_32way) vzeroupper; + pax_force_retaddr ret; ENDPROC(camellia_ecb_dec_32way) @@ -1046,6 +1053,7 @@ ENTRY(camellia_cbc_dec_32way) vzeroupper; + pax_force_retaddr ret; ENDPROC(camellia_cbc_dec_32way) @@ -1184,6 +1192,7 @@ ENTRY(camellia_ctr_32way) vzeroupper; + pax_force_retaddr ret; ENDPROC(camellia_ctr_32way) @@ -1349,6 +1358,7 @@ camellia_xts_crypt_32way: vzeroupper; + pax_force_retaddr ret; ENDPROC(camellia_xts_crypt_32way) diff --git a/arch/x86/crypto/camellia-x86_64-asm_64.S b/arch/x86/crypto/camellia-x86_64-asm_64.S index 310319c..db3d7b5 100644 --- a/arch/x86/crypto/camellia-x86_64-asm_64.S +++ b/arch/x86/crypto/camellia-x86_64-asm_64.S @@ -21,6 +21,7 @@ */ #include +#include .file "camellia-x86_64-asm_64.S" .text @@ -228,12 +229,14 @@ ENTRY(__camellia_enc_blk) enc_outunpack(mov, RT1); movq RRBP, %rbp; + pax_force_retaddr ret; .L__enc_xor: enc_outunpack(xor, RT1); movq RRBP, %rbp; + pax_force_retaddr ret; ENDPROC(__camellia_enc_blk) @@ -272,6 +275,7 @@ ENTRY(camellia_dec_blk) dec_outunpack(); movq RRBP, %rbp; + pax_force_retaddr ret; ENDPROC(camellia_dec_blk) @@ -463,6 +467,7 @@ ENTRY(__camellia_enc_blk_2way) movq RRBP, %rbp; popq %rbx; + pax_force_retaddr ret; .L__enc2_xor: @@ -470,6 +475,7 @@ ENTRY(__camellia_enc_blk_2way) movq RRBP, %rbp; popq %rbx; + pax_force_retaddr ret; ENDPROC(__camellia_enc_blk_2way) @@ -510,5 +516,6 @@ ENTRY(camellia_dec_blk_2way) movq RRBP, %rbp; movq RXOR, %rbx; + pax_force_retaddr ret; ENDPROC(camellia_dec_blk_2way) diff --git a/arch/x86/crypto/cast5-avx-x86_64-asm_64.S b/arch/x86/crypto/cast5-avx-x86_64-asm_64.S index c35fd5d..2d8c7db 100644 --- a/arch/x86/crypto/cast5-avx-x86_64-asm_64.S +++ b/arch/x86/crypto/cast5-avx-x86_64-asm_64.S @@ -24,6 +24,7 @@ */ #include +#include .file "cast5-avx-x86_64-asm_64.S" @@ -281,6 +282,7 @@ __cast5_enc_blk16: outunpack_blocks(RR3, RL3, RTMP, RX, RKM); outunpack_blocks(RR4, RL4, RTMP, RX, RKM); + pax_force_retaddr ret; ENDPROC(__cast5_enc_blk16) @@ -352,6 +354,7 @@ __cast5_dec_blk16: outunpack_blocks(RR3, RL3, RTMP, RX, RKM); outunpack_blocks(RR4, RL4, RTMP, RX, RKM); + pax_force_retaddr ret; .L__skip_dec: @@ -388,6 +391,7 @@ ENTRY(cast5_ecb_enc_16way) vmovdqu RR4, (6*4*4)(%r11); vmovdqu RL4, (7*4*4)(%r11); + pax_force_retaddr ret; ENDPROC(cast5_ecb_enc_16way) @@ -420,6 +424,7 @@ ENTRY(cast5_ecb_dec_16way) vmovdqu RR4, (6*4*4)(%r11); vmovdqu RL4, (7*4*4)(%r11); + pax_force_retaddr ret; ENDPROC(cast5_ecb_dec_16way) @@ -430,10 +435,10 @@ ENTRY(cast5_cbc_dec_16way) * %rdx: src */ - pushq %r12; + pushq %r14; movq %rsi, %r11; - movq %rdx, %r12; + movq %rdx, %r14; vmovdqu (0*16)(%rdx), RL1; vmovdqu (1*16)(%rdx), RR1; @@ -447,16 +452,16 @@ ENTRY(cast5_cbc_dec_16way) call __cast5_dec_blk16; /* xor with src */ - vmovq (%r12), RX; + vmovq (%r14), RX; vpshufd $0x4f, RX, RX; vpxor RX, RR1, RR1; - vpxor 0*16+8(%r12), RL1, RL1; - vpxor 1*16+8(%r12), RR2, RR2; - vpxor 2*16+8(%r12), RL2, RL2; - vpxor 3*16+8(%r12), RR3, RR3; - vpxor 4*16+8(%r12), RL3, RL3; - vpxor 5*16+8(%r12), RR4, RR4; - vpxor 6*16+8(%r12), RL4, RL4; + vpxor 0*16+8(%r14), RL1, RL1; + vpxor 1*16+8(%r14), RR2, RR2; + vpxor 2*16+8(%r14), RL2, RL2; + vpxor 3*16+8(%r14), RR3, RR3; + vpxor 4*16+8(%r14), RL3, RL3; + vpxor 5*16+8(%r14), RR4, RR4; + vpxor 6*16+8(%r14), RL4, RL4; vmovdqu RR1, (0*16)(%r11); vmovdqu RL1, (1*16)(%r11); @@ -467,8 +472,9 @@ ENTRY(cast5_cbc_dec_16way) vmovdqu RR4, (6*16)(%r11); vmovdqu RL4, (7*16)(%r11); - popq %r12; + popq %r14; + pax_force_retaddr ret; ENDPROC(cast5_cbc_dec_16way) @@ -480,10 +486,10 @@ ENTRY(cast5_ctr_16way) * %rcx: iv (big endian, 64bit) */ - pushq %r12; + pushq %r14; movq %rsi, %r11; - movq %rdx, %r12; + movq %rdx, %r14; vpcmpeqd RTMP, RTMP, RTMP; vpsrldq $8, RTMP, RTMP; /* low: -1, high: 0 */ @@ -523,14 +529,14 @@ ENTRY(cast5_ctr_16way) call __cast5_enc_blk16; /* dst = src ^ iv */ - vpxor (0*16)(%r12), RR1, RR1; - vpxor (1*16)(%r12), RL1, RL1; - vpxor (2*16)(%r12), RR2, RR2; - vpxor (3*16)(%r12), RL2, RL2; - vpxor (4*16)(%r12), RR3, RR3; - vpxor (5*16)(%r12), RL3, RL3; - vpxor (6*16)(%r12), RR4, RR4; - vpxor (7*16)(%r12), RL4, RL4; + vpxor (0*16)(%r14), RR1, RR1; + vpxor (1*16)(%r14), RL1, RL1; + vpxor (2*16)(%r14), RR2, RR2; + vpxor (3*16)(%r14), RL2, RL2; + vpxor (4*16)(%r14), RR3, RR3; + vpxor (5*16)(%r14), RL3, RL3; + vpxor (6*16)(%r14), RR4, RR4; + vpxor (7*16)(%r14), RL4, RL4; vmovdqu RR1, (0*16)(%r11); vmovdqu RL1, (1*16)(%r11); vmovdqu RR2, (2*16)(%r11); @@ -540,7 +546,8 @@ ENTRY(cast5_ctr_16way) vmovdqu RR4, (6*16)(%r11); vmovdqu RL4, (7*16)(%r11); - popq %r12; + popq %r14; + pax_force_retaddr ret; ENDPROC(cast5_ctr_16way) diff --git a/arch/x86/crypto/cast6-avx-x86_64-asm_64.S b/arch/x86/crypto/cast6-avx-x86_64-asm_64.S index e3531f8..e123f35 100644 --- a/arch/x86/crypto/cast6-avx-x86_64-asm_64.S +++ b/arch/x86/crypto/cast6-avx-x86_64-asm_64.S @@ -24,6 +24,7 @@ */ #include +#include #include "glue_helper-asm-avx.S" .file "cast6-avx-x86_64-asm_64.S" @@ -295,6 +296,7 @@ __cast6_enc_blk8: outunpack_blocks(RA1, RB1, RC1, RD1, RTMP, RX, RKRF, RKM); outunpack_blocks(RA2, RB2, RC2, RD2, RTMP, RX, RKRF, RKM); + pax_force_retaddr ret; ENDPROC(__cast6_enc_blk8) @@ -340,6 +342,7 @@ __cast6_dec_blk8: outunpack_blocks(RA1, RB1, RC1, RD1, RTMP, RX, RKRF, RKM); outunpack_blocks(RA2, RB2, RC2, RD2, RTMP, RX, RKRF, RKM); + pax_force_retaddr ret; ENDPROC(__cast6_dec_blk8) @@ -358,6 +361,7 @@ ENTRY(cast6_ecb_enc_8way) store_8way(%r11, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2); + pax_force_retaddr ret; ENDPROC(cast6_ecb_enc_8way) @@ -376,6 +380,7 @@ ENTRY(cast6_ecb_dec_8way) store_8way(%r11, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2); + pax_force_retaddr ret; ENDPROC(cast6_ecb_dec_8way) @@ -386,19 +391,20 @@ ENTRY(cast6_cbc_dec_8way) * %rdx: src */ - pushq %r12; + pushq %r14; movq %rsi, %r11; - movq %rdx, %r12; + movq %rdx, %r14; load_8way(%rdx, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2); call __cast6_dec_blk8; - store_cbc_8way(%r12, %r11, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2); + store_cbc_8way(%r14, %r11, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2); - popq %r12; + popq %r14; + pax_force_retaddr ret; ENDPROC(cast6_cbc_dec_8way) @@ -410,20 +416,21 @@ ENTRY(cast6_ctr_8way) * %rcx: iv (little endian, 128bit) */ - pushq %r12; + pushq %r14; movq %rsi, %r11; - movq %rdx, %r12; + movq %rdx, %r14; load_ctr_8way(%rcx, .Lbswap128_mask, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2, RX, RKR, RKM); call __cast6_enc_blk8; - store_ctr_8way(%r12, %r11, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2); + store_ctr_8way(%r14, %r11, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2); - popq %r12; + popq %r14; + pax_force_retaddr ret; ENDPROC(cast6_ctr_8way) @@ -446,6 +453,7 @@ ENTRY(cast6_xts_enc_8way) /* dst <= regs xor IVs(in dst) */ store_xts_8way(%r11, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2); + pax_force_retaddr ret; ENDPROC(cast6_xts_enc_8way) @@ -468,5 +476,6 @@ ENTRY(cast6_xts_dec_8way) /* dst <= regs xor IVs(in dst) */ store_xts_8way(%r11, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2); + pax_force_retaddr ret; ENDPROC(cast6_xts_dec_8way) diff --git a/arch/x86/crypto/crc32c-pcl-intel-asm_64.S b/arch/x86/crypto/crc32c-pcl-intel-asm_64.S index 225be06..2885e731 100644 --- a/arch/x86/crypto/crc32c-pcl-intel-asm_64.S +++ b/arch/x86/crypto/crc32c-pcl-intel-asm_64.S @@ -45,6 +45,7 @@ #include #include +#include ## ISCSI CRC 32 Implementation with crc32 and pclmulqdq Instruction @@ -309,6 +310,7 @@ do_return: popq %rsi popq %rdi popq %rbx + pax_force_retaddr ret ################################################################ @@ -330,7 +332,7 @@ ENDPROC(crc_pcl) ## PCLMULQDQ tables ## Table is 128 entries x 2 words (8 bytes) each ################################################################ -.section .rotata, "a", %progbits +.section .rodata, "a", %progbits .align 8 K_table: .long 0x493c7d27, 0x00000001 diff --git a/arch/x86/crypto/ghash-clmulni-intel_asm.S b/arch/x86/crypto/ghash-clmulni-intel_asm.S index 5d1e007..098cb4f 100644 --- a/arch/x86/crypto/ghash-clmulni-intel_asm.S +++ b/arch/x86/crypto/ghash-clmulni-intel_asm.S @@ -18,6 +18,7 @@ #include #include +#include .data @@ -89,6 +90,7 @@ __clmul_gf128mul_ble: psrlq $1, T2 pxor T2, T1 pxor T1, DATA + pax_force_retaddr ret ENDPROC(__clmul_gf128mul_ble) @@ -101,6 +103,7 @@ ENTRY(clmul_ghash_mul) call __clmul_gf128mul_ble PSHUFB_XMM BSWAP DATA movups DATA, (%rdi) + pax_force_retaddr ret ENDPROC(clmul_ghash_mul) @@ -128,5 +131,6 @@ ENTRY(clmul_ghash_update) PSHUFB_XMM BSWAP DATA movups DATA, (%rdi) .Lupdate_just_ret: + pax_force_retaddr ret ENDPROC(clmul_ghash_update) diff --git a/arch/x86/crypto/salsa20-x86_64-asm_64.S b/arch/x86/crypto/salsa20-x86_64-asm_64.S index 9279e0b..c4b3d2c 100644 --- a/arch/x86/crypto/salsa20-x86_64-asm_64.S +++ b/arch/x86/crypto/salsa20-x86_64-asm_64.S @@ -1,4 +1,5 @@ #include +#include # enter salsa20_encrypt_bytes ENTRY(salsa20_encrypt_bytes) @@ -789,6 +790,7 @@ ENTRY(salsa20_encrypt_bytes) add %r11,%rsp mov %rdi,%rax mov %rsi,%rdx + pax_force_retaddr ret # bytesatleast65: ._bytesatleast65: @@ -889,6 +891,7 @@ ENTRY(salsa20_keysetup) add %r11,%rsp mov %rdi,%rax mov %rsi,%rdx + pax_force_retaddr ret ENDPROC(salsa20_keysetup) @@ -914,5 +917,6 @@ ENTRY(salsa20_ivsetup) add %r11,%rsp mov %rdi,%rax mov %rsi,%rdx + pax_force_retaddr ret ENDPROC(salsa20_ivsetup) diff --git a/arch/x86/crypto/serpent-avx-x86_64-asm_64.S b/arch/x86/crypto/serpent-avx-x86_64-asm_64.S index 2f202f4..d9164d6 100644 --- a/arch/x86/crypto/serpent-avx-x86_64-asm_64.S +++ b/arch/x86/crypto/serpent-avx-x86_64-asm_64.S @@ -24,6 +24,7 @@ */ #include +#include #include "glue_helper-asm-avx.S" .file "serpent-avx-x86_64-asm_64.S" @@ -618,6 +619,7 @@ __serpent_enc_blk8_avx: write_blocks(RA1, RB1, RC1, RD1, RK0, RK1, RK2); write_blocks(RA2, RB2, RC2, RD2, RK0, RK1, RK2); + pax_force_retaddr ret; ENDPROC(__serpent_enc_blk8_avx) @@ -672,6 +674,7 @@ __serpent_dec_blk8_avx: write_blocks(RC1, RD1, RB1, RE1, RK0, RK1, RK2); write_blocks(RC2, RD2, RB2, RE2, RK0, RK1, RK2); + pax_force_retaddr ret; ENDPROC(__serpent_dec_blk8_avx) @@ -688,6 +691,7 @@ ENTRY(serpent_ecb_enc_8way_avx) store_8way(%rsi, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2); + pax_force_retaddr ret; ENDPROC(serpent_ecb_enc_8way_avx) @@ -704,6 +708,7 @@ ENTRY(serpent_ecb_dec_8way_avx) store_8way(%rsi, RC1, RD1, RB1, RE1, RC2, RD2, RB2, RE2); + pax_force_retaddr ret; ENDPROC(serpent_ecb_dec_8way_avx) @@ -720,6 +725,7 @@ ENTRY(serpent_cbc_dec_8way_avx) store_cbc_8way(%rdx, %rsi, RC1, RD1, RB1, RE1, RC2, RD2, RB2, RE2); + pax_force_retaddr ret; ENDPROC(serpent_cbc_dec_8way_avx) @@ -738,6 +744,7 @@ ENTRY(serpent_ctr_8way_avx) store_ctr_8way(%rdx, %rsi, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2); + pax_force_retaddr ret; ENDPROC(serpent_ctr_8way_avx) @@ -758,6 +765,7 @@ ENTRY(serpent_xts_enc_8way_avx) /* dst <= regs xor IVs(in dst) */ store_xts_8way(%rsi, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2); + pax_force_retaddr ret; ENDPROC(serpent_xts_enc_8way_avx) @@ -778,5 +786,6 @@ ENTRY(serpent_xts_dec_8way_avx) /* dst <= regs xor IVs(in dst) */ store_xts_8way(%rsi, RC1, RD1, RB1, RE1, RC2, RD2, RB2, RE2); + pax_force_retaddr ret; ENDPROC(serpent_xts_dec_8way_avx) diff --git a/arch/x86/crypto/serpent-avx2-asm_64.S b/arch/x86/crypto/serpent-avx2-asm_64.S index b222085..abd483c 100644 --- a/arch/x86/crypto/serpent-avx2-asm_64.S +++ b/arch/x86/crypto/serpent-avx2-asm_64.S @@ -15,6 +15,7 @@ */ #include +#include #include "glue_helper-asm-avx2.S" .file "serpent-avx2-asm_64.S" @@ -610,6 +611,7 @@ __serpent_enc_blk16: write_blocks(RA1, RB1, RC1, RD1, RK0, RK1, RK2); write_blocks(RA2, RB2, RC2, RD2, RK0, RK1, RK2); + pax_force_retaddr ret; ENDPROC(__serpent_enc_blk16) @@ -664,6 +666,7 @@ __serpent_dec_blk16: write_blocks(RC1, RD1, RB1, RE1, RK0, RK1, RK2); write_blocks(RC2, RD2, RB2, RE2, RK0, RK1, RK2); + pax_force_retaddr ret; ENDPROC(__serpent_dec_blk16) @@ -684,6 +687,7 @@ ENTRY(serpent_ecb_enc_16way) vzeroupper; + pax_force_retaddr ret; ENDPROC(serpent_ecb_enc_16way) @@ -704,6 +708,7 @@ ENTRY(serpent_ecb_dec_16way) vzeroupper; + pax_force_retaddr ret; ENDPROC(serpent_ecb_dec_16way) @@ -725,6 +730,7 @@ ENTRY(serpent_cbc_dec_16way) vzeroupper; + pax_force_retaddr ret; ENDPROC(serpent_cbc_dec_16way) @@ -748,6 +754,7 @@ ENTRY(serpent_ctr_16way) vzeroupper; + pax_force_retaddr ret; ENDPROC(serpent_ctr_16way) @@ -772,6 +779,7 @@ ENTRY(serpent_xts_enc_16way) vzeroupper; + pax_force_retaddr ret; ENDPROC(serpent_xts_enc_16way) @@ -796,5 +804,6 @@ ENTRY(serpent_xts_dec_16way) vzeroupper; + pax_force_retaddr ret; ENDPROC(serpent_xts_dec_16way) diff --git a/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S b/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S index acc066c..1559cc4 100644 --- a/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S +++ b/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S @@ -25,6 +25,7 @@ */ #include +#include .file "serpent-sse2-x86_64-asm_64.S" .text @@ -690,12 +691,14 @@ ENTRY(__serpent_enc_blk_8way) write_blocks(%rsi, RA1, RB1, RC1, RD1, RK0, RK1, RK2); write_blocks(%rax, RA2, RB2, RC2, RD2, RK0, RK1, RK2); + pax_force_retaddr ret; .L__enc_xor8: xor_blocks(%rsi, RA1, RB1, RC1, RD1, RK0, RK1, RK2); xor_blocks(%rax, RA2, RB2, RC2, RD2, RK0, RK1, RK2); + pax_force_retaddr ret; ENDPROC(__serpent_enc_blk_8way) @@ -750,5 +753,6 @@ ENTRY(serpent_dec_blk_8way) write_blocks(%rsi, RC1, RD1, RB1, RE1, RK0, RK1, RK2); write_blocks(%rax, RC2, RD2, RB2, RE2, RK0, RK1, RK2); + pax_force_retaddr ret; ENDPROC(serpent_dec_blk_8way) diff --git a/arch/x86/crypto/sha1_ssse3_asm.S b/arch/x86/crypto/sha1_ssse3_asm.S index a410950..9dfe7ad 100644 --- a/arch/x86/crypto/sha1_ssse3_asm.S +++ b/arch/x86/crypto/sha1_ssse3_asm.S @@ -29,6 +29,7 @@ */ #include +#include #define CTX %rdi // arg1 #define BUF %rsi // arg2 @@ -75,9 +76,9 @@ push %rbx push %rbp - push %r12 + push %r14 - mov %rsp, %r12 + mov %rsp, %r14 sub $64, %rsp # allocate workspace and $~15, %rsp # align stack @@ -99,11 +100,12 @@ xor %rax, %rax rep stosq - mov %r12, %rsp # deallocate workspace + mov %r14, %rsp # deallocate workspace - pop %r12 + pop %r14 pop %rbp pop %rbx + pax_force_retaddr ret ENDPROC(\name) diff --git a/arch/x86/crypto/sha256-avx-asm.S b/arch/x86/crypto/sha256-avx-asm.S index 92b3b5d..0dc1dcb 100644 --- a/arch/x86/crypto/sha256-avx-asm.S +++ b/arch/x86/crypto/sha256-avx-asm.S @@ -49,6 +49,7 @@ #ifdef CONFIG_AS_AVX #include +#include ## assume buffers not aligned #define VMOVDQ vmovdqu @@ -460,6 +461,7 @@ done_hash: popq %r13 popq %rbp popq %rbx + pax_force_retaddr ret ENDPROC(sha256_transform_avx) diff --git a/arch/x86/crypto/sha256-avx2-asm.S b/arch/x86/crypto/sha256-avx2-asm.S index 570ec5e..cf2b625 100644 --- a/arch/x86/crypto/sha256-avx2-asm.S +++ b/arch/x86/crypto/sha256-avx2-asm.S @@ -50,6 +50,7 @@ #ifdef CONFIG_AS_AVX2 #include +#include ## assume buffers not aligned #define VMOVDQ vmovdqu @@ -720,6 +721,7 @@ done_hash: popq %r12 popq %rbp popq %rbx + pax_force_retaddr ret ENDPROC(sha256_transform_rorx) diff --git a/arch/x86/crypto/sha256-ssse3-asm.S b/arch/x86/crypto/sha256-ssse3-asm.S index 2cedc44..5144899 100644 --- a/arch/x86/crypto/sha256-ssse3-asm.S +++ b/arch/x86/crypto/sha256-ssse3-asm.S @@ -47,6 +47,7 @@ ######################################################################## #include +#include ## assume buffers not aligned #define MOVDQ movdqu @@ -471,6 +472,7 @@ done_hash: popq %rbp popq %rbx + pax_force_retaddr ret ENDPROC(sha256_transform_ssse3) diff --git a/arch/x86/crypto/sha512-avx-asm.S b/arch/x86/crypto/sha512-avx-asm.S index 565274d..af6bc08 100644 --- a/arch/x86/crypto/sha512-avx-asm.S +++ b/arch/x86/crypto/sha512-avx-asm.S @@ -49,6 +49,7 @@ #ifdef CONFIG_AS_AVX #include +#include .text @@ -364,6 +365,7 @@ updateblock: mov frame_RSPSAVE(%rsp), %rsp nowork: + pax_force_retaddr ret ENDPROC(sha512_transform_avx) diff --git a/arch/x86/crypto/sha512-avx2-asm.S b/arch/x86/crypto/sha512-avx2-asm.S index 1f20b35..f25c8c1 100644 --- a/arch/x86/crypto/sha512-avx2-asm.S +++ b/arch/x86/crypto/sha512-avx2-asm.S @@ -51,6 +51,7 @@ #ifdef CONFIG_AS_AVX2 #include +#include .text @@ -678,6 +679,7 @@ done_hash: # Restore Stack Pointer mov frame_RSPSAVE(%rsp), %rsp + pax_force_retaddr ret ENDPROC(sha512_transform_rorx) diff --git a/arch/x86/crypto/sha512-ssse3-asm.S b/arch/x86/crypto/sha512-ssse3-asm.S index e610e29..ffcb5ed 100644 --- a/arch/x86/crypto/sha512-ssse3-asm.S +++ b/arch/x86/crypto/sha512-ssse3-asm.S @@ -48,6 +48,7 @@ ######################################################################## #include +#include .text @@ -363,6 +364,7 @@ updateblock: mov frame_RSPSAVE(%rsp), %rsp nowork: + pax_force_retaddr ret ENDPROC(sha512_transform_ssse3) diff --git a/arch/x86/crypto/twofish-avx-x86_64-asm_64.S b/arch/x86/crypto/twofish-avx-x86_64-asm_64.S index 0505813..b067311 100644 --- a/arch/x86/crypto/twofish-avx-x86_64-asm_64.S +++ b/arch/x86/crypto/twofish-avx-x86_64-asm_64.S @@ -24,6 +24,7 @@ */ #include +#include #include "glue_helper-asm-avx.S" .file "twofish-avx-x86_64-asm_64.S" @@ -284,6 +285,7 @@ __twofish_enc_blk8: outunpack_blocks(RC1, RD1, RA1, RB1, RK1, RX0, RY0, RK2); outunpack_blocks(RC2, RD2, RA2, RB2, RK1, RX0, RY0, RK2); + pax_force_retaddr ret; ENDPROC(__twofish_enc_blk8) @@ -324,6 +326,7 @@ __twofish_dec_blk8: outunpack_blocks(RA1, RB1, RC1, RD1, RK1, RX0, RY0, RK2); outunpack_blocks(RA2, RB2, RC2, RD2, RK1, RX0, RY0, RK2); + pax_force_retaddr ret; ENDPROC(__twofish_dec_blk8) @@ -342,6 +345,7 @@ ENTRY(twofish_ecb_enc_8way) store_8way(%r11, RC1, RD1, RA1, RB1, RC2, RD2, RA2, RB2); + pax_force_retaddr ret; ENDPROC(twofish_ecb_enc_8way) @@ -360,6 +364,7 @@ ENTRY(twofish_ecb_dec_8way) store_8way(%r11, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2); + pax_force_retaddr ret; ENDPROC(twofish_ecb_dec_8way) @@ -370,19 +375,20 @@ ENTRY(twofish_cbc_dec_8way) * %rdx: src */ - pushq %r12; + pushq %r14; movq %rsi, %r11; - movq %rdx, %r12; + movq %rdx, %r14; load_8way(%rdx, RC1, RD1, RA1, RB1, RC2, RD2, RA2, RB2); call __twofish_dec_blk8; - store_cbc_8way(%r12, %r11, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2); + store_cbc_8way(%r14, %r11, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2); - popq %r12; + popq %r14; + pax_force_retaddr ret; ENDPROC(twofish_cbc_dec_8way) @@ -394,20 +400,21 @@ ENTRY(twofish_ctr_8way) * %rcx: iv (little endian, 128bit) */ - pushq %r12; + pushq %r14; movq %rsi, %r11; - movq %rdx, %r12; + movq %rdx, %r14; load_ctr_8way(%rcx, .Lbswap128_mask, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2, RX0, RX1, RY0); call __twofish_enc_blk8; - store_ctr_8way(%r12, %r11, RC1, RD1, RA1, RB1, RC2, RD2, RA2, RB2); + store_ctr_8way(%r14, %r11, RC1, RD1, RA1, RB1, RC2, RD2, RA2, RB2); - popq %r12; + popq %r14; + pax_force_retaddr ret; ENDPROC(twofish_ctr_8way) @@ -430,6 +437,7 @@ ENTRY(twofish_xts_enc_8way) /* dst <= regs xor IVs(in dst) */ store_xts_8way(%r11, RC1, RD1, RA1, RB1, RC2, RD2, RA2, RB2); + pax_force_retaddr ret; ENDPROC(twofish_xts_enc_8way) @@ -452,5 +460,6 @@ ENTRY(twofish_xts_dec_8way) /* dst <= regs xor IVs(in dst) */ store_xts_8way(%r11, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2); + pax_force_retaddr ret; ENDPROC(twofish_xts_dec_8way) diff --git a/arch/x86/crypto/twofish-x86_64-asm_64-3way.S b/arch/x86/crypto/twofish-x86_64-asm_64-3way.S index 1c3b7ce..02f578d 100644 --- a/arch/x86/crypto/twofish-x86_64-asm_64-3way.S +++ b/arch/x86/crypto/twofish-x86_64-asm_64-3way.S @@ -21,6 +21,7 @@ */ #include +#include .file "twofish-x86_64-asm-3way.S" .text @@ -258,6 +259,7 @@ ENTRY(__twofish_enc_blk_3way) popq %r13; popq %r14; popq %r15; + pax_force_retaddr ret; .L__enc_xor3: @@ -269,6 +271,7 @@ ENTRY(__twofish_enc_blk_3way) popq %r13; popq %r14; popq %r15; + pax_force_retaddr ret; ENDPROC(__twofish_enc_blk_3way) @@ -308,5 +311,6 @@ ENTRY(twofish_dec_blk_3way) popq %r13; popq %r14; popq %r15; + pax_force_retaddr ret; ENDPROC(twofish_dec_blk_3way) diff --git a/arch/x86/crypto/twofish-x86_64-asm_64.S b/arch/x86/crypto/twofish-x86_64-asm_64.S index a350c99..c1bac24 100644 --- a/arch/x86/crypto/twofish-x86_64-asm_64.S +++ b/arch/x86/crypto/twofish-x86_64-asm_64.S @@ -22,6 +22,7 @@ #include #include +#include #define a_offset 0 #define b_offset 4 @@ -265,6 +266,7 @@ ENTRY(twofish_enc_blk) popq R1 movl $1,%eax + pax_force_retaddr ret ENDPROC(twofish_enc_blk) @@ -317,5 +319,6 @@ ENTRY(twofish_dec_blk) popq R1 movl $1,%eax + pax_force_retaddr ret ENDPROC(twofish_dec_blk) diff --git a/arch/x86/entry/calling.h b/arch/x86/entry/calling.h index 3c71dd9..008b8db 100644 --- a/arch/x86/entry/calling.h +++ b/arch/x86/entry/calling.h @@ -93,23 +93,26 @@ For 32-bit we have the following conventions - kernel is built with .endm .macro SAVE_C_REGS_HELPER offset=0 rax=1 rcx=1 r8910=1 r11=1 +#ifdef CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_OR + movq %r12, R12+\offset(%rsp) +#endif .if \r11 - movq %r11, 6*8+\offset(%rsp) + movq %r11, R11+\offset(%rsp) .endif .if \r8910 - movq %r10, 7*8+\offset(%rsp) - movq %r9, 8*8+\offset(%rsp) - movq %r8, 9*8+\offset(%rsp) + movq %r10, R10+\offset(%rsp) + movq %r9, R9+\offset(%rsp) + movq %r8, R8+\offset(%rsp) .endif .if \rax - movq %rax, 10*8+\offset(%rsp) + movq %rax, RAX+\offset(%rsp) .endif .if \rcx - movq %rcx, 11*8+\offset(%rsp) + movq %rcx, RCX+\offset(%rsp) .endif - movq %rdx, 12*8+\offset(%rsp) - movq %rsi, 13*8+\offset(%rsp) - movq %rdi, 14*8+\offset(%rsp) + movq %rdx, RDX+\offset(%rsp) + movq %rsi, RSI+\offset(%rsp) + movq %rdi, RDI+\offset(%rsp) .endm .macro SAVE_C_REGS offset=0 SAVE_C_REGS_HELPER \offset, 1, 1, 1, 1 @@ -128,67 +131,78 @@ For 32-bit we have the following conventions - kernel is built with .endm .macro SAVE_EXTRA_REGS offset=0 - movq %r15, 0*8+\offset(%rsp) - movq %r14, 1*8+\offset(%rsp) - movq %r13, 2*8+\offset(%rsp) - movq %r12, 3*8+\offset(%rsp) - movq %rbp, 4*8+\offset(%rsp) - movq %rbx, 5*8+\offset(%rsp) + movq %r15, R15+\offset(%rsp) + movq %r14, R14+\offset(%rsp) + movq %r13, R13+\offset(%rsp) +#ifndef CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_OR + movq %r12, R12+\offset(%rsp) +#endif + movq %rbp, RBP+\offset(%rsp) + movq %rbx, RBX+\offset(%rsp) .endm .macro RESTORE_EXTRA_REGS offset=0 - movq 0*8+\offset(%rsp), %r15 - movq 1*8+\offset(%rsp), %r14 - movq 2*8+\offset(%rsp), %r13 - movq 3*8+\offset(%rsp), %r12 - movq 4*8+\offset(%rsp), %rbp - movq 5*8+\offset(%rsp), %rbx + movq R15+\offset(%rsp), %r15 + movq R14+\offset(%rsp), %r14 + movq R13+\offset(%rsp), %r13 +#ifndef CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_OR + movq R12+\offset(%rsp), %r12 +#endif + movq RBP+\offset(%rsp), %rbp + movq RBX+\offset(%rsp), %rbx .endm .macro ZERO_EXTRA_REGS xorl %r15d, %r15d xorl %r14d, %r14d xorl %r13d, %r13d +#ifndef CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_OR xorl %r12d, %r12d +#endif xorl %ebp, %ebp xorl %ebx, %ebx .endm - .macro RESTORE_C_REGS_HELPER rstor_rax=1, rstor_rcx=1, rstor_r11=1, rstor_r8910=1, rstor_rdx=1 + .macro RESTORE_C_REGS_HELPER rstor_rax=1, rstor_rcx=1, rstor_r11=1, rstor_r8910=1, rstor_rdx=1, rstor_r12=1 +#ifdef CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_OR + .if \rstor_r12 + movq R12(%rsp), %r12 + .endif +#endif .if \rstor_r11 - movq 6*8(%rsp), %r11 + movq R11(%rsp), %r11 .endif .if \rstor_r8910 - movq 7*8(%rsp), %r10 - movq 8*8(%rsp), %r9 - movq 9*8(%rsp), %r8 + movq R10(%rsp), %r10 + movq R9(%rsp), %r9 + movq R8(%rsp), %r8 .endif .if \rstor_rax - movq 10*8(%rsp), %rax + movq RAX(%rsp), %rax .endif .if \rstor_rcx - movq 11*8(%rsp), %rcx + movq RCX(%rsp), %rcx .endif .if \rstor_rdx - movq 12*8(%rsp), %rdx + movq RDX(%rsp), %rdx .endif - movq 13*8(%rsp), %rsi - movq 14*8(%rsp), %rdi + movq RSI(%rsp), %rsi + movq RDI(%rsp), %rdi .endm .macro RESTORE_C_REGS - RESTORE_C_REGS_HELPER 1,1,1,1,1 + RESTORE_C_REGS_HELPER 1,1,1,1,1,1 .endm .macro RESTORE_C_REGS_EXCEPT_RAX - RESTORE_C_REGS_HELPER 0,1,1,1,1 + RESTORE_C_REGS_HELPER 0,1,1,1,1,0 .endm .macro RESTORE_C_REGS_EXCEPT_RCX - RESTORE_C_REGS_HELPER 1,0,1,1,1 + RESTORE_C_REGS_HELPER 1,0,1,1,1,0 .endm .macro RESTORE_C_REGS_EXCEPT_R11 - RESTORE_C_REGS_HELPER 1,1,0,1,1 + RESTORE_C_REGS_HELPER 1,1,0,1,1,1 .endm .macro RESTORE_C_REGS_EXCEPT_RCX_R11 - RESTORE_C_REGS_HELPER 1,0,0,1,1 + RESTORE_C_REGS_HELPER 1,0,0,1,1,1 .endm .macro REMOVE_PT_GPREGS_FROM_STACK addskip=0 diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c index 80dcc92..da58bb6 100644 --- a/arch/x86/entry/common.c +++ b/arch/x86/entry/common.c @@ -150,6 +150,10 @@ unsigned long syscall_trace_enter_phase1(struct pt_regs *regs, u32 arch) return 1; /* Something is enabled that we can't handle in phase 1 */ } +#ifdef CONFIG_GRKERNSEC_SETXID +extern void gr_delayed_cred_worker(void); +#endif + /* Returns the syscall nr to run (which should match regs->orig_ax). */ long syscall_trace_enter_phase2(struct pt_regs *regs, u32 arch, unsigned long phase1_result) @@ -160,6 +164,11 @@ long syscall_trace_enter_phase2(struct pt_regs *regs, u32 arch, BUG_ON(regs != task_pt_regs(current)); +#ifdef CONFIG_GRKERNSEC_SETXID + if (unlikely(test_and_clear_thread_flag(TIF_GRSEC_SETXID))) + gr_delayed_cred_worker(); +#endif + /* * If we stepped into a sysenter/syscall insn, it trapped in * kernel mode; do_debug() cleared TF and set TIF_SINGLESTEP. @@ -207,13 +216,6 @@ long syscall_trace_enter(struct pt_regs *regs) return syscall_trace_enter_phase2(regs, arch, phase1_result); } -static struct thread_info *pt_regs_to_thread_info(struct pt_regs *regs) -{ - unsigned long top_of_stack = - (unsigned long)(regs + 1) + TOP_OF_KERNEL_STACK_PADDING; - return (struct thread_info *)(top_of_stack - THREAD_SIZE); -} - /* Called with IRQs disabled. */ __visible void prepare_exit_to_usermode(struct pt_regs *regs) { @@ -230,7 +232,7 @@ __visible void prepare_exit_to_usermode(struct pt_regs *regs) */ while (true) { u32 cached_flags = - READ_ONCE(pt_regs_to_thread_info(regs)->flags); + READ_ONCE(current_thread_info()->flags); if (!(cached_flags & (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_UPROBE | _TIF_NEED_RESCHED | @@ -271,7 +273,7 @@ __visible void prepare_exit_to_usermode(struct pt_regs *regs) */ __visible void syscall_return_slowpath(struct pt_regs *regs) { - struct thread_info *ti = pt_regs_to_thread_info(regs); + struct thread_info *ti = current_thread_info(); u32 cached_flags = READ_ONCE(ti->flags); bool step; @@ -281,6 +283,11 @@ __visible void syscall_return_slowpath(struct pt_regs *regs) regs->orig_ax)) local_irq_enable(); +#ifdef CONFIG_GRKERNSEC_SETXID + if (unlikely(test_and_clear_thread_flag(TIF_GRSEC_SETXID))) + gr_delayed_cred_worker(); +#endif + /* * First do one-time work. If these work items are enabled, we * want to run them exactly once per syscall exit with IRQs on. @@ -301,7 +308,7 @@ __visible void syscall_return_slowpath(struct pt_regs *regs) step = unlikely( (cached_flags & (_TIF_SINGLESTEP | _TIF_SYSCALL_EMU)) == _TIF_SINGLESTEP); - if (step || cached_flags & _TIF_SYSCALL_TRACE) + if (step || (cached_flags & _TIF_SYSCALL_TRACE)) tracehook_report_syscall_exit(regs, step); } diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S index b2909bf..47ba402 100644 --- a/arch/x86/entry/entry_32.S +++ b/arch/x86/entry/entry_32.S @@ -147,13 +147,154 @@ movl \reg, PT_GS(%esp) .endm .macro SET_KERNEL_GS reg + +#ifdef CONFIG_CC_STACKPROTECTOR movl $(__KERNEL_STACK_CANARY), \reg +#elif defined(CONFIG_PAX_MEMORY_UDEREF) + movl $(__USER_DS), \reg +#else + xorl \reg, \reg +#endif + movl \reg, %gs .endm #endif /* CONFIG_X86_32_LAZY_GS */ -.macro SAVE_ALL +.macro pax_enter_kernel +#ifdef CONFIG_PAX_KERNEXEC + call pax_enter_kernel +#endif +.endm + +.macro pax_exit_kernel +#ifdef CONFIG_PAX_KERNEXEC + call pax_exit_kernel +#endif +.endm + +#ifdef CONFIG_PAX_KERNEXEC +ENTRY(pax_enter_kernel) +#ifdef CONFIG_PARAVIRT + pushl %eax + pushl %ecx + call PARA_INDIRECT(pv_cpu_ops+PV_CPU_read_cr0) + mov %eax, %esi +#else + mov %cr0, %esi +#endif + bts $X86_CR0_WP_BIT, %esi + jnc 1f + mov %cs, %esi + cmp $__KERNEL_CS, %esi + jz 3f + ljmp $__KERNEL_CS, $3f +1: ljmp $__KERNEXEC_KERNEL_CS, $2f +2: +#ifdef CONFIG_PARAVIRT + mov %esi, %eax + call PARA_INDIRECT(pv_cpu_ops+PV_CPU_write_cr0) +#else + mov %esi, %cr0 +#endif +3: +#ifdef CONFIG_PARAVIRT + popl %ecx + popl %eax +#endif + ret +ENDPROC(pax_enter_kernel) + +ENTRY(pax_exit_kernel) +#ifdef CONFIG_PARAVIRT + pushl %eax + pushl %ecx +#endif + mov %cs, %esi + cmp $__KERNEXEC_KERNEL_CS, %esi + jnz 2f +#ifdef CONFIG_PARAVIRT + call PARA_INDIRECT(pv_cpu_ops+PV_CPU_read_cr0); + mov %eax, %esi +#else + mov %cr0, %esi +#endif + btr $X86_CR0_WP_BIT, %esi + ljmp $__KERNEL_CS, $1f +1: +#ifdef CONFIG_PARAVIRT + mov %esi, %eax + call PARA_INDIRECT(pv_cpu_ops+PV_CPU_write_cr0); +#else + mov %esi, %cr0 +#endif +2: +#ifdef CONFIG_PARAVIRT + popl %ecx + popl %eax +#endif + ret +ENDPROC(pax_exit_kernel) +#endif + + .macro pax_erase_kstack +#ifdef CONFIG_PAX_MEMORY_STACKLEAK + call pax_erase_kstack +#endif + .endm + +#ifdef CONFIG_PAX_MEMORY_STACKLEAK +/* + * ebp: thread_info + */ +ENTRY(pax_erase_kstack) + pushl %edi + pushl %ecx + pushl %eax + + mov TI_lowest_stack(%ebp), %edi + mov $-0xBEEF, %eax + std + +1: mov %edi, %ecx + and $THREAD_SIZE_asm - 1, %ecx + shr $2, %ecx + repne scasl + jecxz 2f + + cmp $2*16, %ecx + jc 2f + + mov $2*16, %ecx + repe scasl + jecxz 2f + jne 1b + +2: cld + or $2*4, %edi + mov %esp, %ecx + sub %edi, %ecx + + cmp $THREAD_SIZE_asm, %ecx + jb 3f + ud2 +3: + + shr $2, %ecx + rep stosl + + mov TI_task_thread_sp0(%ebp), %edi + sub $128, %edi + mov %edi, TI_lowest_stack(%ebp) + + popl %eax + popl %ecx + popl %edi + ret +ENDPROC(pax_erase_kstack) +#endif + +.macro __SAVE_ALL _DS cld PUSH_GS pushl %fs @@ -166,7 +307,7 @@ pushl %edx pushl %ecx pushl %ebx - movl $(__USER_DS), %edx + movl $\_DS, %edx movl %edx, %ds movl %edx, %es movl $(__KERNEL_PERCPU), %edx @@ -174,6 +315,15 @@ SET_KERNEL_GS %edx .endm +.macro SAVE_ALL +#if defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) + __SAVE_ALL __KERNEL_DS + pax_enter_kernel +#else + __SAVE_ALL __USER_DS +#endif +.endm + .macro RESTORE_INT_REGS popl %ebx popl %ecx @@ -212,7 +362,7 @@ ENTRY(ret_from_fork) pushl $0x0202 # Reset kernel eflags popfl jmp syscall_exit -END(ret_from_fork) +ENDPROC(ret_from_fork) ENTRY(ret_from_kernel_thread) pushl %eax @@ -252,7 +402,15 @@ ret_from_intr: andl $SEGMENT_RPL_MASK, %eax #endif cmpl $USER_RPL, %eax + +#ifdef CONFIG_PAX_KERNEXEC + jae resume_userspace + + pax_exit_kernel + jmp resume_kernel +#else jb resume_kernel # not returning to v8086 or userspace +#endif ENTRY(resume_userspace) LOCKDEP_SYS_EXIT @@ -260,8 +418,8 @@ ENTRY(resume_userspace) TRACE_IRQS_OFF movl %esp, %eax call prepare_exit_to_usermode - jmp restore_all -END(ret_from_exception) + jmp restore_all_pax +ENDPROC(ret_from_exception) #ifdef CONFIG_PREEMPT ENTRY(resume_kernel) @@ -273,7 +431,7 @@ need_resched: jz restore_all call preempt_schedule_irq jmp need_resched -END(resume_kernel) +ENDPROC(resume_kernel) #endif /* @@ -298,32 +456,44 @@ sysenter_past_esp: pushl $__USER_CS /* * Push current_thread_info()->sysenter_return to the stack. - * A tiny bit of offset fixup is necessary: TI_sysenter_return - * is relative to thread_info, which is at the bottom of the - * kernel stack page. 4*4 means the 4 words pushed above; - * TOP_OF_KERNEL_STACK_PADDING takes us to the top of the stack; - * and THREAD_SIZE takes us to the bottom. */ - pushl ((TI_sysenter_return) - THREAD_SIZE + TOP_OF_KERNEL_STACK_PADDING + 4*4)(%esp) + pushl $0 pushl %eax SAVE_ALL + GET_THREAD_INFO(%ebp) + movl TI_sysenter_return(%ebp), %ebp + movl %ebp, PT_EIP(%esp) ENABLE_INTERRUPTS(CLBR_NONE) /* * Load the potential sixth argument from user stack. * Careful about security. */ + movl PT_OLDESP(%esp),%ebp + +#ifdef CONFIG_PAX_MEMORY_UDEREF + mov PT_OLDSS(%esp), %ds +1: movl %ds:(%ebp), %ebp + push %ss + pop %ds +#else cmpl $__PAGE_OFFSET-3, %ebp jae syscall_fault ASM_STAC 1: movl (%ebp), %ebp ASM_CLAC +#endif + movl %ebp, PT_EBP(%esp) _ASM_EXTABLE(1b, syscall_fault) GET_THREAD_INFO(%ebp) +#ifdef CONFIG_PAX_RANDKSTACK + pax_erase_kstack +#endif + testl $_TIF_WORK_SYSCALL_ENTRY, TI_flags(%ebp) jnz syscall_trace_entry sysenter_do_call: @@ -339,20 +509,38 @@ sysenter_after_call: testl $_TIF_ALLWORK_MASK, %ecx jnz syscall_exit_work_irqs_off sysenter_exit: + +#ifdef CONFIG_PAX_RANDKSTACK + pushl %eax + movl %esp, %eax + call pax_randomize_kstack + popl %eax +#endif + + pax_erase_kstack + /* if something modifies registers it must also disable sysexit */ movl PT_EIP(%esp), %edx movl PT_OLDESP(%esp), %ecx xorl %ebp, %ebp TRACE_IRQS_ON 1: mov PT_FS(%esp), %fs +2: mov PT_DS(%esp), %ds +3: mov PT_ES(%esp), %es PTGS_TO_GS ENABLE_INTERRUPTS_SYSEXIT .pushsection .fixup, "ax" -2: movl $0, PT_FS(%esp) +4: movl $0, PT_FS(%esp) + jmp 1b +5: movl $0, PT_DS(%esp) + jmp 1b +6: movl $0, PT_ES(%esp) jmp 1b .popsection - _ASM_EXTABLE(1b, 2b) + _ASM_EXTABLE(1b, 4b) + _ASM_EXTABLE(2b, 5b) + _ASM_EXTABLE(3b, 6b) PTGS_TO_GS_EX ENDPROC(entry_SYSENTER_32) @@ -362,6 +550,11 @@ ENTRY(entry_INT80_32) pushl %eax # save orig_eax SAVE_ALL GET_THREAD_INFO(%ebp) + +#ifdef CONFIG_PAX_RANDKSTACK + pax_erase_kstack +#endif + # system call tracing in operation / emulation testl $_TIF_WORK_SYSCALL_ENTRY, TI_flags(%ebp) jnz syscall_trace_entry @@ -375,6 +568,15 @@ syscall_exit: LOCKDEP_SYS_EXIT jmp syscall_exit_work +restore_all_pax: + +#ifdef CONFIG_PAX_RANDKSTACK + movl %esp, %eax + call pax_randomize_kstack +#endif + + pax_erase_kstack + restore_all: TRACE_IRQS_IRET restore_all_notrace: @@ -429,14 +631,34 @@ ldt_ss: * compensating for the offset by changing to the ESPFIX segment with * a base address that matches for the difference. */ -#define GDT_ESPFIX_SS PER_CPU_VAR(gdt_page) + (GDT_ENTRY_ESPFIX_SS * 8) +#define GDT_ESPFIX_SS (GDT_ENTRY_ESPFIX_SS * 8)(%ebx) mov %esp, %edx /* load kernel esp */ mov PT_OLDESP(%esp), %eax /* load userspace esp */ mov %dx, %ax /* eax: new kernel esp */ sub %eax, %edx /* offset (low word is 0) */ +#ifdef CONFIG_SMP + movl PER_CPU_VAR(cpu_number), %ebx + shll $PAGE_SHIFT_asm, %ebx + addl $cpu_gdt_table, %ebx +#else + movl $cpu_gdt_table, %ebx +#endif shr $16, %edx - mov %dl, GDT_ESPFIX_SS + 4 /* bits 16..23 */ - mov %dh, GDT_ESPFIX_SS + 7 /* bits 24..31 */ + +#ifdef CONFIG_PAX_KERNEXEC + mov %cr0, %esi + btr $X86_CR0_WP_BIT, %esi + mov %esi, %cr0 +#endif + + mov %dl, 4 + GDT_ESPFIX_SS /* bits 16..23 */ + mov %dh, 7 + GDT_ESPFIX_SS /* bits 24..31 */ + +#ifdef CONFIG_PAX_KERNEXEC + bts $X86_CR0_WP_BIT, %esi + mov %esi, %cr0 +#endif + pushl $__ESPFIX_SS pushl %eax /* new kernel esp */ /* @@ -456,11 +678,14 @@ syscall_trace_entry: movl $-ENOSYS, PT_EAX(%esp) movl %esp, %eax call syscall_trace_enter + + pax_erase_kstack + /* What it returned is what we'll actually use. */ cmpl $(NR_syscalls), %eax jnae syscall_call jmp syscall_exit -END(syscall_trace_entry) +ENDPROC(syscall_trace_entry) # perform syscall exit tracing ALIGN @@ -471,25 +696,29 @@ syscall_exit_work_irqs_off: syscall_exit_work: movl %esp, %eax call syscall_return_slowpath - jmp restore_all -END(syscall_exit_work) + jmp restore_all_pax +ENDPROC(syscall_exit_work) syscall_fault: +#ifdef CONFIG_PAX_MEMORY_UDEREF + push %ss + pop %ds +#endif ASM_CLAC GET_THREAD_INFO(%ebp) movl $-EFAULT, PT_EAX(%esp) jmp resume_userspace -END(syscall_fault) +ENDPROC(syscall_fault) syscall_badsys: movl $-ENOSYS, %eax jmp syscall_after_call -END(syscall_badsys) +ENDPROC(syscall_badsys) sysenter_badsys: movl $-ENOSYS, %eax jmp sysenter_after_call -END(sysenter_badsys) +ENDPROC(sysenter_badsys) .macro FIXUP_ESPFIX_STACK /* @@ -501,8 +730,15 @@ END(sysenter_badsys) */ #ifdef CONFIG_X86_ESPFIX32 /* fixup the stack */ - mov GDT_ESPFIX_SS + 4, %al /* bits 16..23 */ - mov GDT_ESPFIX_SS + 7, %ah /* bits 24..31 */ +#ifdef CONFIG_SMP + movl PER_CPU_VAR(cpu_number), %ebx + shll $PAGE_SHIFT_asm, %ebx + addl $cpu_gdt_table, %ebx +#else + movl $cpu_gdt_table, %ebx +#endif + mov 4 + GDT_ESPFIX_SS, %al /* bits 16..23 */ + mov 7 + GDT_ESPFIX_SS, %ah /* bits 24..31 */ shl $16, %eax addl %esp, %eax /* the adjusted stack pointer */ pushl $__KERNEL_DS @@ -538,7 +774,7 @@ ENTRY(irq_entries_start) jmp common_interrupt .align 8 .endr -END(irq_entries_start) +ENDPROC(irq_entries_start) /* * the CPU automatically disables interrupts when executing an IRQ vector, @@ -585,7 +821,7 @@ ENTRY(coprocessor_error) pushl $0 pushl $do_coprocessor_error jmp error_code -END(coprocessor_error) +ENDPROC(coprocessor_error) ENTRY(simd_coprocessor_error) ASM_CLAC @@ -599,25 +835,25 @@ ENTRY(simd_coprocessor_error) pushl $do_simd_coprocessor_error #endif jmp error_code -END(simd_coprocessor_error) +ENDPROC(simd_coprocessor_error) ENTRY(device_not_available) ASM_CLAC pushl $-1 # mark this as an int pushl $do_device_not_available jmp error_code -END(device_not_available) +ENDPROC(device_not_available) #ifdef CONFIG_PARAVIRT ENTRY(native_iret) iret _ASM_EXTABLE(native_iret, iret_exc) -END(native_iret) +ENDPROC(native_iret) ENTRY(native_irq_enable_sysexit) sti sysexit -END(native_irq_enable_sysexit) +ENDPROC(native_irq_enable_sysexit) #endif ENTRY(overflow) @@ -625,59 +861,59 @@ ENTRY(overflow) pushl $0 pushl $do_overflow jmp error_code -END(overflow) +ENDPROC(overflow) ENTRY(bounds) ASM_CLAC pushl $0 pushl $do_bounds jmp error_code -END(bounds) +ENDPROC(bounds) ENTRY(invalid_op) ASM_CLAC pushl $0 pushl $do_invalid_op jmp error_code -END(invalid_op) +ENDPROC(invalid_op) ENTRY(coprocessor_segment_overrun) ASM_CLAC pushl $0 pushl $do_coprocessor_segment_overrun jmp error_code -END(coprocessor_segment_overrun) +ENDPROC(coprocessor_segment_overrun) ENTRY(invalid_TSS) ASM_CLAC pushl $do_invalid_TSS jmp error_code -END(invalid_TSS) +ENDPROC(invalid_TSS) ENTRY(segment_not_present) ASM_CLAC pushl $do_segment_not_present jmp error_code -END(segment_not_present) +ENDPROC(segment_not_present) ENTRY(stack_segment) ASM_CLAC pushl $do_stack_segment jmp error_code -END(stack_segment) +ENDPROC(stack_segment) ENTRY(alignment_check) ASM_CLAC pushl $do_alignment_check jmp error_code -END(alignment_check) +ENDPROC(alignment_check) ENTRY(divide_error) ASM_CLAC pushl $0 # no error code pushl $do_divide_error jmp error_code -END(divide_error) +ENDPROC(divide_error) #ifdef CONFIG_X86_MCE ENTRY(machine_check) @@ -685,7 +921,7 @@ ENTRY(machine_check) pushl $0 pushl machine_check_vector jmp error_code -END(machine_check) +ENDPROC(machine_check) #endif ENTRY(spurious_interrupt_bug) @@ -693,7 +929,7 @@ ENTRY(spurious_interrupt_bug) pushl $0 pushl $do_spurious_interrupt_bug jmp error_code -END(spurious_interrupt_bug) +ENDPROC(spurious_interrupt_bug) #ifdef CONFIG_XEN /* @@ -800,7 +1036,7 @@ BUILD_INTERRUPT3(hyperv_callback_vector, HYPERVISOR_CALLBACK_VECTOR, ENTRY(mcount) ret -END(mcount) +ENDPROC(mcount) ENTRY(ftrace_caller) pushl %eax @@ -830,7 +1066,7 @@ ftrace_graph_call: .globl ftrace_stub ftrace_stub: ret -END(ftrace_caller) +ENDPROC(ftrace_caller) ENTRY(ftrace_regs_caller) pushf /* push flags before compare (in cs location) */ @@ -928,7 +1164,7 @@ trace: popl %ecx popl %eax jmp ftrace_stub -END(mcount) +ENDPROC(mcount) #endif /* CONFIG_DYNAMIC_FTRACE */ #endif /* CONFIG_FUNCTION_TRACER */ @@ -946,7 +1182,7 @@ ENTRY(ftrace_graph_caller) popl %ecx popl %eax ret -END(ftrace_graph_caller) +ENDPROC(ftrace_graph_caller) .globl return_to_handler return_to_handler: @@ -994,14 +1230,17 @@ error_code: movl $-1, PT_ORIG_EAX(%esp) # no syscall to restart REG_TO_PTGS %ecx SET_KERNEL_GS %ecx - movl $(__USER_DS), %ecx + movl $(__KERNEL_DS), %ecx movl %ecx, %ds movl %ecx, %es + + pax_enter_kernel + TRACE_IRQS_OFF movl %esp, %eax # pt_regs pointer call *%edi jmp ret_from_exception -END(page_fault) +ENDPROC(page_fault) /* * Debug traps and NMI can happen at the one SYSENTER instruction @@ -1039,7 +1278,7 @@ debug_stack_correct: movl %esp, %eax # pt_regs pointer call do_debug jmp ret_from_exception -END(debug) +ENDPROC(debug) /* * NMI is doubly nasty. It can happen _while_ we're handling @@ -1078,6 +1317,9 @@ nmi_stack_correct: xorl %edx, %edx # zero error code movl %esp, %eax # pt_regs pointer call do_nmi + + pax_exit_kernel + jmp restore_all_notrace nmi_stack_fixup: @@ -1111,11 +1353,14 @@ nmi_espfix_stack: FIXUP_ESPFIX_STACK # %eax == %esp xorl %edx, %edx # zero error code call do_nmi + + pax_exit_kernel + RESTORE_REGS lss 12+4(%esp), %esp # back to espfix stack jmp irq_return #endif -END(nmi) +ENDPROC(nmi) ENTRY(int3) ASM_CLAC @@ -1126,17 +1371,17 @@ ENTRY(int3) movl %esp, %eax # pt_regs pointer call do_int3 jmp ret_from_exception -END(int3) +ENDPROC(int3) ENTRY(general_protection) pushl $do_general_protection jmp error_code -END(general_protection) +ENDPROC(general_protection) #ifdef CONFIG_KVM_GUEST ENTRY(async_page_fault) ASM_CLAC pushl $do_async_page_fault jmp error_code -END(async_page_fault) +ENDPROC(async_page_fault) #endif diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index 055a01d..348b266 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -36,6 +36,8 @@ #include #include #include +#include +#include /* Avoid __ASSEMBLER__'ifying just for this. */ #include @@ -53,6 +55,402 @@ ENTRY(native_usergs_sysret64) ENDPROC(native_usergs_sysret64) #endif /* CONFIG_PARAVIRT */ + .macro ljmpq sel, off +#if defined(CONFIG_MPSC) || defined(CONFIG_MCORE2) || defined (CONFIG_MATOM) + .byte 0x48; ljmp *1234f(%rip) + .pushsection .rodata + .align 16 + 1234: .quad \off; .word \sel + .popsection +#else + pushq $\sel + pushq $\off + lretq +#endif + .endm + + .macro pax_enter_kernel + pax_set_fptr_mask +#if defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) + call pax_enter_kernel +#endif + .endm + + .macro pax_exit_kernel +#if defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) + call pax_exit_kernel +#endif + .endm + +#if defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) +ENTRY(pax_enter_kernel) + pushq %rdi + +#ifdef CONFIG_PARAVIRT + PV_SAVE_REGS(CLBR_RDI) +#endif + +#ifdef CONFIG_PAX_KERNEXEC + GET_CR0_INTO_RDI + bts $X86_CR0_WP_BIT,%rdi + jnc 3f + mov %cs,%edi + cmp $__KERNEL_CS,%edi + jnz 2f +1: +#endif + +#ifdef CONFIG_PAX_MEMORY_UDEREF + ALTERNATIVE "jmp 111f", "", X86_FEATURE_PCID + GET_CR3_INTO_RDI + cmp $0,%dil + jnz 112f + mov $__KERNEL_DS,%edi + mov %edi,%ss + jmp 111f +112: cmp $1,%dil + jz 113f + ud2 +113: sub $4097,%rdi + bts $63,%rdi + SET_RDI_INTO_CR3 + mov $__UDEREF_KERNEL_DS,%edi + mov %edi,%ss +111: +#endif + +#ifdef CONFIG_PARAVIRT + PV_RESTORE_REGS(CLBR_RDI) +#endif + + popq %rdi + pax_force_retaddr + retq + +#ifdef CONFIG_PAX_KERNEXEC +2: ljmpq __KERNEL_CS,1b +3: ljmpq __KERNEXEC_KERNEL_CS,4f +4: SET_RDI_INTO_CR0 + jmp 1b +#endif +ENDPROC(pax_enter_kernel) + +ENTRY(pax_exit_kernel) + pushq %rdi + +#ifdef CONFIG_PARAVIRT + PV_SAVE_REGS(CLBR_RDI) +#endif + +#ifdef CONFIG_PAX_KERNEXEC + mov %cs,%rdi + cmp $__KERNEXEC_KERNEL_CS,%edi + jz 2f + GET_CR0_INTO_RDI + bts $X86_CR0_WP_BIT,%rdi + jnc 4f +1: +#endif + +#ifdef CONFIG_PAX_MEMORY_UDEREF + ALTERNATIVE "jmp 111f", "", X86_FEATURE_PCID + mov %ss,%edi + cmp $__UDEREF_KERNEL_DS,%edi + jnz 111f + GET_CR3_INTO_RDI + cmp $0,%dil + jz 112f + ud2 +112: add $4097,%rdi + bts $63,%rdi + SET_RDI_INTO_CR3 + mov $__KERNEL_DS,%edi + mov %edi,%ss +111: +#endif + +#ifdef CONFIG_PARAVIRT + PV_RESTORE_REGS(CLBR_RDI); +#endif + + popq %rdi + pax_force_retaddr + retq + +#ifdef CONFIG_PAX_KERNEXEC +2: GET_CR0_INTO_RDI + btr $X86_CR0_WP_BIT,%rdi + jnc 4f + ljmpq __KERNEL_CS,3f +3: SET_RDI_INTO_CR0 + jmp 1b +4: ud2 + jmp 4b +#endif +ENDPROC(pax_exit_kernel) +#endif + + .macro pax_enter_kernel_user + pax_set_fptr_mask +#ifdef CONFIG_PAX_MEMORY_UDEREF + call pax_enter_kernel_user +#endif + .endm + + .macro pax_exit_kernel_user +#ifdef CONFIG_PAX_MEMORY_UDEREF + call pax_exit_kernel_user +#endif +#ifdef CONFIG_PAX_RANDKSTACK + pushq %rax + pushq %r11 + call pax_randomize_kstack + popq %r11 + popq %rax +#endif + .endm + +#ifdef CONFIG_PAX_MEMORY_UDEREF +ENTRY(pax_enter_kernel_user) + pushq %rdi + pushq %rbx + +#ifdef CONFIG_PARAVIRT + PV_SAVE_REGS(CLBR_RDI) +#endif + + ALTERNATIVE "jmp 111f", "", X86_FEATURE_PCID + GET_CR3_INTO_RDI + cmp $1,%dil + jnz 4f + sub $4097,%rdi + bts $63,%rdi + SET_RDI_INTO_CR3 + jmp 3f +111: + + GET_CR3_INTO_RDI + mov %rdi,%rbx + add $__START_KERNEL_map,%rbx + sub phys_base(%rip),%rbx + +#ifdef CONFIG_PARAVIRT + cmpl $0, pv_info+PARAVIRT_enabled + jz 1f + pushq %rdi + i = 0 + .rept USER_PGD_PTRS + mov i*8(%rbx),%rsi + mov $0,%sil + lea i*8(%rbx),%rdi + call PARA_INDIRECT(pv_mmu_ops+PV_MMU_set_pgd_batched) + i = i + 1 + .endr + popq %rdi + jmp 2f +1: +#endif + + i = 0 + .rept USER_PGD_PTRS + movb $0,i*8(%rbx) + i = i + 1 + .endr + +2: SET_RDI_INTO_CR3 + +#ifdef CONFIG_PAX_KERNEXEC + GET_CR0_INTO_RDI + bts $X86_CR0_WP_BIT,%rdi + SET_RDI_INTO_CR0 +#endif + +3: + +#ifdef CONFIG_PARAVIRT + PV_RESTORE_REGS(CLBR_RDI) +#endif + + popq %rbx + popq %rdi + pax_force_retaddr + retq +4: ud2 +ENDPROC(pax_enter_kernel_user) + +ENTRY(pax_exit_kernel_user) + pushq %rdi + pushq %rbx + +#ifdef CONFIG_PARAVIRT + PV_SAVE_REGS(CLBR_RDI) +#endif + + GET_CR3_INTO_RDI + ALTERNATIVE "jmp 1f", "", X86_FEATURE_PCID + cmp $0,%dil + jnz 3f + add $4097,%rdi + bts $63,%rdi + SET_RDI_INTO_CR3 + jmp 2f +1: + + mov %rdi,%rbx + +#ifdef CONFIG_PAX_KERNEXEC + GET_CR0_INTO_RDI + btr $X86_CR0_WP_BIT,%rdi + jnc 3f + SET_RDI_INTO_CR0 +#endif + + add $__START_KERNEL_map,%rbx + sub phys_base(%rip),%rbx + +#ifdef CONFIG_PARAVIRT + cmpl $0, pv_info+PARAVIRT_enabled + jz 1f + i = 0 + .rept USER_PGD_PTRS + mov i*8(%rbx),%rsi + mov $0x67,%sil + lea i*8(%rbx),%rdi + call PARA_INDIRECT(pv_mmu_ops+PV_MMU_set_pgd_batched) + i = i + 1 + .endr + jmp 2f +1: +#endif + + i = 0 + .rept USER_PGD_PTRS + movb $0x67,i*8(%rbx) + i = i + 1 + .endr +2: + +#ifdef CONFIG_PARAVIRT + PV_RESTORE_REGS(CLBR_RDI) +#endif + + popq %rbx + popq %rdi + pax_force_retaddr + retq +3: ud2 +ENDPROC(pax_exit_kernel_user) +#endif + + .macro pax_enter_kernel_nmi + pax_set_fptr_mask + +#ifdef CONFIG_PAX_KERNEXEC + GET_CR0_INTO_RDI + bts $X86_CR0_WP_BIT,%rdi + jc 110f + SET_RDI_INTO_CR0 + or $2,%ebx +110: +#endif + +#ifdef CONFIG_PAX_MEMORY_UDEREF + ALTERNATIVE "jmp 111f", "", X86_FEATURE_PCID + GET_CR3_INTO_RDI + cmp $0,%dil + jz 111f + sub $4097,%rdi + or $4,%ebx + bts $63,%rdi + SET_RDI_INTO_CR3 + mov $__UDEREF_KERNEL_DS,%edi + mov %edi,%ss +111: +#endif + .endm + + .macro pax_exit_kernel_nmi +#ifdef CONFIG_PAX_KERNEXEC + btr $1,%ebx + jnc 110f + GET_CR0_INTO_RDI + btr $X86_CR0_WP_BIT,%rdi + SET_RDI_INTO_CR0 +110: +#endif + +#ifdef CONFIG_PAX_MEMORY_UDEREF + ALTERNATIVE "jmp 111f", "", X86_FEATURE_PCID + btr $2,%ebx + jnc 111f + GET_CR3_INTO_RDI + add $4097,%rdi + bts $63,%rdi + SET_RDI_INTO_CR3 + mov $__KERNEL_DS,%edi + mov %edi,%ss +111: +#endif + .endm + + .macro pax_erase_kstack +#ifdef CONFIG_PAX_MEMORY_STACKLEAK + call pax_erase_kstack +#endif + .endm + +#ifdef CONFIG_PAX_MEMORY_STACKLEAK +ENTRY(pax_erase_kstack) + pushq %rdi + pushq %rcx + pushq %rax + pushq %r11 + + GET_THREAD_INFO(%r11) + mov TI_lowest_stack(%r11), %rdi + mov $-0xBEEF, %rax + std + +1: mov %edi, %ecx + and $THREAD_SIZE_asm - 1, %ecx + shr $3, %ecx + repne scasq + jecxz 2f + + cmp $2*8, %ecx + jc 2f + + mov $2*8, %ecx + repe scasq + jecxz 2f + jne 1b + +2: cld + or $2*8, %rdi + mov %esp, %ecx + sub %edi, %ecx + + cmp $THREAD_SIZE_asm, %rcx + jb 3f + ud2 +3: + + shr $3, %ecx + rep stosq + + mov TI_task_thread_sp0(%r11), %rdi + sub $256, %rdi + mov %rdi, TI_lowest_stack(%r11) + + popq %r11 + popq %rax + popq %rcx + popq %rdi + pax_force_retaddr + ret +ENDPROC(pax_erase_kstack) +#endif + .macro TRACE_IRQS_IRETQ #ifdef CONFIG_TRACE_IRQFLAGS bt $9, EFLAGS(%rsp) /* interrupts off? */ @@ -88,7 +486,7 @@ ENDPROC(native_usergs_sysret64) .endm .macro TRACE_IRQS_IRETQ_DEBUG - bt $9, EFLAGS(%rsp) /* interrupts off? */ + bt $X86_EFLAGS_IF_BIT, EFLAGS(%rsp) /* interrupts off? */ jnc 1f TRACE_IRQS_ON_DEBUG 1: @@ -148,14 +546,6 @@ GLOBAL(entry_SYSCALL_64_after_swapgs) /* Construct struct pt_regs on stack */ pushq $__USER_DS /* pt_regs->ss */ pushq PER_CPU_VAR(rsp_scratch) /* pt_regs->sp */ - /* - * Re-enable interrupts. - * We use 'rsp_scratch' as a scratch space, hence irq-off block above - * must execute atomically in the face of possible interrupt-driven - * task preemption. We must enable interrupts only after we're done - * with using rsp_scratch: - */ - ENABLE_INTERRUPTS(CLBR_NONE) pushq %r11 /* pt_regs->flags */ pushq $__USER_CS /* pt_regs->cs */ pushq %rcx /* pt_regs->ip */ @@ -171,7 +561,27 @@ GLOBAL(entry_SYSCALL_64_after_swapgs) pushq %r11 /* pt_regs->r11 */ sub $(6*8), %rsp /* pt_regs->bp, bx, r12-15 not saved */ - testl $_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) +#ifdef CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_OR + movq %r12, R12(%rsp) +#endif + + pax_enter_kernel_user + +#ifdef CONFIG_PAX_RANDKSTACK + pax_erase_kstack +#endif + + /* + * Re-enable interrupts. + * We use 'rsp_scratch' as a scratch space, hence irq-off block above + * must execute atomically in the face of possible interrupt-driven + * task preemption. We must enable interrupts only after we're done + * with using rsp_scratch: + */ + ENABLE_INTERRUPTS(CLBR_NONE) + + GET_THREAD_INFO(%rcx) + testl $_TIF_WORK_SYSCALL_ENTRY, TI_flags(%rcx) jnz tracesys entry_SYSCALL_64_fastpath: #if __SYSCALL_MASK == ~0 @@ -204,9 +614,13 @@ entry_SYSCALL_64_fastpath: * flags (TIF_NOTIFY_RESUME, TIF_USER_RETURN_NOTIFY, etc) set is * very bad. */ - testl $_TIF_ALLWORK_MASK, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) + GET_THREAD_INFO(%rcx) + testl $_TIF_ALLWORK_MASK, TI_flags(%rcx) jnz int_ret_from_sys_call_irqs_off /* Go to the slow path */ + pax_exit_kernel_user + pax_erase_kstack + RESTORE_C_REGS_EXCEPT_RCX_R11 movq RIP(%rsp), %rcx movq EFLAGS(%rsp), %r11 @@ -240,6 +654,9 @@ tracesys: call syscall_trace_enter_phase1 test %rax, %rax jnz tracesys_phase2 /* if needed, run the slow path */ + + pax_erase_kstack + RESTORE_C_REGS_EXCEPT_RAX /* else restore clobbered regs */ movq ORIG_RAX(%rsp), %rax jmp entry_SYSCALL_64_fastpath /* and return to the fast path */ @@ -251,6 +668,8 @@ tracesys_phase2: movq %rax, %rdx call syscall_trace_enter_phase2 + pax_erase_kstack + /* * Reload registers from stack in case ptrace changed them. * We don't reload %rax because syscall_trace_entry_phase2() returned @@ -279,6 +698,8 @@ GLOBAL(int_ret_from_sys_call) SAVE_EXTRA_REGS movq %rsp, %rdi call syscall_return_slowpath /* returns with IRQs disabled */ + pax_exit_kernel_user + pax_erase_kstack RESTORE_EXTRA_REGS TRACE_IRQS_IRETQ /* we're about to change IF */ @@ -353,14 +774,14 @@ syscall_return_via_sysret: opportunistic_sysret_failed: SWAPGS jmp restore_c_regs_and_iret -END(entry_SYSCALL_64) +ENDPROC(entry_SYSCALL_64) .macro FORK_LIKE func ENTRY(stub_\func) SAVE_EXTRA_REGS 8 jmp sys_\func -END(stub_\func) +ENDPROC(stub_\func) .endm FORK_LIKE clone @@ -380,7 +801,7 @@ return_from_execve: ZERO_EXTRA_REGS movq %rax, RAX(%rsp) jmp int_ret_from_sys_call -END(stub_execve) +ENDPROC(stub_execve) /* * Remaining execve stubs are only 7 bytes long. * ENTRY() often aligns to 16 bytes, which in this case has no benefits. @@ -389,7 +810,7 @@ END(stub_execve) GLOBAL(stub_execveat) call sys_execveat jmp return_from_execve -END(stub_execveat) +ENDPROC(stub_execveat) #if defined(CONFIG_X86_X32_ABI) || defined(CONFIG_IA32_EMULATION) .align 8 @@ -397,15 +818,15 @@ GLOBAL(stub_x32_execve) GLOBAL(stub32_execve) call compat_sys_execve jmp return_from_execve -END(stub32_execve) -END(stub_x32_execve) +ENDPROC(stub32_execve) +ENDPROC(stub_x32_execve) .align 8 GLOBAL(stub_x32_execveat) GLOBAL(stub32_execveat) call compat_sys_execveat jmp return_from_execve -END(stub32_execveat) -END(stub_x32_execveat) +ENDPROC(stub32_execveat) +ENDPROC(stub_x32_execveat) #endif /* @@ -434,7 +855,7 @@ ENTRY(stub_x32_rt_sigreturn) SAVE_EXTRA_REGS 8 call sys32_x32_rt_sigreturn jmp return_from_stub -END(stub_x32_rt_sigreturn) +ENDPROC(stub_x32_rt_sigreturn) #endif /* @@ -473,7 +894,7 @@ ENTRY(ret_from_fork) movl $0, RAX(%rsp) RESTORE_EXTRA_REGS jmp int_ret_from_sys_call -END(ret_from_fork) +ENDPROC(ret_from_fork) /* * Build the entry stubs with some assembler magic. @@ -488,7 +909,7 @@ ENTRY(irq_entries_start) jmp common_interrupt .align 8 .endr -END(irq_entries_start) +ENDPROC(irq_entries_start) /* * Interrupt entry/exit. @@ -513,11 +934,19 @@ END(irq_entries_start) * tracking that we're in kernel mode. */ SWAPGS +#ifdef CONFIG_PAX_MEMORY_UDEREF + pax_enter_kernel_user +#else + pax_enter_kernel +#endif + #ifdef CONFIG_CONTEXT_TRACKING call enter_from_user_mode #endif -1: + jmp 2f +1: pax_enter_kernel +2: /* * Save previous stack pointer, optionally switch to interrupt stack. * irq_count is used to check if a CPU is already on an interrupt stack @@ -529,6 +958,7 @@ END(irq_entries_start) incl PER_CPU_VAR(irq_count) cmovzq PER_CPU_VAR(irq_stack_ptr), %rsp pushq %rdi + /* We entered an interrupt context - irqs are off: */ TRACE_IRQS_OFF @@ -561,6 +991,8 @@ ret_from_intr: GLOBAL(retint_user) mov %rsp,%rdi call prepare_exit_to_usermode + pax_exit_kernel_user +# pax_erase_kstack TRACE_IRQS_IRETQ SWAPGS jmp restore_regs_and_iret @@ -578,6 +1010,21 @@ retint_kernel: jmp 0b 1: #endif + + pax_exit_kernel + +#if defined(CONFIG_EFI) && defined(CONFIG_PAX_KERNEXEC) + /* This is a quirk to allow IRQs/NMIs/MCEs during early EFI setup, + * namely calling EFI runtime services with a phys mapping. We're + * starting off with NOPs and patch in the real instrumentation + * (BTS/OR) before starting any userland process; even before starting + * up the APs. + */ + ALTERNATIVE "", "pax_force_retaddr 16*8", X86_FEATURE_ALWAYS +#else + pax_force_retaddr RIP +#endif + /* * The iretq could re-enable interrupts: */ @@ -621,15 +1068,15 @@ native_irq_return_ldt: SWAPGS movq PER_CPU_VAR(espfix_waddr), %rdi movq %rax, (0*8)(%rdi) /* RAX */ - movq (2*8)(%rsp), %rax /* RIP */ + movq (2*8 + RIP-RIP)(%rsp), %rax /* RIP */ movq %rax, (1*8)(%rdi) - movq (3*8)(%rsp), %rax /* CS */ + movq (2*8 + CS-RIP)(%rsp), %rax /* CS */ movq %rax, (2*8)(%rdi) - movq (4*8)(%rsp), %rax /* RFLAGS */ + movq (2*8 + EFLAGS-RIP)(%rsp), %rax /* RFLAGS */ movq %rax, (3*8)(%rdi) - movq (6*8)(%rsp), %rax /* SS */ + movq (2*8 + SS-RIP)(%rsp), %rax /* SS */ movq %rax, (5*8)(%rdi) - movq (5*8)(%rsp), %rax /* RSP */ + movq (2*8 + RSP-RIP)(%rsp), %rax /* RSP */ movq %rax, (4*8)(%rdi) andl $0xffff0000, %eax popq %rdi @@ -639,7 +1086,7 @@ native_irq_return_ldt: popq %rax jmp native_irq_return_iret #endif -END(common_interrupt) +ENDPROC(common_interrupt) /* * APIC interrupts. @@ -651,7 +1098,7 @@ ENTRY(\sym) .Lcommon_\sym: interrupt \do_sym jmp ret_from_intr -END(\sym) +ENDPROC(\sym) .endm #ifdef CONFIG_TRACING @@ -716,7 +1163,7 @@ apicinterrupt IRQ_WORK_VECTOR irq_work_interrupt smp_irq_work_interrupt /* * Exception entry points. */ -#define CPU_TSS_IST(x) PER_CPU_VAR(cpu_tss) + (TSS_ist + ((x) - 1) * 8) +#define CPU_TSS_IST(x) (TSS_ist + ((x) - 1) * 8)(%r13) .macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1 ENTRY(\sym) @@ -763,6 +1210,12 @@ ENTRY(\sym) .endif .if \shift_ist != -1 +#ifdef CONFIG_SMP + imul $TSS_size, PER_CPU_VAR(cpu_number), %r13d + lea cpu_tss(%r13), %r13 +#else + lea cpu_tss(%rip), %r13 +#endif subq $EXCEPTION_STKSZ, CPU_TSS_IST(\shift_ist) .endif @@ -806,7 +1259,7 @@ ENTRY(\sym) jmp error_exit /* %ebx: no swapgs flag */ .endif -END(\sym) +ENDPROC(\sym) .endm #ifdef CONFIG_TRACING @@ -848,8 +1301,9 @@ gs_change: 2: mfence /* workaround */ SWAPGS popfq + pax_force_retaddr ret -END(native_load_gs_index) +ENDPROC(native_load_gs_index) _ASM_EXTABLE(gs_change, bad_gs) .section .fixup, "ax" @@ -871,8 +1325,9 @@ ENTRY(do_softirq_own_stack) call __do_softirq leaveq decl PER_CPU_VAR(irq_count) + pax_force_retaddr ret -END(do_softirq_own_stack) +ENDPROC(do_softirq_own_stack) #ifdef CONFIG_XEN idtentry xen_hypervisor_callback xen_do_hypervisor_callback has_error_code=0 @@ -908,7 +1363,7 @@ ENTRY(xen_do_hypervisor_callback) /* do_hypervisor_callback(struct *pt_regs) */ call xen_maybe_preempt_hcall #endif jmp error_exit -END(xen_do_hypervisor_callback) +ENDPROC(xen_do_hypervisor_callback) /* * Hypervisor uses this for application faults while it executes. @@ -953,7 +1408,7 @@ ENTRY(xen_failsafe_callback) SAVE_C_REGS SAVE_EXTRA_REGS jmp error_exit -END(xen_failsafe_callback) +ENDPROC(xen_failsafe_callback) apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \ xen_hvm_callback_vector xen_evtchn_do_upcall @@ -1002,8 +1457,34 @@ ENTRY(paranoid_entry) js 1f /* negative -> in kernel */ SWAPGS xorl %ebx, %ebx -1: ret -END(paranoid_entry) +1: +#ifdef CONFIG_PAX_MEMORY_UDEREF + testb $3, CS+8(%rsp) + jz 1f + pax_enter_kernel_user + jmp 2f +#endif +1: pax_enter_kernel +2: + pax_force_retaddr + ret +ENDPROC(paranoid_entry) + +ENTRY(paranoid_entry_nmi) + cld + SAVE_C_REGS 8 + SAVE_EXTRA_REGS 8 + movl $1, %ebx + movl $MSR_GS_BASE, %ecx + rdmsr + testl %edx, %edx + js 1f /* negative -> in kernel */ + SWAPGS + xorl %ebx, %ebx +1: pax_enter_kernel_nmi + pax_force_retaddr + ret +ENDPROC(paranoid_entry_nmi) /* * "Paranoid" exit path from exception stack. This is invoked @@ -1020,19 +1501,26 @@ END(paranoid_entry) ENTRY(paranoid_exit) DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF_DEBUG - testl %ebx, %ebx /* swapgs needed? */ + testl $1, %ebx /* swapgs needed? */ jnz paranoid_exit_no_swapgs +#ifdef CONFIG_PAX_MEMORY_UDEREF + pax_exit_kernel_user +#else + pax_exit_kernel +#endif TRACE_IRQS_IRETQ SWAPGS_UNSAFE_STACK jmp paranoid_exit_restore paranoid_exit_no_swapgs: + pax_exit_kernel TRACE_IRQS_IRETQ_DEBUG paranoid_exit_restore: RESTORE_EXTRA_REGS RESTORE_C_REGS REMOVE_PT_GPREGS_FROM_STACK 8 + pax_force_retaddr_bts INTERRUPT_RETURN -END(paranoid_exit) +ENDPROC(paranoid_exit) /* * Save all registers in pt_regs, and switch gs if needed. @@ -1046,21 +1534,26 @@ ENTRY(error_entry) testb $3, CS+8(%rsp) jz .Lerror_kernelspace -.Lerror_entry_from_usermode_swapgs: /* * We entered from user mode or we're pretending to have entered * from user mode due to an IRET fault. */ SWAPGS +#ifdef CONFIG_PAX_MEMORY_UDEREF + pax_enter_kernel_user +#else + pax_enter_kernel +#endif + .Lerror_entry_from_usermode_after_swapgs: #ifdef CONFIG_CONTEXT_TRACKING call enter_from_user_mode #endif .Lerror_entry_done: - TRACE_IRQS_OFF + pax_force_retaddr ret /* @@ -1078,14 +1571,16 @@ ENTRY(error_entry) cmpq %rax, RIP+8(%rsp) je .Lbstep_iret cmpq $gs_change, RIP+8(%rsp) - jne .Lerror_entry_done + jne 1f /* * hack: gs_change can fail with user gsbase. If this happens, fix up * gsbase and proceed. We'll fix up the exception and land in * gs_change's error handler with kernel gsbase. */ - jmp .Lerror_entry_from_usermode_swapgs + SWAPGS +1: pax_enter_kernel + jmp .Lerror_entry_done .Lbstep_iret: /* Fix truncated RIP */ @@ -1099,6 +1594,12 @@ ENTRY(error_entry) */ SWAPGS +#ifdef CONFIG_PAX_MEMORY_UDEREF + pax_enter_kernel_user +#else + pax_enter_kernel +#endif + /* * Pretend that the exception came from user mode: set up pt_regs * as if we faulted immediately after IRET and clear EBX so that @@ -1109,11 +1610,11 @@ ENTRY(error_entry) mov %rax, %rsp decl %ebx jmp .Lerror_entry_from_usermode_after_swapgs -END(error_entry) +ENDPROC(error_entry) /* - * On entry, EBS is a "return to kernel mode" flag: + * On entry, EBX is a "return to kernel mode" flag: * 1: already in kernel mode, don't need SWAPGS * 0: user gsbase is loaded, we need SWAPGS and standard preparation for return to usermode */ @@ -1121,10 +1622,10 @@ ENTRY(error_exit) movl %ebx, %eax DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF - testl %eax, %eax + testl $1, %eax jnz retint_kernel jmp retint_user -END(error_exit) +ENDPROC(error_exit) /* Runs on exception stack */ ENTRY(nmi) @@ -1178,6 +1679,8 @@ ENTRY(nmi) * other IST entries. */ + ASM_CLAC + /* Use %rdx as our temp variable throughout */ pushq %rdx @@ -1221,6 +1724,12 @@ ENTRY(nmi) pushq %r14 /* pt_regs->r14 */ pushq %r15 /* pt_regs->r15 */ +#if defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) + xorl %ebx, %ebx +#endif + + pax_enter_kernel_nmi + /* * At this point we no longer need to worry about stack damage * due to nesting -- we're on the normal thread stack and we're @@ -1231,12 +1740,19 @@ ENTRY(nmi) movq $-1, %rsi call do_nmi + pax_exit_kernel_nmi + /* * Return back to user mode. We must *not* do the normal exit * work, because we don't want to enable interrupts. Fortunately, * do_nmi doesn't modify pt_regs. */ SWAPGS + +#if defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) + movq RBX(%rsp), %rbx +#endif + jmp restore_c_regs_and_iret .Lnmi_from_kernel: @@ -1358,6 +1874,7 @@ nested_nmi_out: popq %rdx /* We are returning to kernel mode, so this cannot result in a fault. */ +# pax_force_retaddr_bts INTERRUPT_RETURN first_nmi: @@ -1431,20 +1948,22 @@ end_repeat_nmi: ALLOC_PT_GPREGS_ON_STACK /* - * Use paranoid_entry to handle SWAPGS, but no need to use paranoid_exit + * Use paranoid_entry_nmi to handle SWAPGS, but no need to use paranoid_exit * as we should not be calling schedule in NMI context. * Even with normal interrupts enabled. An NMI should not be * setting NEED_RESCHED or anything that normal interrupts and * exceptions might do. */ - call paranoid_entry + call paranoid_entry_nmi /* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */ movq %rsp, %rdi movq $-1, %rsi call do_nmi - testl %ebx, %ebx /* swapgs needed? */ + pax_exit_kernel_nmi + + testl $1, %ebx /* swapgs needed? */ jnz nmi_restore nmi_swapgs: SWAPGS_UNSAFE_STACK @@ -1455,6 +1974,8 @@ nmi_restore: /* Point RSP at the "iret" frame. */ REMOVE_PT_GPREGS_FROM_STACK 6*8 + pax_force_retaddr_bts + /* * Clear "NMI executing". Set DF first so that we can easily * distinguish the remaining code between here and IRET from @@ -1472,9 +1993,9 @@ nmi_restore: * mode, so this cannot result in a fault. */ INTERRUPT_RETURN -END(nmi) +ENDPROC(nmi) ENTRY(ignore_sysret) mov $-ENOSYS, %eax sysret -END(ignore_sysret) +ENDPROC(ignore_sysret) diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S index a9360d4..e87da3e 100644 --- a/arch/x86/entry/entry_64_compat.S +++ b/arch/x86/entry/entry_64_compat.S @@ -13,8 +13,10 @@ #include #include #include +#include #include #include +#include /* Avoid __ASSEMBLER__'ifying just for this. */ #include @@ -35,6 +37,32 @@ ENTRY(native_usergs_sysret32) ENDPROC(native_usergs_sysret32) #endif + .macro pax_enter_kernel_user + pax_set_fptr_mask +#ifdef CONFIG_PAX_MEMORY_UDEREF + call pax_enter_kernel_user +#endif + .endm + + .macro pax_exit_kernel_user +#ifdef CONFIG_PAX_MEMORY_UDEREF + call pax_exit_kernel_user +#endif +#ifdef CONFIG_PAX_RANDKSTACK + pushq %rax + pushq %r11 + call pax_randomize_kstack + popq %r11 + popq %rax +#endif + .endm + + .macro pax_erase_kstack +#ifdef CONFIG_PAX_MEMORY_STACKLEAK + call pax_erase_kstack +#endif + .endm + /* * 32-bit SYSENTER instruction entry. * @@ -65,20 +93,21 @@ ENTRY(entry_SYSENTER_compat) */ SWAPGS_UNSAFE_STACK movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp - ENABLE_INTERRUPTS(CLBR_NONE) /* Zero-extending 32-bit regs, do not remove */ movl %ebp, %ebp movl %eax, %eax - movl ASM_THREAD_INFO(TI_sysenter_return, %rsp, 0), %r10d + GET_THREAD_INFO(%r11) + movl TI_sysenter_return(%r11), %r11d /* Construct struct pt_regs on stack */ pushq $__USER32_DS /* pt_regs->ss */ pushq %rbp /* pt_regs->sp */ pushfq /* pt_regs->flags */ + orl $X86_EFLAGS_IF,(%rsp) pushq $__USER32_CS /* pt_regs->cs */ - pushq %r10 /* pt_regs->ip = thread_info->sysenter_return */ + pushq %r11 /* pt_regs->ip = thread_info->sysenter_return */ pushq %rax /* pt_regs->orig_ax */ pushq %rdi /* pt_regs->di */ pushq %rsi /* pt_regs->si */ @@ -88,15 +117,37 @@ ENTRY(entry_SYSENTER_compat) cld sub $(10*8), %rsp /* pt_regs->r8-11, bp, bx, r12-15 not saved */ +#ifdef CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_OR + movq %r12, R12(%rsp) +#endif + + pax_enter_kernel_user + +#ifdef CONFIG_PAX_RANDKSTACK + pax_erase_kstack +#endif + + ENABLE_INTERRUPTS(CLBR_NONE) + /* * no need to do an access_ok check here because rbp has been * 32-bit zero extended */ + +#ifdef CONFIG_PAX_MEMORY_UDEREF + addq pax_user_shadow_base, %rbp + ASM_PAX_OPEN_USERLAND +#endif + ASM_STAC 1: movl (%rbp), %ebp _ASM_EXTABLE(1b, ia32_badarg) ASM_CLAC +#ifdef CONFIG_PAX_MEMORY_UDEREF + ASM_PAX_CLOSE_USERLAND +#endif + /* * Sysenter doesn't filter flags, so we need to clear NT * ourselves. To save a few cycles, we can check whether @@ -106,8 +157,9 @@ ENTRY(entry_SYSENTER_compat) jnz sysenter_fix_flags sysenter_flags_fixed: - orl $TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS) - testl $_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) + GET_THREAD_INFO(%r11) + orl $TS_COMPAT, TI_status(%r11) + testl $_TIF_WORK_SYSCALL_ENTRY, TI_flags(%r11) jnz sysenter_tracesys sysenter_do_call: @@ -123,9 +175,10 @@ sysenter_dispatch: call *ia32_sys_call_table(, %rax, 8) movq %rax, RAX(%rsp) 1: + GET_THREAD_INFO(%r11) DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF - testl $_TIF_ALLWORK_MASK, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) + testl $_TIF_ALLWORK_MASK, TI_flags(%r11) jnz sysexit_audit sysexit_from_sys_call: /* @@ -138,11 +191,18 @@ sysexit_from_sys_call: * This code path is still called 'sysexit' because it pairs * with 'sysenter' and it uses the SYSENTER calling convention. */ - andl $~TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS) + pax_exit_kernel_user + pax_erase_kstack + andl $~TS_COMPAT, TI_status(%r11) movl RIP(%rsp), %ecx /* User %eip */ movq RAX(%rsp), %rax movl RSI(%rsp), %esi movl RDI(%rsp), %edi + +#ifdef CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_OR + movq R12(%rsp), %r12 +#endif + xorl %edx, %edx /* Do not leak kernel information */ xorq %r8, %r8 xorq %r9, %r9 @@ -195,6 +255,8 @@ sysexit_from_sys_call: movl %eax, %edi /* arg1 (RDI) <= syscall number (EAX) */ call __audit_syscall_entry + pax_erase_kstack + /* * We are going to jump back to the syscall dispatch code. * Prepare syscall args as required by the 64-bit C ABI. @@ -212,7 +274,7 @@ sysexit_from_sys_call: .macro auditsys_exit exit TRACE_IRQS_ON ENABLE_INTERRUPTS(CLBR_NONE) - testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) + testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), TI_flags(%r11) jnz ia32_ret_from_sys_call movl %eax, %esi /* second arg, syscall return value */ cmpl $-MAX_ERRNO, %eax /* is it an error ? */ @@ -221,10 +283,11 @@ sysexit_from_sys_call: 1: setbe %al /* 1 if error, 0 if not */ movzbl %al, %edi /* zero-extend that into %edi */ call __audit_syscall_exit + GET_THREAD_INFO(%r11) movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %edi DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF - testl %edi, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) + testl %edi, TI_flags(%r11) jz \exit xorl %eax, %eax /* Do not leak kernel information */ movq %rax, R11(%rsp) @@ -250,7 +313,7 @@ sysenter_fix_flags: sysenter_tracesys: #ifdef CONFIG_AUDITSYSCALL - testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT), ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) + testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT), TI_flags(%r11) jz sysenter_auditsys #endif SAVE_EXTRA_REGS @@ -270,6 +333,9 @@ sysenter_tracesys: movl %eax, %eax /* zero extension */ RESTORE_EXTRA_REGS + + pax_erase_kstack + jmp sysenter_do_call ENDPROC(entry_SYSENTER_compat) @@ -312,7 +378,6 @@ ENTRY(entry_SYSCALL_compat) SWAPGS_UNSAFE_STACK movl %esp, %r8d movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp - ENABLE_INTERRUPTS(CLBR_NONE) /* Zero-extending 32-bit regs, do not remove */ movl %eax, %eax @@ -332,16 +397,40 @@ ENTRY(entry_SYSCALL_compat) pushq $-ENOSYS /* pt_regs->ax */ sub $(10*8), %rsp /* pt_regs->r8-11, bp, bx, r12-15 not saved */ +#ifdef CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_OR + movq %r12, R12(%rsp) +#endif + + pax_enter_kernel_user + +#ifdef CONFIG_PAX_RANDKSTACK + pax_erase_kstack +#endif + + ENABLE_INTERRUPTS(CLBR_NONE) + /* * No need to do an access_ok check here because r8 has been * 32-bit zero extended: */ + +#ifdef CONFIG_PAX_MEMORY_UDEREF + addq pax_user_shadow_base, %r8 + ASM_PAX_OPEN_USERLAND +#endif + ASM_STAC 1: movl (%r8), %r9d _ASM_EXTABLE(1b, ia32_badarg) ASM_CLAC - orl $TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS) - testl $_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) + +#ifdef CONFIG_PAX_MEMORY_UDEREF + ASM_PAX_CLOSE_USERLAND +#endif + + GET_THREAD_INFO(%r11) + orl $TS_COMPAT,TI_status(%r11) + testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r11) jnz cstar_tracesys cstar_do_call: @@ -359,19 +448,27 @@ cstar_dispatch: call *ia32_sys_call_table(, %rax, 8) movq %rax, RAX(%rsp) 1: + GET_THREAD_INFO(%r11) DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF - testl $_TIF_ALLWORK_MASK, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) + testl $_TIF_ALLWORK_MASK, TI_flags(%r11) jnz sysretl_audit sysretl_from_sys_call: - andl $~TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS) + pax_exit_kernel_user + pax_erase_kstack + andl $~TS_COMPAT, TI_status(%r11) movl RDX(%rsp), %edx movl RSI(%rsp), %esi movl RDI(%rsp), %edi movl RIP(%rsp), %ecx movl EFLAGS(%rsp), %r11d - movq RAX(%rsp), %rax + movq RAX(%rsp), %rax + +#ifdef CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_OR + movq R12(%rsp), %r12 +#endif + xorq %r10, %r10 xorq %r9, %r9 xorq %r8, %r8 @@ -406,7 +503,7 @@ sysretl_audit: cstar_tracesys: #ifdef CONFIG_AUDITSYSCALL - testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT), ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) + testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT), TI_flags(%r11) jz cstar_auditsys #endif xchgl %r9d, %ebp @@ -429,6 +526,9 @@ cstar_tracesys: RESTORE_EXTRA_REGS xchgl %ebp, %r9d + + pax_erase_kstack + jmp cstar_do_call END(entry_SYSCALL_compat) @@ -449,6 +549,11 @@ ia32_badarg: */ ASM_CLAC /* undo STAC */ + +#ifdef CONFIG_PAX_MEMORY_UDEREF + ASM_PAX_CLOSE_USERLAND +#endif + movq $-EFAULT, RAX(%rsp) /* return -EFAULT if possible */ /* Fill in the rest of pt_regs */ @@ -505,14 +610,8 @@ ia32_ret_from_sys_call: */ ENTRY(entry_INT80_compat) - /* - * Interrupts are off on entry. - * We do not frame this tiny irq-off block with TRACE_IRQS_OFF/ON, - * it is too small to ever cause noticeable irq latency. - */ PARAVIRT_ADJUST_EXCEPTION_FRAME SWAPGS - ENABLE_INTERRUPTS(CLBR_NONE) /* Zero-extending 32-bit regs, do not remove */ movl %eax, %eax @@ -531,8 +630,26 @@ ENTRY(entry_INT80_compat) cld sub $(6*8), %rsp /* pt_regs->bp, bx, r12-15 not saved */ - orl $TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS) - testl $_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) +#ifdef CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_OR + movq %r12, R12(%rsp) +#endif + + pax_enter_kernel_user + +#ifdef CONFIG_PAX_RANDKSTACK + pax_erase_kstack +#endif + + /* + * Interrupts are off on entry. + * We do not frame this tiny irq-off block with TRACE_IRQS_OFF/ON, + * it is too small to ever cause noticeable irq latency. + */ + ENABLE_INTERRUPTS(CLBR_NONE) + + GET_THREAD_INFO(%r11) + orl $TS_COMPAT, TI_status(%r11) + testl $_TIF_WORK_SYSCALL_ENTRY, TI_flags(%r11) jnz ia32_tracesys ia32_do_call: @@ -567,6 +684,9 @@ ia32_tracesys: movl RDI(%rsp), %edi movl %eax, %eax /* zero extension */ RESTORE_EXTRA_REGS + + pax_erase_kstack + jmp ia32_do_call END(entry_INT80_compat) diff --git a/arch/x86/entry/thunk_64.S b/arch/x86/entry/thunk_64.S index efb2b93..8a9cb8e 100644 --- a/arch/x86/entry/thunk_64.S +++ b/arch/x86/entry/thunk_64.S @@ -8,6 +8,7 @@ #include #include "calling.h" #include +#include /* rdi: arg1 ... normal C conventions. rax is saved/restored. */ .macro THUNK name, func, put_ret_addr_in_rdi=0 @@ -62,6 +63,7 @@ restore: popq %rdx popq %rsi popq %rdi + pax_force_retaddr ret _ASM_NOKPROBE(restore) #endif diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile index a3d0767..36d66c9 100644 --- a/arch/x86/entry/vdso/Makefile +++ b/arch/x86/entry/vdso/Makefile @@ -175,7 +175,7 @@ quiet_cmd_vdso = VDSO $@ -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) && \ sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@' -VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=both) \ +VDSO_LDFLAGS = -fPIC -shared -Wl,--no-undefined $(call cc-ldoption, -Wl$(comma)--hash-style=both) \ $(call cc-ldoption, -Wl$(comma)--build-id) -Wl,-Bsymbolic $(LTO_CFLAGS) GCOV_PROFILE := n diff --git a/arch/x86/entry/vdso/vdso2c.h b/arch/x86/entry/vdso/vdso2c.h index 0224987..0359810 100644 --- a/arch/x86/entry/vdso/vdso2c.h +++ b/arch/x86/entry/vdso/vdso2c.h @@ -12,7 +12,7 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len, unsigned long load_size = -1; /* Work around bogus warning */ unsigned long mapping_size; ELF(Ehdr) *hdr = (ELF(Ehdr) *)raw_addr; - int i; + unsigned int i; unsigned long j; ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr, *secstrings_hdr, *alt_sec = NULL; @@ -83,7 +83,7 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len, for (i = 0; i < GET_LE(&symtab_hdr->sh_size) / GET_LE(&symtab_hdr->sh_entsize); i++) { - int k; + unsigned int k; ELF(Sym) *sym = raw_addr + GET_LE(&symtab_hdr->sh_offset) + GET_LE(&symtab_hdr->sh_entsize) * i; const char *name = raw_addr + GET_LE(&strtab_hdr->sh_offset) + @@ -140,7 +140,7 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len, fprintf(outfile, "#include \n"); fprintf(outfile, "\n"); fprintf(outfile, - "static unsigned char raw_data[%lu] __page_aligned_data = {", + "static unsigned char raw_data[%lu] __page_aligned_rodata = {", mapping_size); for (j = 0; j < stripped_len; j++) { if (j % 10 == 0) @@ -150,7 +150,7 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len, } fprintf(outfile, "\n};\n\n"); - fprintf(outfile, "static struct page *pages[%lu];\n\n", + fprintf(outfile, "static struct page *pages[%lu] __read_only;\n\n", mapping_size / 4096); fprintf(outfile, "const struct vdso_image %s = {\n", name); diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c index 4345431..50ae49a 100644 --- a/arch/x86/entry/vdso/vma.c +++ b/arch/x86/entry/vdso/vma.c @@ -19,10 +19,7 @@ #include #include #include - -#if defined(CONFIG_X86_64) -unsigned int __read_mostly vdso64_enabled = 1; -#endif +#include void __init init_vdso_image(const struct vdso_image *image) { @@ -101,6 +98,11 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr) .pages = no_pages, }; +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + calculate_addr = false; +#endif + if (calculate_addr) { addr = vdso_addr(current->mm->start_stack, image->size - image->sym_vvar_start); @@ -111,14 +113,14 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr) down_write(&mm->mmap_sem); addr = get_unmapped_area(NULL, addr, - image->size - image->sym_vvar_start, 0, 0); + image->size - image->sym_vvar_start, 0, MAP_EXECUTABLE); if (IS_ERR_VALUE(addr)) { ret = addr; goto up_fail; } text_start = addr - image->sym_vvar_start; - current->mm->context.vdso = (void __user *)text_start; + mm->context.vdso = text_start; /* * MAYWRITE to allow gdb to COW and set breakpoints @@ -163,15 +165,12 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr) hpet_address >> PAGE_SHIFT, PAGE_SIZE, pgprot_noncached(PAGE_READONLY)); - - if (ret) - goto up_fail; } #endif up_fail: if (ret) - current->mm->context.vdso = NULL; + current->mm->context.vdso = 0; up_write(&mm->mmap_sem); return ret; @@ -191,8 +190,8 @@ static int load_vdso32(void) if (selected_vdso32->sym_VDSO32_SYSENTER_RETURN) current_thread_info()->sysenter_return = - current->mm->context.vdso + - selected_vdso32->sym_VDSO32_SYSENTER_RETURN; + (void __force_user *)(current->mm->context.vdso + + selected_vdso32->sym_VDSO32_SYSENTER_RETURN); return 0; } @@ -201,9 +200,6 @@ static int load_vdso32(void) #ifdef CONFIG_X86_64 int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { - if (!vdso64_enabled) - return 0; - return map_vdso(&vdso_image_64, true); } @@ -212,12 +208,8 @@ int compat_arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { #ifdef CONFIG_X86_X32_ABI - if (test_thread_flag(TIF_X32)) { - if (!vdso64_enabled) - return 0; - + if (test_thread_flag(TIF_X32)) return map_vdso(&vdso_image_x32, true); - } #endif #ifdef CONFIG_IA32_EMULATION return load_vdso32(); @@ -234,15 +226,6 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) #endif #ifdef CONFIG_X86_64 -static __init int vdso_setup(char *s) -{ - vdso64_enabled = simple_strtoul(s, NULL, 0); - return 0; -} -__setup("vdso=", vdso_setup); -#endif - -#ifdef CONFIG_X86_64 static void vgetcpu_cpu_init(void *arg) { int cpu = smp_processor_id(); diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c index b160c0c..a00ee2f 100644 --- a/arch/x86/entry/vsyscall/vsyscall_64.c +++ b/arch/x86/entry/vsyscall/vsyscall_64.c @@ -38,15 +38,13 @@ #define CREATE_TRACE_POINTS #include "vsyscall_trace.h" -static enum { EMULATE, NATIVE, NONE } vsyscall_mode = EMULATE; +static enum { EMULATE, NONE } vsyscall_mode = EMULATE; static int __init vsyscall_setup(char *str) { if (str) { if (!strcmp("emulate", str)) vsyscall_mode = EMULATE; - else if (!strcmp("native", str)) - vsyscall_mode = NATIVE; else if (!strcmp("none", str)) vsyscall_mode = NONE; else @@ -264,8 +262,7 @@ do_ret: return true; sigsegv: - force_sig(SIGSEGV, current); - return true; + do_group_exit(SIGKILL); } /* @@ -283,8 +280,8 @@ static const struct vm_operations_struct gate_vma_ops = { static struct vm_area_struct gate_vma = { .vm_start = VSYSCALL_ADDR, .vm_end = VSYSCALL_ADDR + PAGE_SIZE, - .vm_page_prot = PAGE_READONLY_EXEC, - .vm_flags = VM_READ | VM_EXEC, + .vm_page_prot = PAGE_READONLY, + .vm_flags = VM_READ, .vm_ops = &gate_vma_ops, }; @@ -325,10 +322,7 @@ void __init map_vsyscall(void) unsigned long physaddr_vsyscall = __pa_symbol(&__vsyscall_page); if (vsyscall_mode != NONE) - __set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall, - vsyscall_mode == NATIVE - ? PAGE_KERNEL_VSYSCALL - : PAGE_KERNEL_VVAR); + __set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall, PAGE_KERNEL_VVAR); BUILD_BUG_ON((unsigned long)__fix_to_virt(VSYSCALL_PAGE) != (unsigned long)VSYSCALL_ADDR); diff --git a/arch/x86/entry/vsyscall/vsyscall_emu_64.S b/arch/x86/entry/vsyscall/vsyscall_emu_64.S index c9596a9..805b68d 100644 --- a/arch/x86/entry/vsyscall/vsyscall_emu_64.S +++ b/arch/x86/entry/vsyscall/vsyscall_emu_64.S @@ -12,7 +12,7 @@ #include #include -__PAGE_ALIGNED_DATA +.section ".data..read_only", "a" .globl __vsyscall_page .balign PAGE_SIZE, 0xcc .type __vsyscall_page, @object diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c index ae6aad1..719d6d9 100644 --- a/arch/x86/ia32/ia32_aout.c +++ b/arch/x86/ia32/ia32_aout.c @@ -153,6 +153,8 @@ static int aout_core_dump(struct coredump_params *cprm) unsigned long dump_start, dump_size; struct user32 dump; + memset(&dump, 0, sizeof(dump)); + fs = get_fs(); set_fs(KERNEL_DS); has_dumped = 1; diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index a0a19b7..10b0289 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c @@ -123,7 +123,7 @@ asmlinkage long sys32_sigreturn(void) if (__get_user(set.sig[0], &frame->sc.oldmask) || (_COMPAT_NSIG_WORDS > 1 && __copy_from_user((((char *) &set.sig) + 4), - &frame->extramask, + frame->extramask, sizeof(frame->extramask)))) goto badframe; @@ -243,7 +243,7 @@ static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, sp -= frame_size; /* Align the stack pointer according to the i386 ABI, * i.e. so that on function entry ((sp + 4) & 15) == 0. */ - sp = ((sp + 4) & -16ul) - 4; + sp = ((sp - 12) & -16ul) - 4; return (void __user *) sp; } @@ -288,10 +288,10 @@ int ia32_setup_frame(int sig, struct ksignal *ksig, } else { /* Return stub is in 32bit vsyscall page */ if (current->mm->context.vdso) - restorer = current->mm->context.vdso + - selected_vdso32->sym___kernel_sigreturn; + restorer = (void __force_user *)(current->mm->context.vdso + + selected_vdso32->sym___kernel_sigreturn); else - restorer = &frame->retcode; + restorer = frame->retcode; } put_user_try { @@ -301,7 +301,7 @@ int ia32_setup_frame(int sig, struct ksignal *ksig, * These are actually not used anymore, but left because some * gdb versions depend on them as a marker. */ - put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode); + put_user_ex(*((const u64 *)&code), (u64 __user *)frame->retcode); } put_user_catch(err); if (err) @@ -343,7 +343,7 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig, 0xb8, __NR_ia32_rt_sigreturn, 0x80cd, - 0, + 0 }; frame = get_sigframe(ksig, regs, sizeof(*frame), &fpstate); @@ -366,16 +366,19 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig, if (ksig->ka.sa.sa_flags & SA_RESTORER) restorer = ksig->ka.sa.sa_restorer; + else if (current->mm->context.vdso) + /* Return stub is in 32bit vsyscall page */ + restorer = (void __force_user *)(current->mm->context.vdso + + selected_vdso32->sym___kernel_rt_sigreturn); else - restorer = current->mm->context.vdso + - selected_vdso32->sym___kernel_rt_sigreturn; + restorer = frame->retcode; put_user_ex(ptr_to_compat(restorer), &frame->pretcode); /* * Not actually used anymore, but left because some gdb * versions need it. */ - put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode); + put_user_ex(*((const u64 *)&code), (u64 __user *)frame->retcode); } put_user_catch(err); err |= copy_siginfo_to_user32(&frame->info, &ksig->info); diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c index 719cd70..72af944 100644 --- a/arch/x86/ia32/sys_ia32.c +++ b/arch/x86/ia32/sys_ia32.c @@ -49,18 +49,26 @@ #define AA(__x) ((unsigned long)(__x)) +static inline loff_t compose_loff(unsigned int high, unsigned int low) +{ + loff_t retval = low; + + BUILD_BUG_ON(sizeof retval != sizeof low + sizeof high); + __builtin_memcpy((unsigned char *)&retval + sizeof low, &high, sizeof high); + return retval; +} asmlinkage long sys32_truncate64(const char __user *filename, - unsigned long offset_low, - unsigned long offset_high) + unsigned int offset_low, + unsigned int offset_high) { - return sys_truncate(filename, ((loff_t) offset_high << 32) | offset_low); + return sys_truncate(filename, compose_loff(offset_high, offset_low)); } -asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long offset_low, - unsigned long offset_high) +asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned int offset_low, + unsigned int offset_high) { - return sys_ftruncate(fd, ((loff_t) offset_high << 32) | offset_low); + return sys_ftruncate(fd, ((unsigned long) offset_high << 32) | offset_low); } /* @@ -69,8 +77,8 @@ asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long offset_low, */ static int cp_stat64(struct stat64 __user *ubuf, struct kstat *stat) { - typeof(ubuf->st_uid) uid = 0; - typeof(ubuf->st_gid) gid = 0; + typeof(((struct stat64 *)0)->st_uid) uid = 0; + typeof(((struct stat64 *)0)->st_gid) gid = 0; SET_UID(uid, from_kuid_munged(current_user_ns(), stat->uid)); SET_GID(gid, from_kgid_munged(current_user_ns(), stat->gid)); if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct stat64)) || @@ -196,29 +204,29 @@ long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high, __u32 len_low, __u32 len_high, int advice) { return sys_fadvise64_64(fd, - (((u64)offset_high)<<32) | offset_low, - (((u64)len_high)<<32) | len_low, + compose_loff(offset_high, offset_low), + compose_loff(len_high, len_low), advice); } asmlinkage ssize_t sys32_readahead(int fd, unsigned off_lo, unsigned off_hi, size_t count) { - return sys_readahead(fd, ((u64)off_hi << 32) | off_lo, count); + return sys_readahead(fd, compose_loff(off_hi, off_lo), count); } asmlinkage long sys32_sync_file_range(int fd, unsigned off_low, unsigned off_hi, unsigned n_low, unsigned n_hi, int flags) { return sys_sync_file_range(fd, - ((u64)off_hi << 32) | off_low, - ((u64)n_hi << 32) | n_low, flags); + compose_loff(off_hi, off_low), + compose_loff(n_hi, n_low), flags); } asmlinkage long sys32_fadvise64(int fd, unsigned offset_lo, unsigned offset_hi, - size_t len, int advice) + int len, int advice) { - return sys_fadvise64_64(fd, ((u64)offset_hi << 32) | offset_lo, + return sys_fadvise64_64(fd, compose_loff(offset_hi, offset_lo), len, advice); } @@ -226,6 +234,6 @@ asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_lo, unsigned offset_hi, unsigned len_lo, unsigned len_hi) { - return sys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo, - ((u64)len_hi << 32) | len_lo); + return sys_fallocate(fd, mode, compose_loff(offset_hi, offset_lo), + compose_loff(len_hi, len_lo)); } diff --git a/arch/x86/include/asm/alternative-asm.h b/arch/x86/include/asm/alternative-asm.h index e7636ba..e1fb78a 100644 --- a/arch/x86/include/asm/alternative-asm.h +++ b/arch/x86/include/asm/alternative-asm.h @@ -18,6 +18,45 @@ .endm #endif +#ifdef KERNEXEC_PLUGIN + .macro pax_force_retaddr_bts rip=0 + btsq $63,\rip(%rsp) + .endm +#ifdef CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_BTS + .macro pax_force_retaddr rip=0, reload=0 + btsq $63,\rip(%rsp) + .endm + .macro pax_force_fptr ptr + btsq $63,\ptr + .endm + .macro pax_set_fptr_mask + .endm +#endif +#ifdef CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_OR + .macro pax_force_retaddr rip=0, reload=0 + .if \reload + pax_set_fptr_mask + .endif + orq %r12,\rip(%rsp) + .endm + .macro pax_force_fptr ptr + orq %r12,\ptr + .endm + .macro pax_set_fptr_mask + movabs $0x8000000000000000,%r12 + .endm +#endif +#else + .macro pax_force_retaddr rip=0, reload=0 + .endm + .macro pax_force_fptr ptr + .endm + .macro pax_force_retaddr_bts rip=0 + .endm + .macro pax_set_fptr_mask + .endm +#endif + /* * Issue one struct alt_instr descriptor entry (need to put it into * the section .altinstructions, see below). This entry contains @@ -50,7 +89,7 @@ altinstruction_entry 140b,143f,\feature,142b-140b,144f-143f,142b-141b .popsection - .pushsection .altinstr_replacement,"ax" + .pushsection .altinstr_replacement,"a" 143: \newinstr 144: @@ -86,7 +125,7 @@ altinstruction_entry 140b,144f,\feature2,142b-140b,145f-144f,142b-141b .popsection - .pushsection .altinstr_replacement,"ax" + .pushsection .altinstr_replacement,"a" 143: \newinstr1 144: diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 7bfc85b..65d1ec4 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -136,7 +136,7 @@ static inline int alternatives_text_reserved(void *start, void *end) ".pushsection .altinstructions,\"a\"\n" \ ALTINSTR_ENTRY(feature, 1) \ ".popsection\n" \ - ".pushsection .altinstr_replacement, \"ax\"\n" \ + ".pushsection .altinstr_replacement, \"a\"\n" \ ALTINSTR_REPLACEMENT(newinstr, feature, 1) \ ".popsection" @@ -146,7 +146,7 @@ static inline int alternatives_text_reserved(void *start, void *end) ALTINSTR_ENTRY(feature1, 1) \ ALTINSTR_ENTRY(feature2, 2) \ ".popsection\n" \ - ".pushsection .altinstr_replacement, \"ax\"\n" \ + ".pushsection .altinstr_replacement, \"a\"\n" \ ALTINSTR_REPLACEMENT(newinstr1, feature1, 1) \ ALTINSTR_REPLACEMENT(newinstr2, feature2, 2) \ ".popsection" diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index ebf6d5e..91c1cf2 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -45,7 +45,7 @@ static inline void generic_apic_probe(void) #ifdef CONFIG_X86_LOCAL_APIC -extern unsigned int apic_verbosity; +extern int apic_verbosity; extern int local_apic_timer_c2_ok; extern int disable_apic; diff --git a/arch/x86/include/asm/apm.h b/arch/x86/include/asm/apm.h index 20370c6..a2eb9b0 100644 --- a/arch/x86/include/asm/apm.h +++ b/arch/x86/include/asm/apm.h @@ -34,7 +34,7 @@ static inline void apm_bios_call_asm(u32 func, u32 ebx_in, u32 ecx_in, __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" - "lcall *%%cs:apm_bios_entry\n\t" + "lcall *%%ss:apm_bios_entry\n\t" "setc %%al\n\t" "popl %%ebp\n\t" "popl %%edi\n\t" @@ -58,7 +58,7 @@ static inline u8 apm_bios_call_simple_asm(u32 func, u32 ebx_in, __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" - "lcall *%%cs:apm_bios_entry\n\t" + "lcall *%%ss:apm_bios_entry\n\t" "setc %%bl\n\t" "popl %%ebp\n\t" "popl %%edi\n\t" diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h index fb52aa6..527487e 100644 --- a/arch/x86/include/asm/atomic.h +++ b/arch/x86/include/asm/atomic.h @@ -28,6 +28,17 @@ static __always_inline int atomic_read(const atomic_t *v) } /** + * atomic_read_unchecked - read atomic variable + * @v: pointer of type atomic_unchecked_t + * + * Atomically reads the value of @v. + */ +static __always_inline int __intentional_overflow(-1) atomic_read_unchecked(const atomic_unchecked_t *v) +{ + return ACCESS_ONCE((v)->counter); +} + +/** * atomic_set - set atomic variable * @v: pointer of type atomic_t * @i: required value @@ -40,6 +51,18 @@ static __always_inline void atomic_set(atomic_t *v, int i) } /** + * atomic_set_unchecked - set atomic variable + * @v: pointer of type atomic_unchecked_t + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static __always_inline void atomic_set_unchecked(atomic_unchecked_t *v, int i) +{ + v->counter = i; +} + +/** * atomic_add - add integer to atomic variable * @i: integer value to add * @v: pointer of type atomic_t @@ -48,7 +71,29 @@ static __always_inline void atomic_set(atomic_t *v, int i) */ static __always_inline void atomic_add(int i, atomic_t *v) { - asm volatile(LOCK_PREFIX "addl %1,%0" + asm volatile(LOCK_PREFIX "addl %1,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "subl %1,%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + : "+m" (v->counter) + : "ir" (i)); +} + +/** + * atomic_add_unchecked - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type atomic_unchecked_t + * + * Atomically adds @i to @v. + */ +static __always_inline void atomic_add_unchecked(int i, atomic_unchecked_t *v) +{ + asm volatile(LOCK_PREFIX "addl %1,%0\n" : "+m" (v->counter) : "ir" (i)); } @@ -62,7 +107,29 @@ static __always_inline void atomic_add(int i, atomic_t *v) */ static __always_inline void atomic_sub(int i, atomic_t *v) { - asm volatile(LOCK_PREFIX "subl %1,%0" + asm volatile(LOCK_PREFIX "subl %1,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "addl %1,%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + : "+m" (v->counter) + : "ir" (i)); +} + +/** + * atomic_sub_unchecked - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type atomic_unchecked_t + * + * Atomically subtracts @i from @v. + */ +static __always_inline void atomic_sub_unchecked(int i, atomic_unchecked_t *v) +{ + asm volatile(LOCK_PREFIX "subl %1,%0\n" : "+m" (v->counter) : "ir" (i)); } @@ -78,7 +145,7 @@ static __always_inline void atomic_sub(int i, atomic_t *v) */ static __always_inline int atomic_sub_and_test(int i, atomic_t *v) { - GEN_BINARY_RMWcc(LOCK_PREFIX "subl", v->counter, "er", i, "%0", "e"); + GEN_BINARY_RMWcc(LOCK_PREFIX "subl", LOCK_PREFIX "addl", v->counter, "er", i, "%0", "e"); } /** @@ -89,7 +156,27 @@ static __always_inline int atomic_sub_and_test(int i, atomic_t *v) */ static __always_inline void atomic_inc(atomic_t *v) { - asm volatile(LOCK_PREFIX "incl %0" + asm volatile(LOCK_PREFIX "incl %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "decl %0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + : "+m" (v->counter)); +} + +/** + * atomic_inc_unchecked - increment atomic variable + * @v: pointer of type atomic_unchecked_t + * + * Atomically increments @v by 1. + */ +static __always_inline void atomic_inc_unchecked(atomic_unchecked_t *v) +{ + asm volatile(LOCK_PREFIX "incl %0\n" : "+m" (v->counter)); } @@ -101,7 +188,27 @@ static __always_inline void atomic_inc(atomic_t *v) */ static __always_inline void atomic_dec(atomic_t *v) { - asm volatile(LOCK_PREFIX "decl %0" + asm volatile(LOCK_PREFIX "decl %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "incl %0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + : "+m" (v->counter)); +} + +/** + * atomic_dec_unchecked - decrement atomic variable + * @v: pointer of type atomic_unchecked_t + * + * Atomically decrements @v by 1. + */ +static __always_inline void atomic_dec_unchecked(atomic_unchecked_t *v) +{ + asm volatile(LOCK_PREFIX "decl %0\n" : "+m" (v->counter)); } @@ -115,7 +222,7 @@ static __always_inline void atomic_dec(atomic_t *v) */ static __always_inline int atomic_dec_and_test(atomic_t *v) { - GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, "%0", "e"); + GEN_UNARY_RMWcc(LOCK_PREFIX "decl", LOCK_PREFIX "incl", v->counter, "%0", "e"); } /** @@ -128,7 +235,20 @@ static __always_inline int atomic_dec_and_test(atomic_t *v) */ static __always_inline int atomic_inc_and_test(atomic_t *v) { - GEN_UNARY_RMWcc(LOCK_PREFIX "incl", v->counter, "%0", "e"); + GEN_UNARY_RMWcc(LOCK_PREFIX "incl", LOCK_PREFIX "decl", v->counter, "%0", "e"); +} + +/** + * atomic_inc_and_test_unchecked - increment and test + * @v: pointer of type atomic_unchecked_t + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +static __always_inline int atomic_inc_and_test_unchecked(atomic_unchecked_t *v) +{ + GEN_UNARY_RMWcc_unchecked(LOCK_PREFIX "incl", v->counter, "%0", "e"); } /** @@ -142,7 +262,7 @@ static __always_inline int atomic_inc_and_test(atomic_t *v) */ static __always_inline int atomic_add_negative(int i, atomic_t *v) { - GEN_BINARY_RMWcc(LOCK_PREFIX "addl", v->counter, "er", i, "%0", "s"); + GEN_BINARY_RMWcc(LOCK_PREFIX "addl", LOCK_PREFIX "subl", v->counter, "er", i, "%0", "s"); } /** @@ -152,7 +272,19 @@ static __always_inline int atomic_add_negative(int i, atomic_t *v) * * Atomically adds @i to @v and returns @i + @v */ -static __always_inline int atomic_add_return(int i, atomic_t *v) +static __always_inline int __intentional_overflow(-1) atomic_add_return(int i, atomic_t *v) +{ + return i + xadd_check_overflow(&v->counter, i); +} + +/** + * atomic_add_return_unchecked - add integer and return + * @i: integer value to add + * @v: pointer of type atomi_uncheckedc_t + * + * Atomically adds @i to @v and returns @i + @v + */ +static __always_inline int atomic_add_return_unchecked(int i, atomic_unchecked_t *v) { return i + xadd(&v->counter, i); } @@ -164,15 +296,24 @@ static __always_inline int atomic_add_return(int i, atomic_t *v) * * Atomically subtracts @i from @v and returns @v - @i */ -static __always_inline int atomic_sub_return(int i, atomic_t *v) +static __always_inline int __intentional_overflow(-1) atomic_sub_return(int i, atomic_t *v) { return atomic_add_return(-i, v); } #define atomic_inc_return(v) (atomic_add_return(1, v)) +static __always_inline int atomic_inc_return_unchecked(atomic_unchecked_t *v) +{ + return atomic_add_return_unchecked(1, v); +} #define atomic_dec_return(v) (atomic_sub_return(1, v)) -static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new) +static __always_inline int __intentional_overflow(-1) atomic_cmpxchg(atomic_t *v, int old, int new) +{ + return cmpxchg(&v->counter, old, new); +} + +static __always_inline int atomic_cmpxchg_unchecked(atomic_unchecked_t *v, int old, int new) { return cmpxchg(&v->counter, old, new); } @@ -182,6 +323,11 @@ static inline int atomic_xchg(atomic_t *v, int new) return xchg(&v->counter, new); } +static inline int atomic_xchg_unchecked(atomic_unchecked_t *v, int new) +{ + return xchg(&v->counter, new); +} + #define ATOMIC_OP(op) \ static inline void atomic_##op(int i, atomic_t *v) \ { \ @@ -208,12 +354,25 @@ ATOMIC_OP(xor) */ static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) { - int c, old; + int c, old, new; c = atomic_read(v); for (;;) { - if (unlikely(c == (u))) + if (unlikely(c == u)) break; - old = atomic_cmpxchg((v), c, c + (a)); + + asm volatile("addl %2,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + "subl %2,%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + : "=r" (new) + : "0" (c), "ir" (a)); + + old = atomic_cmpxchg(v, c, new); if (likely(old == c)) break; c = old; @@ -222,6 +381,49 @@ static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) } /** + * atomic_inc_not_zero_hint - increment if not null + * @v: pointer of type atomic_t + * @hint: probable value of the atomic before the increment + * + * This version of atomic_inc_not_zero() gives a hint of probable + * value of the atomic. This helps processor to not read the memory + * before doing the atomic read/modify/write cycle, lowering + * number of bus transactions on some arches. + * + * Returns: 0 if increment was not done, 1 otherwise. + */ +#define atomic_inc_not_zero_hint atomic_inc_not_zero_hint +static inline int atomic_inc_not_zero_hint(atomic_t *v, int hint) +{ + int val, c = hint, new; + + /* sanity test, should be removed by compiler if hint is a constant */ + if (!hint) + return __atomic_add_unless(v, 1, 0); + + do { + asm volatile("incl %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + "decl %0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + : "=r" (new) + : "0" (c)); + + val = atomic_cmpxchg(v, c, new); + if (val == c) + return 1; + c = val; + } while (c); + + return 0; +} + +/** * atomic_inc_short - increment of a short integer * @v: pointer to type int * diff --git a/arch/x86/include/asm/atomic64_32.h b/arch/x86/include/asm/atomic64_32.h index a11c30b..66fd8a0 100644 --- a/arch/x86/include/asm/atomic64_32.h +++ b/arch/x86/include/asm/atomic64_32.h @@ -12,6 +12,14 @@ typedef struct { u64 __aligned(8) counter; } atomic64_t; +#ifdef CONFIG_PAX_REFCOUNT +typedef struct { + u64 __aligned(8) counter; +} atomic64_unchecked_t; +#else +typedef atomic64_t atomic64_unchecked_t; +#endif + #define ATOMIC64_INIT(val) { (val) } #define __ATOMIC64_DECL(sym) void atomic64_##sym(atomic64_t *, ...) @@ -37,21 +45,31 @@ typedef struct { ATOMIC64_DECL_ONE(sym##_386) ATOMIC64_DECL_ONE(add_386); +ATOMIC64_DECL_ONE(add_unchecked_386); ATOMIC64_DECL_ONE(sub_386); +ATOMIC64_DECL_ONE(sub_unchecked_386); ATOMIC64_DECL_ONE(inc_386); +ATOMIC64_DECL_ONE(inc_unchecked_386); ATOMIC64_DECL_ONE(dec_386); +ATOMIC64_DECL_ONE(dec_unchecked_386); #endif #define alternative_atomic64(f, out, in...) \ __alternative_atomic64(f, f, ASM_OUTPUT2(out), ## in) ATOMIC64_DECL(read); +ATOMIC64_DECL(read_unchecked); ATOMIC64_DECL(set); +ATOMIC64_DECL(set_unchecked); ATOMIC64_DECL(xchg); ATOMIC64_DECL(add_return); +ATOMIC64_DECL(add_return_unchecked); ATOMIC64_DECL(sub_return); +ATOMIC64_DECL(sub_return_unchecked); ATOMIC64_DECL(inc_return); +ATOMIC64_DECL(inc_return_unchecked); ATOMIC64_DECL(dec_return); +ATOMIC64_DECL(dec_return_unchecked); ATOMIC64_DECL(dec_if_positive); ATOMIC64_DECL(inc_not_zero); ATOMIC64_DECL(add_unless); @@ -77,6 +95,21 @@ static inline long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n } /** + * atomic64_cmpxchg_unchecked - cmpxchg atomic64 variable + * @p: pointer to type atomic64_unchecked_t + * @o: expected value + * @n: new value + * + * Atomically sets @v to @n if it was equal to @o and returns + * the old value. + */ + +static inline long long atomic64_cmpxchg_unchecked(atomic64_unchecked_t *v, long long o, long long n) +{ + return cmpxchg64(&v->counter, o, n); +} + +/** * atomic64_xchg - xchg atomic64 variable * @v: pointer to type atomic64_t * @n: value to assign @@ -112,6 +145,22 @@ static inline void atomic64_set(atomic64_t *v, long long i) } /** + * atomic64_set_unchecked - set atomic64 variable + * @v: pointer to type atomic64_unchecked_t + * @n: value to assign + * + * Atomically sets the value of @v to @n. + */ +static inline void atomic64_set_unchecked(atomic64_unchecked_t *v, long long i) +{ + unsigned high = (unsigned)(i >> 32); + unsigned low = (unsigned)i; + alternative_atomic64(set, /* no output */, + "S" (v), "b" (low), "c" (high) + : "eax", "edx", "memory"); +} + +/** * atomic64_read - read atomic64 variable * @v: pointer to type atomic64_t * @@ -125,6 +174,19 @@ static inline long long atomic64_read(const atomic64_t *v) } /** + * atomic64_read_unchecked - read atomic64 variable + * @v: pointer to type atomic64_unchecked_t + * + * Atomically reads the value of @v and returns it. + */ +static inline long long __intentional_overflow(-1) atomic64_read_unchecked(const atomic64_unchecked_t *v) +{ + long long r; + alternative_atomic64(read, "=&A" (r), "c" (v) : "memory"); + return r; + } + +/** * atomic64_add_return - add and return * @i: integer value to add * @v: pointer to type atomic64_t @@ -139,6 +201,21 @@ static inline long long atomic64_add_return(long long i, atomic64_t *v) return i; } +/** + * atomic64_add_return_unchecked - add and return + * @i: integer value to add + * @v: pointer to type atomic64_unchecked_t + * + * Atomically adds @i to @v and returns @i + *@v + */ +static inline long long atomic64_add_return_unchecked(long long i, atomic64_unchecked_t *v) +{ + alternative_atomic64(add_return_unchecked, + ASM_OUTPUT2("+A" (i), "+c" (v)), + ASM_NO_INPUT_CLOBBER("memory")); + return i; +} + /* * Other variants with different arithmetic operators: */ @@ -158,6 +235,14 @@ static inline long long atomic64_inc_return(atomic64_t *v) return a; } +static inline long long atomic64_inc_return_unchecked(atomic64_unchecked_t *v) +{ + long long a; + alternative_atomic64(inc_return_unchecked, "=&A" (a), + "S" (v) : "memory", "ecx"); + return a; +} + static inline long long atomic64_dec_return(atomic64_t *v) { long long a; @@ -182,6 +267,21 @@ static inline long long atomic64_add(long long i, atomic64_t *v) } /** + * atomic64_add_unchecked - add integer to atomic64 variable + * @i: integer value to add + * @v: pointer to type atomic64_unchecked_t + * + * Atomically adds @i to @v. + */ +static inline long long atomic64_add_unchecked(long long i, atomic64_unchecked_t *v) +{ + __alternative_atomic64(add_unchecked, add_return_unchecked, + ASM_OUTPUT2("+A" (i), "+c" (v)), + ASM_NO_INPUT_CLOBBER("memory")); + return i; +} + +/** * atomic64_sub - subtract the atomic64 variable * @i: integer value to subtract * @v: pointer to type atomic64_t diff --git a/arch/x86/include/asm/atomic64_64.h b/arch/x86/include/asm/atomic64_64.h index 50e33ef..d36dd50 100644 --- a/arch/x86/include/asm/atomic64_64.h +++ b/arch/x86/include/asm/atomic64_64.h @@ -22,6 +22,18 @@ static inline long atomic64_read(const atomic64_t *v) } /** + * atomic64_read_unchecked - read atomic64 variable + * @v: pointer of type atomic64_unchecked_t + * + * Atomically reads the value of @v. + * Doesn't imply a read memory barrier. + */ +static inline long __intentional_overflow(-1) atomic64_read_unchecked(const atomic64_unchecked_t *v) +{ + return ACCESS_ONCE((v)->counter); +} + +/** * atomic64_set - set atomic64 variable * @v: pointer to type atomic64_t * @i: required value @@ -34,6 +46,18 @@ static inline void atomic64_set(atomic64_t *v, long i) } /** + * atomic64_set_unchecked - set atomic64 variable + * @v: pointer to type atomic64_unchecked_t + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static inline void atomic64_set_unchecked(atomic64_unchecked_t *v, long i) +{ + v->counter = i; +} + +/** * atomic64_add - add integer to atomic64 variable * @i: integer value to add * @v: pointer to type atomic64_t @@ -42,6 +66,28 @@ static inline void atomic64_set(atomic64_t *v, long i) */ static __always_inline void atomic64_add(long i, atomic64_t *v) { + asm volatile(LOCK_PREFIX "addq %1,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "subq %1,%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + : "=m" (v->counter) + : "er" (i), "m" (v->counter)); +} + +/** + * atomic64_add_unchecked - add integer to atomic64 variable + * @i: integer value to add + * @v: pointer to type atomic64_unchecked_t + * + * Atomically adds @i to @v. + */ +static __always_inline void atomic64_add_unchecked(long i, atomic64_unchecked_t *v) +{ asm volatile(LOCK_PREFIX "addq %1,%0" : "=m" (v->counter) : "er" (i), "m" (v->counter)); @@ -56,7 +102,29 @@ static __always_inline void atomic64_add(long i, atomic64_t *v) */ static inline void atomic64_sub(long i, atomic64_t *v) { - asm volatile(LOCK_PREFIX "subq %1,%0" + asm volatile(LOCK_PREFIX "subq %1,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "addq %1,%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + : "=m" (v->counter) + : "er" (i), "m" (v->counter)); +} + +/** + * atomic64_sub_unchecked - subtract the atomic64 variable + * @i: integer value to subtract + * @v: pointer to type atomic64_unchecked_t + * + * Atomically subtracts @i from @v. + */ +static inline void atomic64_sub_unchecked(long i, atomic64_unchecked_t *v) +{ + asm volatile(LOCK_PREFIX "subq %1,%0\n" : "=m" (v->counter) : "er" (i), "m" (v->counter)); } @@ -72,7 +140,7 @@ static inline void atomic64_sub(long i, atomic64_t *v) */ static inline int atomic64_sub_and_test(long i, atomic64_t *v) { - GEN_BINARY_RMWcc(LOCK_PREFIX "subq", v->counter, "er", i, "%0", "e"); + GEN_BINARY_RMWcc(LOCK_PREFIX "subq", LOCK_PREFIX "addq", v->counter, "er", i, "%0", "e"); } /** @@ -83,6 +151,27 @@ static inline int atomic64_sub_and_test(long i, atomic64_t *v) */ static __always_inline void atomic64_inc(atomic64_t *v) { + asm volatile(LOCK_PREFIX "incq %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "decq %0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + : "=m" (v->counter) + : "m" (v->counter)); +} + +/** + * atomic64_inc_unchecked - increment atomic64 variable + * @v: pointer to type atomic64_unchecked_t + * + * Atomically increments @v by 1. + */ +static __always_inline void atomic64_inc_unchecked(atomic64_unchecked_t *v) +{ asm volatile(LOCK_PREFIX "incq %0" : "=m" (v->counter) : "m" (v->counter)); @@ -96,7 +185,28 @@ static __always_inline void atomic64_inc(atomic64_t *v) */ static __always_inline void atomic64_dec(atomic64_t *v) { - asm volatile(LOCK_PREFIX "decq %0" + asm volatile(LOCK_PREFIX "decq %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "incq %0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + : "=m" (v->counter) + : "m" (v->counter)); +} + +/** + * atomic64_dec_unchecked - decrement atomic64 variable + * @v: pointer to type atomic64_t + * + * Atomically decrements @v by 1. + */ +static __always_inline void atomic64_dec_unchecked(atomic64_unchecked_t *v) +{ + asm volatile(LOCK_PREFIX "decq %0\n" : "=m" (v->counter) : "m" (v->counter)); } @@ -111,7 +221,7 @@ static __always_inline void atomic64_dec(atomic64_t *v) */ static inline int atomic64_dec_and_test(atomic64_t *v) { - GEN_UNARY_RMWcc(LOCK_PREFIX "decq", v->counter, "%0", "e"); + GEN_UNARY_RMWcc(LOCK_PREFIX "decq", LOCK_PREFIX "incq", v->counter, "%0", "e"); } /** @@ -124,7 +234,7 @@ static inline int atomic64_dec_and_test(atomic64_t *v) */ static inline int atomic64_inc_and_test(atomic64_t *v) { - GEN_UNARY_RMWcc(LOCK_PREFIX "incq", v->counter, "%0", "e"); + GEN_UNARY_RMWcc(LOCK_PREFIX "incq", LOCK_PREFIX "decq", v->counter, "%0", "e"); } /** @@ -138,7 +248,7 @@ static inline int atomic64_inc_and_test(atomic64_t *v) */ static inline int atomic64_add_negative(long i, atomic64_t *v) { - GEN_BINARY_RMWcc(LOCK_PREFIX "addq", v->counter, "er", i, "%0", "s"); + GEN_BINARY_RMWcc(LOCK_PREFIX "addq", LOCK_PREFIX "subq", v->counter, "er", i, "%0", "s"); } /** @@ -150,6 +260,18 @@ static inline int atomic64_add_negative(long i, atomic64_t *v) */ static __always_inline long atomic64_add_return(long i, atomic64_t *v) { + return i + xadd_check_overflow(&v->counter, i); +} + +/** + * atomic64_add_return_unchecked - add and return + * @i: integer value to add + * @v: pointer to type atomic64_unchecked_t + * + * Atomically adds @i to @v and returns @i + @v + */ +static __always_inline long atomic64_add_return_unchecked(long i, atomic64_unchecked_t *v) +{ return i + xadd(&v->counter, i); } @@ -159,6 +281,10 @@ static inline long atomic64_sub_return(long i, atomic64_t *v) } #define atomic64_inc_return(v) (atomic64_add_return(1, (v))) +static inline long atomic64_inc_return_unchecked(atomic64_unchecked_t *v) +{ + return atomic64_add_return_unchecked(1, v); +} #define atomic64_dec_return(v) (atomic64_sub_return(1, (v))) static inline long atomic64_cmpxchg(atomic64_t *v, long old, long new) @@ -166,6 +292,11 @@ static inline long atomic64_cmpxchg(atomic64_t *v, long old, long new) return cmpxchg(&v->counter, old, new); } +static inline long atomic64_cmpxchg_unchecked(atomic64_unchecked_t *v, long old, long new) +{ + return cmpxchg(&v->counter, old, new); +} + static inline long atomic64_xchg(atomic64_t *v, long new) { return xchg(&v->counter, new); @@ -182,17 +313,30 @@ static inline long atomic64_xchg(atomic64_t *v, long new) */ static inline int atomic64_add_unless(atomic64_t *v, long a, long u) { - long c, old; + long c, old, new; c = atomic64_read(v); for (;;) { - if (unlikely(c == (u))) + if (unlikely(c == u)) break; - old = atomic64_cmpxchg((v), c, c + (a)); + + asm volatile("add %2,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + "sub %2,%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + : "=r" (new) + : "0" (c), "ir" (a)); + + old = atomic64_cmpxchg(v, c, new); if (likely(old == c)) break; c = old; } - return c != (u); + return c != u; } #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h index cfe3b95..d01b118 100644 --- a/arch/x86/include/asm/bitops.h +++ b/arch/x86/include/asm/bitops.h @@ -50,7 +50,7 @@ * a mask operation on a byte. */ #define IS_IMMEDIATE(nr) (__builtin_constant_p(nr)) -#define CONST_MASK_ADDR(nr, addr) BITOP_ADDR((void *)(addr) + ((nr)>>3)) +#define CONST_MASK_ADDR(nr, addr) BITOP_ADDR((volatile void *)(addr) + ((nr)>>3)) #define CONST_MASK(nr) (1 << ((nr) & 7)) /** @@ -203,7 +203,7 @@ static inline void change_bit(long nr, volatile unsigned long *addr) */ static inline int test_and_set_bit(long nr, volatile unsigned long *addr) { - GEN_BINARY_RMWcc(LOCK_PREFIX "bts", *addr, "Ir", nr, "%0", "c"); + GEN_BINARY_RMWcc_unchecked(LOCK_PREFIX "bts", *addr, "Ir", nr, "%0", "c"); } /** @@ -249,7 +249,7 @@ static inline int __test_and_set_bit(long nr, volatile unsigned long *addr) */ static inline int test_and_clear_bit(long nr, volatile unsigned long *addr) { - GEN_BINARY_RMWcc(LOCK_PREFIX "btr", *addr, "Ir", nr, "%0", "c"); + GEN_BINARY_RMWcc_unchecked(LOCK_PREFIX "btr", *addr, "Ir", nr, "%0", "c"); } /** @@ -302,7 +302,7 @@ static inline int __test_and_change_bit(long nr, volatile unsigned long *addr) */ static inline int test_and_change_bit(long nr, volatile unsigned long *addr) { - GEN_BINARY_RMWcc(LOCK_PREFIX "btc", *addr, "Ir", nr, "%0", "c"); + GEN_BINARY_RMWcc_unchecked(LOCK_PREFIX "btc", *addr, "Ir", nr, "%0", "c"); } static __always_inline int constant_test_bit(long nr, const volatile unsigned long *addr) @@ -343,7 +343,7 @@ static int test_bit(int nr, const volatile unsigned long *addr); * * Undefined if no bit exists, so code should check against 0 first. */ -static inline unsigned long __ffs(unsigned long word) +static inline unsigned long __intentional_overflow(-1) __ffs(unsigned long word) { asm("rep; bsf %1,%0" : "=r" (word) @@ -357,7 +357,7 @@ static inline unsigned long __ffs(unsigned long word) * * Undefined if no zero exists, so code should check against ~0UL first. */ -static inline unsigned long ffz(unsigned long word) +static inline unsigned long __intentional_overflow(-1) ffz(unsigned long word) { asm("rep; bsf %1,%0" : "=r" (word) @@ -371,7 +371,7 @@ static inline unsigned long ffz(unsigned long word) * * Undefined if no set bit exists, so code should check against 0 first. */ -static inline unsigned long __fls(unsigned long word) +static inline unsigned long __intentional_overflow(-1) __fls(unsigned long word) { asm("bsr %1,%0" : "=r" (word) @@ -434,7 +434,7 @@ static inline int ffs(int x) * set bit if value is nonzero. The last (most significant) bit is * at position 32. */ -static inline int fls(int x) +static inline int __intentional_overflow(-1) fls(int x) { int r; @@ -476,7 +476,7 @@ static inline int fls(int x) * at position 64. */ #ifdef CONFIG_X86_64 -static __always_inline int fls64(__u64 x) +static __always_inline __intentional_overflow(-1) int fls64(__u64 x) { int bitpos = -1; /* diff --git a/arch/x86/include/asm/boot.h b/arch/x86/include/asm/boot.h index 4fa687a..4ca636f 100644 --- a/arch/x86/include/asm/boot.h +++ b/arch/x86/include/asm/boot.h @@ -6,7 +6,7 @@ #include /* Physical address where kernel should be loaded. */ -#define LOAD_PHYSICAL_ADDR ((CONFIG_PHYSICAL_START \ +#define ____LOAD_PHYSICAL_ADDR ((CONFIG_PHYSICAL_START \ + (CONFIG_PHYSICAL_ALIGN - 1)) \ & ~(CONFIG_PHYSICAL_ALIGN - 1)) diff --git a/arch/x86/include/asm/cache.h b/arch/x86/include/asm/cache.h index 48f99f1..d78ebf9 100644 --- a/arch/x86/include/asm/cache.h +++ b/arch/x86/include/asm/cache.h @@ -5,12 +5,13 @@ /* L1 cache line size */ #define L1_CACHE_SHIFT (CONFIG_X86_L1_CACHE_SHIFT) -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) #define __read_mostly __attribute__((__section__(".data..read_mostly"))) +#define __read_only __attribute__((__section__(".data..read_only"))) #define INTERNODE_CACHE_SHIFT CONFIG_X86_INTERNODE_CACHE_SHIFT -#define INTERNODE_CACHE_BYTES (1 << INTERNODE_CACHE_SHIFT) +#define INTERNODE_CACHE_BYTES (_AC(1,UL) << INTERNODE_CACHE_SHIFT) #ifdef CONFIG_X86_VSMP #ifdef CONFIG_SMP diff --git a/arch/x86/include/asm/checksum_32.h b/arch/x86/include/asm/checksum_32.h index f50de69..2b0a458 100644 --- a/arch/x86/include/asm/checksum_32.h +++ b/arch/x86/include/asm/checksum_32.h @@ -31,6 +31,14 @@ asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst, int len, __wsum sum, int *src_err_ptr, int *dst_err_ptr); +asmlinkage __wsum csum_partial_copy_generic_to_user(const void *src, void *dst, + int len, __wsum sum, + int *src_err_ptr, int *dst_err_ptr); + +asmlinkage __wsum csum_partial_copy_generic_from_user(const void *src, void *dst, + int len, __wsum sum, + int *src_err_ptr, int *dst_err_ptr); + /* * Note: when you get a NULL pointer exception here this means someone * passed in an incorrect kernel address to one of these functions. @@ -53,7 +61,7 @@ static inline __wsum csum_partial_copy_from_user(const void __user *src, might_sleep(); stac(); - ret = csum_partial_copy_generic((__force void *)src, dst, + ret = csum_partial_copy_generic_from_user((__force void *)src, dst, len, sum, err_ptr, NULL); clac(); @@ -187,7 +195,7 @@ static inline __wsum csum_and_copy_to_user(const void *src, might_sleep(); if (access_ok(VERIFY_WRITE, dst, len)) { stac(); - ret = csum_partial_copy_generic(src, (__force void *)dst, + ret = csum_partial_copy_generic_to_user(src, (__force void *)dst, len, sum, NULL, err_ptr); clac(); return ret; diff --git a/arch/x86/include/asm/cmpxchg.h b/arch/x86/include/asm/cmpxchg.h index ad19841..0784041 100644 --- a/arch/x86/include/asm/cmpxchg.h +++ b/arch/x86/include/asm/cmpxchg.h @@ -14,8 +14,12 @@ extern void __cmpxchg_wrong_size(void) __compiletime_error("Bad argument size for cmpxchg"); extern void __xadd_wrong_size(void) __compiletime_error("Bad argument size for xadd"); +extern void __xadd_check_overflow_wrong_size(void) + __compiletime_error("Bad argument size for xadd_check_overflow"); extern void __add_wrong_size(void) __compiletime_error("Bad argument size for add"); +extern void __add_check_overflow_wrong_size(void) + __compiletime_error("Bad argument size for add_check_overflow"); /* * Constants for operation sizes. On 32-bit, the 64-bit size it set to @@ -67,6 +71,38 @@ extern void __add_wrong_size(void) __ret; \ }) +#ifdef CONFIG_PAX_REFCOUNT +#define __xchg_op_check_overflow(ptr, arg, op, lock) \ + ({ \ + __typeof__ (*(ptr)) __ret = (arg); \ + switch (sizeof(*(ptr))) { \ + case __X86_CASE_L: \ + asm volatile (lock #op "l %0, %1\n" \ + "jno 0f\n" \ + "mov %0,%1\n" \ + "int $4\n0:\n" \ + _ASM_EXTABLE(0b, 0b) \ + : "+r" (__ret), "+m" (*(ptr)) \ + : : "memory", "cc"); \ + break; \ + case __X86_CASE_Q: \ + asm volatile (lock #op "q %q0, %1\n" \ + "jno 0f\n" \ + "mov %0,%1\n" \ + "int $4\n0:\n" \ + _ASM_EXTABLE(0b, 0b) \ + : "+r" (__ret), "+m" (*(ptr)) \ + : : "memory", "cc"); \ + break; \ + default: \ + __ ## op ## _check_overflow_wrong_size(); \ + } \ + __ret; \ + }) +#else +#define __xchg_op_check_overflow(ptr, arg, op, lock) __xchg_op(ptr, arg, op, lock) +#endif + /* * Note: no "lock" prefix even on SMP: xchg always implies lock anyway. * Since this is generally used to protect other memory information, we @@ -165,6 +201,9 @@ extern void __add_wrong_size(void) #define xadd_sync(ptr, inc) __xadd((ptr), (inc), "lock; ") #define xadd_local(ptr, inc) __xadd((ptr), (inc), "") +#define __xadd_check_overflow(ptr, inc, lock) __xchg_op_check_overflow((ptr), (inc), xadd, lock) +#define xadd_check_overflow(ptr, inc) __xadd_check_overflow((ptr), (inc), LOCK_PREFIX) + #define __add(ptr, inc, lock) \ ({ \ __typeof__ (*(ptr)) __ret = (inc); \ diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h index acdee09..e5c31cd 100644 --- a/arch/x86/include/asm/compat.h +++ b/arch/x86/include/asm/compat.h @@ -41,7 +41,11 @@ typedef s64 __attribute__((aligned(4))) compat_s64; typedef u32 compat_uint_t; typedef u32 compat_ulong_t; typedef u64 __attribute__((aligned(4))) compat_u64; +#ifdef CHECKER_PLUGIN_USER typedef u32 compat_uptr_t; +#else +typedef u32 __user compat_uptr_t; +#endif struct compat_timespec { compat_time_t tv_sec; diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 9727b3b..183784a 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -216,7 +216,8 @@ #define X86_FEATURE_PAUSEFILTER ( 8*32+13) /* AMD filtered pause intercept */ #define X86_FEATURE_PFTHRESHOLD ( 8*32+14) /* AMD pause filter threshold */ #define X86_FEATURE_VMMCALL ( 8*32+15) /* Prefer vmmcall to vmcall */ - +#define X86_FEATURE_PCIDUDEREF ( 8*32+30) /* PaX PCID based UDEREF */ +#define X86_FEATURE_STRONGUDEREF (8*32+31) /* PaX PCID based strong UDEREF */ /* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */ #define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/ @@ -224,7 +225,7 @@ #define X86_FEATURE_BMI1 ( 9*32+ 3) /* 1st group bit manipulation extensions */ #define X86_FEATURE_HLE ( 9*32+ 4) /* Hardware Lock Elision */ #define X86_FEATURE_AVX2 ( 9*32+ 5) /* AVX2 instructions */ -#define X86_FEATURE_SMEP ( 9*32+ 7) /* Supervisor Mode Execution Protection */ +#define X86_FEATURE_SMEP ( 9*32+ 7) /* Supervisor Mode Execution Prevention */ #define X86_FEATURE_BMI2 ( 9*32+ 8) /* 2nd group bit manipulation extensions */ #define X86_FEATURE_ERMS ( 9*32+ 9) /* Enhanced REP MOVSB/STOSB */ #define X86_FEATURE_INVPCID ( 9*32+10) /* Invalidate Processor Context ID */ @@ -404,6 +405,7 @@ extern const char * const x86_bug_flags[NBUGINTS*32]; #define cpu_has_eager_fpu boot_cpu_has(X86_FEATURE_EAGER_FPU) #define cpu_has_topoext boot_cpu_has(X86_FEATURE_TOPOEXT) #define cpu_has_bpext boot_cpu_has(X86_FEATURE_BPEXT) +#define cpu_has_pcid boot_cpu_has(X86_FEATURE_PCID) #if __GNUC__ >= 4 extern void warn_pre_alternatives(void); @@ -457,7 +459,8 @@ static __always_inline __pure bool __static_cpu_has(u16 bit) #ifdef CONFIG_X86_DEBUG_STATIC_CPU_HAS t_warn: - warn_pre_alternatives(); + if (bit != X86_FEATURE_PCID && bit != X86_FEATURE_INVPCID && bit != X86_FEATURE_PCIDUDEREF) + warn_pre_alternatives(); return false; #endif @@ -478,7 +481,7 @@ static __always_inline __pure bool __static_cpu_has(u16 bit) ".section .discard,\"aw\",@progbits\n" " .byte 0xff + (4f-3f) - (2b-1b)\n" /* size check */ ".previous\n" - ".section .altinstr_replacement,\"ax\"\n" + ".section .altinstr_replacement,\"a\"\n" "3: movb $1,%0\n" "4:\n" ".previous\n" @@ -513,7 +516,7 @@ static __always_inline __pure bool _static_cpu_has_safe(u16 bit) " .byte 5f - 4f\n" /* repl len */ " .byte 3b - 2b\n" /* pad len */ ".previous\n" - ".section .altinstr_replacement,\"ax\"\n" + ".section .altinstr_replacement,\"a\"\n" "4: jmp %l[t_no]\n" "5:\n" ".previous\n" @@ -548,7 +551,7 @@ static __always_inline __pure bool _static_cpu_has_safe(u16 bit) ".section .discard,\"aw\",@progbits\n" " .byte 0xff + (4f-3f) - (2b-1b)\n" /* size check */ ".previous\n" - ".section .altinstr_replacement,\"ax\"\n" + ".section .altinstr_replacement,\"a\"\n" "3: movb $0,%0\n" "4:\n" ".previous\n" @@ -563,7 +566,7 @@ static __always_inline __pure bool _static_cpu_has_safe(u16 bit) ".section .discard,\"aw\",@progbits\n" " .byte 0xff + (6f-5f) - (4b-3b)\n" /* size check */ ".previous\n" - ".section .altinstr_replacement,\"ax\"\n" + ".section .altinstr_replacement,\"a\"\n" "5: movb $1,%0\n" "6:\n" ".previous\n" diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h index 4e10d73..7319a47 100644 --- a/arch/x86/include/asm/desc.h +++ b/arch/x86/include/asm/desc.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -17,6 +18,7 @@ static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *in desc->type = (info->read_exec_only ^ 1) << 1; desc->type |= info->contents << 2; + desc->type |= info->seg_not_present ^ 1; desc->s = 1; desc->dpl = 0x3; @@ -35,19 +37,14 @@ static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *in } extern struct desc_ptr idt_descr; -extern gate_desc idt_table[]; -extern struct desc_ptr debug_idt_descr; -extern gate_desc debug_idt_table[]; - -struct gdt_page { - struct desc_struct gdt[GDT_ENTRIES]; -} __attribute__((aligned(PAGE_SIZE))); - -DECLARE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page); +extern gate_desc idt_table[IDT_ENTRIES]; +extern const struct desc_ptr debug_idt_descr; +extern gate_desc debug_idt_table[IDT_ENTRIES]; +extern struct desc_struct cpu_gdt_table[NR_CPUS][PAGE_SIZE / sizeof(struct desc_struct)]; static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) { - return per_cpu(gdt_page, cpu).gdt; + return cpu_gdt_table[cpu]; } #ifdef CONFIG_X86_64 @@ -72,8 +69,14 @@ static inline void pack_gate(gate_desc *gate, unsigned char type, unsigned long base, unsigned dpl, unsigned flags, unsigned short seg) { - gate->a = (seg << 16) | (base & 0xffff); - gate->b = (base & 0xffff0000) | (((0x80 | type | (dpl << 5)) & 0xff) << 8); + gate->gate.offset_low = base; + gate->gate.seg = seg; + gate->gate.reserved = 0; + gate->gate.type = type; + gate->gate.s = 0; + gate->gate.dpl = dpl; + gate->gate.p = 1; + gate->gate.offset_high = base >> 16; } #endif @@ -118,12 +121,16 @@ static inline void paravirt_free_ldt(struct desc_struct *ldt, unsigned entries) static inline void native_write_idt_entry(gate_desc *idt, int entry, const gate_desc *gate) { + pax_open_kernel(); memcpy(&idt[entry], gate, sizeof(*gate)); + pax_close_kernel(); } static inline void native_write_ldt_entry(struct desc_struct *ldt, int entry, const void *desc) { + pax_open_kernel(); memcpy(&ldt[entry], desc, 8); + pax_close_kernel(); } static inline void @@ -137,7 +144,9 @@ native_write_gdt_entry(struct desc_struct *gdt, int entry, const void *desc, int default: size = sizeof(*gdt); break; } + pax_open_kernel(); memcpy(&gdt[entry], desc, size); + pax_close_kernel(); } static inline void pack_descriptor(struct desc_struct *desc, unsigned long base, @@ -210,7 +219,9 @@ static inline void native_set_ldt(const void *addr, unsigned int entries) static inline void native_load_tr_desc(void) { + pax_open_kernel(); asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8)); + pax_close_kernel(); } static inline void native_load_gdt(const struct desc_ptr *dtr) @@ -247,8 +258,10 @@ static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) struct desc_struct *gdt = get_cpu_gdt_table(cpu); unsigned int i; + pax_open_kernel(); for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]; + pax_close_kernel(); } /* This intentionally ignores lm, since 32-bit apps don't have that field. */ @@ -280,7 +293,7 @@ static inline void clear_LDT(void) set_ldt(NULL, 0); } -static inline unsigned long get_desc_base(const struct desc_struct *desc) +static inline unsigned long __intentional_overflow(-1) get_desc_base(const struct desc_struct *desc) { return (unsigned)(desc->base0 | ((desc->base1) << 16) | ((desc->base2) << 24)); } @@ -304,7 +317,7 @@ static inline void set_desc_limit(struct desc_struct *desc, unsigned long limit) } #ifdef CONFIG_X86_64 -static inline void set_nmi_gate(int gate, void *addr) +static inline void set_nmi_gate(int gate, const void *addr) { gate_desc s; @@ -314,14 +327,14 @@ static inline void set_nmi_gate(int gate, void *addr) #endif #ifdef CONFIG_TRACING -extern struct desc_ptr trace_idt_descr; -extern gate_desc trace_idt_table[]; +extern const struct desc_ptr trace_idt_descr; +extern gate_desc trace_idt_table[IDT_ENTRIES]; static inline void write_trace_idt_entry(int entry, const gate_desc *gate) { write_idt_entry(trace_idt_table, entry, gate); } -static inline void _trace_set_gate(int gate, unsigned type, void *addr, +static inline void _trace_set_gate(int gate, unsigned type, const void *addr, unsigned dpl, unsigned ist, unsigned seg) { gate_desc s; @@ -341,7 +354,7 @@ static inline void write_trace_idt_entry(int entry, const gate_desc *gate) #define _trace_set_gate(gate, type, addr, dpl, ist, seg) #endif -static inline void _set_gate(int gate, unsigned type, void *addr, +static inline void _set_gate(int gate, unsigned type, const void *addr, unsigned dpl, unsigned ist, unsigned seg) { gate_desc s; @@ -364,14 +377,14 @@ static inline void _set_gate(int gate, unsigned type, void *addr, #define set_intr_gate_notrace(n, addr) \ do { \ BUG_ON((unsigned)n > 0xFF); \ - _set_gate(n, GATE_INTERRUPT, (void *)addr, 0, 0, \ + _set_gate(n, GATE_INTERRUPT, (const void *)addr, 0, 0, \ __KERNEL_CS); \ } while (0) #define set_intr_gate(n, addr) \ do { \ set_intr_gate_notrace(n, addr); \ - _trace_set_gate(n, GATE_INTERRUPT, (void *)trace_##addr,\ + _trace_set_gate(n, GATE_INTERRUPT, (const void *)trace_##addr,\ 0, 0, __KERNEL_CS); \ } while (0) @@ -399,19 +412,19 @@ static inline void alloc_system_vector(int vector) /* * This routine sets up an interrupt gate at directory privilege level 3. */ -static inline void set_system_intr_gate(unsigned int n, void *addr) +static inline void set_system_intr_gate(unsigned int n, const void *addr) { BUG_ON((unsigned)n > 0xFF); _set_gate(n, GATE_INTERRUPT, addr, 0x3, 0, __KERNEL_CS); } -static inline void set_system_trap_gate(unsigned int n, void *addr) +static inline void set_system_trap_gate(unsigned int n, const void *addr) { BUG_ON((unsigned)n > 0xFF); _set_gate(n, GATE_TRAP, addr, 0x3, 0, __KERNEL_CS); } -static inline void set_trap_gate(unsigned int n, void *addr) +static inline void set_trap_gate(unsigned int n, const void *addr) { BUG_ON((unsigned)n > 0xFF); _set_gate(n, GATE_TRAP, addr, 0, 0, __KERNEL_CS); @@ -420,16 +433,16 @@ static inline void set_trap_gate(unsigned int n, void *addr) static inline void set_task_gate(unsigned int n, unsigned int gdt_entry) { BUG_ON((unsigned)n > 0xFF); - _set_gate(n, GATE_TASK, (void *)0, 0, 0, (gdt_entry<<3)); + _set_gate(n, GATE_TASK, (const void *)0, 0, 0, (gdt_entry<<3)); } -static inline void set_intr_gate_ist(int n, void *addr, unsigned ist) +static inline void set_intr_gate_ist(int n, const void *addr, unsigned ist) { BUG_ON((unsigned)n > 0xFF); _set_gate(n, GATE_INTERRUPT, addr, 0, ist, __KERNEL_CS); } -static inline void set_system_intr_gate_ist(int n, void *addr, unsigned ist) +static inline void set_system_intr_gate_ist(int n, const void *addr, unsigned ist) { BUG_ON((unsigned)n > 0xFF); _set_gate(n, GATE_INTERRUPT, addr, 0x3, ist, __KERNEL_CS); @@ -501,4 +514,17 @@ static inline void load_current_idt(void) else load_idt((const struct desc_ptr *)&idt_descr); } + +#ifdef CONFIG_X86_32 +static inline void set_user_cs(unsigned long base, unsigned long limit, int cpu) +{ + struct desc_struct d; + + if (likely(limit)) + limit = (limit - 1UL) >> PAGE_SHIFT; + pack_descriptor(&d, base, limit, 0xFB, 0xC); + write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_DEFAULT_USER_CS, &d, DESCTYPE_S); +} +#endif + #endif /* _ASM_X86_DESC_H */ diff --git a/arch/x86/include/asm/desc_defs.h b/arch/x86/include/asm/desc_defs.h index 278441f..b95a174 100644 --- a/arch/x86/include/asm/desc_defs.h +++ b/arch/x86/include/asm/desc_defs.h @@ -31,6 +31,12 @@ struct desc_struct { unsigned base1: 8, type: 4, s: 1, dpl: 2, p: 1; unsigned limit: 4, avl: 1, l: 1, d: 1, g: 1, base2: 8; }; + struct { + u16 offset_low; + u16 seg; + unsigned reserved: 8, type: 4, s: 1, dpl: 2, p: 1; + unsigned offset_high: 16; + } gate; }; } __attribute__((packed)); diff --git a/arch/x86/include/asm/div64.h b/arch/x86/include/asm/div64.h index ced283a..ffe04cc 100644 --- a/arch/x86/include/asm/div64.h +++ b/arch/x86/include/asm/div64.h @@ -39,7 +39,7 @@ __mod; \ }) -static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder) +static inline u64 __intentional_overflow(-1) div_u64_rem(u64 dividend, u32 divisor, u32 *remainder) { union { u64 v64; diff --git a/arch/x86/include/asm/dma.h b/arch/x86/include/asm/dma.h index fe884e1..46149ae 100644 --- a/arch/x86/include/asm/dma.h +++ b/arch/x86/include/asm/dma.h @@ -149,6 +149,7 @@ #ifdef CONFIG_ISA_DMA_API extern spinlock_t dma_spin_lock; +static inline unsigned long claim_dma_lock(void) __acquires(&dma_spin_lock); static inline unsigned long claim_dma_lock(void) { unsigned long flags; @@ -156,6 +157,7 @@ static inline unsigned long claim_dma_lock(void) return flags; } +static inline void release_dma_lock(unsigned long flags) __releases(&dma_spin_lock); static inline void release_dma_lock(unsigned long flags) { spin_unlock_irqrestore(&dma_spin_lock, flags); diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index 141c561..120c5386 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h @@ -75,9 +75,6 @@ typedef struct user_fxsr_struct elf_fpxregset_t; #include -#ifdef CONFIG_X86_64 -extern unsigned int vdso64_enabled; -#endif #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION) extern unsigned int vdso32_enabled; #endif @@ -250,7 +247,25 @@ extern int force_personality32; the loader. We need to make sure that it is out of the way of the program that it will "exec", and that there is sufficient room for the brk. */ +#ifdef CONFIG_PAX_SEGMEXEC +#define ELF_ET_DYN_BASE ((current->mm->pax_flags & MF_PAX_SEGMEXEC) ? SEGMEXEC_TASK_SIZE/3*2 : TASK_SIZE/3*2) +#else #define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) +#endif + +#ifdef CONFIG_PAX_ASLR +#ifdef CONFIG_X86_32 +#define PAX_ELF_ET_DYN_BASE 0x10000000UL + +#define PAX_DELTA_MMAP_LEN (current->mm->pax_flags & MF_PAX_SEGMEXEC ? 15 : 16) +#define PAX_DELTA_STACK_LEN (current->mm->pax_flags & MF_PAX_SEGMEXEC ? 15 : 16) +#else +#define PAX_ELF_ET_DYN_BASE 0x400000UL + +#define PAX_DELTA_MMAP_LEN ((test_thread_flag(TIF_ADDR32)) ? 16 : TASK_SIZE_MAX_SHIFT - PAGE_SHIFT - 3) +#define PAX_DELTA_STACK_LEN ((test_thread_flag(TIF_ADDR32)) ? 16 : TASK_SIZE_MAX_SHIFT - PAGE_SHIFT - 3) +#endif +#endif /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. This could be done in user space, @@ -299,17 +314,13 @@ do { \ #define ARCH_DLINFO \ do { \ - if (vdso64_enabled) \ - NEW_AUX_ENT(AT_SYSINFO_EHDR, \ - (unsigned long __force)current->mm->context.vdso); \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, current->mm->context.vdso); \ } while (0) /* As a historical oddity, the x32 and x86_64 vDSOs are controlled together. */ #define ARCH_DLINFO_X32 \ do { \ - if (vdso64_enabled) \ - NEW_AUX_ENT(AT_SYSINFO_EHDR, \ - (unsigned long __force)current->mm->context.vdso); \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, current->mm->context.vdso); \ } while (0) #define AT_SYSINFO 32 @@ -324,10 +335,10 @@ else \ #endif /* !CONFIG_X86_32 */ -#define VDSO_CURRENT_BASE ((unsigned long)current->mm->context.vdso) +#define VDSO_CURRENT_BASE (current->mm->context.vdso) #define VDSO_ENTRY \ - ((unsigned long)current->mm->context.vdso + \ + (current->mm->context.vdso + \ selected_vdso32->sym___kernel_vsyscall) struct linux_binprm; diff --git a/arch/x86/include/asm/emergency-restart.h b/arch/x86/include/asm/emergency-restart.h index 77a99ac..39ff7f5 100644 --- a/arch/x86/include/asm/emergency-restart.h +++ b/arch/x86/include/asm/emergency-restart.h @@ -1,6 +1,6 @@ #ifndef _ASM_X86_EMERGENCY_RESTART_H #define _ASM_X86_EMERGENCY_RESTART_H -extern void machine_emergency_restart(void); +extern void machine_emergency_restart(void) __noreturn; #endif /* _ASM_X86_EMERGENCY_RESTART_H */ diff --git a/arch/x86/include/asm/floppy.h b/arch/x86/include/asm/floppy.h index 1c7eefe..d0e4702 100644 --- a/arch/x86/include/asm/floppy.h +++ b/arch/x86/include/asm/floppy.h @@ -229,18 +229,18 @@ static struct fd_routine_l { int (*_dma_setup)(char *addr, unsigned long size, int mode, int io); } fd_routine[] = { { - request_dma, - free_dma, - get_dma_residue, - dma_mem_alloc, - hard_dma_setup + ._request_dma = request_dma, + ._free_dma = free_dma, + ._get_dma_residue = get_dma_residue, + ._dma_mem_alloc = dma_mem_alloc, + ._dma_setup = hard_dma_setup }, { - vdma_request_dma, - vdma_nop, - vdma_get_dma_residue, - vdma_mem_alloc, - vdma_dma_setup + ._request_dma = vdma_request_dma, + ._free_dma = vdma_nop, + ._get_dma_residue = vdma_get_dma_residue, + ._dma_mem_alloc = vdma_mem_alloc, + ._dma_setup = vdma_dma_setup } }; diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h index 3c3550c..ca9e4c3 100644 --- a/arch/x86/include/asm/fpu/internal.h +++ b/arch/x86/include/asm/fpu/internal.h @@ -97,8 +97,11 @@ extern void fpstate_sanitize_xstate(struct fpu *fpu); #define user_insn(insn, output, input...) \ ({ \ int err; \ + pax_open_userland(); \ asm volatile(ASM_STAC "\n" \ - "1:" #insn "\n\t" \ + "1:" \ + __copyuser_seg \ + #insn "\n\t" \ "2: " ASM_CLAC "\n" \ ".section .fixup,\"ax\"\n" \ "3: movl $-1,%[err]\n" \ @@ -107,6 +110,7 @@ extern void fpstate_sanitize_xstate(struct fpu *fpu); _ASM_EXTABLE(1b, 3b) \ : [err] "=r" (err), output \ : "0"(0), input); \ + pax_close_userland(); \ err; \ }) @@ -186,9 +190,9 @@ static inline int copy_user_to_fregs(struct fregs_state __user *fx) static inline void copy_fxregs_to_kernel(struct fpu *fpu) { if (config_enabled(CONFIG_X86_32)) - asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state.fxsave)); + asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state->fxsave)); else if (config_enabled(CONFIG_AS_FXSAVEQ)) - asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state.fxsave)); + asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state->fxsave)); else { /* Using "rex64; fxsave %0" is broken because, if the memory * operand uses any extended registers for addressing, a second @@ -205,15 +209,15 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu) * an extended register is needed for addressing (fix submitted * to mainline 2005-11-21). * - * asm volatile("rex64/fxsave %0" : "=m" (fpu->state.fxsave)); + * asm volatile("rex64/fxsave %0" : "=m" (fpu->state->fxsave)); * * This, however, we can work around by forcing the compiler to * select an addressing mode that doesn't require extended * registers. */ asm volatile( "rex64/fxsave (%[fx])" - : "=m" (fpu->state.fxsave) - : [fx] "R" (&fpu->state.fxsave)); + : "=m" (fpu->state->fxsave) + : [fx] "R" (&fpu->state->fxsave)); } } @@ -388,12 +392,16 @@ static inline int copy_xregs_to_user(struct xregs_state __user *buf) if (unlikely(err)) return -EFAULT; + pax_open_userland(); __asm__ __volatile__(ASM_STAC "\n" - "1:"XSAVE"\n" + "1:" + __copyuser_seg + XSAVE"\n" "2: " ASM_CLAC "\n" xstate_fault(err) : "D" (buf), "a" (-1), "d" (-1), "0" (err) : "memory"); + pax_close_userland(); return err; } @@ -402,17 +410,21 @@ static inline int copy_xregs_to_user(struct xregs_state __user *buf) */ static inline int copy_user_to_xregs(struct xregs_state __user *buf, u64 mask) { - struct xregs_state *xstate = ((__force struct xregs_state *)buf); + struct xregs_state *xstate = ((__force_kernel struct xregs_state *)buf); u32 lmask = mask; u32 hmask = mask >> 32; int err = 0; + pax_open_userland(); __asm__ __volatile__(ASM_STAC "\n" - "1:"XRSTOR"\n" + "1:" + __copyuser_seg + XRSTOR"\n" "2: " ASM_CLAC "\n" xstate_fault(err) : "D" (xstate), "a" (lmask), "d" (hmask), "0" (err) : "memory"); /* memory required? */ + pax_close_userland(); return err; } @@ -429,7 +441,7 @@ static inline int copy_user_to_xregs(struct xregs_state __user *buf, u64 mask) static inline int copy_fpregs_to_fpstate(struct fpu *fpu) { if (likely(use_xsave())) { - copy_xregs_to_kernel(&fpu->state.xsave); + copy_xregs_to_kernel(&fpu->state->xsave); return 1; } @@ -442,7 +454,7 @@ static inline int copy_fpregs_to_fpstate(struct fpu *fpu) * Legacy FPU register saving, FNSAVE always clears FPU registers, * so we have to mark them inactive: */ - asm volatile("fnsave %[fp]; fwait" : [fp] "=m" (fpu->state.fsave)); + asm volatile("fnsave %[fp]; fwait" : [fp] "=m" (fpu->state->fsave)); return 0; } @@ -471,7 +483,7 @@ static inline void copy_kernel_to_fpregs(union fpregs_state *fpstate) "fnclex\n\t" "emms\n\t" "fildl %P[addr]" /* set F?P to defined value */ - : : [addr] "m" (fpstate)); + : : [addr] "m" (cpu_tss[raw_smp_processor_id()].x86_tss.sp0)); } __copy_kernel_to_fpregs(fpstate); @@ -611,7 +623,7 @@ switch_fpu_prepare(struct fpu *old_fpu, struct fpu *new_fpu, int cpu) if (fpu.preload) { new_fpu->counter++; __fpregs_activate(new_fpu); - prefetch(&new_fpu->state); + prefetch(new_fpu->state); } else { __fpregs_deactivate_hw(); } @@ -623,7 +635,7 @@ switch_fpu_prepare(struct fpu *old_fpu, struct fpu *new_fpu, int cpu) if (fpu_want_lazy_restore(new_fpu, cpu)) fpu.preload = 0; else - prefetch(&new_fpu->state); + prefetch(new_fpu->state); fpregs_activate(new_fpu); } } @@ -643,7 +655,7 @@ switch_fpu_prepare(struct fpu *old_fpu, struct fpu *new_fpu, int cpu) static inline void switch_fpu_finish(struct fpu *new_fpu, fpu_switch_t fpu_switch) { if (fpu_switch.preload) - copy_kernel_to_fpregs(&new_fpu->state); + copy_kernel_to_fpregs(new_fpu->state); } /* diff --git a/arch/x86/include/asm/fpu/types.h b/arch/x86/include/asm/fpu/types.h index c49c517..0a6e089 100644 --- a/arch/x86/include/asm/fpu/types.h +++ b/arch/x86/include/asm/fpu/types.h @@ -189,7 +189,6 @@ union fpregs_state { struct fxregs_state fxsave; struct swregs_state soft; struct xregs_state xsave; - u8 __padding[PAGE_SIZE]; }; /* @@ -199,6 +198,39 @@ union fpregs_state { */ struct fpu { /* + * @state: + * + * In-memory copy of all FPU registers that we save/restore + * over context switches. If the task is using the FPU then + * the registers in the FPU are more recent than this state + * copy. If the task context-switches away then they get + * saved here and represent the FPU state. + * + * After context switches there may be a (short) time period + * during which the in-FPU hardware registers are unchanged + * and still perfectly match this state, if the tasks + * scheduled afterwards are not using the FPU. + * + * This is the 'lazy restore' window of optimization, which + * we track though 'fpu_fpregs_owner_ctx' and 'fpu->last_cpu'. + * + * We detect whether a subsequent task uses the FPU via setting + * CR0::TS to 1, which causes any FPU use to raise a #NM fault. + * + * During this window, if the task gets scheduled again, we + * might be able to skip having to do a restore from this + * memory buffer to the hardware registers - at the cost of + * incurring the overhead of #NM fault traps. + * + * Note that on modern CPUs that support the XSAVEOPT (or other + * optimized XSAVE instructions), we don't use #NM traps anymore, + * as the hardware can track whether FPU registers need saving + * or not. On such CPUs we activate the non-lazy ('eagerfpu') + * logic, which unconditionally saves/restores all FPU state + * across context switches. (if FPU state exists.) + */ + union fpregs_state *state; + /* * @last_cpu: * * Records the last CPU on which this context was loaded into @@ -255,43 +287,6 @@ struct fpu { * deal with bursty apps that only use the FPU for a short time: */ unsigned char counter; - /* - * @state: - * - * In-memory copy of all FPU registers that we save/restore - * over context switches. If the task is using the FPU then - * the registers in the FPU are more recent than this state - * copy. If the task context-switches away then they get - * saved here and represent the FPU state. - * - * After context switches there may be a (short) time period - * during which the in-FPU hardware registers are unchanged - * and still perfectly match this state, if the tasks - * scheduled afterwards are not using the FPU. - * - * This is the 'lazy restore' window of optimization, which - * we track though 'fpu_fpregs_owner_ctx' and 'fpu->last_cpu'. - * - * We detect whether a subsequent task uses the FPU via setting - * CR0::TS to 1, which causes any FPU use to raise a #NM fault. - * - * During this window, if the task gets scheduled again, we - * might be able to skip having to do a restore from this - * memory buffer to the hardware registers - at the cost of - * incurring the overhead of #NM fault traps. - * - * Note that on modern CPUs that support the XSAVEOPT (or other - * optimized XSAVE instructions), we don't use #NM traps anymore, - * as the hardware can track whether FPU registers need saving - * or not. On such CPUs we activate the non-lazy ('eagerfpu') - * logic, which unconditionally saves/restores all FPU state - * across context switches. (if FPU state exists.) - */ - union fpregs_state state; - /* - * WARNING: 'state' is dynamically-sized. Do not put - * anything after it here. - */ }; #endif /* _ASM_X86_FPU_H */ diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h index b4c1f54..e290c08 100644 --- a/arch/x86/include/asm/futex.h +++ b/arch/x86/include/asm/futex.h @@ -12,6 +12,7 @@ #include #define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg) \ + typecheck(u32 __user *, uaddr); \ asm volatile("\t" ASM_STAC "\n" \ "1:\t" insn "\n" \ "2:\t" ASM_CLAC "\n" \ @@ -20,15 +21,16 @@ "\tjmp\t2b\n" \ "\t.previous\n" \ _ASM_EXTABLE(1b, 3b) \ - : "=r" (oldval), "=r" (ret), "+m" (*uaddr) \ + : "=r" (oldval), "=r" (ret), "+m" (*(u32 __user *)____m(uaddr)) \ : "i" (-EFAULT), "0" (oparg), "1" (0)) #define __futex_atomic_op2(insn, ret, oldval, uaddr, oparg) \ + typecheck(u32 __user *, uaddr); \ asm volatile("\t" ASM_STAC "\n" \ "1:\tmovl %2, %0\n" \ "\tmovl\t%0, %3\n" \ "\t" insn "\n" \ - "2:\t" LOCK_PREFIX "cmpxchgl %3, %2\n" \ + "2:\t" LOCK_PREFIX __copyuser_seg"cmpxchgl %3, %2\n" \ "\tjnz\t1b\n" \ "3:\t" ASM_CLAC "\n" \ "\t.section .fixup,\"ax\"\n" \ @@ -38,7 +40,7 @@ _ASM_EXTABLE(1b, 4b) \ _ASM_EXTABLE(2b, 4b) \ : "=&a" (oldval), "=&r" (ret), \ - "+m" (*uaddr), "=&r" (tem) \ + "+m" (*(u32 __user *)____m(uaddr)), "=&r" (tem) \ : "r" (oparg), "i" (-EFAULT), "1" (0)) static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) @@ -57,12 +59,13 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) pagefault_disable(); + pax_open_userland(); switch (op) { case FUTEX_OP_SET: - __futex_atomic_op1("xchgl %0, %2", ret, oldval, uaddr, oparg); + __futex_atomic_op1(__copyuser_seg"xchgl %0, %2", ret, oldval, uaddr, oparg); break; case FUTEX_OP_ADD: - __futex_atomic_op1(LOCK_PREFIX "xaddl %0, %2", ret, oldval, + __futex_atomic_op1(LOCK_PREFIX __copyuser_seg"xaddl %0, %2", ret, oldval, uaddr, oparg); break; case FUTEX_OP_OR: @@ -77,6 +80,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) default: ret = -ENOSYS; } + pax_close_userland(); pagefault_enable(); diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h index 1e3408e..67c5ba1 100644 --- a/arch/x86/include/asm/hw_irq.h +++ b/arch/x86/include/asm/hw_irq.h @@ -158,8 +158,8 @@ static inline void unlock_vector_lock(void) {} #endif /* CONFIG_X86_LOCAL_APIC */ /* Statistics */ -extern atomic_t irq_err_count; -extern atomic_t irq_mis_count; +extern atomic_unchecked_t irq_err_count; +extern atomic_unchecked_t irq_mis_count; extern void elcr_set_level_irq(unsigned int irq); diff --git a/arch/x86/include/asm/i8259.h b/arch/x86/include/asm/i8259.h index 39bcefc..272d904 100644 --- a/arch/x86/include/asm/i8259.h +++ b/arch/x86/include/asm/i8259.h @@ -63,7 +63,7 @@ struct legacy_pic { int (*probe)(void); int (*irq_pending)(unsigned int irq); void (*make_irq)(unsigned int irq); -}; +} __do_const; extern struct legacy_pic *legacy_pic; extern struct legacy_pic null_legacy_pic; diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h index de25aad..dc04476 100644 --- a/arch/x86/include/asm/io.h +++ b/arch/x86/include/asm/io.h @@ -42,6 +42,7 @@ #include #include #include +#include #define build_mmio_read(name, size, type, reg, barrier) \ static inline type name(const volatile void __iomem *addr) \ @@ -54,12 +55,12 @@ static inline void name(type val, volatile void __iomem *addr) \ "m" (*(volatile type __force *)addr) barrier); } build_mmio_read(readb, "b", unsigned char, "=q", :"memory") -build_mmio_read(readw, "w", unsigned short, "=r", :"memory") -build_mmio_read(readl, "l", unsigned int, "=r", :"memory") +build_mmio_read(__intentional_overflow(-1) readw, "w", unsigned short, "=r", :"memory") +build_mmio_read(__intentional_overflow(-1) readl, "l", unsigned int, "=r", :"memory") build_mmio_read(__readb, "b", unsigned char, "=q", ) -build_mmio_read(__readw, "w", unsigned short, "=r", ) -build_mmio_read(__readl, "l", unsigned int, "=r", ) +build_mmio_read(__intentional_overflow(-1) __readw, "w", unsigned short, "=r", ) +build_mmio_read(__intentional_overflow(-1) __readl, "l", unsigned int, "=r", ) build_mmio_write(writeb, "b", unsigned char, "q", :"memory") build_mmio_write(writew, "w", unsigned short, "r", :"memory") @@ -115,7 +116,7 @@ build_mmio_write(writeq, "q", unsigned long, "r", :"memory") * this function */ -static inline phys_addr_t virt_to_phys(volatile void *address) +static inline phys_addr_t __intentional_overflow(-1) virt_to_phys(volatile void *address) { return __pa(address); } @@ -194,7 +195,7 @@ static inline void __iomem *ioremap(resource_size_t offset, unsigned long size) return ioremap_nocache(offset, size); } -extern void iounmap(volatile void __iomem *addr); +extern void iounmap(const volatile void __iomem *addr); extern void set_iounmap_nonlazy(void); @@ -202,6 +203,17 @@ extern void set_iounmap_nonlazy(void); #include +#define ARCH_HAS_VALID_PHYS_ADDR_RANGE +static inline int valid_phys_addr_range(unsigned long addr, size_t count) +{ + return ((addr + count + PAGE_SIZE - 1) >> PAGE_SHIFT) < (1ULL << (boot_cpu_data.x86_phys_bits - PAGE_SHIFT)) ? 1 : 0; +} + +static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t count) +{ + return (pfn + (count >> PAGE_SHIFT)) < (1ULL << (boot_cpu_data.x86_phys_bits - PAGE_SHIFT)) ? 1 : 0; +} + /* * Convert a virtual cached pointer to an uncached pointer */ diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h index b77f5ed..a2f791e 100644 --- a/arch/x86/include/asm/irqflags.h +++ b/arch/x86/include/asm/irqflags.h @@ -137,6 +137,11 @@ static inline notrace unsigned long arch_local_irq_save(void) swapgs; \ sysretl +#define GET_CR0_INTO_RDI mov %cr0, %rdi +#define SET_RDI_INTO_CR0 mov %rdi, %cr0 +#define GET_CR3_INTO_RDI mov %cr3, %rdi +#define SET_RDI_INTO_CR3 mov %rdi, %cr3 + #else #define INTERRUPT_RETURN iret #define ENABLE_INTERRUPTS_SYSEXIT sti; sysexit diff --git a/arch/x86/include/asm/kprobes.h b/arch/x86/include/asm/kprobes.h index 4421b5d..8543006 100644 --- a/arch/x86/include/asm/kprobes.h +++ b/arch/x86/include/asm/kprobes.h @@ -37,13 +37,8 @@ typedef u8 kprobe_opcode_t; #define RELATIVEJUMP_SIZE 5 #define RELATIVECALL_OPCODE 0xe8 #define RELATIVE_ADDR_SIZE 4 -#define MAX_STACK_SIZE 64 -#define MIN_STACK_SIZE(ADDR) \ - (((MAX_STACK_SIZE) < (((unsigned long)current_thread_info()) + \ - THREAD_SIZE - (unsigned long)(ADDR))) \ - ? (MAX_STACK_SIZE) \ - : (((unsigned long)current_thread_info()) + \ - THREAD_SIZE - (unsigned long)(ADDR))) +#define MAX_STACK_SIZE 64UL +#define MIN_STACK_SIZE(ADDR) min(MAX_STACK_SIZE, current->thread.sp0 - (unsigned long)(ADDR)) #define flush_insn_slot(p) do { } while (0) diff --git a/arch/x86/include/asm/local.h b/arch/x86/include/asm/local.h index 4ad6560..75c7bdd 100644 --- a/arch/x86/include/asm/local.h +++ b/arch/x86/include/asm/local.h @@ -10,33 +10,97 @@ typedef struct { atomic_long_t a; } local_t; +typedef struct { + atomic_long_unchecked_t a; +} local_unchecked_t; + #define LOCAL_INIT(i) { ATOMIC_LONG_INIT(i) } #define local_read(l) atomic_long_read(&(l)->a) +#define local_read_unchecked(l) atomic_long_read_unchecked(&(l)->a) #define local_set(l, i) atomic_long_set(&(l)->a, (i)) +#define local_set_unchecked(l, i) atomic_long_set_unchecked(&(l)->a, (i)) static inline void local_inc(local_t *l) { - asm volatile(_ASM_INC "%0" + asm volatile(_ASM_INC "%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + _ASM_DEC "%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + : "+m" (l->a.counter)); +} + +static inline void local_inc_unchecked(local_unchecked_t *l) +{ + asm volatile(_ASM_INC "%0\n" : "+m" (l->a.counter)); } static inline void local_dec(local_t *l) { - asm volatile(_ASM_DEC "%0" + asm volatile(_ASM_DEC "%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + _ASM_INC "%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + : "+m" (l->a.counter)); +} + +static inline void local_dec_unchecked(local_unchecked_t *l) +{ + asm volatile(_ASM_DEC "%0\n" : "+m" (l->a.counter)); } static inline void local_add(long i, local_t *l) { - asm volatile(_ASM_ADD "%1,%0" + asm volatile(_ASM_ADD "%1,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + _ASM_SUB "%1,%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + : "+m" (l->a.counter) + : "ir" (i)); +} + +static inline void local_add_unchecked(long i, local_unchecked_t *l) +{ + asm volatile(_ASM_ADD "%1,%0\n" : "+m" (l->a.counter) : "ir" (i)); } static inline void local_sub(long i, local_t *l) { - asm volatile(_ASM_SUB "%1,%0" + asm volatile(_ASM_SUB "%1,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + _ASM_ADD "%1,%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + : "+m" (l->a.counter) + : "ir" (i)); +} + +static inline void local_sub_unchecked(long i, local_unchecked_t *l) +{ + asm volatile(_ASM_SUB "%1,%0\n" : "+m" (l->a.counter) : "ir" (i)); } @@ -52,7 +116,7 @@ static inline void local_sub(long i, local_t *l) */ static inline int local_sub_and_test(long i, local_t *l) { - GEN_BINARY_RMWcc(_ASM_SUB, l->a.counter, "er", i, "%0", "e"); + GEN_BINARY_RMWcc(_ASM_SUB, _ASM_ADD, l->a.counter, "er", i, "%0", "e"); } /** @@ -65,7 +129,7 @@ static inline int local_sub_and_test(long i, local_t *l) */ static inline int local_dec_and_test(local_t *l) { - GEN_UNARY_RMWcc(_ASM_DEC, l->a.counter, "%0", "e"); + GEN_UNARY_RMWcc(_ASM_DEC, _ASM_INC, l->a.counter, "%0", "e"); } /** @@ -78,7 +142,7 @@ static inline int local_dec_and_test(local_t *l) */ static inline int local_inc_and_test(local_t *l) { - GEN_UNARY_RMWcc(_ASM_INC, l->a.counter, "%0", "e"); + GEN_UNARY_RMWcc(_ASM_INC, _ASM_DEC, l->a.counter, "%0", "e"); } /** @@ -92,7 +156,7 @@ static inline int local_inc_and_test(local_t *l) */ static inline int local_add_negative(long i, local_t *l) { - GEN_BINARY_RMWcc(_ASM_ADD, l->a.counter, "er", i, "%0", "s"); + GEN_BINARY_RMWcc(_ASM_ADD, _ASM_SUB, l->a.counter, "er", i, "%0", "s"); } /** @@ -105,6 +169,30 @@ static inline int local_add_negative(long i, local_t *l) static inline long local_add_return(long i, local_t *l) { long __i = i; + asm volatile(_ASM_XADD "%0, %1\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + _ASM_MOV "%0,%1\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + : "+r" (i), "+m" (l->a.counter) + : : "memory"); + return i + __i; +} + +/** + * local_add_return_unchecked - add and return + * @i: integer value to add + * @l: pointer to type local_unchecked_t + * + * Atomically adds @i to @l and returns @i + @l + */ +static inline long local_add_return_unchecked(long i, local_unchecked_t *l) +{ + long __i = i; asm volatile(_ASM_XADD "%0, %1;" : "+r" (i), "+m" (l->a.counter) : : "memory"); @@ -121,6 +209,8 @@ static inline long local_sub_return(long i, local_t *l) #define local_cmpxchg(l, o, n) \ (cmpxchg_local(&((l)->a.counter), (o), (n))) +#define local_cmpxchg_unchecked(l, o, n) \ + (cmpxchg_local(&((l)->a.counter), (o), (n))) /* Always has a lock prefix */ #define local_xchg(l, n) (xchg(&((l)->a.counter), (n))) diff --git a/arch/x86/include/asm/mman.h b/arch/x86/include/asm/mman.h new file mode 100644 index 0000000..2bfd3ba --- /dev/null +++ b/arch/x86/include/asm/mman.h @@ -0,0 +1,15 @@ +#ifndef _X86_MMAN_H +#define _X86_MMAN_H + +#include + +#ifdef __KERNEL__ +#ifndef __ASSEMBLY__ +#ifdef CONFIG_X86_32 +#define arch_mmap_check i386_mmap_check +int i386_mmap_check(unsigned long addr, unsigned long len, unsigned long flags); +#endif +#endif +#endif + +#endif /* X86_MMAN_H */ diff --git a/arch/x86/include/asm/mmu.h b/arch/x86/include/asm/mmu.h index 55234d5..7e3c4bf 100644 --- a/arch/x86/include/asm/mmu.h +++ b/arch/x86/include/asm/mmu.h @@ -19,7 +19,19 @@ typedef struct { #endif struct mutex lock; - void __user *vdso; + unsigned long vdso; + +#ifdef CONFIG_X86_32 +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) + unsigned long user_cs_base; + unsigned long user_cs_limit; + +#if defined(CONFIG_PAX_PAGEEXEC) && defined(CONFIG_SMP) + cpumask_t cpu_user_cs_mask; +#endif + +#endif +#endif atomic_t perf_rdpmc_allowed; /* nonzero if rdpmc is allowed */ } mm_context_t; diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h index 379cd36..25f4ba2 100644 --- a/arch/x86/include/asm/mmu_context.h +++ b/arch/x86/include/asm/mmu_context.h @@ -46,7 +46,7 @@ struct ldt_struct { * allocations, but it's not worth trying to optimize. */ struct desc_struct *entries; - int size; + unsigned int size; }; /* @@ -98,26 +98,95 @@ static inline void load_mm_ldt(struct mm_struct *mm) static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { + +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) + if (!(static_cpu_has(X86_FEATURE_PCIDUDEREF))) { + unsigned int i; + pgd_t *pgd; + + pax_open_kernel(); + pgd = get_cpu_pgd(smp_processor_id(), kernel); + for (i = USER_PGD_PTRS; i < 2 * USER_PGD_PTRS; ++i) + set_pgd_batched(pgd+i, native_make_pgd(0)); + pax_close_kernel(); + } +#endif + #ifdef CONFIG_SMP if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_OK) this_cpu_write(cpu_tlbstate.state, TLBSTATE_LAZY); #endif } +static inline void pax_switch_mm(struct mm_struct *next, unsigned int cpu) +{ + +#ifdef CONFIG_PAX_PER_CPU_PGD + pax_open_kernel(); + +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) + if (static_cpu_has(X86_FEATURE_PCIDUDEREF)) + __clone_user_pgds(get_cpu_pgd(cpu, user), next->pgd); + else +#endif + + __clone_user_pgds(get_cpu_pgd(cpu, kernel), next->pgd); + + __shadow_user_pgds(get_cpu_pgd(cpu, kernel) + USER_PGD_PTRS, next->pgd); + + pax_close_kernel(); + + BUG_ON((__pa(get_cpu_pgd(cpu, kernel)) | PCID_KERNEL) != (read_cr3() & __PHYSICAL_MASK) && (__pa(get_cpu_pgd(cpu, user)) | PCID_USER) != (read_cr3() & __PHYSICAL_MASK)); + +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) + if (static_cpu_has(X86_FEATURE_PCIDUDEREF)) { + if (static_cpu_has(X86_FEATURE_INVPCID)) { + u64 descriptor[2]; + descriptor[0] = PCID_USER; + asm volatile(__ASM_INVPCID : : "d"(&descriptor), "a"(INVPCID_SINGLE_CONTEXT) : "memory"); + if (!static_cpu_has(X86_FEATURE_STRONGUDEREF)) { + descriptor[0] = PCID_KERNEL; + asm volatile(__ASM_INVPCID : : "d"(&descriptor), "a"(INVPCID_SINGLE_CONTEXT) : "memory"); + } + } else { + write_cr3(__pa(get_cpu_pgd(cpu, user)) | PCID_USER); + if (static_cpu_has(X86_FEATURE_STRONGUDEREF)) + write_cr3(__pa(get_cpu_pgd(cpu, kernel)) | PCID_KERNEL | PCID_NOFLUSH); + else + write_cr3(__pa(get_cpu_pgd(cpu, kernel)) | PCID_KERNEL); + } + } else +#endif + + load_cr3(get_cpu_pgd(cpu, kernel)); +#endif + +} + static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) { unsigned cpu = smp_processor_id(); +#if defined(CONFIG_X86_32) && defined(CONFIG_SMP) && (defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC)) + int tlbstate = TLBSTATE_OK; +#endif if (likely(prev != next)) { #ifdef CONFIG_SMP +#if defined(CONFIG_X86_32) && (defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC)) + tlbstate = this_cpu_read(cpu_tlbstate.state); +#endif this_cpu_write(cpu_tlbstate.state, TLBSTATE_OK); this_cpu_write(cpu_tlbstate.active_mm, next); #endif cpumask_set_cpu(cpu, mm_cpumask(next)); /* Re-load page tables */ +#ifdef CONFIG_PAX_PER_CPU_PGD + pax_switch_mm(next, cpu); +#else load_cr3(next->pgd); +#endif trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL); /* Stop flush ipis for the previous mm */ @@ -142,9 +211,31 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, if (unlikely(prev->context.ldt != next->context.ldt)) load_mm_ldt(next); #endif + +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_PAGEEXEC) && defined(CONFIG_SMP) + if (!(__supported_pte_mask & _PAGE_NX)) { + smp_mb__before_atomic(); + cpumask_clear_cpu(cpu, &prev->context.cpu_user_cs_mask); + smp_mb__after_atomic(); + cpumask_set_cpu(cpu, &next->context.cpu_user_cs_mask); + } +#endif + +#if defined(CONFIG_X86_32) && (defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC)) + if (unlikely(prev->context.user_cs_base != next->context.user_cs_base || + prev->context.user_cs_limit != next->context.user_cs_limit)) + set_user_cs(next->context.user_cs_base, next->context.user_cs_limit, cpu); +#ifdef CONFIG_SMP + else if (unlikely(tlbstate != TLBSTATE_OK)) + set_user_cs(next->context.user_cs_base, next->context.user_cs_limit, cpu); +#endif +#endif + } + else { + pax_switch_mm(next, cpu); + #ifdef CONFIG_SMP - else { this_cpu_write(cpu_tlbstate.state, TLBSTATE_OK); BUG_ON(this_cpu_read(cpu_tlbstate.active_mm) != next); @@ -161,13 +252,30 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, * tlb flush IPI delivery. We must reload CR3 * to make sure to use no freed page tables. */ + +#ifndef CONFIG_PAX_PER_CPU_PGD load_cr3(next->pgd); trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL); +#endif + load_mm_cr4(next); load_mm_ldt(next); + +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_PAGEEXEC) + if (!(__supported_pte_mask & _PAGE_NX)) + cpumask_set_cpu(cpu, &next->context.cpu_user_cs_mask); +#endif + +#if defined(CONFIG_X86_32) && (defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC)) +#ifdef CONFIG_PAX_PAGEEXEC + if (!((next->pax_flags & MF_PAX_PAGEEXEC) && (__supported_pte_mask & _PAGE_NX))) +#endif + set_user_cs(next->context.user_cs_base, next->context.user_cs_limit, cpu); +#endif + } +#endif } -#endif } #define activate_mm(prev, next) \ diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h index e3b7819..b257c64 100644 --- a/arch/x86/include/asm/module.h +++ b/arch/x86/include/asm/module.h @@ -5,6 +5,7 @@ #ifdef CONFIG_X86_64 /* X86_64 does not define MODULE_PROC_FAMILY */ +#define MODULE_PROC_FAMILY "" #elif defined CONFIG_M486 #define MODULE_PROC_FAMILY "486 " #elif defined CONFIG_M586 @@ -57,8 +58,20 @@ #error unknown processor family #endif -#ifdef CONFIG_X86_32 -# define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY +#ifdef CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_BTS +#define MODULE_PAX_KERNEXEC "KERNEXEC_BTS " +#elif defined(CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_OR) +#define MODULE_PAX_KERNEXEC "KERNEXEC_OR " +#else +#define MODULE_PAX_KERNEXEC "" #endif +#ifdef CONFIG_PAX_MEMORY_UDEREF +#define MODULE_PAX_UDEREF "UDEREF " +#else +#define MODULE_PAX_UDEREF "" +#endif + +#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY MODULE_PAX_KERNEXEC MODULE_PAX_UDEREF + #endif /* _ASM_X86_MODULE_H */ diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h index 5f2fc44..106caa6 100644 --- a/arch/x86/include/asm/nmi.h +++ b/arch/x86/include/asm/nmi.h @@ -36,26 +36,35 @@ enum { typedef int (*nmi_handler_t)(unsigned int, struct pt_regs *); +struct nmiaction; + +struct nmiwork { + const struct nmiaction *action; + u64 max_duration; + struct irq_work irq_work; +}; + struct nmiaction { struct list_head list; nmi_handler_t handler; - u64 max_duration; - struct irq_work irq_work; unsigned long flags; const char *name; -}; + struct nmiwork *work; +} __do_const; #define register_nmi_handler(t, fn, fg, n, init...) \ ({ \ - static struct nmiaction init fn##_na = { \ + static struct nmiwork fn##_nw; \ + static const struct nmiaction init fn##_na = { \ .handler = (fn), \ .name = (n), \ .flags = (fg), \ + .work = &fn##_nw, \ }; \ __register_nmi_handler((t), &fn##_na); \ }) -int __register_nmi_handler(unsigned int, struct nmiaction *); +int __register_nmi_handler(unsigned int, const struct nmiaction *); void unregister_nmi_handler(unsigned int, const char *); diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h index 802dde3..9183e68 100644 --- a/arch/x86/include/asm/page.h +++ b/arch/x86/include/asm/page.h @@ -52,6 +52,7 @@ static inline void copy_user_page(void *to, void *from, unsigned long vaddr, __phys_addr_symbol(__phys_reloc_hide((unsigned long)(x))) #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) +#define __early_va(x) ((void *)((unsigned long)(x)+__START_KERNEL_map - phys_base)) #define __boot_va(x) __va(x) #define __boot_pa(x) __pa(x) @@ -60,11 +61,21 @@ static inline void copy_user_page(void *to, void *from, unsigned long vaddr, * virt_to_page(kaddr) returns a valid pointer if and only if * virt_addr_valid(kaddr) returns true. */ -#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) extern bool __virt_addr_valid(unsigned long kaddr); #define virt_addr_valid(kaddr) __virt_addr_valid((unsigned long) (kaddr)) +#ifdef CONFIG_GRKERNSEC_KSTACKOVERFLOW +#define virt_to_page(kaddr) \ + ({ \ + const void *__kaddr = (const void *)(kaddr); \ + BUG_ON(!virt_addr_valid(__kaddr)); \ + pfn_to_page(__pa(__kaddr) >> PAGE_SHIFT); \ + }) +#else +#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) +#endif + #endif /* __ASSEMBLY__ */ #include diff --git a/arch/x86/include/asm/page_32.h b/arch/x86/include/asm/page_32.h index 904f528..b4d0d24 100644 --- a/arch/x86/include/asm/page_32.h +++ b/arch/x86/include/asm/page_32.h @@ -7,11 +7,17 @@ #define __phys_addr_nodebug(x) ((x) - PAGE_OFFSET) #ifdef CONFIG_DEBUG_VIRTUAL -extern unsigned long __phys_addr(unsigned long); +extern unsigned long __intentional_overflow(-1) __phys_addr(unsigned long); #else -#define __phys_addr(x) __phys_addr_nodebug(x) +static inline unsigned long __intentional_overflow(-1) __phys_addr(unsigned long x) +{ + return __phys_addr_nodebug(x); +} #endif -#define __phys_addr_symbol(x) __phys_addr(x) +static inline unsigned long __intentional_overflow(-1) __phys_addr_symbol(unsigned long x) +{ + return __phys_addr(x); +} #define __phys_reloc_hide(x) RELOC_HIDE((x), 0) #ifdef CONFIG_FLATMEM diff --git a/arch/x86/include/asm/page_64.h b/arch/x86/include/asm/page_64.h index b3bebf9..cb419e7 100644 --- a/arch/x86/include/asm/page_64.h +++ b/arch/x86/include/asm/page_64.h @@ -7,9 +7,9 @@ /* duplicated to the one in bootmem.h */ extern unsigned long max_pfn; -extern unsigned long phys_base; +extern const unsigned long phys_base; -static inline unsigned long __phys_addr_nodebug(unsigned long x) +static inline unsigned long __intentional_overflow(-1) __phys_addr_nodebug(unsigned long x) { unsigned long y = x - __START_KERNEL_map; @@ -20,12 +20,14 @@ static inline unsigned long __phys_addr_nodebug(unsigned long x) } #ifdef CONFIG_DEBUG_VIRTUAL -extern unsigned long __phys_addr(unsigned long); -extern unsigned long __phys_addr_symbol(unsigned long); +extern unsigned long __intentional_overflow(-1) __phys_addr(unsigned long); +extern unsigned long __intentional_overflow(-1) __phys_addr_symbol(unsigned long); #else #define __phys_addr(x) __phys_addr_nodebug(x) -#define __phys_addr_symbol(x) \ - ((unsigned long)(x) - __START_KERNEL_map + phys_base) +static inline unsigned long __intentional_overflow(-1) __phys_addr_symbol(unsigned long x) +{ + return x - __START_KERNEL_map + phys_base; +} #endif #define __phys_reloc_hide(x) (x) diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index 10d0596..16a2a7c 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h @@ -530,7 +530,7 @@ static inline pmd_t __pmd(pmdval_t val) return (pmd_t) { ret }; } -static inline pmdval_t pmd_val(pmd_t pmd) +static inline __intentional_overflow(-1) pmdval_t pmd_val(pmd_t pmd) { pmdval_t ret; @@ -596,6 +596,18 @@ static inline void set_pgd(pgd_t *pgdp, pgd_t pgd) val); } +static inline void set_pgd_batched(pgd_t *pgdp, pgd_t pgd) +{ + pgdval_t val = native_pgd_val(pgd); + + if (sizeof(pgdval_t) > sizeof(long)) + PVOP_VCALL3(pv_mmu_ops.set_pgd_batched, pgdp, + val, (u64)val >> 32); + else + PVOP_VCALL2(pv_mmu_ops.set_pgd_batched, pgdp, + val); +} + static inline void pgd_clear(pgd_t *pgdp) { set_pgd(pgdp, __pgd(0)); @@ -680,6 +692,21 @@ static inline void __set_fixmap(unsigned /* enum fixed_addresses */ idx, pv_mmu_ops.set_fixmap(idx, phys, flags); } +#ifdef CONFIG_PAX_KERNEXEC +static inline unsigned long pax_open_kernel(void) +{ + return PVOP_CALL0(unsigned long, pv_mmu_ops.pax_open_kernel); +} + +static inline unsigned long pax_close_kernel(void) +{ + return PVOP_CALL0(unsigned long, pv_mmu_ops.pax_close_kernel); +} +#else +static inline unsigned long pax_open_kernel(void) { return 0; } +static inline unsigned long pax_close_kernel(void) { return 0; } +#endif + #if defined(CONFIG_SMP) && defined(CONFIG_PARAVIRT_SPINLOCKS) #ifdef CONFIG_QUEUED_SPINLOCKS @@ -903,7 +930,7 @@ extern void default_banner(void); #define PARA_PATCH(struct, off) ((PARAVIRT_PATCH_##struct + (off)) / 4) #define PARA_SITE(ptype, clobbers, ops) _PVSITE(ptype, clobbers, ops, .long, 4) -#define PARA_INDIRECT(addr) *%cs:addr +#define PARA_INDIRECT(addr) *%ss:addr #endif #define INTERRUPT_RETURN \ @@ -973,6 +1000,21 @@ extern void default_banner(void); PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_usergs_sysret64), \ CLBR_NONE, \ jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_usergs_sysret64)) + +#define GET_CR0_INTO_RDI \ + call PARA_INDIRECT(pv_cpu_ops+PV_CPU_read_cr0); \ + mov %rax,%rdi + +#define SET_RDI_INTO_CR0 \ + call PARA_INDIRECT(pv_cpu_ops+PV_CPU_write_cr0) + +#define GET_CR3_INTO_RDI \ + call PARA_INDIRECT(pv_mmu_ops+PV_MMU_read_cr3); \ + mov %rax,%rdi + +#define SET_RDI_INTO_CR3 \ + call PARA_INDIRECT(pv_mmu_ops+PV_MMU_write_cr3) + #endif /* CONFIG_X86_32 */ #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h index 31247b5..6b5b8ef 100644 --- a/arch/x86/include/asm/paravirt_types.h +++ b/arch/x86/include/asm/paravirt_types.h @@ -84,7 +84,7 @@ struct pv_init_ops { */ unsigned (*patch)(u8 type, u16 clobber, void *insnbuf, unsigned long addr, unsigned len); -}; +} __no_const __no_randomize_layout; struct pv_lazy_ops { @@ -92,12 +92,12 @@ struct pv_lazy_ops { void (*enter)(void); void (*leave)(void); void (*flush)(void); -}; +} __no_randomize_layout; struct pv_time_ops { unsigned long long (*sched_clock)(void); unsigned long long (*steal_clock)(int cpu); -}; +} __no_const __no_randomize_layout; struct pv_cpu_ops { /* hooks for various privileged instructions */ @@ -190,7 +190,7 @@ struct pv_cpu_ops { void (*start_context_switch)(struct task_struct *prev); void (*end_context_switch)(struct task_struct *next); -}; +} __no_const __no_randomize_layout; struct pv_irq_ops { /* @@ -213,7 +213,7 @@ struct pv_irq_ops { #ifdef CONFIG_X86_64 void (*adjust_exception_frame)(void); #endif -}; +} __no_randomize_layout; struct pv_apic_ops { #ifdef CONFIG_X86_LOCAL_APIC @@ -221,7 +221,7 @@ struct pv_apic_ops { unsigned long start_eip, unsigned long start_esp); #endif -}; +} __no_const __no_randomize_layout; struct pv_mmu_ops { unsigned long (*read_cr2)(void); @@ -311,6 +311,7 @@ struct pv_mmu_ops { struct paravirt_callee_save make_pud; void (*set_pgd)(pgd_t *pudp, pgd_t pgdval); + void (*set_pgd_batched)(pgd_t *pudp, pgd_t pgdval); #endif /* CONFIG_PGTABLE_LEVELS == 4 */ #endif /* CONFIG_PGTABLE_LEVELS >= 3 */ @@ -322,7 +323,13 @@ struct pv_mmu_ops { an mfn. We can tell which is which from the index. */ void (*set_fixmap)(unsigned /* enum fixed_addresses */ idx, phys_addr_t phys, pgprot_t flags); -}; + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long (*pax_open_kernel)(void); + unsigned long (*pax_close_kernel)(void); +#endif + +} __no_randomize_layout; struct arch_spinlock; #ifdef CONFIG_SMP @@ -344,11 +351,14 @@ struct pv_lock_ops { struct paravirt_callee_save lock_spinning; void (*unlock_kick)(struct arch_spinlock *lock, __ticket_t ticket); #endif /* !CONFIG_QUEUED_SPINLOCKS */ -}; +} __no_randomize_layout; /* This contains all the paravirt structures: we get a convenient * number for each function using the offset which we use to indicate - * what to patch. */ + * what to patch. + * shouldn't be randomized due to the "NEAT TRICK" in paravirt.c + */ + struct paravirt_patch_template { struct pv_init_ops pv_init_ops; struct pv_time_ops pv_time_ops; @@ -357,7 +367,7 @@ struct paravirt_patch_template { struct pv_apic_ops pv_apic_ops; struct pv_mmu_ops pv_mmu_ops; struct pv_lock_ops pv_lock_ops; -}; +} __no_randomize_layout; extern struct pv_info pv_info; extern struct pv_init_ops pv_init_ops; diff --git a/arch/x86/include/asm/pgalloc.h b/arch/x86/include/asm/pgalloc.h index bf7f8b5..ca5799d 100644 --- a/arch/x86/include/asm/pgalloc.h +++ b/arch/x86/include/asm/pgalloc.h @@ -63,6 +63,13 @@ static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) { paravirt_alloc_pte(mm, __pa(pte) >> PAGE_SHIFT); + set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE)); +} + +static inline void pmd_populate_user(struct mm_struct *mm, + pmd_t *pmd, pte_t *pte) +{ + paravirt_alloc_pte(mm, __pa(pte) >> PAGE_SHIFT); set_pmd(pmd, __pmd(__pa(pte) | _PAGE_TABLE)); } @@ -108,12 +115,22 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd, #ifdef CONFIG_X86_PAE extern void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd); +static inline void pud_populate_kernel(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd) +{ + pud_populate(mm, pudp, pmd); +} #else /* !CONFIG_X86_PAE */ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) { paravirt_alloc_pmd(mm, __pa(pmd) >> PAGE_SHIFT); set_pud(pud, __pud(_PAGE_TABLE | __pa(pmd))); } + +static inline void pud_populate_kernel(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) +{ + paravirt_alloc_pmd(mm, __pa(pmd) >> PAGE_SHIFT); + set_pud(pud, __pud(_KERNPG_TABLE | __pa(pmd))); +} #endif /* CONFIG_X86_PAE */ #if CONFIG_PGTABLE_LEVELS > 3 @@ -123,6 +140,12 @@ static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pud))); } +static inline void pgd_populate_kernel(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) +{ + paravirt_alloc_pud(mm, __pa(pud) >> PAGE_SHIFT); + set_pgd(pgd, __pgd(_KERNPG_TABLE | __pa(pud))); +} + static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) { return (pud_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT); diff --git a/arch/x86/include/asm/pgtable-2level.h b/arch/x86/include/asm/pgtable-2level.h index fd74a11..35fd5af 100644 --- a/arch/x86/include/asm/pgtable-2level.h +++ b/arch/x86/include/asm/pgtable-2level.h @@ -18,7 +18,9 @@ static inline void native_set_pte(pte_t *ptep , pte_t pte) static inline void native_set_pmd(pmd_t *pmdp, pmd_t pmd) { + pax_open_kernel(); *pmdp = pmd; + pax_close_kernel(); } static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte) diff --git a/arch/x86/include/asm/pgtable-3level.h b/arch/x86/include/asm/pgtable-3level.h index cdaa58c..ae30f0d 100644 --- a/arch/x86/include/asm/pgtable-3level.h +++ b/arch/x86/include/asm/pgtable-3level.h @@ -92,12 +92,16 @@ static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte) static inline void native_set_pmd(pmd_t *pmdp, pmd_t pmd) { + pax_open_kernel(); set_64bit((unsigned long long *)(pmdp), native_pmd_val(pmd)); + pax_close_kernel(); } static inline void native_set_pud(pud_t *pudp, pud_t pud) { + pax_open_kernel(); set_64bit((unsigned long long *)(pudp), native_pud_val(pud)); + pax_close_kernel(); } /* @@ -116,9 +120,12 @@ static inline void native_pte_clear(struct mm_struct *mm, unsigned long addr, static inline void native_pmd_clear(pmd_t *pmd) { u32 *tmp = (u32 *)pmd; + + pax_open_kernel(); *tmp = 0; smp_wmb(); *(tmp + 1) = 0; + pax_close_kernel(); } static inline void pud_clear(pud_t *pudp) diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 867da5b..7ec083d 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -47,6 +47,7 @@ extern struct mm_struct *pgd_page_get_mm(struct page *page); #ifndef __PAGETABLE_PUD_FOLDED #define set_pgd(pgdp, pgd) native_set_pgd(pgdp, pgd) +#define set_pgd_batched(pgdp, pgd) native_set_pgd_batched(pgdp, pgd) #define pgd_clear(pgd) native_pgd_clear(pgd) #endif @@ -84,12 +85,53 @@ extern struct mm_struct *pgd_page_get_mm(struct page *page); #define arch_end_context_switch(prev) do {} while(0) +#define pax_open_kernel() native_pax_open_kernel() +#define pax_close_kernel() native_pax_close_kernel() #endif /* CONFIG_PARAVIRT */ +#define __HAVE_ARCH_PAX_OPEN_KERNEL +#define __HAVE_ARCH_PAX_CLOSE_KERNEL + +#ifdef CONFIG_PAX_KERNEXEC +static inline unsigned long native_pax_open_kernel(void) +{ + unsigned long cr0; + + preempt_disable(); + barrier(); + cr0 = read_cr0() ^ X86_CR0_WP; + BUG_ON(cr0 & X86_CR0_WP); + write_cr0(cr0); + barrier(); + return cr0 ^ X86_CR0_WP; +} + +static inline unsigned long native_pax_close_kernel(void) +{ + unsigned long cr0; + + barrier(); + cr0 = read_cr0() ^ X86_CR0_WP; + BUG_ON(!(cr0 & X86_CR0_WP)); + write_cr0(cr0); + barrier(); + preempt_enable_no_resched(); + return cr0 ^ X86_CR0_WP; +} +#else +static inline unsigned long native_pax_open_kernel(void) { return 0; } +static inline unsigned long native_pax_close_kernel(void) { return 0; } +#endif + /* * The following only work if pte_present() is true. * Undefined behaviour if not.. */ +static inline int pte_user(pte_t pte) +{ + return pte_val(pte) & _PAGE_USER; +} + static inline int pte_dirty(pte_t pte) { return pte_flags(pte) & _PAGE_DIRTY; @@ -150,6 +192,11 @@ static inline unsigned long pud_pfn(pud_t pud) return (pud_val(pud) & PTE_PFN_MASK) >> PAGE_SHIFT; } +static inline unsigned long pgd_pfn(pgd_t pgd) +{ + return (pgd_val(pgd) & PTE_PFN_MASK) >> PAGE_SHIFT; +} + #define pte_page(pte) pfn_to_page(pte_pfn(pte)) static inline int pmd_large(pmd_t pte) @@ -203,9 +250,29 @@ static inline pte_t pte_wrprotect(pte_t pte) return pte_clear_flags(pte, _PAGE_RW); } +static inline pte_t pte_mkread(pte_t pte) +{ + return __pte(pte_val(pte) | _PAGE_USER); +} + static inline pte_t pte_mkexec(pte_t pte) { - return pte_clear_flags(pte, _PAGE_NX); +#ifdef CONFIG_X86_PAE + if (__supported_pte_mask & _PAGE_NX) + return pte_clear_flags(pte, _PAGE_NX); + else +#endif + return pte_set_flags(pte, _PAGE_USER); +} + +static inline pte_t pte_exprotect(pte_t pte) +{ +#ifdef CONFIG_X86_PAE + if (__supported_pte_mask & _PAGE_NX) + return pte_set_flags(pte, _PAGE_NX); + else +#endif + return pte_clear_flags(pte, _PAGE_USER); } static inline pte_t pte_mkdirty(pte_t pte) @@ -426,6 +493,16 @@ pte_t *populate_extra_pte(unsigned long vaddr); #endif #ifndef __ASSEMBLY__ + +#ifdef CONFIG_PAX_PER_CPU_PGD +extern pgd_t cpu_pgd[NR_CPUS][2][PTRS_PER_PGD]; +enum cpu_pgd_type {kernel = 0, user = 1}; +static inline pgd_t *get_cpu_pgd(unsigned int cpu, enum cpu_pgd_type type) +{ + return cpu_pgd[cpu][type]; +} +#endif + #include #include #include @@ -577,7 +654,7 @@ static inline unsigned long pud_page_vaddr(pud_t pud) * Currently stuck as a macro due to indirect forward reference to * linux/mmzone.h's __section_mem_map_addr() definition: */ -#define pud_page(pud) pfn_to_page(pud_val(pud) >> PAGE_SHIFT) +#define pud_page(pud) pfn_to_page((pud_val(pud) & PTE_PFN_MASK) >> PAGE_SHIFT) /* Find an entry in the second-level page table.. */ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address) @@ -617,7 +694,7 @@ static inline unsigned long pgd_page_vaddr(pgd_t pgd) * Currently stuck as a macro due to indirect forward reference to * linux/mmzone.h's __section_mem_map_addr() definition: */ -#define pgd_page(pgd) pfn_to_page(pgd_val(pgd) >> PAGE_SHIFT) +#define pgd_page(pgd) pfn_to_page((pgd_val(pgd) & PTE_PFN_MASK) >> PAGE_SHIFT) /* to find an entry in a page-table-directory. */ static inline unsigned long pud_index(unsigned long address) @@ -632,7 +709,7 @@ static inline pud_t *pud_offset(pgd_t *pgd, unsigned long address) static inline int pgd_bad(pgd_t pgd) { - return (pgd_flags(pgd) & ~_PAGE_USER) != _KERNPG_TABLE; + return (pgd_flags(pgd) & ~(_PAGE_USER | _PAGE_NX)) != _KERNPG_TABLE; } static inline int pgd_none(pgd_t pgd) @@ -655,7 +732,12 @@ static inline int pgd_none(pgd_t pgd) * pgd_offset() returns a (pgd_t *) * pgd_index() is used get the offset into the pgd page's array of pgd_t's; */ -#define pgd_offset(mm, address) ((mm)->pgd + pgd_index((address))) +#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address)) + +#ifdef CONFIG_PAX_PER_CPU_PGD +#define pgd_offset_cpu(cpu, type, address) (get_cpu_pgd(cpu, type) + pgd_index(address)) +#endif + /* * a shortcut which implies the use of the kernel's pgd, instead * of a process's @@ -666,6 +748,25 @@ static inline int pgd_none(pgd_t pgd) #define KERNEL_PGD_BOUNDARY pgd_index(PAGE_OFFSET) #define KERNEL_PGD_PTRS (PTRS_PER_PGD - KERNEL_PGD_BOUNDARY) +#ifdef CONFIG_X86_32 +#define USER_PGD_PTRS KERNEL_PGD_BOUNDARY +#else +#define TASK_SIZE_MAX_SHIFT CONFIG_TASK_SIZE_MAX_SHIFT +#define USER_PGD_PTRS (_AC(1,UL) << (TASK_SIZE_MAX_SHIFT - PGDIR_SHIFT)) + +#ifdef CONFIG_PAX_MEMORY_UDEREF +#ifdef __ASSEMBLY__ +#define pax_user_shadow_base pax_user_shadow_base(%rip) +#else +extern unsigned long pax_user_shadow_base; +extern pgdval_t clone_pgd_mask; +#endif +#else +#define pax_user_shadow_base (0UL) +#endif + +#endif + #ifndef __ASSEMBLY__ extern int direct_gbpages; @@ -832,11 +933,24 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, * dst and src can be on the same page, but the range must not overlap, * and must not cross a page boundary. */ -static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count) +static inline void clone_pgd_range(pgd_t *dst, const pgd_t *src, int count) { - memcpy(dst, src, count * sizeof(pgd_t)); + pax_open_kernel(); + while (count--) + *dst++ = *src++; + pax_close_kernel(); } +#ifdef CONFIG_PAX_PER_CPU_PGD +extern void __clone_user_pgds(pgd_t *dst, const pgd_t *src); +#endif + +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) +extern void __shadow_user_pgds(pgd_t *dst, const pgd_t *src); +#else +static inline void __shadow_user_pgds(pgd_t *dst, const pgd_t *src) {} +#endif + #define PTE_SHIFT ilog2(PTRS_PER_PTE) static inline int page_level_shift(enum pg_level level) { diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h index b6c0b40..3535d47 100644 --- a/arch/x86/include/asm/pgtable_32.h +++ b/arch/x86/include/asm/pgtable_32.h @@ -25,9 +25,6 @@ struct mm_struct; struct vm_area_struct; -extern pgd_t swapper_pg_dir[1024]; -extern pgd_t initial_page_table[1024]; - static inline void pgtable_cache_init(void) { } static inline void check_pgt_cache(void) { } void paging_init(void); @@ -45,6 +42,12 @@ void paging_init(void); # include #endif +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; +extern pgd_t initial_page_table[PTRS_PER_PGD]; +#ifdef CONFIG_X86_PAE +extern pmd_t swapper_pm_dir[PTRS_PER_PGD][PTRS_PER_PMD]; +#endif + #if defined(CONFIG_HIGHPTE) #define pte_offset_map(dir, address) \ ((pte_t *)kmap_atomic(pmd_page(*(dir))) + \ @@ -59,12 +62,17 @@ void paging_init(void); /* Clear a kernel PTE and flush it from the TLB */ #define kpte_clear_flush(ptep, vaddr) \ do { \ + pax_open_kernel(); \ pte_clear(&init_mm, (vaddr), (ptep)); \ + pax_close_kernel(); \ __flush_tlb_one((vaddr)); \ } while (0) #endif /* !__ASSEMBLY__ */ +#define HAVE_ARCH_UNMAPPED_AREA +#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN + /* * kern_addr_valid() is (1) for FLATMEM and (0) for * SPARSEMEM and DISCONTIGMEM diff --git a/arch/x86/include/asm/pgtable_32_types.h b/arch/x86/include/asm/pgtable_32_types.h index 9fb2f2b..8e18c70 100644 --- a/arch/x86/include/asm/pgtable_32_types.h +++ b/arch/x86/include/asm/pgtable_32_types.h @@ -8,7 +8,7 @@ */ #ifdef CONFIG_X86_PAE # include -# define PMD_SIZE (1UL << PMD_SHIFT) +# define PMD_SIZE (_AC(1, UL) << PMD_SHIFT) # define PMD_MASK (~(PMD_SIZE - 1)) #else # include @@ -46,6 +46,28 @@ extern bool __vmalloc_start_set; /* set once high_memory is set */ # define VMALLOC_END (FIXADDR_START - 2 * PAGE_SIZE) #endif +#ifdef CONFIG_PAX_KERNEXEC +#ifndef __ASSEMBLY__ +extern unsigned char MODULES_EXEC_VADDR[]; +extern unsigned char MODULES_EXEC_END[]; + +extern unsigned char __LOAD_PHYSICAL_ADDR[]; +#define LOAD_PHYSICAL_ADDR ((unsigned long)__LOAD_PHYSICAL_ADDR) +static inline unsigned long __intentional_overflow(-1) ktla_ktva(unsigned long addr) +{ + return addr + LOAD_PHYSICAL_ADDR + PAGE_OFFSET; + +} +static inline unsigned long __intentional_overflow(-1) ktva_ktla(unsigned long addr) +{ + return addr - LOAD_PHYSICAL_ADDR - PAGE_OFFSET; +} +#endif +#else +#define ktla_ktva(addr) (addr) +#define ktva_ktla(addr) (addr) +#endif + #define MODULES_VADDR VMALLOC_START #define MODULES_END VMALLOC_END #define MODULES_LEN (MODULES_VADDR - MODULES_END) diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h index 2ee7811..afd76c0 100644 --- a/arch/x86/include/asm/pgtable_64.h +++ b/arch/x86/include/asm/pgtable_64.h @@ -16,11 +16,17 @@ extern pud_t level3_kernel_pgt[512]; extern pud_t level3_ident_pgt[512]; +extern pud_t level3_vmalloc_start_pgt[512]; +extern pud_t level3_vmalloc_end_pgt[512]; +extern pud_t level3_vmemmap_pgt[512]; +extern pud_t level2_vmemmap_pgt[512]; extern pmd_t level2_kernel_pgt[512]; extern pmd_t level2_fixmap_pgt[512]; -extern pmd_t level2_ident_pgt[512]; -extern pte_t level1_fixmap_pgt[512]; -extern pgd_t init_level4_pgt[]; +extern pmd_t level2_ident_pgt[2][512]; +extern pte_t level1_modules_pgt[4][512]; +extern pte_t level1_fixmap_pgt[3][512]; +extern pte_t level1_vsyscall_pgt[512]; +extern pgd_t init_level4_pgt[512]; #define swapper_pg_dir init_level4_pgt @@ -62,7 +68,9 @@ static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte) static inline void native_set_pmd(pmd_t *pmdp, pmd_t pmd) { + pax_open_kernel(); *pmdp = pmd; + pax_close_kernel(); } static inline void native_pmd_clear(pmd_t *pmd) @@ -98,7 +106,9 @@ static inline pmd_t native_pmdp_get_and_clear(pmd_t *xp) static inline void native_set_pud(pud_t *pudp, pud_t pud) { + pax_open_kernel(); *pudp = pud; + pax_close_kernel(); } static inline void native_pud_clear(pud_t *pud) @@ -108,6 +118,13 @@ static inline void native_pud_clear(pud_t *pud) static inline void native_set_pgd(pgd_t *pgdp, pgd_t pgd) { + pax_open_kernel(); + *pgdp = pgd; + pax_close_kernel(); +} + +static inline void native_set_pgd_batched(pgd_t *pgdp, pgd_t pgd) +{ *pgdp = pgd; } diff --git a/arch/x86/include/asm/pgtable_64_types.h b/arch/x86/include/asm/pgtable_64_types.h index e6844df..432b56e 100644 --- a/arch/x86/include/asm/pgtable_64_types.h +++ b/arch/x86/include/asm/pgtable_64_types.h @@ -60,11 +60,16 @@ typedef struct { pteval_t pte; } pte_t; #define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) #define MODULES_END _AC(0xffffffffff000000, UL) #define MODULES_LEN (MODULES_END - MODULES_VADDR) +#define MODULES_EXEC_VADDR MODULES_VADDR +#define MODULES_EXEC_END MODULES_END #define ESPFIX_PGD_ENTRY _AC(-2, UL) #define ESPFIX_BASE_ADDR (ESPFIX_PGD_ENTRY << PGDIR_SHIFT) #define EFI_VA_START ( -4 * (_AC(1, UL) << 30)) #define EFI_VA_END (-68 * (_AC(1, UL) << 30)) +#define ktla_ktva(addr) (addr) +#define ktva_ktla(addr) (addr) + #define EARLY_DYNAMIC_PAGE_TABLES 64 #endif /* _ASM_X86_PGTABLE_64_DEFS_H */ diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h index 13f310b..f0ef42e 100644 --- a/arch/x86/include/asm/pgtable_types.h +++ b/arch/x86/include/asm/pgtable_types.h @@ -85,8 +85,10 @@ #if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE) #define _PAGE_NX (_AT(pteval_t, 1) << _PAGE_BIT_NX) -#else +#elif defined(CONFIG_KMEMCHECK) || defined(CONFIG_MEM_SOFT_DIRTY) #define _PAGE_NX (_AT(pteval_t, 0)) +#else +#define _PAGE_NX (_AT(pteval_t, 1) << _PAGE_BIT_HIDDEN) #endif #define _PAGE_PROTNONE (_AT(pteval_t, 1) << _PAGE_BIT_PROTNONE) @@ -141,6 +143,9 @@ enum page_cache_mode { #define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | \ _PAGE_ACCESSED) +#define PAGE_READONLY_NOEXEC PAGE_READONLY +#define PAGE_SHARED_NOEXEC PAGE_SHARED + #define __PAGE_KERNEL_EXEC \ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_GLOBAL) #define __PAGE_KERNEL (__PAGE_KERNEL_EXEC | _PAGE_NX) @@ -148,7 +153,7 @@ enum page_cache_mode { #define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW) #define __PAGE_KERNEL_RX (__PAGE_KERNEL_EXEC & ~_PAGE_RW) #define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_NOCACHE) -#define __PAGE_KERNEL_VSYSCALL (__PAGE_KERNEL_RX | _PAGE_USER) +#define __PAGE_KERNEL_VSYSCALL (__PAGE_KERNEL_RO | _PAGE_USER) #define __PAGE_KERNEL_VVAR (__PAGE_KERNEL_RO | _PAGE_USER) #define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE) #define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE) @@ -194,7 +199,7 @@ enum page_cache_mode { #ifdef CONFIG_X86_64 #define __PAGE_KERNEL_IDENT_LARGE_EXEC __PAGE_KERNEL_LARGE_EXEC #else -#define PTE_IDENT_ATTR 0x003 /* PRESENT+RW */ +#define PTE_IDENT_ATTR 0x063 /* PRESENT+RW+DIRTY+ACCESSED */ #define PDE_IDENT_ATTR 0x063 /* PRESENT+RW+DIRTY+ACCESSED */ #define PGD_IDENT_ATTR 0x001 /* PRESENT (no other attributes) */ #endif @@ -233,7 +238,17 @@ static inline pgdval_t pgd_flags(pgd_t pgd) { return native_pgd_val(pgd) & PTE_FLAGS_MASK; } +#endif +#if CONFIG_PGTABLE_LEVELS == 3 +#include +#endif + +#if CONFIG_PGTABLE_LEVELS == 2 +#include +#endif + +#ifndef __ASSEMBLY__ #if CONFIG_PGTABLE_LEVELS > 3 typedef struct { pudval_t pud; } pud_t; @@ -247,8 +262,6 @@ static inline pudval_t native_pud_val(pud_t pud) return pud.pud; } #else -#include - static inline pudval_t native_pud_val(pud_t pud) { return native_pgd_val(pud.pgd); @@ -268,8 +281,6 @@ static inline pmdval_t native_pmd_val(pmd_t pmd) return pmd.pmd; } #else -#include - static inline pmdval_t native_pmd_val(pmd_t pmd) { return native_pgd_val(pmd.pud.pgd); @@ -362,7 +373,6 @@ typedef struct page *pgtable_t; extern pteval_t __supported_pte_mask; extern void set_nx(void); -extern int nx_enabled; #define pgprot_writecombine pgprot_writecombine extern pgprot_t pgprot_writecombine(pgprot_t prot); diff --git a/arch/x86/include/asm/pmem.h b/arch/x86/include/asm/pmem.h index d8ce3ec..96b12e2 100644 --- a/arch/x86/include/asm/pmem.h +++ b/arch/x86/include/asm/pmem.h @@ -41,7 +41,7 @@ static inline void arch_memcpy_to_pmem(void __pmem *dst, const void *src, * before the WARN+BUG. */ unwritten = __copy_from_user_inatomic_nocache((void __force *) dst, - (void __user *) src, n); + (void __force_user *) src, n); if (WARN(unwritten, "%s: fault copying %p <- %p unwritten: %d\n", __func__, dst, src, unwritten)) BUG(); diff --git a/arch/x86/include/asm/preempt.h b/arch/x86/include/asm/preempt.h index b12f810..aedcc13 100644 --- a/arch/x86/include/asm/preempt.h +++ b/arch/x86/include/asm/preempt.h @@ -84,7 +84,7 @@ static __always_inline void __preempt_count_sub(int val) */ static __always_inline bool __preempt_count_dec_and_test(void) { - GEN_UNARY_RMWcc("decl", __preempt_count, __percpu_arg(0), "e"); + GEN_UNARY_RMWcc("decl", "incl", __preempt_count, __percpu_arg(0), "e"); } /* diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 19577dd..f4acc54 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -136,7 +136,7 @@ struct cpuinfo_x86 { /* Index into per_cpu list: */ u16 cpu_index; u32 microcode; -}; +} __randomize_layout; #define X86_VENDOR_INTEL 0 #define X86_VENDOR_CYRIX 1 @@ -206,9 +206,21 @@ static inline void native_cpuid(unsigned int *eax, unsigned int *ebx, : "memory"); } +/* invpcid (%rdx),%rax */ +#define __ASM_INVPCID ".byte 0x66,0x0f,0x38,0x82,0x02" + +#define INVPCID_SINGLE_ADDRESS 0UL +#define INVPCID_SINGLE_CONTEXT 1UL +#define INVPCID_ALL_GLOBAL 2UL +#define INVPCID_ALL_NONGLOBAL 3UL + +#define PCID_KERNEL 0UL +#define PCID_USER 1UL +#define PCID_NOFLUSH (1UL << 63) + static inline void load_cr3(pgd_t *pgdir) { - write_cr3(__pa(pgdir)); + write_cr3(__pa(pgdir) | PCID_KERNEL); } #ifdef CONFIG_X86_32 @@ -305,11 +317,9 @@ struct tss_struct { } ____cacheline_aligned; -DECLARE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss); +extern struct tss_struct cpu_tss[NR_CPUS]; -#ifdef CONFIG_X86_32 DECLARE_PER_CPU(unsigned long, cpu_current_top_of_stack); -#endif /* * Save the original ist values for checking stack pointers during debugging @@ -381,6 +391,7 @@ struct thread_struct { unsigned short ds; unsigned short fsindex; unsigned short gsindex; + unsigned short ss; #endif #ifdef CONFIG_X86_32 unsigned long ip; @@ -390,6 +401,9 @@ struct thread_struct { #endif unsigned long gs; + /* Floating point and extended processor state */ + struct fpu fpu; + /* Save middle states of ptrace breakpoints */ struct perf_event *ptrace_bps[HBP_NUM]; /* Debug status used for traps, single steps, etc... */ @@ -409,13 +423,6 @@ struct thread_struct { unsigned long iopl; /* Max allowed port in the bitmap, in bytes: */ unsigned io_bitmap_max; - - /* Floating point and extended processor state */ - struct fpu fpu; - /* - * WARNING: 'fpu' is dynamically-sized. It *MUST* be at - * the end. - */ }; /* @@ -457,10 +464,10 @@ static inline void native_swapgs(void) #endif } -static inline unsigned long current_top_of_stack(void) +static inline unsigned long current_top_of_stack(unsigned int cpu) { #ifdef CONFIG_X86_64 - return this_cpu_read_stable(cpu_tss.x86_tss.sp0); + return cpu_tss[cpu].x86_tss.sp0; #else /* sp0 on x86_32 is special in and around vm86 mode. */ return this_cpu_read_stable(cpu_current_top_of_stack); @@ -695,19 +702,29 @@ static inline void spin_lock_prefetch(const void *x) #define TOP_OF_INIT_STACK ((unsigned long)&init_stack + sizeof(init_stack) - \ TOP_OF_KERNEL_STACK_PADDING) +extern union fpregs_state init_fpregs_state; + #ifdef CONFIG_X86_32 /* * User space process size: 3GB (default). */ #define TASK_SIZE PAGE_OFFSET #define TASK_SIZE_MAX TASK_SIZE + +#ifdef CONFIG_PAX_SEGMEXEC +#define SEGMEXEC_TASK_SIZE (TASK_SIZE / 2) +#define STACK_TOP ((current->mm->pax_flags & MF_PAX_SEGMEXEC)?SEGMEXEC_TASK_SIZE:TASK_SIZE) +#else #define STACK_TOP TASK_SIZE -#define STACK_TOP_MAX STACK_TOP +#endif + +#define STACK_TOP_MAX TASK_SIZE #define INIT_THREAD { \ .sp0 = TOP_OF_INIT_STACK, \ .sysenter_cs = __KERNEL_CS, \ .io_bitmap_ptr = NULL, \ + .fpu.state = &init_fpregs_state, \ } extern unsigned long thread_saved_pc(struct task_struct *tsk); @@ -722,12 +739,7 @@ extern unsigned long thread_saved_pc(struct task_struct *tsk); * "struct pt_regs" is possible, but they may contain the * completely wrong values. */ -#define task_pt_regs(task) \ -({ \ - unsigned long __ptr = (unsigned long)task_stack_page(task); \ - __ptr += THREAD_SIZE - TOP_OF_KERNEL_STACK_PADDING; \ - ((struct pt_regs *)__ptr) - 1; \ -}) +#define task_pt_regs(tsk) ((struct pt_regs *)(tsk)->thread.sp0 - 1) #define KSTK_ESP(task) (task_pt_regs(task)->sp) @@ -741,13 +753,13 @@ extern unsigned long thread_saved_pc(struct task_struct *tsk); * particular problem by preventing anything from being mapped * at the maximum canonical address. */ -#define TASK_SIZE_MAX ((1UL << 47) - PAGE_SIZE) +#define TASK_SIZE_MAX ((1UL << TASK_SIZE_MAX_SHIFT) - PAGE_SIZE) /* This decides where the kernel will search for a free chunk of vm * space during mmap's. */ #define IA32_PAGE_OFFSET ((current->personality & ADDR_LIMIT_3GB) ? \ - 0xc0000000 : 0xFFFFe000) + 0xc0000000 : 0xFFFFf000) #define TASK_SIZE (test_thread_flag(TIF_ADDR32) ? \ IA32_PAGE_OFFSET : TASK_SIZE_MAX) @@ -758,7 +770,8 @@ extern unsigned long thread_saved_pc(struct task_struct *tsk); #define STACK_TOP_MAX TASK_SIZE_MAX #define INIT_THREAD { \ - .sp0 = TOP_OF_INIT_STACK \ + .sp0 = TOP_OF_INIT_STACK, \ + .fpu.state = &init_fpregs_state, \ } /* @@ -781,6 +794,10 @@ extern void start_thread(struct pt_regs *regs, unsigned long new_ip, */ #define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)) +#ifdef CONFIG_PAX_SEGMEXEC +#define SEGMEXEC_TASK_UNMAPPED_BASE (PAGE_ALIGN(SEGMEXEC_TASK_SIZE / 3)) +#endif + #define KSTK_EIP(task) (task_pt_regs(task)->ip) /* Get/set a process' ability to use the timestamp counter instruction */ @@ -826,7 +843,7 @@ static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves) return 0; } -extern unsigned long arch_align_stack(unsigned long sp); +#define arch_align_stack(x) ((x) & ~0xfUL) extern void free_init_pages(char *what, unsigned long begin, unsigned long end); void default_idle(void); @@ -836,6 +853,6 @@ bool xen_set_default_idle(void); #define xen_set_default_idle 0 #endif -void stop_this_cpu(void *dummy); +void stop_this_cpu(void *dummy) __noreturn; void df_debug(struct pt_regs *regs, long error_code); #endif /* _ASM_X86_PROCESSOR_H */ diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index 6271281..e2ba226 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h @@ -124,15 +124,16 @@ static inline int v8086_mode(struct pt_regs *regs) #ifdef CONFIG_X86_64 static inline bool user_64bit_mode(struct pt_regs *regs) { + unsigned long cs = regs->cs & 0xffff; #ifndef CONFIG_PARAVIRT /* * On non-paravirt systems, this is the only long mode CPL 3 * selector. We do not allow long mode selectors in the LDT. */ - return regs->cs == __USER_CS; + return cs == __USER_CS; #else /* Headers are too twisted for this to go in paravirt.h. */ - return regs->cs == __USER_CS || regs->cs == pv_info.extra_user_64bit_cs; + return cs == __USER_CS || cs == pv_info.extra_user_64bit_cs; #endif } @@ -179,9 +180,11 @@ static inline unsigned long regs_get_register(struct pt_regs *regs, * Traps from the kernel do not save sp and ss. * Use the helper function to retrieve sp. */ - if (offset == offsetof(struct pt_regs, sp) && - regs->cs == __KERNEL_CS) - return kernel_stack_pointer(regs); + if (offset == offsetof(struct pt_regs, sp)) { + unsigned long cs = regs->cs & 0xffff; + if (cs == __KERNEL_CS || cs == __KERNEXEC_KERNEL_CS) + return kernel_stack_pointer(regs); + } #endif return *(unsigned long *)((unsigned long)regs + offset); } diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h index 9c6b890..5305f53 100644 --- a/arch/x86/include/asm/realmode.h +++ b/arch/x86/include/asm/realmode.h @@ -22,16 +22,14 @@ struct real_mode_header { #endif /* APM/BIOS reboot */ u32 machine_real_restart_asm; -#ifdef CONFIG_X86_64 u32 machine_real_restart_seg; -#endif }; /* This must match data at trampoline_32/64.S */ struct trampoline_header { #ifdef CONFIG_X86_32 u32 start; - u16 gdt_pad; + u16 boot_cs; u16 gdt_limit; u32 gdt_base; #else diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h index a82c4f1..ac45053 100644 --- a/arch/x86/include/asm/reboot.h +++ b/arch/x86/include/asm/reboot.h @@ -6,13 +6,13 @@ struct pt_regs; struct machine_ops { - void (*restart)(char *cmd); - void (*halt)(void); - void (*power_off)(void); + void (* __noreturn restart)(char *cmd); + void (* __noreturn halt)(void); + void (* __noreturn power_off)(void); void (*shutdown)(void); void (*crash_shutdown)(struct pt_regs *); - void (*emergency_restart)(void); -}; + void (* __noreturn emergency_restart)(void); +} __no_const; extern struct machine_ops machine_ops; diff --git a/arch/x86/include/asm/rmwcc.h b/arch/x86/include/asm/rmwcc.h index 8f7866a..e442f20 100644 --- a/arch/x86/include/asm/rmwcc.h +++ b/arch/x86/include/asm/rmwcc.h @@ -3,7 +3,34 @@ #ifdef CC_HAVE_ASM_GOTO -#define __GEN_RMWcc(fullop, var, cc, ...) \ +#ifdef CONFIG_PAX_REFCOUNT +#define __GEN_RMWcc(fullop, fullantiop, var, cc, ...) \ +do { \ + asm_volatile_goto (fullop \ + ";jno 0f\n" \ + fullantiop \ + ";int $4\n0:\n" \ + _ASM_EXTABLE(0b, 0b) \ + ";j" cc " %l[cc_label]" \ + : : "m" (var), ## __VA_ARGS__ \ + : "memory" : cc_label); \ + return 0; \ +cc_label: \ + return 1; \ +} while (0) +#else +#define __GEN_RMWcc(fullop, fullantiop, var, cc, ...) \ +do { \ + asm_volatile_goto (fullop ";j" cc " %l[cc_label]" \ + : : "m" (var), ## __VA_ARGS__ \ + : "memory" : cc_label); \ + return 0; \ +cc_label: \ + return 1; \ +} while (0) +#endif + +#define __GEN_RMWcc_unchecked(fullop, var, cc, ...) \ do { \ asm_volatile_goto (fullop "; j" cc " %l[cc_label]" \ : : "m" (var), ## __VA_ARGS__ \ @@ -13,15 +40,46 @@ cc_label: \ return 1; \ } while (0) -#define GEN_UNARY_RMWcc(op, var, arg0, cc) \ - __GEN_RMWcc(op " " arg0, var, cc) +#define GEN_UNARY_RMWcc(op, antiop, var, arg0, cc) \ + __GEN_RMWcc(op " " arg0, antiop " " arg0, var, cc) -#define GEN_BINARY_RMWcc(op, var, vcon, val, arg0, cc) \ - __GEN_RMWcc(op " %1, " arg0, var, cc, vcon (val)) +#define GEN_UNARY_RMWcc_unchecked(op, var, arg0, cc) \ + __GEN_RMWcc_unchecked(op " " arg0, var, cc) + +#define GEN_BINARY_RMWcc(op, antiop, var, vcon, val, arg0, cc) \ + __GEN_RMWcc(op " %1, " arg0, antiop " %1, " arg0, var, cc, vcon (val)) + +#define GEN_BINARY_RMWcc_unchecked(op, var, vcon, val, arg0, cc) \ + __GEN_RMWcc_unchecked(op " %1, " arg0, var, cc, vcon (val)) #else /* !CC_HAVE_ASM_GOTO */ -#define __GEN_RMWcc(fullop, var, cc, ...) \ +#ifdef CONFIG_PAX_REFCOUNT +#define __GEN_RMWcc(fullop, fullantiop, var, cc, ...) \ +do { \ + char c; \ + asm volatile (fullop \ + ";jno 0f\n" \ + fullantiop \ + ";int $4\n0:\n" \ + _ASM_EXTABLE(0b, 0b) \ + "; set" cc " %1" \ + : "+m" (var), "=qm" (c) \ + : __VA_ARGS__ : "memory"); \ + return c != 0; \ +} while (0) +#else +#define __GEN_RMWcc(fullop, fullantiop, var, cc, ...) \ +do { \ + char c; \ + asm volatile (fullop "; set" cc " %1" \ + : "+m" (var), "=qm" (c) \ + : __VA_ARGS__ : "memory"); \ + return c != 0; \ +} while (0) +#endif + +#define __GEN_RMWcc_unchecked(fullop, var, cc, ...) \ do { \ char c; \ asm volatile (fullop "; set" cc " %1" \ @@ -30,11 +88,17 @@ do { \ return c != 0; \ } while (0) -#define GEN_UNARY_RMWcc(op, var, arg0, cc) \ - __GEN_RMWcc(op " " arg0, var, cc) +#define GEN_UNARY_RMWcc(op, antiop, var, arg0, cc) \ + __GEN_RMWcc(op " " arg0, antiop " " arg0, var, cc) + +#define GEN_UNARY_RMWcc_unchecked(op, var, arg0, cc) \ + __GEN_RMWcc_unchecked(op " " arg0, var, cc) + +#define GEN_BINARY_RMWcc(op, antiop, var, vcon, val, arg0, cc) \ + __GEN_RMWcc(op " %2, " arg0, antiop " %2, " arg0, var, cc, vcon (val)) -#define GEN_BINARY_RMWcc(op, var, vcon, val, arg0, cc) \ - __GEN_RMWcc(op " %2, " arg0, var, cc, vcon (val)) +#define GEN_BINARY_RMWcc_unchecked(op, var, vcon, val, arg0, cc) \ + __GEN_RMWcc_unchecked(op " %2, " arg0, var, cc, vcon (val)) #endif /* CC_HAVE_ASM_GOTO */ diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h index cad82c9..2e5c5c1 100644 --- a/arch/x86/include/asm/rwsem.h +++ b/arch/x86/include/asm/rwsem.h @@ -64,6 +64,14 @@ static inline void __down_read(struct rw_semaphore *sem) { asm volatile("# beginning down_read\n\t" LOCK_PREFIX _ASM_INC "(%1)\n\t" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX _ASM_DEC "(%1)\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + /* adds 0x00000001 */ " jns 1f\n" " call call_rwsem_down_read_failed\n" @@ -85,6 +93,14 @@ static inline int __down_read_trylock(struct rw_semaphore *sem) "1:\n\t" " mov %1,%2\n\t" " add %3,%2\n\t" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + "sub %3,%2\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + " jle 2f\n\t" LOCK_PREFIX " cmpxchg %2,%0\n\t" " jnz 1b\n\t" @@ -104,6 +120,14 @@ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) long tmp; asm volatile("# beginning down_write\n\t" LOCK_PREFIX " xadd %1,(%2)\n\t" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + "mov %1,(%2)\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + /* adds 0xffff0001, returns the old value */ " test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t" /* was the active mask 0 before? */ @@ -155,6 +179,14 @@ static inline void __up_read(struct rw_semaphore *sem) long tmp; asm volatile("# beginning __up_read\n\t" LOCK_PREFIX " xadd %1,(%2)\n\t" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + "mov %1,(%2)\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + /* subtracts 1, returns the old value */ " jns 1f\n\t" " call call_rwsem_wake\n" /* expects old value in %edx */ @@ -173,6 +205,14 @@ static inline void __up_write(struct rw_semaphore *sem) long tmp; asm volatile("# beginning __up_write\n\t" LOCK_PREFIX " xadd %1,(%2)\n\t" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + "mov %1,(%2)\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + /* subtracts 0xffff0001, returns the old value */ " jns 1f\n\t" " call call_rwsem_wake\n" /* expects old value in %edx */ @@ -190,6 +230,14 @@ static inline void __downgrade_write(struct rw_semaphore *sem) { asm volatile("# beginning __downgrade_write\n\t" LOCK_PREFIX _ASM_ADD "%2,(%1)\n\t" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX _ASM_SUB "%2,(%1)\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + /* * transitions 0xZZZZ0001 -> 0xYYYY0001 (i386) * 0xZZZZZZZZ00000001 -> 0xYYYYYYYY00000001 (x86_64) @@ -208,7 +256,15 @@ static inline void __downgrade_write(struct rw_semaphore *sem) */ static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) { - asm volatile(LOCK_PREFIX _ASM_ADD "%1,%0" + asm volatile(LOCK_PREFIX _ASM_ADD "%1,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX _ASM_SUB "%1,%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + : "+m" (sem->count) : "er" (delta)); } @@ -218,7 +274,7 @@ static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) */ static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem) { - return delta + xadd(&sem->count, delta); + return delta + xadd_check_overflow(&sem->count, delta); } #endif /* __KERNEL__ */ diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h index 7d5a192..23ef1aa 100644 --- a/arch/x86/include/asm/segment.h +++ b/arch/x86/include/asm/segment.h @@ -82,14 +82,20 @@ * 26 - ESPFIX small SS * 27 - per-cpu [ offset to per-cpu data area ] * 28 - stack_canary-20 [ for stack protector ] <=== cacheline #8 - * 29 - unused - * 30 - unused + * 29 - PCI BIOS CS + * 30 - PCI BIOS DS * 31 - TSS for double fault handler */ +#define GDT_ENTRY_KERNEXEC_EFI_CS (1) +#define GDT_ENTRY_KERNEXEC_EFI_DS (2) +#define __KERNEXEC_EFI_CS (GDT_ENTRY_KERNEXEC_EFI_CS*8) +#define __KERNEXEC_EFI_DS (GDT_ENTRY_KERNEXEC_EFI_DS*8) + #define GDT_ENTRY_TLS_MIN 6 #define GDT_ENTRY_TLS_MAX (GDT_ENTRY_TLS_MIN + GDT_ENTRY_TLS_ENTRIES - 1) #define GDT_ENTRY_KERNEL_CS 12 +#define GDT_ENTRY_KERNEXEC_KERNEL_CS 4 #define GDT_ENTRY_KERNEL_DS 13 #define GDT_ENTRY_DEFAULT_USER_CS 14 #define GDT_ENTRY_DEFAULT_USER_DS 15 @@ -106,6 +112,12 @@ #define GDT_ENTRY_PERCPU 27 #define GDT_ENTRY_STACK_CANARY 28 +#define GDT_ENTRY_PCIBIOS_CS 29 +#define __PCIBIOS_DS (GDT_ENTRY_PCIBIOS_DS * 8) + +#define GDT_ENTRY_PCIBIOS_DS 30 +#define __PCIBIOS_CS (GDT_ENTRY_PCIBIOS_CS * 8) + #define GDT_ENTRY_DOUBLEFAULT_TSS 31 /* @@ -118,6 +130,7 @@ */ #define __KERNEL_CS (GDT_ENTRY_KERNEL_CS*8) +#define __KERNEXEC_KERNEL_CS (GDT_ENTRY_KERNEXEC_KERNEL_CS*8) #define __KERNEL_DS (GDT_ENTRY_KERNEL_DS*8) #define __USER_DS (GDT_ENTRY_DEFAULT_USER_DS*8 + 3) #define __USER_CS (GDT_ENTRY_DEFAULT_USER_CS*8 + 3) @@ -129,7 +142,7 @@ #define PNP_CS16 (GDT_ENTRY_PNPBIOS_CS16*8) /* "Is this PNP code selector (PNP_CS32 or PNP_CS16)?" */ -#define SEGMENT_IS_PNP_CODE(x) (((x) & 0xf4) == PNP_CS32) +#define SEGMENT_IS_PNP_CODE(x) (((x) & 0xFFFCU) == PNP_CS32 || ((x) & 0xFFFCU) == PNP_CS16) /* data segment for BIOS: */ #define PNP_DS (GDT_ENTRY_PNPBIOS_DS*8) @@ -176,6 +189,8 @@ #define GDT_ENTRY_DEFAULT_USER_DS 5 #define GDT_ENTRY_DEFAULT_USER_CS 6 +#define GDT_ENTRY_KERNEXEC_KERNEL_CS 7 + /* Needs two entries */ #define GDT_ENTRY_TSS 8 /* Needs two entries */ @@ -187,10 +202,12 @@ /* Abused to load per CPU data from limit */ #define GDT_ENTRY_PER_CPU 15 +#define GDT_ENTRY_UDEREF_KERNEL_DS 16 + /* * Number of entries in the GDT table: */ -#define GDT_ENTRIES 16 +#define GDT_ENTRIES 17 /* * Segment selector values corresponding to the above entries: @@ -200,7 +217,9 @@ */ #define __KERNEL32_CS (GDT_ENTRY_KERNEL32_CS*8) #define __KERNEL_CS (GDT_ENTRY_KERNEL_CS*8) +#define __KERNEXEC_KERNEL_CS (GDT_ENTRY_KERNEXEC_KERNEL_CS*8) #define __KERNEL_DS (GDT_ENTRY_KERNEL_DS*8) +#define __UDEREF_KERNEL_DS (GDT_ENTRY_UDEREF_KERNEL_DS*8) #define __USER32_CS (GDT_ENTRY_DEFAULT_USER32_CS*8 + 3) #define __USER_DS (GDT_ENTRY_DEFAULT_USER_DS*8 + 3) #define __USER32_DS __USER_DS diff --git a/arch/x86/include/asm/smap.h b/arch/x86/include/asm/smap.h index ba665eb..0f72938 100644 --- a/arch/x86/include/asm/smap.h +++ b/arch/x86/include/asm/smap.h @@ -25,6 +25,18 @@ #include +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) +#define ASM_PAX_OPEN_USERLAND \ + ALTERNATIVE "", "call __pax_open_userland", X86_FEATURE_STRONGUDEREF + +#define ASM_PAX_CLOSE_USERLAND \ + ALTERNATIVE "", "call __pax_close_userland", X86_FEATURE_STRONGUDEREF + +#else +#define ASM_PAX_OPEN_USERLAND +#define ASM_PAX_CLOSE_USERLAND +#endif + #ifdef CONFIG_X86_SMAP #define ASM_CLAC \ @@ -44,6 +56,37 @@ #include +#define __HAVE_ARCH_PAX_OPEN_USERLAND +#define __HAVE_ARCH_PAX_CLOSE_USERLAND + +extern void __pax_open_userland(void); +static __always_inline unsigned long pax_open_userland(void) +{ + +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) + asm volatile(ALTERNATIVE("", "call %P[open]", X86_FEATURE_STRONGUDEREF) + : + : [open] "i" (__pax_open_userland) + : "memory", "rax"); +#endif + + return 0; +} + +extern void __pax_close_userland(void); +static __always_inline unsigned long pax_close_userland(void) +{ + +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) + asm volatile(ALTERNATIVE("", "call %P[close]", X86_FEATURE_STRONGUDEREF) + : + : [close] "i" (__pax_close_userland) + : "memory", "rax"); +#endif + + return 0; +} + #ifdef CONFIG_X86_SMAP static __always_inline void clac(void) diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h index 222a6a3..839da8d 100644 --- a/arch/x86/include/asm/smp.h +++ b/arch/x86/include/asm/smp.h @@ -35,7 +35,7 @@ DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_core_map); /* cpus sharing the last level cache: */ DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_llc_shared_map); DECLARE_PER_CPU_READ_MOSTLY(u16, cpu_llc_id); -DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number); +DECLARE_PER_CPU_READ_MOSTLY(unsigned int, cpu_number); static inline struct cpumask *cpu_llc_shared_mask(int cpu) { @@ -68,7 +68,7 @@ struct smp_ops { void (*send_call_func_ipi)(const struct cpumask *mask); void (*send_call_func_single_ipi)(int cpu); -}; +} __no_const; /* Globals due to paravirt */ extern void set_cpu_sibling_map(int cpu); @@ -182,14 +182,8 @@ extern unsigned disabled_cpus; extern int safe_smp_processor_id(void); #elif defined(CONFIG_X86_64_SMP) -#define raw_smp_processor_id() (this_cpu_read(cpu_number)) - -#define stack_smp_processor_id() \ -({ \ - struct thread_info *ti; \ - __asm__("andq %%rsp,%0; ":"=r" (ti) : "0" (CURRENT_MASK)); \ - ti->cpu; \ -}) +#define raw_smp_processor_id() (this_cpu_read(cpu_number)) +#define stack_smp_processor_id() raw_smp_processor_id() #define safe_smp_processor_id() smp_processor_id() #endif diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h index 58505f0..bff3b5b 100644 --- a/arch/x86/include/asm/stackprotector.h +++ b/arch/x86/include/asm/stackprotector.h @@ -49,7 +49,7 @@ * head_32 for boot CPU and setup_per_cpu_areas() for others. */ #define GDT_STACK_CANARY_INIT \ - [GDT_ENTRY_STACK_CANARY] = GDT_ENTRY_INIT(0x4090, 0, 0x18), + [GDT_ENTRY_STACK_CANARY] = GDT_ENTRY_INIT(0x4090, 0, 0x17), /* * Initialize the stackprotector canary value. @@ -114,7 +114,7 @@ static inline void setup_stack_canary_segment(int cpu) static inline void load_stack_canary_segment(void) { -#ifdef CONFIG_X86_32 +#if defined(CONFIG_X86_32) && !defined(CONFIG_PAX_MEMORY_UDEREF) asm volatile ("mov %0, %%gs" : : "r" (0)); #endif } diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h index 70bbe39..4ae2bd4 100644 --- a/arch/x86/include/asm/stacktrace.h +++ b/arch/x86/include/asm/stacktrace.h @@ -11,28 +11,20 @@ extern int kstack_depth_to_print; -struct thread_info; +struct task_struct; struct stacktrace_ops; -typedef unsigned long (*walk_stack_t)(struct thread_info *tinfo, - unsigned long *stack, - unsigned long bp, - const struct stacktrace_ops *ops, - void *data, - unsigned long *end, - int *graph); +typedef unsigned long walk_stack_t(struct task_struct *task, + void *stack_start, + unsigned long *stack, + unsigned long bp, + const struct stacktrace_ops *ops, + void *data, + unsigned long *end, + int *graph); -extern unsigned long -print_context_stack(struct thread_info *tinfo, - unsigned long *stack, unsigned long bp, - const struct stacktrace_ops *ops, void *data, - unsigned long *end, int *graph); - -extern unsigned long -print_context_stack_bp(struct thread_info *tinfo, - unsigned long *stack, unsigned long bp, - const struct stacktrace_ops *ops, void *data, - unsigned long *end, int *graph); +extern walk_stack_t print_context_stack; +extern walk_stack_t print_context_stack_bp; /* Generic stack tracer with callbacks */ @@ -40,7 +32,7 @@ struct stacktrace_ops { void (*address)(void *data, unsigned long address, int reliable); /* On negative return stop dumping */ int (*stack)(void *data, char *name); - walk_stack_t walk_stack; + walk_stack_t *walk_stack; }; void dump_trace(struct task_struct *tsk, struct pt_regs *regs, diff --git a/arch/x86/include/asm/switch_to.h b/arch/x86/include/asm/switch_to.h index d7f3b3b..3cc39f1 100644 --- a/arch/x86/include/asm/switch_to.h +++ b/arch/x86/include/asm/switch_to.h @@ -108,7 +108,7 @@ do { \ "call __switch_to\n\t" \ "movq "__percpu_arg([current_task])",%%rsi\n\t" \ __switch_canary \ - "movq %P[thread_info](%%rsi),%%r8\n\t" \ + "movq "__percpu_arg([thread_info])",%%r8\n\t" \ "movq %%rax,%%rdi\n\t" \ "testl %[_tif_fork],%P[ti_flags](%%r8)\n\t" \ "jnz ret_from_fork\n\t" \ @@ -119,7 +119,7 @@ do { \ [threadrsp] "i" (offsetof(struct task_struct, thread.sp)), \ [ti_flags] "i" (offsetof(struct thread_info, flags)), \ [_tif_fork] "i" (_TIF_FORK), \ - [thread_info] "i" (offsetof(struct task_struct, stack)), \ + [thread_info] "m" (current_tinfo), \ [current_task] "m" (current_task) \ __switch_canary_iparam \ : "memory", "cc" __EXTRA_CLOBBER) diff --git a/arch/x86/include/asm/sys_ia32.h b/arch/x86/include/asm/sys_ia32.h index 82c34ee..940fa40 100644 --- a/arch/x86/include/asm/sys_ia32.h +++ b/arch/x86/include/asm/sys_ia32.h @@ -20,8 +20,8 @@ #include /* ia32/sys_ia32.c */ -asmlinkage long sys32_truncate64(const char __user *, unsigned long, unsigned long); -asmlinkage long sys32_ftruncate64(unsigned int, unsigned long, unsigned long); +asmlinkage long sys32_truncate64(const char __user *, unsigned int, unsigned int); +asmlinkage long sys32_ftruncate64(unsigned int, unsigned int, unsigned int); asmlinkage long sys32_stat64(const char __user *, struct stat64 __user *); asmlinkage long sys32_lstat64(const char __user *, struct stat64 __user *); @@ -42,7 +42,7 @@ long sys32_vm86_warning(void); asmlinkage ssize_t sys32_readahead(int, unsigned, unsigned, size_t); asmlinkage long sys32_sync_file_range(int, unsigned, unsigned, unsigned, unsigned, int); -asmlinkage long sys32_fadvise64(int, unsigned, unsigned, size_t, int); +asmlinkage long sys32_fadvise64(int, unsigned, unsigned, int, int); asmlinkage long sys32_fallocate(int, int, unsigned, unsigned, unsigned, unsigned); diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 8afdc3e..ca2f1b4 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -39,7 +39,7 @@ # define TOP_OF_KERNEL_STACK_PADDING 8 # endif #else -# define TOP_OF_KERNEL_STACK_PADDING 0 +# define TOP_OF_KERNEL_STACK_PADDING 16 #endif /* @@ -53,27 +53,26 @@ struct task_struct; #include struct thread_info { - struct task_struct *task; /* main task structure */ __u32 flags; /* low level flags */ __u32 status; /* thread synchronous flags */ __u32 cpu; /* current CPU */ int saved_preempt_count; mm_segment_t addr_limit; void __user *sysenter_return; + unsigned long lowest_stack; unsigned int sig_on_uaccess_error:1; unsigned int uaccess_err:1; /* uaccess failed */ }; -#define INIT_THREAD_INFO(tsk) \ +#define INIT_THREAD_INFO \ { \ - .task = &tsk, \ .flags = 0, \ .cpu = 0, \ .saved_preempt_count = INIT_PREEMPT_COUNT, \ .addr_limit = KERNEL_DS, \ } -#define init_thread_info (init_thread_union.thread_info) +#define init_thread_info (init_thread_union.stack) #define init_stack (init_thread_union.stack) #else /* !__ASSEMBLY__ */ @@ -113,6 +112,7 @@ struct thread_info { #define TIF_SYSCALL_TRACEPOINT 28 /* syscall tracepoint instrumentation */ #define TIF_ADDR32 29 /* 32-bit address space on 64 bits */ #define TIF_X32 30 /* 32-bit native x86-64 binary */ +#define TIF_GRSEC_SETXID 31 /* update credentials on syscall entry/exit */ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) @@ -136,17 +136,18 @@ struct thread_info { #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) #define _TIF_ADDR32 (1 << TIF_ADDR32) #define _TIF_X32 (1 << TIF_X32) +#define _TIF_GRSEC_SETXID (1 << TIF_GRSEC_SETXID) /* work to do in syscall_trace_enter() */ #define _TIF_WORK_SYSCALL_ENTRY \ (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | _TIF_SYSCALL_AUDIT | \ _TIF_SECCOMP | _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT | \ - _TIF_NOHZ) + _TIF_NOHZ | _TIF_GRSEC_SETXID) /* work to do on any return to user space */ #define _TIF_ALLWORK_MASK \ ((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_TRACEPOINT | \ - _TIF_NOHZ) + _TIF_NOHZ | _TIF_GRSEC_SETXID) /* flags to check in __switch_to() */ #define _TIF_WORK_CTXSW \ @@ -164,9 +165,11 @@ struct thread_info { */ #ifndef __ASSEMBLY__ +DECLARE_PER_CPU(struct thread_info *, current_tinfo); + static inline struct thread_info *current_thread_info(void) { - return (struct thread_info *)(current_top_of_stack() - THREAD_SIZE); + return this_cpu_read_stable(current_tinfo); } static inline unsigned long current_stack_pointer(void) @@ -182,14 +185,9 @@ static inline unsigned long current_stack_pointer(void) #else /* !__ASSEMBLY__ */ -#ifdef CONFIG_X86_64 -# define cpu_current_top_of_stack (cpu_tss + TSS_sp0) -#endif - /* Load thread_info address into "reg" */ #define GET_THREAD_INFO(reg) \ - _ASM_MOV PER_CPU_VAR(cpu_current_top_of_stack),reg ; \ - _ASM_SUB $(THREAD_SIZE),reg ; + _ASM_MOV PER_CPU_VAR(current_tinfo),reg ; /* * ASM operand which evaluates to a 'thread_info' address of @@ -282,5 +280,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); + +#define __HAVE_THREAD_FUNCTIONS +#define task_thread_info(task) (&(task)->tinfo) +#define task_stack_page(task) ((task)->stack) +#define setup_thread_stack(p, org) do {} while (0) +#define end_of_stack(p) ((unsigned long *)task_stack_page(p) + 1) + #endif #endif /* _ASM_X86_THREAD_INFO_H */ diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h index 6df2029..a359a58 100644 --- a/arch/x86/include/asm/tlbflush.h +++ b/arch/x86/include/asm/tlbflush.h @@ -86,18 +86,44 @@ static inline void cr4_set_bits_and_update_boot(unsigned long mask) static inline void __native_flush_tlb(void) { + if (static_cpu_has(X86_FEATURE_INVPCID)) { + u64 descriptor[2]; + + descriptor[0] = PCID_KERNEL; + asm volatile(__ASM_INVPCID : : "d"(&descriptor), "a"(INVPCID_ALL_NONGLOBAL) : "memory"); + return; + } + +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) + if (static_cpu_has(X86_FEATURE_PCIDUDEREF)) { + unsigned int cpu = raw_get_cpu(); + + native_write_cr3(__pa(get_cpu_pgd(cpu, user)) | PCID_USER); + native_write_cr3(__pa(get_cpu_pgd(cpu, kernel)) | PCID_KERNEL); + raw_put_cpu_no_resched(); + return; + } +#endif + native_write_cr3(native_read_cr3()); } static inline void __native_flush_tlb_global_irq_disabled(void) { - unsigned long cr4; + if (static_cpu_has(X86_FEATURE_INVPCID)) { + u64 descriptor[2]; - cr4 = this_cpu_read(cpu_tlbstate.cr4); - /* clear PGE */ - native_write_cr4(cr4 & ~X86_CR4_PGE); - /* write old PGE again and flush TLBs */ - native_write_cr4(cr4); + descriptor[0] = PCID_KERNEL; + asm volatile(__ASM_INVPCID : : "d"(&descriptor), "a"(INVPCID_ALL_GLOBAL) : "memory"); + } else { + unsigned long cr4; + + cr4 = this_cpu_read(cpu_tlbstate.cr4); + /* clear PGE */ + native_write_cr4(cr4 & ~X86_CR4_PGE); + /* write old PGE again and flush TLBs */ + native_write_cr4(cr4); + } } static inline void __native_flush_tlb_global(void) @@ -118,6 +144,43 @@ static inline void __native_flush_tlb_global(void) static inline void __native_flush_tlb_single(unsigned long addr) { + if (static_cpu_has(X86_FEATURE_INVPCID)) { + u64 descriptor[2]; + + descriptor[0] = PCID_KERNEL; + descriptor[1] = addr; + +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) + if (static_cpu_has(X86_FEATURE_PCIDUDEREF)) { + if (!static_cpu_has(X86_FEATURE_STRONGUDEREF) || addr >= TASK_SIZE_MAX) { + if (addr < TASK_SIZE_MAX) + descriptor[1] += pax_user_shadow_base; + asm volatile(__ASM_INVPCID : : "d"(&descriptor), "a"(INVPCID_SINGLE_ADDRESS) : "memory"); + } + + descriptor[0] = PCID_USER; + descriptor[1] = addr; + } +#endif + + asm volatile(__ASM_INVPCID : : "d"(&descriptor), "a"(INVPCID_SINGLE_ADDRESS) : "memory"); + return; + } + +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) + if (static_cpu_has(X86_FEATURE_PCIDUDEREF)) { + unsigned int cpu = raw_get_cpu(); + + native_write_cr3(__pa(get_cpu_pgd(cpu, user)) | PCID_USER | PCID_NOFLUSH); + asm volatile("invlpg (%0)" ::"r" (addr) : "memory"); + native_write_cr3(__pa(get_cpu_pgd(cpu, kernel)) | PCID_KERNEL | PCID_NOFLUSH); + raw_put_cpu_no_resched(); + + if (!static_cpu_has(X86_FEATURE_STRONGUDEREF) && addr < TASK_SIZE_MAX) + addr += pax_user_shadow_base; + } +#endif + asm volatile("invlpg (%0)" ::"r" (addr) : "memory"); } diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index a8df874..e0aaf5f 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,12 @@ #define get_ds() (KERNEL_DS) #define get_fs() (current_thread_info()->addr_limit) +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_MEMORY_UDEREF) +void __set_fs(mm_segment_t x); +void set_fs(mm_segment_t x); +#else #define set_fs(x) (current_thread_info()->addr_limit = (x)) +#endif #define segment_eq(a, b) ((a).seg == (b).seg) @@ -86,8 +92,36 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un * checks that the pointer is in the user space range - after calling * this function, memory access functions may still return -EFAULT. */ -#define access_ok(type, addr, size) \ - likely(!__range_not_ok(addr, size, user_addr_max())) +extern int _cond_resched(void); +#define access_ok_noprefault(type, addr, size) (likely(!__range_not_ok(addr, size, user_addr_max()))) +#define access_ok(type, addr, size) \ +({ \ + unsigned long __size = size; \ + unsigned long __addr = (unsigned long)addr; \ + bool __ret_ao = __range_not_ok(__addr, __size, user_addr_max()) == 0;\ + if (__ret_ao && __size) { \ + unsigned long __addr_ao = __addr & PAGE_MASK; \ + unsigned long __end_ao = __addr + __size - 1; \ + if (unlikely((__end_ao ^ __addr_ao) & PAGE_MASK)) { \ + while (__addr_ao <= __end_ao) { \ + char __c_ao; \ + __addr_ao += PAGE_SIZE; \ + if (__size > PAGE_SIZE) \ + _cond_resched(); \ + if (__get_user(__c_ao, (char __user *)__addr)) \ + break; \ + if ((type) != VERIFY_WRITE) { \ + __addr = __addr_ao; \ + continue; \ + } \ + if (__put_user(__c_ao, (char __user *)__addr)) \ + break; \ + __addr = __addr_ao; \ + } \ + } \ + } \ + __ret_ao; \ +}) /* * The exception table consists of pairs of addresses relative to the @@ -135,11 +169,13 @@ extern int __get_user_8(void); extern int __get_user_bad(void); /* - * This is a type: either unsigned long, if the argument fits into - * that type, or otherwise unsigned long long. + * This is a type: either (un)signed int, if the argument fits into + * that type, or otherwise (un)signed long long. */ #define __inttype(x) \ -__typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL)) +__typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0U), \ + __builtin_choose_expr(__type_is_unsigned(__typeof__(x)), 0ULL, 0LL),\ + __builtin_choose_expr(__type_is_unsigned(__typeof__(x)), 0U, 0))) /** * get_user: - Get a simple variable from user space. @@ -178,10 +214,12 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL)) register __inttype(*(ptr)) __val_gu asm("%"_ASM_DX); \ __chk_user_ptr(ptr); \ might_fault(); \ + pax_open_userland(); \ asm volatile("call __get_user_%P3" \ : "=a" (__ret_gu), "=r" (__val_gu) \ : "0" (ptr), "i" (sizeof(*(ptr)))); \ (x) = (__force __typeof__(*(ptr))) __val_gu; \ + pax_close_userland(); \ __ret_gu; \ }) @@ -189,13 +227,21 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL)) asm volatile("call __put_user_" #size : "=a" (__ret_pu) \ : "0" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx") - +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_MEMORY_UDEREF) +#define __copyuser_seg "gs;" +#define __COPYUSER_SET_ES "pushl %%gs; popl %%es\n" +#define __COPYUSER_RESTORE_ES "pushl %%ss; popl %%es\n" +#else +#define __copyuser_seg +#define __COPYUSER_SET_ES +#define __COPYUSER_RESTORE_ES +#endif #ifdef CONFIG_X86_32 #define __put_user_asm_u64(x, addr, err, errret) \ asm volatile(ASM_STAC "\n" \ - "1: movl %%eax,0(%2)\n" \ - "2: movl %%edx,4(%2)\n" \ + "1: "__copyuser_seg"movl %%eax,0(%2)\n" \ + "2: "__copyuser_seg"movl %%edx,4(%2)\n" \ "3: " ASM_CLAC "\n" \ ".section .fixup,\"ax\"\n" \ "4: movl %3,%0\n" \ @@ -208,8 +254,8 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL)) #define __put_user_asm_ex_u64(x, addr) \ asm volatile(ASM_STAC "\n" \ - "1: movl %%eax,0(%1)\n" \ - "2: movl %%edx,4(%1)\n" \ + "1: "__copyuser_seg"movl %%eax,0(%1)\n" \ + "2: "__copyuser_seg"movl %%edx,4(%1)\n" \ "3: " ASM_CLAC "\n" \ _ASM_EXTABLE_EX(1b, 2b) \ _ASM_EXTABLE_EX(2b, 3b) \ @@ -257,10 +303,11 @@ extern void __put_user_8(void); #define put_user(x, ptr) \ ({ \ int __ret_pu; \ - __typeof__(*(ptr)) __pu_val; \ + __inttype(*(ptr)) __pu_val; \ __chk_user_ptr(ptr); \ might_fault(); \ - __pu_val = x; \ + __pu_val = (__inttype(*(ptr)))(x); \ + pax_open_userland(); \ switch (sizeof(*(ptr))) { \ case 1: \ __put_user_x(1, __pu_val, ptr, __ret_pu); \ @@ -278,6 +325,7 @@ extern void __put_user_8(void); __put_user_x(X, __pu_val, ptr, __ret_pu); \ break; \ } \ + pax_close_userland(); \ __ret_pu; \ }) @@ -341,10 +389,10 @@ do { \ __chk_user_ptr(ptr); \ switch (size) { \ case 1: \ - __get_user_asm(x, ptr, retval, "b", "b", "=q", errret); \ + __get_user_asm(x, ptr, retval, "zbl", "k", "=r", errret);\ break; \ case 2: \ - __get_user_asm(x, ptr, retval, "w", "w", "=r", errret); \ + __get_user_asm(x, ptr, retval, "zwl", "k", "=r", errret);\ break; \ case 4: \ __get_user_asm(x, ptr, retval, "l", "k", "=r", errret); \ @@ -358,27 +406,31 @@ do { \ } while (0) #define __get_user_asm(x, addr, err, itype, rtype, ltype, errret) \ +do { \ + pax_open_userland(); \ asm volatile(ASM_STAC "\n" \ - "1: mov"itype" %2,%"rtype"1\n" \ + "1: "__copyuser_seg"mov"itype" %2,%"rtype"1\n"\ "2: " ASM_CLAC "\n" \ ".section .fixup,\"ax\"\n" \ "3: mov %3,%0\n" \ - " xor"itype" %"rtype"1,%"rtype"1\n" \ + " xorl %k1,%k1\n" \ " jmp 2b\n" \ ".previous\n" \ _ASM_EXTABLE(1b, 3b) \ - : "=r" (err), ltype(x) \ - : "m" (__m(addr)), "i" (errret), "0" (err)) + : "=r" (err), ltype (x) \ + : "m" (__m(addr)), "i" (errret), "0" (err)); \ + pax_close_userland(); \ +} while (0) #define __get_user_size_ex(x, ptr, size) \ do { \ __chk_user_ptr(ptr); \ switch (size) { \ case 1: \ - __get_user_asm_ex(x, ptr, "b", "b", "=q"); \ + __get_user_asm_ex(x, ptr, "zbl", "k", "=r"); \ break; \ case 2: \ - __get_user_asm_ex(x, ptr, "w", "w", "=r"); \ + __get_user_asm_ex(x, ptr, "zwl", "k", "=r"); \ break; \ case 4: \ __get_user_asm_ex(x, ptr, "l", "k", "=r"); \ @@ -392,7 +444,7 @@ do { \ } while (0) #define __get_user_asm_ex(x, addr, itype, rtype, ltype) \ - asm volatile("1: mov"itype" %1,%"rtype"0\n" \ + asm volatile("1: "__copyuser_seg"mov"itype" %1,%"rtype"0\n"\ "2:\n" \ _ASM_EXTABLE_EX(1b, 2b) \ : ltype(x) : "m" (__m(addr))) @@ -407,15 +459,26 @@ do { \ #define __get_user_nocheck(x, ptr, size) \ ({ \ int __gu_err; \ - unsigned long __gu_val; \ + __inttype(*(ptr)) __gu_val; \ __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \ - (x) = (__force __typeof__(*(ptr)))__gu_val; \ + (x) = (__typeof__(*(ptr)))__gu_val; \ __gu_err; \ }) /* FIXME: this hack is definitely wrong -AK */ struct __large_struct { unsigned long buf[100]; }; -#define __m(x) (*(struct __large_struct __user *)(x)) +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) +#define ____m(x) \ +({ \ + unsigned long ____x = (unsigned long)(x); \ + if (____x < pax_user_shadow_base) \ + ____x += pax_user_shadow_base; \ + (typeof(x))____x; \ +}) +#else +#define ____m(x) (x) +#endif +#define __m(x) (*(struct __large_struct __user *)____m(x)) /* * Tell gcc we read from memory instead of writing: this is because @@ -423,8 +486,10 @@ struct __large_struct { unsigned long buf[100]; }; * aliasing issues. */ #define __put_user_asm(x, addr, err, itype, rtype, ltype, errret) \ +do { \ + pax_open_userland(); \ asm volatile(ASM_STAC "\n" \ - "1: mov"itype" %"rtype"1,%2\n" \ + "1: "__copyuser_seg"mov"itype" %"rtype"1,%2\n"\ "2: " ASM_CLAC "\n" \ ".section .fixup,\"ax\"\n" \ "3: mov %3,%0\n" \ @@ -432,10 +497,12 @@ struct __large_struct { unsigned long buf[100]; }; ".previous\n" \ _ASM_EXTABLE(1b, 3b) \ : "=r"(err) \ - : ltype(x), "m" (__m(addr)), "i" (errret), "0" (err)) + : ltype (x), "m" (__m(addr)), "i" (errret), "0" (err));\ + pax_close_userland(); \ +} while (0) #define __put_user_asm_ex(x, addr, itype, rtype, ltype) \ - asm volatile("1: mov"itype" %"rtype"0,%1\n" \ + asm volatile("1: "__copyuser_seg"mov"itype" %"rtype"0,%1\n"\ "2:\n" \ _ASM_EXTABLE_EX(1b, 2b) \ : : ltype(x), "m" (__m(addr))) @@ -445,11 +512,13 @@ struct __large_struct { unsigned long buf[100]; }; */ #define uaccess_try do { \ current_thread_info()->uaccess_err = 0; \ + pax_open_userland(); \ stac(); \ barrier(); #define uaccess_catch(err) \ clac(); \ + pax_close_userland(); \ (err) |= (current_thread_info()->uaccess_err ? -EFAULT : 0); \ } while (0) @@ -475,8 +544,12 @@ struct __large_struct { unsigned long buf[100]; }; * On error, the variable @x is set to zero. */ +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) +#define __get_user(x, ptr) get_user((x), (ptr)) +#else #define __get_user(x, ptr) \ __get_user_nocheck((x), (ptr), sizeof(*(ptr))) +#endif /** * __put_user: - Write a simple value into user space, with less checking. @@ -499,8 +572,12 @@ struct __large_struct { unsigned long buf[100]; }; * Returns zero on success, or -EFAULT on error. */ +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) +#define __put_user(x, ptr) put_user((x), (ptr)) +#else #define __put_user(x, ptr) \ __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr))) +#endif #define __get_user_unaligned __get_user #define __put_user_unaligned __put_user @@ -518,7 +595,7 @@ struct __large_struct { unsigned long buf[100]; }; #define get_user_ex(x, ptr) do { \ unsigned long __gue_val; \ __get_user_size_ex((__gue_val), (ptr), (sizeof(*(ptr)))); \ - (x) = (__force __typeof__(*(ptr)))__gue_val; \ + (x) = (__typeof__(*(ptr)))__gue_val; \ } while (0) #define put_user_try uaccess_try @@ -536,7 +613,7 @@ extern __must_check long strlen_user(const char __user *str); extern __must_check long strnlen_user(const char __user *str, long n); unsigned long __must_check clear_user(void __user *mem, unsigned long len); -unsigned long __must_check __clear_user(void __user *mem, unsigned long len); +unsigned long __must_check __clear_user(void __user *mem, unsigned long len) __size_overflow(2); extern void __cmpxchg_wrong_size(void) __compiletime_error("Bad argument size for cmpxchg"); @@ -544,21 +621,22 @@ extern void __cmpxchg_wrong_size(void) #define __user_atomic_cmpxchg_inatomic(uval, ptr, old, new, size) \ ({ \ int __ret = 0; \ - __typeof__(ptr) __uval = (uval); \ - __typeof__(*(ptr)) __old = (old); \ - __typeof__(*(ptr)) __new = (new); \ + __typeof__(uval) __uval = (uval); \ + __typeof__(*(uval)) __old = (old); \ + __typeof__(*(uval)) __new = (new); \ + pax_open_userland(); \ switch (size) { \ case 1: \ { \ asm volatile("\t" ASM_STAC "\n" \ - "1:\t" LOCK_PREFIX "cmpxchgb %4, %2\n" \ + "1:\t" LOCK_PREFIX __copyuser_seg"cmpxchgb %4, %2\n"\ "2:\t" ASM_CLAC "\n" \ "\t.section .fixup, \"ax\"\n" \ "3:\tmov %3, %0\n" \ "\tjmp 2b\n" \ "\t.previous\n" \ _ASM_EXTABLE(1b, 3b) \ - : "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \ + : "+r" (__ret), "=a" (__old), "+m" (*____m(ptr))\ : "i" (-EFAULT), "q" (__new), "1" (__old) \ : "memory" \ ); \ @@ -567,14 +645,14 @@ extern void __cmpxchg_wrong_size(void) case 2: \ { \ asm volatile("\t" ASM_STAC "\n" \ - "1:\t" LOCK_PREFIX "cmpxchgw %4, %2\n" \ + "1:\t" LOCK_PREFIX __copyuser_seg"cmpxchgw %4, %2\n"\ "2:\t" ASM_CLAC "\n" \ "\t.section .fixup, \"ax\"\n" \ "3:\tmov %3, %0\n" \ "\tjmp 2b\n" \ "\t.previous\n" \ _ASM_EXTABLE(1b, 3b) \ - : "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \ + : "+r" (__ret), "=a" (__old), "+m" (*____m(ptr))\ : "i" (-EFAULT), "r" (__new), "1" (__old) \ : "memory" \ ); \ @@ -583,14 +661,14 @@ extern void __cmpxchg_wrong_size(void) case 4: \ { \ asm volatile("\t" ASM_STAC "\n" \ - "1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n" \ + "1:\t" LOCK_PREFIX __copyuser_seg"cmpxchgl %4, %2\n"\ "2:\t" ASM_CLAC "\n" \ "\t.section .fixup, \"ax\"\n" \ "3:\tmov %3, %0\n" \ "\tjmp 2b\n" \ "\t.previous\n" \ _ASM_EXTABLE(1b, 3b) \ - : "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \ + : "+r" (__ret), "=a" (__old), "+m" (*____m(ptr))\ : "i" (-EFAULT), "r" (__new), "1" (__old) \ : "memory" \ ); \ @@ -602,14 +680,14 @@ extern void __cmpxchg_wrong_size(void) __cmpxchg_wrong_size(); \ \ asm volatile("\t" ASM_STAC "\n" \ - "1:\t" LOCK_PREFIX "cmpxchgq %4, %2\n" \ + "1:\t" LOCK_PREFIX __copyuser_seg"cmpxchgq %4, %2\n"\ "2:\t" ASM_CLAC "\n" \ "\t.section .fixup, \"ax\"\n" \ "3:\tmov %3, %0\n" \ "\tjmp 2b\n" \ "\t.previous\n" \ _ASM_EXTABLE(1b, 3b) \ - : "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \ + : "+r" (__ret), "=a" (__old), "+m" (*____m(ptr))\ : "i" (-EFAULT), "r" (__new), "1" (__old) \ : "memory" \ ); \ @@ -618,6 +696,7 @@ extern void __cmpxchg_wrong_size(void) default: \ __cmpxchg_wrong_size(); \ } \ + pax_close_userland(); \ *__uval = __old; \ __ret; \ }) @@ -641,17 +720,6 @@ extern struct movsl_mask { #define ARCH_HAS_NOCACHE_UACCESS 1 -#ifdef CONFIG_X86_32 -# include -#else -# include -#endif - -unsigned long __must_check _copy_from_user(void *to, const void __user *from, - unsigned n); -unsigned long __must_check _copy_to_user(void __user *to, const void *from, - unsigned n); - #ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS # define copy_user_diag __compiletime_error #else @@ -661,7 +729,7 @@ unsigned long __must_check _copy_to_user(void __user *to, const void *from, extern void copy_user_diag("copy_from_user() buffer size is too small") copy_from_user_overflow(void); extern void copy_user_diag("copy_to_user() buffer size is too small") -copy_to_user_overflow(void) __asm__("copy_from_user_overflow"); +copy_to_user_overflow(void); #undef copy_user_diag @@ -674,7 +742,7 @@ __copy_from_user_overflow(void) __asm__("copy_from_user_overflow"); extern void __compiletime_warning("copy_to_user() buffer size is not provably correct") -__copy_to_user_overflow(void) __asm__("copy_from_user_overflow"); +__copy_to_user_overflow(void) __asm__("copy_to_user_overflow"); #define __copy_to_user_overflow(size, count) __copy_to_user_overflow() #else @@ -689,10 +757,16 @@ __copy_from_user_overflow(int size, unsigned long count) #endif +#ifdef CONFIG_X86_32 +# include +#else +# include +#endif + static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) { - int sz = __compiletime_object_size(to); + size_t sz = __compiletime_object_size(to); might_fault(); @@ -714,12 +788,15 @@ copy_from_user(void *to, const void __user *from, unsigned long n) * case, and do only runtime checking for non-constant sizes. */ - if (likely(sz < 0 || sz >= n)) - n = _copy_from_user(to, from, n); - else if(__builtin_constant_p(n)) - copy_from_user_overflow(); - else - __copy_from_user_overflow(sz, n); + if (likely(sz != (size_t)-1 && sz < n)) { + if(__builtin_constant_p(n)) + copy_from_user_overflow(); + else + __copy_from_user_overflow(sz, n); + } else if (access_ok(VERIFY_READ, from, n)) + n = __copy_from_user(to, from, n); + else if ((long)n > 0) + memset(to, 0, n); return n; } @@ -727,17 +804,18 @@ copy_from_user(void *to, const void __user *from, unsigned long n) static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) { - int sz = __compiletime_object_size(from); + size_t sz = __compiletime_object_size(from); might_fault(); /* See the comment in copy_from_user() above. */ - if (likely(sz < 0 || sz >= n)) - n = _copy_to_user(to, from, n); - else if(__builtin_constant_p(n)) - copy_to_user_overflow(); - else - __copy_to_user_overflow(sz, n); + if (likely(sz != (size_t)-1 && sz < n)) { + if(__builtin_constant_p(n)) + copy_to_user_overflow(); + else + __copy_to_user_overflow(sz, n); + } else if (access_ok(VERIFY_WRITE, to, n)) + n = __copy_to_user(to, from, n); return n; } diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h index f5dcb52..da2c15b 100644 --- a/arch/x86/include/asm/uaccess_32.h +++ b/arch/x86/include/asm/uaccess_32.h @@ -40,9 +40,14 @@ unsigned long __must_check __copy_from_user_ll_nocache_nozero * anything, so this is accurate. */ -static __always_inline unsigned long __must_check +static __always_inline __size_overflow(3) unsigned long __must_check __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n) { + if ((long)n < 0) + return n; + + check_object_size(from, n, true); + if (__builtin_constant_p(n)) { unsigned long ret; @@ -87,12 +92,16 @@ static __always_inline unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n) { might_fault(); + return __copy_to_user_inatomic(to, from, n); } -static __always_inline unsigned long +static __always_inline __size_overflow(3) unsigned long __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n) { + if ((long)n < 0) + return n; + /* Avoid zeroing the tail if the copy fails.. * If 'n' is constant and 1, 2, or 4, we do still zero on a failure, * but as the zeroing behaviour is only significant when n is not @@ -143,6 +152,12 @@ static __always_inline unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n) { might_fault(); + + if ((long)n < 0) + return n; + + check_object_size(to, n, false); + if (__builtin_constant_p(n)) { unsigned long ret; @@ -165,6 +180,10 @@ static __always_inline unsigned long __copy_from_user_nocache(void *to, const void __user *from, unsigned long n) { might_fault(); + + if ((long)n < 0) + return n; + if (__builtin_constant_p(n)) { unsigned long ret; @@ -187,7 +206,10 @@ static __always_inline unsigned long __copy_from_user_inatomic_nocache(void *to, const void __user *from, unsigned long n) { - return __copy_from_user_ll_nocache_nozero(to, from, n); + if ((long)n < 0) + return n; + + return __copy_from_user_ll_nocache_nozero(to, from, n); } #endif /* _ASM_X86_UACCESS_32_H */ diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h index f2f9b39..2ae1bf8 100644 --- a/arch/x86/include/asm/uaccess_64.h +++ b/arch/x86/include/asm/uaccess_64.h @@ -10,6 +10,9 @@ #include #include #include +#include + +#define set_fs(x) (current_thread_info()->addr_limit = (x)) /* * Copy To/From Userspace @@ -23,8 +26,8 @@ copy_user_generic_string(void *to, const void *from, unsigned len); __must_check unsigned long copy_user_generic_unrolled(void *to, const void *from, unsigned len); -static __always_inline __must_check unsigned long -copy_user_generic(void *to, const void *from, unsigned len) +static __always_inline __must_check __size_overflow(3) unsigned long +copy_user_generic(void *to, const void *from, unsigned long len) { unsigned ret; @@ -46,121 +49,170 @@ copy_user_generic(void *to, const void *from, unsigned len) } __must_check unsigned long -copy_in_user(void __user *to, const void __user *from, unsigned len); +copy_in_user(void __user *to, const void __user *from, unsigned long len); static __always_inline __must_check -int __copy_from_user_nocheck(void *dst, const void __user *src, unsigned size) +unsigned long __copy_from_user_nocheck(void *dst, const void __user *src, unsigned long size) { - int ret = 0; + size_t sz = __compiletime_object_size(dst); + unsigned ret = 0; + + if (size > INT_MAX) + return size; + + check_object_size(dst, size, false); + +#ifdef CONFIG_PAX_MEMORY_UDEREF + if (!access_ok_noprefault(VERIFY_READ, src, size)) + return size; +#endif + + if (unlikely(sz != (size_t)-1 && sz < size)) { + if(__builtin_constant_p(size)) + copy_from_user_overflow(); + else + __copy_from_user_overflow(sz, size); + return size; + } if (!__builtin_constant_p(size)) - return copy_user_generic(dst, (__force void *)src, size); + return copy_user_generic(dst, (__force_kernel const void *)____m(src), size); switch (size) { - case 1:__get_user_asm(*(u8 *)dst, (u8 __user *)src, + case 1:__get_user_asm(*(u8 *)dst, (const u8 __user *)src, ret, "b", "b", "=q", 1); return ret; - case 2:__get_user_asm(*(u16 *)dst, (u16 __user *)src, + case 2:__get_user_asm(*(u16 *)dst, (const u16 __user *)src, ret, "w", "w", "=r", 2); return ret; - case 4:__get_user_asm(*(u32 *)dst, (u32 __user *)src, + case 4:__get_user_asm(*(u32 *)dst, (const u32 __user *)src, ret, "l", "k", "=r", 4); return ret; - case 8:__get_user_asm(*(u64 *)dst, (u64 __user *)src, + case 8:__get_user_asm(*(u64 *)dst, (const u64 __user *)src, ret, "q", "", "=r", 8); return ret; case 10: - __get_user_asm(*(u64 *)dst, (u64 __user *)src, + __get_user_asm(*(u64 *)dst, (const u64 __user *)src, ret, "q", "", "=r", 10); if (unlikely(ret)) return ret; __get_user_asm(*(u16 *)(8 + (char *)dst), - (u16 __user *)(8 + (char __user *)src), + (const u16 __user *)(8 + (const char __user *)src), ret, "w", "w", "=r", 2); return ret; case 16: - __get_user_asm(*(u64 *)dst, (u64 __user *)src, + __get_user_asm(*(u64 *)dst, (const u64 __user *)src, ret, "q", "", "=r", 16); if (unlikely(ret)) return ret; __get_user_asm(*(u64 *)(8 + (char *)dst), - (u64 __user *)(8 + (char __user *)src), + (const u64 __user *)(8 + (const char __user *)src), ret, "q", "", "=r", 8); return ret; default: - return copy_user_generic(dst, (__force void *)src, size); + return copy_user_generic(dst, (__force_kernel const void *)____m(src), size); } } static __always_inline __must_check -int __copy_from_user(void *dst, const void __user *src, unsigned size) +unsigned long __copy_from_user(void *dst, const void __user *src, unsigned long size) { might_fault(); return __copy_from_user_nocheck(dst, src, size); } static __always_inline __must_check -int __copy_to_user_nocheck(void __user *dst, const void *src, unsigned size) +unsigned long __copy_to_user_nocheck(void __user *dst, const void *src, unsigned long size) { - int ret = 0; + size_t sz = __compiletime_object_size(src); + unsigned ret = 0; + + if (size > INT_MAX) + return size; + + check_object_size(src, size, true); + +#ifdef CONFIG_PAX_MEMORY_UDEREF + if (!access_ok_noprefault(VERIFY_WRITE, dst, size)) + return size; +#endif + + if (unlikely(sz != (size_t)-1 && sz < size)) { + if(__builtin_constant_p(size)) + copy_to_user_overflow(); + else + __copy_to_user_overflow(sz, size); + return size; + } if (!__builtin_constant_p(size)) - return copy_user_generic((__force void *)dst, src, size); + return copy_user_generic((__force_kernel void *)____m(dst), src, size); switch (size) { - case 1:__put_user_asm(*(u8 *)src, (u8 __user *)dst, + case 1:__put_user_asm(*(const u8 *)src, (u8 __user *)dst, ret, "b", "b", "iq", 1); return ret; - case 2:__put_user_asm(*(u16 *)src, (u16 __user *)dst, + case 2:__put_user_asm(*(const u16 *)src, (u16 __user *)dst, ret, "w", "w", "ir", 2); return ret; - case 4:__put_user_asm(*(u32 *)src, (u32 __user *)dst, + case 4:__put_user_asm(*(const u32 *)src, (u32 __user *)dst, ret, "l", "k", "ir", 4); return ret; - case 8:__put_user_asm(*(u64 *)src, (u64 __user *)dst, + case 8:__put_user_asm(*(const u64 *)src, (u64 __user *)dst, ret, "q", "", "er", 8); return ret; case 10: - __put_user_asm(*(u64 *)src, (u64 __user *)dst, + __put_user_asm(*(const u64 *)src, (u64 __user *)dst, ret, "q", "", "er", 10); if (unlikely(ret)) return ret; asm("":::"memory"); - __put_user_asm(4[(u16 *)src], 4 + (u16 __user *)dst, + __put_user_asm(4[(const u16 *)src], 4 + (u16 __user *)dst, ret, "w", "w", "ir", 2); return ret; case 16: - __put_user_asm(*(u64 *)src, (u64 __user *)dst, + __put_user_asm(*(const u64 *)src, (u64 __user *)dst, ret, "q", "", "er", 16); if (unlikely(ret)) return ret; asm("":::"memory"); - __put_user_asm(1[(u64 *)src], 1 + (u64 __user *)dst, + __put_user_asm(1[(const u64 *)src], 1 + (u64 __user *)dst, ret, "q", "", "er", 8); return ret; default: - return copy_user_generic((__force void *)dst, src, size); + return copy_user_generic((__force_kernel void *)____m(dst), src, size); } } static __always_inline __must_check -int __copy_to_user(void __user *dst, const void *src, unsigned size) +unsigned long __copy_to_user(void __user *dst, const void *src, unsigned long size) { might_fault(); return __copy_to_user_nocheck(dst, src, size); } static __always_inline __must_check -int __copy_in_user(void __user *dst, const void __user *src, unsigned size) +unsigned long __copy_in_user(void __user *dst, const void __user *src, unsigned size) { - int ret = 0; + unsigned ret = 0; might_fault(); + + if (size > INT_MAX) + return size; + +#ifdef CONFIG_PAX_MEMORY_UDEREF + if (!access_ok_noprefault(VERIFY_READ, src, size)) + return size; + if (!access_ok_noprefault(VERIFY_WRITE, dst, size)) + return size; +#endif + if (!__builtin_constant_p(size)) - return copy_user_generic((__force void *)dst, - (__force void *)src, size); + return copy_user_generic((__force_kernel void *)____m(dst), + (__force_kernel const void *)____m(src), size); switch (size) { case 1: { u8 tmp; - __get_user_asm(tmp, (u8 __user *)src, + __get_user_asm(tmp, (const u8 __user *)src, ret, "b", "b", "=q", 1); if (likely(!ret)) __put_user_asm(tmp, (u8 __user *)dst, @@ -169,7 +221,7 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size) } case 2: { u16 tmp; - __get_user_asm(tmp, (u16 __user *)src, + __get_user_asm(tmp, (const u16 __user *)src, ret, "w", "w", "=r", 2); if (likely(!ret)) __put_user_asm(tmp, (u16 __user *)dst, @@ -179,7 +231,7 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size) case 4: { u32 tmp; - __get_user_asm(tmp, (u32 __user *)src, + __get_user_asm(tmp, (const u32 __user *)src, ret, "l", "k", "=r", 4); if (likely(!ret)) __put_user_asm(tmp, (u32 __user *)dst, @@ -188,7 +240,7 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size) } case 8: { u64 tmp; - __get_user_asm(tmp, (u64 __user *)src, + __get_user_asm(tmp, (const u64 __user *)src, ret, "q", "", "=r", 8); if (likely(!ret)) __put_user_asm(tmp, (u64 __user *)dst, @@ -196,41 +248,58 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size) return ret; } default: - return copy_user_generic((__force void *)dst, - (__force void *)src, size); + return copy_user_generic((__force_kernel void *)____m(dst), + (__force_kernel const void *)____m(src), size); } } -static __must_check __always_inline int -__copy_from_user_inatomic(void *dst, const void __user *src, unsigned size) +static __must_check __always_inline unsigned long +__copy_from_user_inatomic(void *dst, const void __user *src, unsigned long size) { return __copy_from_user_nocheck(dst, src, size); } -static __must_check __always_inline int -__copy_to_user_inatomic(void __user *dst, const void *src, unsigned size) +static __must_check __always_inline unsigned long +__copy_to_user_inatomic(void __user *dst, const void *src, unsigned long size) { return __copy_to_user_nocheck(dst, src, size); } -extern long __copy_user_nocache(void *dst, const void __user *src, - unsigned size, int zerorest); +extern unsigned long __copy_user_nocache(void *dst, const void __user *src, + unsigned long size, int zerorest); -static inline int -__copy_from_user_nocache(void *dst, const void __user *src, unsigned size) +static inline unsigned long +__copy_from_user_nocache(void *dst, const void __user *src, unsigned long size) { might_fault(); + + if (size > INT_MAX) + return size; + +#ifdef CONFIG_PAX_MEMORY_UDEREF + if (!access_ok_noprefault(VERIFY_READ, src, size)) + return size; +#endif + return __copy_user_nocache(dst, src, size, 1); } -static inline int +static inline unsigned long __copy_from_user_inatomic_nocache(void *dst, const void __user *src, - unsigned size) + unsigned long size) { + if (size > INT_MAX) + return size; + +#ifdef CONFIG_PAX_MEMORY_UDEREF + if (!access_ok_noprefault(VERIFY_READ, src, size)) + return size; +#endif + return __copy_user_nocache(dst, src, size, 0); } unsigned long -copy_user_handle_tail(char *to, char *from, unsigned len); +copy_user_handle_tail(char __user *to, char __user *from, unsigned long len) __size_overflow(3); #endif /* _ASM_X86_UACCESS_64_H */ diff --git a/arch/x86/include/asm/word-at-a-time.h b/arch/x86/include/asm/word-at-a-time.h index 5b238981..77fdd78 100644 --- a/arch/x86/include/asm/word-at-a-time.h +++ b/arch/x86/include/asm/word-at-a-time.h @@ -11,7 +11,7 @@ * and shift, for example. */ struct word_at_a_time { - const unsigned long one_bits, high_bits; + unsigned long one_bits, high_bits; }; #define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) } diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index 48d34d2..90671c7 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h @@ -129,7 +129,7 @@ struct x86_init_ops { struct x86_init_timers timers; struct x86_init_iommu iommu; struct x86_init_pci pci; -}; +} __no_const; /** * struct x86_cpuinit_ops - platform specific cpu hotplug setups @@ -140,7 +140,7 @@ struct x86_cpuinit_ops { void (*setup_percpu_clockev)(void); void (*early_percpu_clock_init)(void); void (*fixup_cpu_id)(struct cpuinfo_x86 *c, int node); -}; +} __no_const; struct timespec; @@ -168,7 +168,7 @@ struct x86_platform_ops { void (*save_sched_clock_state)(void); void (*restore_sched_clock_state)(void); void (*apic_post_init)(void); -}; +} __no_const; struct pci_dev; @@ -177,12 +177,12 @@ struct x86_msi_ops { void (*teardown_msi_irq)(unsigned int irq); void (*teardown_msi_irqs)(struct pci_dev *dev); void (*restore_msi_irqs)(struct pci_dev *dev); -}; +} __no_const; struct x86_io_apic_ops { unsigned int (*read) (unsigned int apic, unsigned int reg); void (*disable)(void); -}; +} __no_const; extern struct x86_init_ops x86_init; extern struct x86_cpuinit_ops x86_cpuinit; diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index 0679e11..10ba732 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h @@ -80,7 +80,7 @@ static inline int xen_safe_read_ulong(unsigned long *addr, unsigned long *val) * - get_phys_to_machine() is to be called by __pfn_to_mfn() only in special * cases needing an extended handling. */ -static inline unsigned long __pfn_to_mfn(unsigned long pfn) +static inline unsigned long __intentional_overflow(-1) __pfn_to_mfn(unsigned long pfn) { unsigned long mfn; diff --git a/arch/x86/include/uapi/asm/e820.h b/arch/x86/include/uapi/asm/e820.h index 9dafe59..0293c1d 100644 --- a/arch/x86/include/uapi/asm/e820.h +++ b/arch/x86/include/uapi/asm/e820.h @@ -69,7 +69,7 @@ struct e820map { #define ISA_START_ADDRESS 0xa0000 #define ISA_END_ADDRESS 0x100000 -#define BIOS_BEGIN 0x000a0000 +#define BIOS_BEGIN 0x000c0000 #define BIOS_END 0x00100000 #define BIOS_ROM_BASE 0xffe00000 diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index b1b78ff..92eb188 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -30,7 +30,7 @@ obj-$(CONFIG_MODIFY_LDT_SYSCALL) += ldt.o obj-y += setup.o x86_init.o i8259.o irqinit.o jump_label.o obj-$(CONFIG_IRQ_WORK) += irq_work.o obj-y += probe_roms.o -obj-$(CONFIG_X86_32) += i386_ksyms_32.o +obj-$(CONFIG_X86_32) += sys_i386_32.o i386_ksyms_32.o obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o obj-$(CONFIG_X86_64) += mcount_64.o obj-$(CONFIG_X86_ESPFIX64) += espfix_64.o diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index ded848c..b7a508ed 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1327,7 +1327,7 @@ static void __init acpi_reduced_hw_init(void) * If your system is blacklisted here, but you find that acpi=force * works for you, please contact linux-acpi@vger.kernel.org */ -static struct dmi_system_id __initdata acpi_dmi_table[] = { +static const struct dmi_system_id __initconst acpi_dmi_table[] = { /* * Boxes that need ACPI disabled */ @@ -1402,7 +1402,7 @@ static struct dmi_system_id __initdata acpi_dmi_table[] = { }; /* second table for DMI checks that should run after early-quirks */ -static struct dmi_system_id __initdata acpi_dmi_table_late[] = { +static const struct dmi_system_id __initconst acpi_dmi_table_late[] = { /* * HP laptops which use a DSDT reporting as HP/SB400/10000, * which includes some code which overrides all temperature diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index d1daead..acd77e2 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -99,8 +99,12 @@ int x86_acpi_suspend_lowlevel(void) #else /* CONFIG_64BIT */ #ifdef CONFIG_SMP stack_start = (unsigned long)temp_stack + sizeof(temp_stack); + + pax_open_kernel(); early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(smp_processor_id()); + pax_close_kernel(); + initial_gs = per_cpu_offset(smp_processor_id()); #endif initial_code = (unsigned long)wakeup_long64; diff --git a/arch/x86/kernel/acpi/wakeup_32.S b/arch/x86/kernel/acpi/wakeup_32.S index 0c26b1b..a766e85 100644 --- a/arch/x86/kernel/acpi/wakeup_32.S +++ b/arch/x86/kernel/acpi/wakeup_32.S @@ -31,13 +31,11 @@ wakeup_pmode_return: # and restore the stack ... but you need gdt for this to work movl saved_context_esp, %esp - movl %cs:saved_magic, %eax - cmpl $0x12345678, %eax + cmpl $0x12345678, saved_magic jne bogus_magic # jump to place where we left off - movl saved_eip, %eax - jmp *%eax + jmp *(saved_eip) bogus_magic: jmp bogus_magic diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 25f9093..f630040 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -20,6 +20,7 @@ #include #include #include +#include int __read_mostly alternatives_patched; @@ -261,7 +262,9 @@ static void __init_or_module add_nops(void *insns, unsigned int len) unsigned int noplen = len; if (noplen > ASM_NOP_MAX) noplen = ASM_NOP_MAX; + pax_open_kernel(); memcpy(insns, ideal_nops[noplen], noplen); + pax_close_kernel(); insns += noplen; len -= noplen; } @@ -289,6 +292,13 @@ recompute_jump(struct alt_instr *a, u8 *orig_insn, u8 *repl_insn, u8 *insnbuf) if (a->replacementlen != 5) return; +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) + if (orig_insn < (u8 *)_text || (u8 *)_einittext <= orig_insn) + orig_insn = (u8 *)ktva_ktla((unsigned long)orig_insn); + else + orig_insn -= ____LOAD_PHYSICAL_ADDR - LOAD_PHYSICAL_ADDR; +#endif + o_dspl = *(s32 *)(insnbuf + 1); /* next_rip of the replacement JMP */ @@ -364,6 +374,7 @@ void __init_or_module apply_alternatives(struct alt_instr *start, { struct alt_instr *a; u8 *instr, *replacement; + u8 *vinstr, *vreplacement; u8 insnbuf[MAX_PATCH_LEN]; DPRINTK("alt table %p -> %p", start, end); @@ -379,46 +390,71 @@ void __init_or_module apply_alternatives(struct alt_instr *start, for (a = start; a < end; a++) { int insnbuf_sz = 0; - instr = (u8 *)&a->instr_offset + a->instr_offset; - replacement = (u8 *)&a->repl_offset + a->repl_offset; + vinstr = instr = (u8 *)&a->instr_offset + a->instr_offset; + +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) + if ((u8 *)_text - (____LOAD_PHYSICAL_ADDR - LOAD_PHYSICAL_ADDR) <= instr && + instr < (u8 *)_einittext - (____LOAD_PHYSICAL_ADDR - LOAD_PHYSICAL_ADDR)) { + instr += ____LOAD_PHYSICAL_ADDR - LOAD_PHYSICAL_ADDR; + vinstr = (u8 *)ktla_ktva((unsigned long)instr); + } else if ((u8 *)_text <= instr && instr < (u8 *)_einittext) { + vinstr = (u8 *)ktla_ktva((unsigned long)instr); + } else { + instr = (u8 *)ktva_ktla((unsigned long)instr); + } +#endif + + vreplacement = replacement = (u8 *)&a->repl_offset + a->repl_offset; + +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) + if ((u8 *)_text - (____LOAD_PHYSICAL_ADDR - LOAD_PHYSICAL_ADDR) <= replacement && + replacement < (u8 *)_einittext - (____LOAD_PHYSICAL_ADDR - LOAD_PHYSICAL_ADDR)) { + replacement += ____LOAD_PHYSICAL_ADDR - LOAD_PHYSICAL_ADDR; + vreplacement = (u8 *)ktla_ktva((unsigned long)replacement); + } else if ((u8 *)_text <= replacement && replacement < (u8 *)_einittext) { + vreplacement = (u8 *)ktla_ktva((unsigned long)replacement); + } else + replacement = (u8 *)ktva_ktla((unsigned long)replacement); +#endif + BUG_ON(a->instrlen > sizeof(insnbuf)); BUG_ON(a->cpuid >= (NCAPINTS + NBUGINTS) * 32); if (!boot_cpu_has(a->cpuid)) { if (a->padlen > 1) - optimize_nops(a, instr); + optimize_nops(a, vinstr); continue; } - DPRINTK("feat: %d*32+%d, old: (%p, len: %d), repl: (%p, len: %d), pad: %d", + DPRINTK("feat: %d*32+%d, old: (%p/%p, len: %d), repl: (%p, len: %d), pad: %d", a->cpuid >> 5, a->cpuid & 0x1f, - instr, a->instrlen, - replacement, a->replacementlen, a->padlen); + instr, vinstr, a->instrlen, + vreplacement, a->replacementlen, a->padlen); - DUMP_BYTES(instr, a->instrlen, "%p: old_insn: ", instr); - DUMP_BYTES(replacement, a->replacementlen, "%p: rpl_insn: ", replacement); + DUMP_BYTES(vinstr, a->instrlen, "%p: old_insn: ", vinstr); + DUMP_BYTES(vreplacement, a->replacementlen, "%p: rpl_insn: ", vreplacement); - memcpy(insnbuf, replacement, a->replacementlen); + memcpy(insnbuf, vreplacement, a->replacementlen); insnbuf_sz = a->replacementlen; /* 0xe8 is a relative jump; fix the offset. */ if (*insnbuf == 0xe8 && a->replacementlen == 5) { - *(s32 *)(insnbuf + 1) += replacement - instr; + *(s32 *)(insnbuf + 1) += vreplacement - instr; DPRINTK("Fix CALL offset: 0x%x, CALL 0x%lx", *(s32 *)(insnbuf + 1), - (unsigned long)instr + *(s32 *)(insnbuf + 1) + 5); + (unsigned long)vinstr + *(s32 *)(insnbuf + 1) + 5); } - if (a->replacementlen && is_jmp(replacement[0])) - recompute_jump(a, instr, replacement, insnbuf); + if (a->replacementlen && is_jmp(vreplacement[0])) + recompute_jump(a, instr, vreplacement, insnbuf); if (a->instrlen > a->replacementlen) { add_nops(insnbuf + a->replacementlen, a->instrlen - a->replacementlen); insnbuf_sz += a->instrlen - a->replacementlen; } - DUMP_BYTES(insnbuf, insnbuf_sz, "%p: final_insn: ", instr); + DUMP_BYTES(insnbuf, insnbuf_sz, "%p: final_insn: ", vinstr); text_poke_early(instr, insnbuf, insnbuf_sz); } @@ -434,10 +470,16 @@ static void alternatives_smp_lock(const s32 *start, const s32 *end, for (poff = start; poff < end; poff++) { u8 *ptr = (u8 *)poff + *poff; +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) + ptr += ____LOAD_PHYSICAL_ADDR - LOAD_PHYSICAL_ADDR; + if (ptr < (u8 *)_text || (u8 *)_einittext <= ptr) + ptr -= ____LOAD_PHYSICAL_ADDR - LOAD_PHYSICAL_ADDR; +#endif + if (!*poff || ptr < text || ptr >= text_end) continue; /* turn DS segment override prefix into lock prefix */ - if (*ptr == 0x3e) + if (*(u8 *)ktla_ktva((unsigned long)ptr) == 0x3e) text_poke(ptr, ((unsigned char []){0xf0}), 1); } mutex_unlock(&text_mutex); @@ -452,10 +494,16 @@ static void alternatives_smp_unlock(const s32 *start, const s32 *end, for (poff = start; poff < end; poff++) { u8 *ptr = (u8 *)poff + *poff; +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) + ptr += ____LOAD_PHYSICAL_ADDR - LOAD_PHYSICAL_ADDR; + if (ptr < (u8 *)_text || (u8 *)_einittext <= ptr) + ptr -= ____LOAD_PHYSICAL_ADDR - LOAD_PHYSICAL_ADDR; +#endif + if (!*poff || ptr < text || ptr >= text_end) continue; /* turn lock prefix into DS segment override prefix */ - if (*ptr == 0xf0) + if (*(u8 *)ktla_ktva((unsigned long)ptr) == 0xf0) text_poke(ptr, ((unsigned char []){0x3E}), 1); } mutex_unlock(&text_mutex); @@ -592,7 +640,7 @@ void __init_or_module apply_paravirt(struct paravirt_patch_site *start, BUG_ON(p->len > MAX_PATCH_LEN); /* prep the buffer with the original instructions */ - memcpy(insnbuf, p->instr, p->len); + memcpy(insnbuf, (const void *)ktla_ktva((unsigned long)p->instr), p->len); used = pv_init_ops.patch(p->instrtype, p->clobbers, insnbuf, (unsigned long)p->instr, p->len); @@ -639,7 +687,7 @@ void __init alternative_instructions(void) if (!uniproc_patched || num_possible_cpus() == 1) free_init_pages("SMP alternatives", (unsigned long)__smp_locks, - (unsigned long)__smp_locks_end); + PAGE_ALIGN((unsigned long)__smp_locks_end)); #endif apply_paravirt(__parainstructions, __parainstructions_end); @@ -660,13 +708,17 @@ void __init alternative_instructions(void) * instructions. And on the local CPU you need to be protected again NMI or MCE * handlers seeing an inconsistent instruction while you patch. */ -void *__init_or_module text_poke_early(void *addr, const void *opcode, +void *__kprobes text_poke_early(void *addr, const void *opcode, size_t len) { unsigned long flags; local_irq_save(flags); - memcpy(addr, opcode, len); + + pax_open_kernel(); + memcpy((void *)ktla_ktva((unsigned long)addr), opcode, len); sync_core(); + pax_close_kernel(); + local_irq_restore(flags); /* Could also do a CLFLUSH here to speed up CPU recovery; but that causes hangs on some VIA CPUs. */ @@ -688,36 +740,22 @@ void *__init_or_module text_poke_early(void *addr, const void *opcode, */ void *text_poke(void *addr, const void *opcode, size_t len) { - unsigned long flags; - char *vaddr; + unsigned char *vaddr = (void *)ktla_ktva((unsigned long)addr); struct page *pages[2]; - int i; + size_t i; if (!core_kernel_text((unsigned long)addr)) { - pages[0] = vmalloc_to_page(addr); - pages[1] = vmalloc_to_page(addr + PAGE_SIZE); + pages[0] = vmalloc_to_page(vaddr); + pages[1] = vmalloc_to_page(vaddr + PAGE_SIZE); } else { - pages[0] = virt_to_page(addr); + pages[0] = virt_to_page(vaddr); WARN_ON(!PageReserved(pages[0])); - pages[1] = virt_to_page(addr + PAGE_SIZE); + pages[1] = virt_to_page(vaddr + PAGE_SIZE); } BUG_ON(!pages[0]); - local_irq_save(flags); - set_fixmap(FIX_TEXT_POKE0, page_to_phys(pages[0])); - if (pages[1]) - set_fixmap(FIX_TEXT_POKE1, page_to_phys(pages[1])); - vaddr = (char *)fix_to_virt(FIX_TEXT_POKE0); - memcpy(&vaddr[(unsigned long)addr & ~PAGE_MASK], opcode, len); - clear_fixmap(FIX_TEXT_POKE0); - if (pages[1]) - clear_fixmap(FIX_TEXT_POKE1); - local_flush_tlb(); - sync_core(); - /* Could also do a CLFLUSH here to speed up CPU recovery; but - that causes hangs on some VIA CPUs. */ + text_poke_early(addr, opcode, len); for (i = 0; i < len; i++) - BUG_ON(((char *)addr)[i] != ((char *)opcode)[i]); - local_irq_restore(flags); + BUG_ON((vaddr)[i] != ((const unsigned char *)opcode)[i]); return addr; } @@ -771,7 +809,7 @@ int poke_int3_handler(struct pt_regs *regs) */ void *text_poke_bp(void *addr, const void *opcode, size_t len, void *handler) { - unsigned char int3 = 0xcc; + const unsigned char int3 = 0xcc; bp_int3_handler = handler; bp_int3_addr = (u8 *)addr + sizeof(int3); diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 24e94ce..7bd6977 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -171,7 +171,7 @@ int first_system_vector = FIRST_SYSTEM_VECTOR; /* * Debug level, exported for io_apic.c */ -unsigned int apic_verbosity; +int apic_verbosity; int pic_mode; @@ -1868,7 +1868,7 @@ static inline void __smp_error_interrupt(struct pt_regs *regs) apic_write(APIC_ESR, 0); v = apic_read(APIC_ESR); ack_APIC_irq(); - atomic_inc(&irq_err_count); + atomic_inc_unchecked(&irq_err_count); apic_printk(APIC_DEBUG, KERN_DEBUG "APIC error on CPU%d: %02x", smp_processor_id(), v); diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c index f92ab36..1884323 100644 --- a/arch/x86/kernel/apic/apic_flat_64.c +++ b/arch/x86/kernel/apic/apic_flat_64.c @@ -25,7 +25,7 @@ static struct apic apic_physflat; static struct apic apic_flat; -struct apic __read_mostly *apic = &apic_flat; +struct apic *apic __read_only = &apic_flat; EXPORT_SYMBOL_GPL(apic); static int flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id) @@ -154,7 +154,7 @@ static int flat_probe(void) return 1; } -static struct apic apic_flat = { +static struct apic apic_flat __read_only = { .name = "flat", .probe = flat_probe, .acpi_madt_oem_check = flat_acpi_madt_oem_check, @@ -259,7 +259,7 @@ static int physflat_probe(void) return 0; } -static struct apic apic_physflat = { +static struct apic apic_physflat __read_only = { .name = "physical flat", .probe = physflat_probe, diff --git a/arch/x86/kernel/apic/apic_noop.c b/arch/x86/kernel/apic/apic_noop.c index 0d96749..ce6b722 100644 --- a/arch/x86/kernel/apic/apic_noop.c +++ b/arch/x86/kernel/apic/apic_noop.c @@ -108,7 +108,7 @@ static void noop_apic_write(u32 reg, u32 v) WARN_ON_ONCE(cpu_has_apic && !disable_apic); } -struct apic apic_noop = { +struct apic apic_noop __read_only = { .name = "noop", .probe = noop_probe, .acpi_madt_oem_check = NULL, diff --git a/arch/x86/kernel/apic/bigsmp_32.c b/arch/x86/kernel/apic/bigsmp_32.c index 971cf88..a8e01ae 100644 --- a/arch/x86/kernel/apic/bigsmp_32.c +++ b/arch/x86/kernel/apic/bigsmp_32.c @@ -147,7 +147,7 @@ static int probe_bigsmp(void) return dmi_bigsmp; } -static struct apic apic_bigsmp = { +static struct apic apic_bigsmp __read_only = { .name = "bigsmp", .probe = probe_bigsmp, diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 4f28215..e0b9a5d 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -1682,7 +1682,7 @@ static unsigned int startup_ioapic_irq(struct irq_data *data) return was_pending; } -atomic_t irq_mis_count; +atomic_unchecked_t irq_mis_count; #ifdef CONFIG_GENERIC_PENDING_IRQ static bool io_apic_level_ack_pending(struct mp_chip_data *data) @@ -1821,7 +1821,7 @@ static void ioapic_ack_level(struct irq_data *irq_data) * at the cpu. */ if (!(v & (1 << (i & 0x1f)))) { - atomic_inc(&irq_mis_count); + atomic_inc_unchecked(&irq_mis_count); eoi_ioapic_pin(cfg->vector, irq_data->chip_data); } @@ -1867,7 +1867,7 @@ static int ioapic_set_affinity(struct irq_data *irq_data, return ret; } -static struct irq_chip ioapic_chip __read_mostly = { +static struct irq_chip ioapic_chip = { .name = "IO-APIC", .irq_startup = startup_ioapic_irq, .irq_mask = mask_ioapic_irq, @@ -1936,7 +1936,7 @@ static void ack_lapic_irq(struct irq_data *data) ack_APIC_irq(); } -static struct irq_chip lapic_chip __read_mostly = { +static struct irq_chip lapic_chip = { .name = "local-APIC", .irq_mask = mask_lapic_irq, .irq_unmask = unmask_lapic_irq, diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c index 5f1feb6..199d454 100644 --- a/arch/x86/kernel/apic/msi.c +++ b/arch/x86/kernel/apic/msi.c @@ -267,7 +267,7 @@ static void hpet_msi_write_msg(struct irq_data *data, struct msi_msg *msg) hpet_msi_write(irq_data_get_irq_handler_data(data), msg); } -static struct irq_chip hpet_msi_controller = { +static irq_chip_no_const hpet_msi_controller __read_only = { .name = "HPET-MSI", .irq_unmask = hpet_msi_unmask, .irq_mask = hpet_msi_mask, diff --git a/arch/x86/kernel/apic/probe_32.c b/arch/x86/kernel/apic/probe_32.c index 7694ae6..5abb08e 100644 --- a/arch/x86/kernel/apic/probe_32.c +++ b/arch/x86/kernel/apic/probe_32.c @@ -72,7 +72,7 @@ static int probe_default(void) return 1; } -static struct apic apic_default = { +static struct apic apic_default __read_only = { .name = "default", .probe = probe_default, @@ -126,7 +126,7 @@ static struct apic apic_default = { apic_driver(apic_default); -struct apic *apic = &apic_default; +struct apic *apic __read_only = &apic_default; EXPORT_SYMBOL_GPL(apic); static int cmdline_apic __initdata; diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index 861bc59..a721835 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -36,6 +36,7 @@ static struct irq_chip lapic_controller; static struct apic_chip_data *legacy_irq_data[NR_IRQS_LEGACY]; #endif +void lock_vector_lock(void) __acquires(&vector_lock); void lock_vector_lock(void) { /* Used to the online set of cpus does not change @@ -44,6 +45,7 @@ void lock_vector_lock(void) raw_spin_lock(&vector_lock); } +void unlock_vector_lock(void) __releases(&vector_lock); void unlock_vector_lock(void) { raw_spin_unlock(&vector_lock); diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c index cc8311c..d72f027 100644 --- a/arch/x86/kernel/apic/x2apic_cluster.c +++ b/arch/x86/kernel/apic/x2apic_cluster.c @@ -234,7 +234,7 @@ static void cluster_vector_allocation_domain(int cpu, struct cpumask *retmask, cpumask_and(retmask, mask, per_cpu(cpus_in_cluster, cpu)); } -static struct apic apic_x2apic_cluster = { +static struct apic apic_x2apic_cluster __read_only = { .name = "cluster x2apic", .probe = x2apic_cluster_probe, diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c index 662e915..e721634 100644 --- a/arch/x86/kernel/apic/x2apic_phys.c +++ b/arch/x86/kernel/apic/x2apic_phys.c @@ -90,7 +90,7 @@ static int x2apic_phys_probe(void) return apic == &apic_x2apic_phys; } -static struct apic apic_x2apic_phys = { +static struct apic apic_x2apic_phys __read_only = { .name = "physical x2apic", .probe = x2apic_phys_probe, diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 4a13946..067ed8c 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -374,7 +374,7 @@ static int uv_probe(void) return apic == &apic_x2apic_uv_x; } -static struct apic __refdata apic_x2apic_uv_x = { +static struct apic apic_x2apic_uv_x __read_only = { .name = "UV large system", .probe = uv_probe, diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 052c9c3..bc22ccdba 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -432,7 +432,7 @@ static DEFINE_MUTEX(apm_mutex); * This is for buggy BIOS's that refer to (real mode) segment 0x40 * even though they are called in protected mode. */ -static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092, +static const struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4093, (unsigned long)__va(0x400UL), PAGE_SIZE - 0x400 - 1); static const char driver_version[] = "1.16ac"; /* no spaces */ @@ -610,7 +610,10 @@ static long __apm_bios_call(void *_call) BUG_ON(cpu != 0); gdt = get_cpu_gdt_table(cpu); save_desc_40 = gdt[0x40 / 8]; + + pax_open_kernel(); gdt[0x40 / 8] = bad_bios_desc; + pax_close_kernel(); apm_irq_save(flags); APM_DO_SAVE_SEGS; @@ -619,7 +622,11 @@ static long __apm_bios_call(void *_call) &call->esi); APM_DO_RESTORE_SEGS; apm_irq_restore(flags); + + pax_open_kernel(); gdt[0x40 / 8] = save_desc_40; + pax_close_kernel(); + put_cpu(); return call->eax & 0xff; @@ -686,7 +693,10 @@ static long __apm_bios_call_simple(void *_call) BUG_ON(cpu != 0); gdt = get_cpu_gdt_table(cpu); save_desc_40 = gdt[0x40 / 8]; + + pax_open_kernel(); gdt[0x40 / 8] = bad_bios_desc; + pax_close_kernel(); apm_irq_save(flags); APM_DO_SAVE_SEGS; @@ -694,7 +704,11 @@ static long __apm_bios_call_simple(void *_call) &call->eax); APM_DO_RESTORE_SEGS; apm_irq_restore(flags); + + pax_open_kernel(); gdt[0x40 / 8] = save_desc_40; + pax_close_kernel(); + put_cpu(); return error; } @@ -2039,7 +2053,7 @@ static int __init swab_apm_power_in_minutes(const struct dmi_system_id *d) return 0; } -static struct dmi_system_id __initdata apm_dmi_table[] = { +static const struct dmi_system_id __initconst apm_dmi_table[] = { { print_if_true, KERN_WARNING "IBM T23 - BIOS 1.03b+ and controller firmware 1.02+ may be needed for Linux APM.", @@ -2349,12 +2363,15 @@ static int __init apm_init(void) * code to that CPU. */ gdt = get_cpu_gdt_table(0); + + pax_open_kernel(); set_desc_base(&gdt[APM_CS >> 3], (unsigned long)__va((unsigned long)apm_info.bios.cseg << 4)); set_desc_base(&gdt[APM_CS_16 >> 3], (unsigned long)__va((unsigned long)apm_info.bios.cseg_16 << 4)); set_desc_base(&gdt[APM_DS >> 3], (unsigned long)__va((unsigned long)apm_info.bios.dseg << 4)); + pax_close_kernel(); proc_create("apm", 0, NULL, &apm_file_ops); diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c index 8e3d22a1..37118b6 100644 --- a/arch/x86/kernel/asm-offsets.c +++ b/arch/x86/kernel/asm-offsets.c @@ -32,6 +32,8 @@ void common(void) { OFFSET(TI_flags, thread_info, flags); OFFSET(TI_status, thread_info, status); OFFSET(TI_addr_limit, thread_info, addr_limit); + OFFSET(TI_lowest_stack, thread_info, lowest_stack); + DEFINE(TI_task_thread_sp0, offsetof(struct task_struct, thread.sp0) - offsetof(struct task_struct, tinfo)); BLANK(); OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx); @@ -73,8 +75,26 @@ void common(void) { #endif OFFSET(PV_CPU_read_cr0, pv_cpu_ops, read_cr0); OFFSET(PV_MMU_read_cr2, pv_mmu_ops, read_cr2); + +#ifdef CONFIG_PAX_KERNEXEC + OFFSET(PV_CPU_write_cr0, pv_cpu_ops, write_cr0); #endif +#ifdef CONFIG_PAX_MEMORY_UDEREF + OFFSET(PV_MMU_read_cr3, pv_mmu_ops, read_cr3); + OFFSET(PV_MMU_write_cr3, pv_mmu_ops, write_cr3); +#ifdef CONFIG_X86_64 + OFFSET(PV_MMU_set_pgd_batched, pv_mmu_ops, set_pgd_batched); +#endif +#endif + +#endif + + BLANK(); + DEFINE(PAGE_SIZE_asm, PAGE_SIZE); + DEFINE(PAGE_SHIFT_asm, PAGE_SHIFT); + DEFINE(THREAD_SIZE_asm, THREAD_SIZE); + #ifdef CONFIG_XEN BLANK(); OFFSET(XEN_vcpu_info_mask, vcpu_info, evtchn_upcall_mask); diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c index d8f42f9..a46f1fc 100644 --- a/arch/x86/kernel/asm-offsets_64.c +++ b/arch/x86/kernel/asm-offsets_64.c @@ -59,6 +59,7 @@ int main(void) BLANK(); #undef ENTRY + DEFINE(TSS_size, sizeof(struct tss_struct)); OFFSET(TSS_ist, tss_struct, x86_tss.ist); OFFSET(TSS_sp0, tss_struct, x86_tss.sp0); BLANK(); diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 4eb065c..40dd012 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -8,10 +8,6 @@ CFLAGS_REMOVE_common.o = -pg CFLAGS_REMOVE_perf_event.o = -pg endif -# Make sure load_percpu_segment has no stackprotector -nostackp := $(call cc-option, -fno-stack-protector) -CFLAGS_common.o := $(nostackp) - obj-y := intel_cacheinfo.o scattered.o topology.o obj-y += common.o obj-y += rdrand.o diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 4a70fc6..7720ca5 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -754,7 +754,7 @@ static void init_amd(struct cpuinfo_x86 *c) static unsigned int amd_size_cache(struct cpuinfo_x86 *c, unsigned int size) { /* AMD errata T13 (order #21922) */ - if ((c->x86 == 6)) { + if (c->x86 == 6) { /* Duron Rev A0 */ if (c->x86_model == 3 && c->x86_mask == 0) size = 64; diff --git a/arch/x86/kernel/cpu/bugs_64.c b/arch/x86/kernel/cpu/bugs_64.c index 04f0fe5..3c0598c 100644 --- a/arch/x86/kernel/cpu/bugs_64.c +++ b/arch/x86/kernel/cpu/bugs_64.c @@ -10,6 +10,7 @@ #include #include #include +#include void __init check_bugs(void) { @@ -18,6 +19,7 @@ void __init check_bugs(void) printk(KERN_INFO "CPU: "); print_cpu_info(&boot_cpu_data); #endif + set_memory_nx((unsigned long)_sinitdata, (__START_KERNEL_map + KERNEL_IMAGE_SIZE - (unsigned long)_sinitdata) >> PAGE_SHIFT); alternative_instructions(); /* diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 1a292573..f917fff 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -92,60 +92,6 @@ static const struct cpu_dev default_cpu = { static const struct cpu_dev *this_cpu = &default_cpu; -DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = { -#ifdef CONFIG_X86_64 - /* - * We need valid kernel segments for data and code in long mode too - * IRET will check the segment types kkeil 2000/10/28 - * Also sysret mandates a special GDT layout - * - * TLS descriptors are currently at a different place compared to i386. - * Hopefully nobody expects them at a fixed place (Wine?) - */ - [GDT_ENTRY_KERNEL32_CS] = GDT_ENTRY_INIT(0xc09b, 0, 0xfffff), - [GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(0xa09b, 0, 0xfffff), - [GDT_ENTRY_KERNEL_DS] = GDT_ENTRY_INIT(0xc093, 0, 0xfffff), - [GDT_ENTRY_DEFAULT_USER32_CS] = GDT_ENTRY_INIT(0xc0fb, 0, 0xfffff), - [GDT_ENTRY_DEFAULT_USER_DS] = GDT_ENTRY_INIT(0xc0f3, 0, 0xfffff), - [GDT_ENTRY_DEFAULT_USER_CS] = GDT_ENTRY_INIT(0xa0fb, 0, 0xfffff), -#else - [GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(0xc09a, 0, 0xfffff), - [GDT_ENTRY_KERNEL_DS] = GDT_ENTRY_INIT(0xc092, 0, 0xfffff), - [GDT_ENTRY_DEFAULT_USER_CS] = GDT_ENTRY_INIT(0xc0fa, 0, 0xfffff), - [GDT_ENTRY_DEFAULT_USER_DS] = GDT_ENTRY_INIT(0xc0f2, 0, 0xfffff), - /* - * Segments used for calling PnP BIOS have byte granularity. - * They code segments and data segments have fixed 64k limits, - * the transfer segment sizes are set at run time. - */ - /* 32-bit code */ - [GDT_ENTRY_PNPBIOS_CS32] = GDT_ENTRY_INIT(0x409a, 0, 0xffff), - /* 16-bit code */ - [GDT_ENTRY_PNPBIOS_CS16] = GDT_ENTRY_INIT(0x009a, 0, 0xffff), - /* 16-bit data */ - [GDT_ENTRY_PNPBIOS_DS] = GDT_ENTRY_INIT(0x0092, 0, 0xffff), - /* 16-bit data */ - [GDT_ENTRY_PNPBIOS_TS1] = GDT_ENTRY_INIT(0x0092, 0, 0), - /* 16-bit data */ - [GDT_ENTRY_PNPBIOS_TS2] = GDT_ENTRY_INIT(0x0092, 0, 0), - /* - * The APM segments have byte granularity and their bases - * are set at run time. All have 64k limits. - */ - /* 32-bit code */ - [GDT_ENTRY_APMBIOS_BASE] = GDT_ENTRY_INIT(0x409a, 0, 0xffff), - /* 16-bit code */ - [GDT_ENTRY_APMBIOS_BASE+1] = GDT_ENTRY_INIT(0x009a, 0, 0xffff), - /* data */ - [GDT_ENTRY_APMBIOS_BASE+2] = GDT_ENTRY_INIT(0x4092, 0, 0xffff), - - [GDT_ENTRY_ESPFIX_SS] = GDT_ENTRY_INIT(0xc092, 0, 0xfffff), - [GDT_ENTRY_PERCPU] = GDT_ENTRY_INIT(0xc092, 0, 0xfffff), - GDT_STACK_CANARY_INIT -#endif -} }; -EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); - static int __init x86_mpx_setup(char *s) { /* require an exact match without trailing characters */ @@ -287,6 +233,109 @@ static __always_inline void setup_smap(struct cpuinfo_x86 *c) } } +#ifdef CONFIG_PAX_MEMORY_UDEREF +#ifdef CONFIG_X86_64 +static bool uderef_enabled __read_only = true; +unsigned long pax_user_shadow_base __read_only; +EXPORT_SYMBOL(pax_user_shadow_base); +extern char pax_enter_kernel_user[]; +extern char pax_exit_kernel_user[]; + +static int __init setup_pax_weakuderef(char *str) +{ + if (uderef_enabled) + pax_user_shadow_base = 1UL << TASK_SIZE_MAX_SHIFT; + return 1; +} +__setup("pax_weakuderef", setup_pax_weakuderef); +#endif + +static int __init setup_pax_nouderef(char *str) +{ +#ifdef CONFIG_X86_32 + unsigned int cpu; + struct desc_struct *gdt; + + for (cpu = 0; cpu < nr_cpu_ids; cpu++) { + gdt = get_cpu_gdt_table(cpu); + gdt[GDT_ENTRY_KERNEL_DS].type = 3; + gdt[GDT_ENTRY_KERNEL_DS].limit = 0xf; + gdt[GDT_ENTRY_DEFAULT_USER_CS].limit = 0xf; + gdt[GDT_ENTRY_DEFAULT_USER_DS].limit = 0xf; + } + loadsegment(ds, __KERNEL_DS); + loadsegment(es, __KERNEL_DS); + loadsegment(ss, __KERNEL_DS); +#else + memcpy(pax_enter_kernel_user, (unsigned char []){0xc3}, 1); + memcpy(pax_exit_kernel_user, (unsigned char []){0xc3}, 1); + clone_pgd_mask = ~(pgdval_t)0UL; + pax_user_shadow_base = 0UL; + setup_clear_cpu_cap(X86_FEATURE_PCIDUDEREF); + uderef_enabled = false; +#endif + + return 0; +} +early_param("pax_nouderef", setup_pax_nouderef); +#endif + +#ifdef CONFIG_X86_64 +static __init int setup_disable_pcid(char *arg) +{ + setup_clear_cpu_cap(X86_FEATURE_PCID); + setup_clear_cpu_cap(X86_FEATURE_INVPCID); + +#ifdef CONFIG_PAX_MEMORY_UDEREF + if (uderef_enabled) + pax_user_shadow_base = 1UL << TASK_SIZE_MAX_SHIFT; +#endif + + return 1; +} +__setup("nopcid", setup_disable_pcid); + +static void setup_pcid(struct cpuinfo_x86 *c) +{ + if (cpu_has(c, X86_FEATURE_PCID)) { + printk("PAX: PCID detected\n"); + cr4_set_bits(X86_CR4_PCIDE); + } else + clear_cpu_cap(c, X86_FEATURE_INVPCID); + + if (cpu_has(c, X86_FEATURE_INVPCID)) + printk("PAX: INVPCID detected\n"); + +#ifdef CONFIG_PAX_MEMORY_UDEREF + if (!uderef_enabled) { + printk("PAX: UDEREF disabled\n"); + return; + } + + if (!cpu_has(c, X86_FEATURE_PCID)) { + pax_open_kernel(); + pax_user_shadow_base = 1UL << TASK_SIZE_MAX_SHIFT; + pax_close_kernel(); + printk("PAX: slow and weak UDEREF enabled\n"); + return; + } + + set_cpu_cap(c, X86_FEATURE_PCIDUDEREF); + + pax_open_kernel(); + clone_pgd_mask = ~(pgdval_t)0UL; + pax_close_kernel(); + if (pax_user_shadow_base) + printk("PAX: weak UDEREF enabled\n"); + else { + set_cpu_cap(c, X86_FEATURE_STRONGUDEREF); + printk("PAX: strong UDEREF enabled\n"); + } +#endif + +} +#endif + /* * Some CPU features depend on higher CPUID levels, which may not always * be available due to CPUID level capping or broken virtualization @@ -387,7 +436,7 @@ void switch_to_new_gdt(int cpu) { struct desc_ptr gdt_descr; - gdt_descr.address = (long)get_cpu_gdt_table(cpu); + gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu); gdt_descr.size = GDT_SIZE - 1; load_gdt(&gdt_descr); /* Reload the per-cpu base */ @@ -918,6 +967,20 @@ static void identify_cpu(struct cpuinfo_x86 *c) setup_smep(c); setup_smap(c); +#ifdef CONFIG_X86_32 +#ifdef CONFIG_PAX_PAGEEXEC + if (!(__supported_pte_mask & _PAGE_NX)) + clear_cpu_cap(c, X86_FEATURE_PSE); +#endif +#if defined(CONFIG_PAX_SEGMEXEC) || defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) + clear_cpu_cap(c, X86_FEATURE_SEP); +#endif +#endif + +#ifdef CONFIG_X86_64 + setup_pcid(c); +#endif + /* * The vendor-specific functions might have changed features. * Now we do "generic changes." @@ -992,7 +1055,7 @@ void enable_sep_cpu(void) int cpu; cpu = get_cpu(); - tss = &per_cpu(cpu_tss, cpu); + tss = cpu_tss + cpu; if (!boot_cpu_has(X86_FEATURE_SEP)) goto out; @@ -1138,10 +1201,12 @@ static __init int setup_disablecpuid(char *arg) } __setup("clearcpuid=", setup_disablecpuid); +DEFINE_PER_CPU(struct thread_info *, current_tinfo) = &init_task.tinfo; +EXPORT_PER_CPU_SYMBOL(current_tinfo); + #ifdef CONFIG_X86_64 -struct desc_ptr idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) idt_table }; -struct desc_ptr debug_idt_descr = { NR_VECTORS * 16 - 1, - (unsigned long) debug_idt_table }; +struct desc_ptr idt_descr __read_only = { NR_VECTORS * 16 - 1, (unsigned long) idt_table }; +const struct desc_ptr debug_idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) debug_idt_table }; DEFINE_PER_CPU_FIRST(union irq_stack_union, irq_stack_union) __aligned(PAGE_SIZE) __visible; @@ -1253,21 +1318,21 @@ EXPORT_PER_CPU_SYMBOL(current_task); DEFINE_PER_CPU(int, __preempt_count) = INIT_PREEMPT_COUNT; EXPORT_PER_CPU_SYMBOL(__preempt_count); +#ifdef CONFIG_CC_STACKPROTECTOR +DEFINE_PER_CPU_ALIGNED(struct stack_canary, stack_canary); +#endif + +#endif /* CONFIG_X86_64 */ + /* * On x86_32, vm86 modifies tss.sp0, so sp0 isn't a reliable way to find * the top of the kernel stack. Use an extra percpu variable to track the * top of the kernel stack directly. */ DEFINE_PER_CPU(unsigned long, cpu_current_top_of_stack) = - (unsigned long)&init_thread_union + THREAD_SIZE; + (unsigned long)&init_thread_union - 16 + THREAD_SIZE; EXPORT_PER_CPU_SYMBOL(cpu_current_top_of_stack); -#ifdef CONFIG_CC_STACKPROTECTOR -DEFINE_PER_CPU_ALIGNED(struct stack_canary, stack_canary); -#endif - -#endif /* CONFIG_X86_64 */ - /* * Clear all 6 debug registers: */ @@ -1343,7 +1408,7 @@ void cpu_init(void) */ load_ucode_ap(); - t = &per_cpu(cpu_tss, cpu); + t = cpu_tss + cpu; oist = &per_cpu(orig_ist, cpu); #ifdef CONFIG_NUMA @@ -1375,7 +1440,6 @@ void cpu_init(void) wrmsrl(MSR_KERNEL_GS_BASE, 0); barrier(); - x86_configure_nx(); x2apic_setup(); /* @@ -1427,7 +1491,7 @@ void cpu_init(void) { int cpu = smp_processor_id(); struct task_struct *curr = current; - struct tss_struct *t = &per_cpu(cpu_tss, cpu); + struct tss_struct *t = cpu_tss + cpu; struct thread_struct *thread = &curr->thread; wait_for_master_cpu(cpu); diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index be4febc..f7af533 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -519,25 +519,23 @@ cache_private_attrs_is_visible(struct kobject *kobj, return 0; } +static struct attribute *amd_l3_attrs[4]; + static struct attribute_group cache_private_group = { .is_visible = cache_private_attrs_is_visible, + .attrs = amd_l3_attrs, }; static void init_amd_l3_attrs(void) { int n = 1; - static struct attribute **amd_l3_attrs; - - if (amd_l3_attrs) /* already initialized */ - return; if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) n += 2; if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING)) n += 1; - amd_l3_attrs = kcalloc(n, sizeof(*amd_l3_attrs), GFP_KERNEL); - if (!amd_l3_attrs) + if (n > 1 && amd_l3_attrs[0]) /* already initialized */ return; n = 0; @@ -547,8 +545,6 @@ static void init_amd_l3_attrs(void) } if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING)) amd_l3_attrs[n++] = &dev_attr_subcaches.attr; - - cache_private_group.attrs = amd_l3_attrs; } const struct attribute_group * @@ -559,7 +555,7 @@ cache_get_priv_group(struct cacheinfo *this_leaf) if (this_leaf->level < 3 || !nb) return NULL; - if (nb && nb->l3_cache.indices) + if (nb->l3_cache.indices) init_amd_l3_attrs(); return &cache_private_group; diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 9d014b82..8186c29 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -47,6 +47,7 @@ #include #include #include +#include #include "mce-internal.h" @@ -212,8 +213,7 @@ static struct notifier_block mce_srao_nb; void mce_register_decode_chain(struct notifier_block *nb) { /* Ensure SRAO notifier has the highest priority in the decode chain. */ - if (nb != &mce_srao_nb && nb->priority == INT_MAX) - nb->priority -= 1; + BUG_ON(nb != &mce_srao_nb && nb->priority == INT_MAX); atomic_notifier_chain_register(&x86_mce_decoder_chain, nb); } @@ -237,7 +237,7 @@ static void print_mce(struct mce *m) !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "", m->cs, m->ip); - if (m->cs == __KERNEL_CS) + if (m->cs == __KERNEL_CS || m->cs == __KERNEXEC_KERNEL_CS) print_symbol("{%s}", m->ip); pr_cont("\n"); } @@ -270,10 +270,10 @@ static void print_mce(struct mce *m) #define PANIC_TIMEOUT 5 /* 5 seconds */ -static atomic_t mce_panicked; +static atomic_unchecked_t mce_panicked; static int fake_panic; -static atomic_t mce_fake_panicked; +static atomic_unchecked_t mce_fake_panicked; /* Panic in progress. Enable interrupts and wait for final IPI */ static void wait_for_panic(void) @@ -297,7 +297,7 @@ static void mce_panic(const char *msg, struct mce *final, char *exp) /* * Make sure only one CPU runs in machine check panic */ - if (atomic_inc_return(&mce_panicked) > 1) + if (atomic_inc_return_unchecked(&mce_panicked) > 1) wait_for_panic(); barrier(); @@ -305,7 +305,7 @@ static void mce_panic(const char *msg, struct mce *final, char *exp) console_verbose(); } else { /* Don't log too much for fake panic */ - if (atomic_inc_return(&mce_fake_panicked) > 1) + if (atomic_inc_return_unchecked(&mce_fake_panicked) > 1) return; } /* First print corrected ones that are still unlogged */ @@ -344,7 +344,7 @@ static void mce_panic(const char *msg, struct mce *final, char *exp) if (!fake_panic) { if (panic_timeout == 0) panic_timeout = mca_cfg.panic_timeout; - panic(msg); + panic("%s", msg); } else pr_emerg(HW_ERR "Fake kernel panic: %s\n", msg); } @@ -697,7 +697,7 @@ static int mce_timed_out(u64 *t, const char *msg) * might have been modified by someone else. */ rmb(); - if (atomic_read(&mce_panicked)) + if (atomic_read_unchecked(&mce_panicked)) wait_for_panic(); if (!mca_cfg.monarch_timeout) goto out; @@ -1654,7 +1654,7 @@ static void unexpected_machine_check(struct pt_regs *regs, long error_code) } /* Call the installed machine check handler for this CPU setup. */ -void (*machine_check_vector)(struct pt_regs *, long error_code) = +void (*machine_check_vector)(struct pt_regs *, long error_code) __read_only = unexpected_machine_check; /* @@ -1683,7 +1683,9 @@ void mcheck_cpu_init(struct cpuinfo_x86 *c) return; } + pax_open_kernel(); machine_check_vector = do_machine_check; + pax_close_kernel(); __mcheck_cpu_init_generic(); __mcheck_cpu_init_vendor(c); @@ -1714,7 +1716,7 @@ void mcheck_cpu_clear(struct cpuinfo_x86 *c) */ static DEFINE_SPINLOCK(mce_chrdev_state_lock); -static int mce_chrdev_open_count; /* #times opened */ +static local_t mce_chrdev_open_count; /* #times opened */ static int mce_chrdev_open_exclu; /* already open exclusive? */ static int mce_chrdev_open(struct inode *inode, struct file *file) @@ -1722,7 +1724,7 @@ static int mce_chrdev_open(struct inode *inode, struct file *file) spin_lock(&mce_chrdev_state_lock); if (mce_chrdev_open_exclu || - (mce_chrdev_open_count && (file->f_flags & O_EXCL))) { + (local_read(&mce_chrdev_open_count) && (file->f_flags & O_EXCL))) { spin_unlock(&mce_chrdev_state_lock); return -EBUSY; @@ -1730,7 +1732,7 @@ static int mce_chrdev_open(struct inode *inode, struct file *file) if (file->f_flags & O_EXCL) mce_chrdev_open_exclu = 1; - mce_chrdev_open_count++; + local_inc(&mce_chrdev_open_count); spin_unlock(&mce_chrdev_state_lock); @@ -1741,7 +1743,7 @@ static int mce_chrdev_release(struct inode *inode, struct file *file) { spin_lock(&mce_chrdev_state_lock); - mce_chrdev_open_count--; + local_dec(&mce_chrdev_open_count); mce_chrdev_open_exclu = 0; spin_unlock(&mce_chrdev_state_lock); @@ -2421,7 +2423,7 @@ static __init void mce_init_banks(void) for (i = 0; i < mca_cfg.banks; i++) { struct mce_bank *b = &mce_banks[i]; - struct device_attribute *a = &b->attr; + device_attribute_no_const *a = &b->attr; sysfs_attr_init(&a->attr); a->attr.name = b->attrname; @@ -2528,7 +2530,7 @@ struct dentry *mce_get_debugfs_dir(void) static void mce_reset(void) { cpu_missing = 0; - atomic_set(&mce_fake_panicked, 0); + atomic_set_unchecked(&mce_fake_panicked, 0); atomic_set(&mce_executing, 0); atomic_set(&mce_callin, 0); atomic_set(&global_nwo, 0); diff --git a/arch/x86/kernel/cpu/mcheck/p5.c b/arch/x86/kernel/cpu/mcheck/p5.c index 12402e1..9e0f230 100644 --- a/arch/x86/kernel/cpu/mcheck/p5.c +++ b/arch/x86/kernel/cpu/mcheck/p5.c @@ -12,6 +12,7 @@ #include #include #include +#include /* By default disabled */ int mce_p5_enabled __read_mostly; @@ -54,7 +55,9 @@ void intel_p5_mcheck_init(struct cpuinfo_x86 *c) if (!cpu_has(c, X86_FEATURE_MCE)) return; + pax_open_kernel(); machine_check_vector = pentium_machine_check; + pax_close_kernel(); /* Make sure the vector pointer is visible before we enable MCEs: */ wmb(); diff --git a/arch/x86/kernel/cpu/mcheck/winchip.c b/arch/x86/kernel/cpu/mcheck/winchip.c index 01dd870..6fd1c59 100644 --- a/arch/x86/kernel/cpu/mcheck/winchip.c +++ b/arch/x86/kernel/cpu/mcheck/winchip.c @@ -11,6 +11,7 @@ #include #include #include +#include /* Machine check handler for WinChip C6: */ static void winchip_machine_check(struct pt_regs *regs, long error_code) @@ -28,7 +29,9 @@ void winchip_mcheck_init(struct cpuinfo_x86 *c) { u32 lo, hi; + pax_open_kernel(); machine_check_vector = winchip_machine_check; + pax_close_kernel(); /* Make sure the vector pointer is visible before we enable MCEs: */ wmb(); diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 969dc17..a9c3fdd 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -237,13 +237,13 @@ static enum ucode_state request_microcode_fw(int cpu, struct device *device, static int get_ucode_user(void *to, const void *from, size_t n) { - return copy_from_user(to, from, n); + return copy_from_user(to, (const void __force_user *)from, n); } static enum ucode_state request_microcode_user(int cpu, const void __user *buf, size_t size) { - return generic_load_microcode(cpu, (void *)buf, size, &get_ucode_user); + return generic_load_microcode(cpu, (__force_kernel void *)buf, size, &get_ucode_user); } static void microcode_fini_cpu(int cpu) diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c index 3b533cf..b40d426 100644 --- a/arch/x86/kernel/cpu/mtrr/generic.c +++ b/arch/x86/kernel/cpu/mtrr/generic.c @@ -723,7 +723,8 @@ static DEFINE_RAW_SPINLOCK(set_atomicity_lock); * The caller must ensure that local interrupts are disabled and * are reenabled after post_set() has been called. */ -static void prepare_set(void) __acquires(set_atomicity_lock) +static void prepare_set(void) __acquires(&set_atomicity_lock); +static void prepare_set(void) { unsigned long cr0; @@ -759,7 +760,8 @@ static void prepare_set(void) __acquires(set_atomicity_lock) wbinvd(); } -static void post_set(void) __releases(set_atomicity_lock) +static void post_set(void) __releases(&set_atomicity_lock); +static void post_set(void) { /* Flush TLBs (no need to flush caches - they are disabled) */ count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL); diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c index f891b47..9dff300 100644 --- a/arch/x86/kernel/cpu/mtrr/main.c +++ b/arch/x86/kernel/cpu/mtrr/main.c @@ -72,7 +72,7 @@ static DEFINE_MUTEX(mtrr_mutex); u64 size_or_mask, size_and_mask; static bool mtrr_aps_delayed_init; -static const struct mtrr_ops *mtrr_ops[X86_VENDOR_NUM]; +static const struct mtrr_ops *mtrr_ops[X86_VENDOR_NUM] __read_only; const struct mtrr_ops *mtrr_if; diff --git a/arch/x86/kernel/cpu/mtrr/mtrr.h b/arch/x86/kernel/cpu/mtrr/mtrr.h index 951884d..4796b75 100644 --- a/arch/x86/kernel/cpu/mtrr/mtrr.h +++ b/arch/x86/kernel/cpu/mtrr/mtrr.h @@ -25,7 +25,7 @@ struct mtrr_ops { int (*validate_add_page)(unsigned long base, unsigned long size, unsigned int type); int (*have_wrcomb)(void); -}; +} __do_const; extern int generic_get_free_region(unsigned long base, unsigned long size, int replace_reg); diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 66dd3fe9..c9bfa35 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1518,7 +1518,7 @@ static void __init pmu_check_apic(void) } -static struct attribute_group x86_pmu_format_group = { +static attribute_group_no_const x86_pmu_format_group = { .name = "format", .attrs = NULL, }; @@ -1617,7 +1617,7 @@ static struct attribute *events_attr[] = { NULL, }; -static struct attribute_group x86_pmu_events_group = { +static attribute_group_no_const x86_pmu_events_group = { .name = "events", .attrs = events_attr, }; @@ -2176,7 +2176,7 @@ valid_user_frame(const void __user *fp, unsigned long size) static unsigned long get_segment_base(unsigned int segment) { struct desc_struct *desc; - int idx = segment >> 3; + unsigned int idx = segment >> 3; if ((segment & SEGMENT_TI_MASK) == SEGMENT_LDT) { #ifdef CONFIG_MODIFY_LDT_SYSCALL @@ -2198,7 +2198,7 @@ static unsigned long get_segment_base(unsigned int segment) if (idx > GDT_ENTRIES) return 0; - desc = raw_cpu_ptr(gdt_page.gdt) + idx; + desc = get_cpu_gdt_table(smp_processor_id()) + idx; } return get_desc_base(desc); @@ -2288,7 +2288,7 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) break; perf_callchain_store(entry, frame.return_address); - fp = frame.next_frame; + fp = (const void __force_user *)frame.next_frame; } } diff --git a/arch/x86/kernel/cpu/perf_event_amd_iommu.c b/arch/x86/kernel/cpu/perf_event_amd_iommu.c index 97242a9..cf9c30e 100644 --- a/arch/x86/kernel/cpu/perf_event_amd_iommu.c +++ b/arch/x86/kernel/cpu/perf_event_amd_iommu.c @@ -402,7 +402,7 @@ static void perf_iommu_del(struct perf_event *event, int flags) static __init int _init_events_attrs(struct perf_amd_iommu *perf_iommu) { struct attribute **attrs; - struct attribute_group *attr_group; + attribute_group_no_const *attr_group; int i = 0, j; while (amd_iommu_v2_event_descs[i].attr.attr.name) diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index f63360b..5bf835d 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -2119,6 +2119,8 @@ __intel_get_event_constraints(struct cpu_hw_events *cpuc, int idx, } static void +intel_start_scheduling(struct cpu_hw_events *cpuc) __acquires(&cpuc->excl_cntrs->lock); +static void intel_start_scheduling(struct cpu_hw_events *cpuc) { struct intel_excl_cntrs *excl_cntrs = cpuc->excl_cntrs; @@ -2128,14 +2130,18 @@ intel_start_scheduling(struct cpu_hw_events *cpuc) /* * nothing needed if in group validation mode */ - if (cpuc->is_fake || !is_ht_workaround_enabled()) + if (cpuc->is_fake || !is_ht_workaround_enabled()) { + __acquire(&excl_cntrs->lock); return; + } /* * no exclusion needed */ - if (WARN_ON_ONCE(!excl_cntrs)) + if (WARN_ON_ONCE(!excl_cntrs)) { + __acquire(&excl_cntrs->lock); return; + } xl = &excl_cntrs->states[tid]; @@ -2175,6 +2181,8 @@ static void intel_commit_scheduling(struct cpu_hw_events *cpuc, int idx, int cnt } static void +intel_stop_scheduling(struct cpu_hw_events *cpuc) __releases(&cpuc->excl_cntrs->lock); +static void intel_stop_scheduling(struct cpu_hw_events *cpuc) { struct intel_excl_cntrs *excl_cntrs = cpuc->excl_cntrs; @@ -2184,13 +2192,18 @@ intel_stop_scheduling(struct cpu_hw_events *cpuc) /* * nothing needed if in group validation mode */ - if (cpuc->is_fake || !is_ht_workaround_enabled()) + if (cpuc->is_fake || !is_ht_workaround_enabled()) { + __release(&excl_cntrs->lock); return; + } + /* * no exclusion needed */ - if (WARN_ON_ONCE(!excl_cntrs)) + if (WARN_ON_ONCE(!excl_cntrs)) { + __release(&excl_cntrs->lock); return; + } xl = &excl_cntrs->states[tid]; @@ -2373,19 +2386,22 @@ static void intel_put_excl_constraints(struct cpu_hw_events *cpuc, * unused now. */ if (hwc->idx >= 0) { + bool sched_started; + xl = &excl_cntrs->states[tid]; + sched_started = xl->sched_started; /* * put_constraint may be called from x86_schedule_events() * which already has the lock held so here make locking * conditional. */ - if (!xl->sched_started) + if (!sched_started) raw_spin_lock(&excl_cntrs->lock); xl->state[hwc->idx] = INTEL_EXCL_UNUSED; - if (!xl->sched_started) + if (!sched_started) raw_spin_unlock(&excl_cntrs->lock); } } @@ -3258,10 +3274,10 @@ __init int intel_pmu_init(void) x86_pmu.num_counters_fixed = max((int)edx.split.num_counters_fixed, 3); if (boot_cpu_has(X86_FEATURE_PDCM)) { - u64 capabilities; + u64 capabilities = x86_pmu.intel_cap.capabilities; - rdmsrl(MSR_IA32_PERF_CAPABILITIES, capabilities); - x86_pmu.intel_cap.capabilities = capabilities; + if (rdmsrl_safe(MSR_IA32_PERF_CAPABILITIES, &x86_pmu.intel_cap.capabilities)) + x86_pmu.intel_cap.capabilities = capabilities; } intel_ds_init(); diff --git a/arch/x86/kernel/cpu/perf_event_intel_bts.c b/arch/x86/kernel/cpu/perf_event_intel_bts.c index d1c0f25..9d7332c 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_bts.c +++ b/arch/x86/kernel/cpu/perf_event_intel_bts.c @@ -250,7 +250,7 @@ static void bts_event_start(struct perf_event *event, int flags) __bts_event_start(event); /* PMI handler: this counter is running and likely generating PMIs */ - ACCESS_ONCE(bts->started) = 1; + ACCESS_ONCE_RW(bts->started) = 1; } static void __bts_event_stop(struct perf_event *event) @@ -264,7 +264,7 @@ static void __bts_event_stop(struct perf_event *event) if (event->hw.state & PERF_HES_STOPPED) return; - ACCESS_ONCE(event->hw.state) |= PERF_HES_STOPPED; + ACCESS_ONCE_RW(event->hw.state) |= PERF_HES_STOPPED; } static void bts_event_stop(struct perf_event *event, int flags) @@ -272,7 +272,7 @@ static void bts_event_stop(struct perf_event *event, int flags) struct bts_ctx *bts = this_cpu_ptr(&bts_ctx); /* PMI handler: don't restart this counter */ - ACCESS_ONCE(bts->started) = 0; + ACCESS_ONCE_RW(bts->started) = 0; __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 377e8f8..2982f48 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) goto out; } - event_attr_intel_cqm_llc_scale.event_str = str; + pax_open_kernel(); + *(const char **)&event_attr_intel_cqm_llc_scale.event_str = str; + pax_close_kernel(); ret = intel_cqm_setup_rmid_cache(); if (ret) diff --git a/arch/x86/kernel/cpu/perf_event_intel_pt.c b/arch/x86/kernel/cpu/perf_event_intel_pt.c index 4216928..cdae603 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_pt.c +++ b/arch/x86/kernel/cpu/perf_event_intel_pt.c @@ -132,16 +132,12 @@ static const struct attribute_group *pt_attr_groups[] = { static int __init pt_pmu_hw_init(void) { - struct dev_ext_attribute *de_attrs; - struct attribute **attrs; - size_t size; - int ret; + static struct dev_ext_attribute de_attrs[ARRAY_SIZE(pt_caps)]; + static struct attribute *attrs[ARRAY_SIZE(pt_caps)]; long i; - attrs = NULL; - ret = -ENODEV; if (!test_cpu_cap(&boot_cpu_data, X86_FEATURE_INTEL_PT)) - goto fail; + return -ENODEV; for (i = 0; i < PT_CPUID_LEAVES; i++) { cpuid_count(20, i, @@ -151,39 +147,25 @@ static int __init pt_pmu_hw_init(void) &pt_pmu.caps[CR_EDX + i*PT_CPUID_REGS_NUM]); } - ret = -ENOMEM; - size = sizeof(struct attribute *) * (ARRAY_SIZE(pt_caps)+1); - attrs = kzalloc(size, GFP_KERNEL); - if (!attrs) - goto fail; - - size = sizeof(struct dev_ext_attribute) * (ARRAY_SIZE(pt_caps)+1); - de_attrs = kzalloc(size, GFP_KERNEL); - if (!de_attrs) - goto fail; - + pax_open_kernel(); for (i = 0; i < ARRAY_SIZE(pt_caps); i++) { - struct dev_ext_attribute *de_attr = de_attrs + i; + 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; 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; attrs[i] = &de_attr->attr.attr; } - pt_cap_group.attrs = attrs; + *(struct attribute ***)&pt_cap_group.attrs = attrs; + pax_close_kernel(); return 0; - -fail: - kfree(attrs); - - return ret; } #define RTIT_CTL_CYC_PSB (RTIT_CTL_CYCLEACC | \ @@ -999,7 +981,7 @@ static void pt_event_start(struct perf_event *event, int mode) return; } - ACCESS_ONCE(pt->handle_nmi) = 1; + ACCESS_ONCE_RW(pt->handle_nmi) = 1; event->hw.state = 0; pt_config_buffer(buf->cur->table, buf->cur_idx, @@ -1015,7 +997,7 @@ static void pt_event_stop(struct perf_event *event, int mode) * Protect against the PMI racing with disabling wrmsr, * see comment in intel_pt_interrupt(). */ - ACCESS_ONCE(pt->handle_nmi) = 0; + ACCESS_ONCE_RW(pt->handle_nmi) = 0; pt_config_start(false); if (event->hw.state == PERF_HES_STOPPED) diff --git a/arch/x86/kernel/cpu/perf_event_intel_rapl.c b/arch/x86/kernel/cpu/perf_event_intel_rapl.c index 81431c0..bc7524c 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_rapl.c +++ b/arch/x86/kernel/cpu/perf_event_intel_rapl.c @@ -502,7 +502,7 @@ static struct attribute *rapl_events_knl_attr[] = { NULL, }; -static struct attribute_group rapl_pmu_events_group = { +static attribute_group_no_const rapl_pmu_events_group __read_only = { .name = "events", .attrs = NULL, /* patched at runtime */ }; diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c index 560e525..f5d28a9 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c @@ -731,7 +731,7 @@ static void __init uncore_types_exit(struct intel_uncore_type **types) static int __init uncore_type_init(struct intel_uncore_type *type) { struct intel_uncore_pmu *pmus; - struct attribute_group *attr_group; + attribute_group_no_const *attr_group; struct attribute **attrs; int i, j; diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h index 72c54c2..c4170a4b 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h @@ -115,7 +115,7 @@ struct intel_uncore_box { struct uncore_event_desc { struct kobj_attribute attr; const char *config; -}; +} __do_const; ssize_t uncore_event_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); diff --git a/arch/x86/kernel/crash_dump_64.c b/arch/x86/kernel/crash_dump_64.c index afa64ad..dce67dd 100644 --- a/arch/x86/kernel/crash_dump_64.c +++ b/arch/x86/kernel/crash_dump_64.c @@ -36,7 +36,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, return -ENOMEM; if (userbuf) { - if (copy_to_user(buf, vaddr + offset, csize)) { + if (copy_to_user((char __force_user *)buf, vaddr + offset, csize)) { iounmap(vaddr); return -EFAULT; } diff --git a/arch/x86/kernel/doublefault.c b/arch/x86/kernel/doublefault.c index f6dfd93..892ade4 100644 --- a/arch/x86/kernel/doublefault.c +++ b/arch/x86/kernel/doublefault.c @@ -12,7 +12,7 @@ #define DOUBLEFAULT_STACKSIZE (1024) static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE]; -#define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE) +#define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE-2) #define ptr_ok(x) ((x) > PAGE_OFFSET && (x) < PAGE_OFFSET + MAXMEM) @@ -22,7 +22,7 @@ static void doublefault_fn(void) unsigned long gdt, tss; native_store_gdt(&gdt_desc); - gdt = gdt_desc.address; + gdt = (unsigned long)gdt_desc.address; printk(KERN_EMERG "PANIC: double fault, gdt at %08lx [%d bytes]\n", gdt, gdt_desc.size); @@ -59,10 +59,10 @@ struct tss_struct doublefault_tss __cacheline_aligned = { /* 0x2 bit is always set */ .flags = X86_EFLAGS_SF | 0x2, .sp = STACK_START, - .es = __USER_DS, + .es = __KERNEL_DS, .cs = __KERNEL_CS, .ss = __KERNEL_DS, - .ds = __USER_DS, + .ds = __KERNEL_DS, .fs = __KERNEL_PERCPU, .__cr3 = __pa_nodebug(swapper_pg_dir), diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 9c30acf..8cf2411 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -2,6 +2,9 @@ * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs */ +#ifdef CONFIG_GRKERNSEC_HIDESYM +#define __INCLUDED_BY_HIDESYM 1 +#endif #include #include #include @@ -35,23 +38,21 @@ static void printk_stack_address(unsigned long address, int reliable, void printk_address(unsigned long address) { - pr_cont(" [<%p>] %pS\n", (void *)address, (void *)address); + pr_cont(" [<%p>] %pA\n", (void *)address, (void *)address); } #ifdef CONFIG_FUNCTION_GRAPH_TRACER static void print_ftrace_graph_addr(unsigned long addr, void *data, const struct stacktrace_ops *ops, - struct thread_info *tinfo, int *graph) + struct task_struct *task, int *graph) { - struct task_struct *task; unsigned long ret_addr; int index; if (addr != (unsigned long)return_to_handler) return; - task = tinfo->task; index = task->curr_ret_stack; if (!task->ret_stack || index < *graph) @@ -68,7 +69,7 @@ print_ftrace_graph_addr(unsigned long addr, void *data, static inline void print_ftrace_graph_addr(unsigned long addr, void *data, const struct stacktrace_ops *ops, - struct thread_info *tinfo, int *graph) + struct task_struct *task, int *graph) { } #endif @@ -79,10 +80,8 @@ print_ftrace_graph_addr(unsigned long addr, void *data, * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack */ -static inline int valid_stack_ptr(struct thread_info *tinfo, - void *p, unsigned int size, void *end) +static inline int valid_stack_ptr(void *t, void *p, unsigned int size, void *end) { - void *t = tinfo; if (end) { if (p < end && p >= (end-THREAD_SIZE)) return 1; @@ -93,14 +92,14 @@ static inline int valid_stack_ptr(struct thread_info *tinfo, } unsigned long -print_context_stack(struct thread_info *tinfo, +print_context_stack(struct task_struct *task, void *stack_start, unsigned long *stack, unsigned long bp, const struct stacktrace_ops *ops, void *data, unsigned long *end, int *graph) { struct stack_frame *frame = (struct stack_frame *)bp; - while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) { + while (valid_stack_ptr(stack_start, stack, sizeof(*stack), end)) { unsigned long addr; addr = *stack; @@ -112,7 +111,7 @@ print_context_stack(struct thread_info *tinfo, } else { ops->address(data, addr, 0); } - print_ftrace_graph_addr(addr, data, ops, tinfo, graph); + print_ftrace_graph_addr(addr, data, ops, task, graph); } stack++; } @@ -121,7 +120,7 @@ print_context_stack(struct thread_info *tinfo, EXPORT_SYMBOL_GPL(print_context_stack); unsigned long -print_context_stack_bp(struct thread_info *tinfo, +print_context_stack_bp(struct task_struct *task, void *stack_start, unsigned long *stack, unsigned long bp, const struct stacktrace_ops *ops, void *data, unsigned long *end, int *graph) @@ -129,7 +128,7 @@ print_context_stack_bp(struct thread_info *tinfo, struct stack_frame *frame = (struct stack_frame *)bp; unsigned long *ret_addr = &frame->return_address; - while (valid_stack_ptr(tinfo, ret_addr, sizeof(*ret_addr), end)) { + while (valid_stack_ptr(stack_start, ret_addr, sizeof(*ret_addr), end)) { unsigned long addr = *ret_addr; if (!__kernel_text_address(addr)) @@ -138,7 +137,7 @@ print_context_stack_bp(struct thread_info *tinfo, ops->address(data, addr, 1); frame = frame->next_frame; ret_addr = &frame->return_address; - print_ftrace_graph_addr(addr, data, ops, tinfo, graph); + print_ftrace_graph_addr(addr, data, ops, task, graph); } return (unsigned long)frame; @@ -226,6 +225,8 @@ unsigned long oops_begin(void) EXPORT_SYMBOL_GPL(oops_begin); NOKPROBE_SYMBOL(oops_begin); +extern void gr_handle_kernel_exploit(void); + void oops_end(unsigned long flags, struct pt_regs *regs, int signr) { if (regs && kexec_should_crash(current)) @@ -247,7 +248,10 @@ void oops_end(unsigned long flags, struct pt_regs *regs, int signr) panic("Fatal exception in interrupt"); if (panic_on_oops) panic("Fatal exception"); - do_exit(signr); + + gr_handle_kernel_exploit(); + + do_group_exit(signr); } NOKPROBE_SYMBOL(oops_end); diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c index 464ffd6..01f2cda 100644 --- a/arch/x86/kernel/dumpstack_32.c +++ b/arch/x86/kernel/dumpstack_32.c @@ -61,15 +61,14 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, bp = stack_frame(task, regs); for (;;) { - struct thread_info *context; + void *stack_start = (void *)((unsigned long)stack & ~(THREAD_SIZE-1)); void *end_stack; end_stack = is_hardirq_stack(stack, cpu); if (!end_stack) end_stack = is_softirq_stack(stack, cpu); - context = task_thread_info(task); - bp = ops->walk_stack(context, stack, bp, ops, data, + bp = ops->walk_stack(task, stack_start, stack, bp, ops, data, end_stack, &graph); /* Stop if not on irq stack */ @@ -137,16 +136,17 @@ void show_regs(struct pt_regs *regs) unsigned int code_len = code_bytes; unsigned char c; u8 *ip; + unsigned long cs_base = get_desc_base(&get_cpu_gdt_table(0)[(0xffff & regs->cs) >> 3]); pr_emerg("Stack:\n"); show_stack_log_lvl(NULL, regs, ®s->sp, 0, KERN_EMERG); pr_emerg("Code:"); - ip = (u8 *)regs->ip - code_prologue; + ip = (u8 *)regs->ip - code_prologue + cs_base; if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) { /* try starting at IP */ - ip = (u8 *)regs->ip; + ip = (u8 *)regs->ip + cs_base; code_len = code_len - code_prologue + 1; } for (i = 0; i < code_len; i++, ip++) { @@ -155,7 +155,7 @@ void show_regs(struct pt_regs *regs) pr_cont(" Bad EIP value."); break; } - if (ip == (u8 *)regs->ip) + if (ip == (u8 *)regs->ip + cs_base) pr_cont(" <%02x>", c); else pr_cont(" %02x", c); @@ -168,6 +168,7 @@ int is_valid_bugaddr(unsigned long ip) { unsigned short ud2; + ip = ktla_ktva(ip); if (ip < PAGE_OFFSET) return 0; if (probe_kernel_address((unsigned short *)ip, ud2)) @@ -175,3 +176,15 @@ int is_valid_bugaddr(unsigned long ip) return ud2 == 0x0b0f; } + +#if defined(CONFIG_PAX_MEMORY_STACKLEAK) || defined(CONFIG_PAX_USERCOPY) +void __used pax_check_alloca(unsigned long size) +{ + unsigned long sp = (unsigned long)&sp, stack_left; + + /* all kernel stacks are of the same size */ + stack_left = sp & (THREAD_SIZE - 1); + BUG_ON(stack_left < 256 || size >= stack_left - 256); +} +EXPORT_SYMBOL(pax_check_alloca); +#endif diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index 5f1c626..1cba97e 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c @@ -153,12 +153,12 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, const struct stacktrace_ops *ops, void *data) { const unsigned cpu = get_cpu(); - struct thread_info *tinfo; unsigned long *irq_stack = (unsigned long *)per_cpu(irq_stack_ptr, cpu); unsigned long dummy; unsigned used = 0; int graph = 0; int done = 0; + void *stack_start; if (!task) task = current; @@ -179,7 +179,6 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, * current stack address. If the stacks consist of nested * exceptions */ - tinfo = task_thread_info(task); while (!done) { unsigned long *stack_end; enum stack_type stype; @@ -202,7 +201,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, if (ops->stack(data, id) < 0) break; - bp = ops->walk_stack(tinfo, stack, bp, ops, + bp = ops->walk_stack(task, stack_end - EXCEPTION_STKSZ, stack, bp, ops, data, stack_end, &graph); ops->stack(data, ""); /* @@ -210,6 +209,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, * second-to-last pointer (index -2 to end) in the * exception stack: */ + if ((u16)stack_end[-1] != __KERNEL_DS) + goto out; stack = (unsigned long *) stack_end[-2]; done = 0; break; @@ -218,7 +219,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, if (ops->stack(data, "IRQ") < 0) break; - bp = ops->walk_stack(tinfo, stack, bp, + bp = ops->walk_stack(task, irq_stack, stack, bp, ops, data, stack_end, &graph); /* * We link to the next stack (which would be @@ -240,7 +241,9 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, /* * This handles the process stack: */ - bp = ops->walk_stack(tinfo, stack, bp, ops, data, NULL, &graph); + stack_start = (void *)((unsigned long)stack & ~(THREAD_SIZE-1)); + bp = ops->walk_stack(task, stack_start, stack, bp, ops, data, NULL, &graph); +out: put_cpu(); } EXPORT_SYMBOL(dump_trace); @@ -347,8 +350,55 @@ int is_valid_bugaddr(unsigned long ip) { unsigned short ud2; - if (__copy_from_user(&ud2, (const void __user *) ip, sizeof(ud2))) + if (probe_kernel_address((unsigned short *)ip, ud2)) return 0; return ud2 == 0x0b0f; } + +#if defined(CONFIG_PAX_MEMORY_STACKLEAK) || defined(CONFIG_PAX_USERCOPY) +void __used pax_check_alloca(unsigned long size) +{ + unsigned long sp = (unsigned long)&sp, stack_start, stack_end; + unsigned cpu, used; + char *id; + + /* check the process stack first */ + stack_start = (unsigned long)task_stack_page(current); + stack_end = stack_start + THREAD_SIZE; + if (likely(stack_start <= sp && sp < stack_end)) { + unsigned long stack_left = sp & (THREAD_SIZE - 1); + BUG_ON(stack_left < 256 || size >= stack_left - 256); + return; + } + + cpu = get_cpu(); + + /* check the irq stacks */ + stack_end = (unsigned long)per_cpu(irq_stack_ptr, cpu); + stack_start = stack_end - IRQ_STACK_SIZE; + if (stack_start <= sp && sp < stack_end) { + unsigned long stack_left = sp & (IRQ_STACK_SIZE - 1); + put_cpu(); + BUG_ON(stack_left < 256 || size >= stack_left - 256); + return; + } + + /* check the exception stacks */ + used = 0; + stack_end = (unsigned long)in_exception_stack(cpu, sp, &used, &id); + stack_start = stack_end - EXCEPTION_STKSZ; + if (stack_end && stack_start <= sp && sp < stack_end) { + unsigned long stack_left = sp & (EXCEPTION_STKSZ - 1); + put_cpu(); + BUG_ON(stack_left < 256 || size >= stack_left - 256); + return; + } + + put_cpu(); + + /* unknown stack */ + BUG(); +} +EXPORT_SYMBOL(pax_check_alloca); +#endif diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index a102564..d1f0b73 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -803,8 +803,8 @@ unsigned long __init e820_end_of_low_ram_pfn(void) static void early_panic(char *msg) { - early_printk(msg); - panic(msg); + early_printk("%s", msg); + panic("%s", msg); } static int userdef __initdata; diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c index eec40f5..4fee808 100644 --- a/arch/x86/kernel/early_printk.c +++ b/arch/x86/kernel/early_printk.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/kernel/espfix_64.c b/arch/x86/kernel/espfix_64.c index 4d38416..ec7cc4e 100644 --- a/arch/x86/kernel/espfix_64.c +++ b/arch/x86/kernel/espfix_64.c @@ -41,6 +41,7 @@ #include #include #include +#include /* * Note: we only need 6*8 = 48 bytes for the espfix stack, but round @@ -70,8 +71,10 @@ static DEFINE_MUTEX(espfix_init_mutex); #define ESPFIX_MAX_PAGES DIV_ROUND_UP(CONFIG_NR_CPUS, ESPFIX_STACKS_PER_PAGE) static void *espfix_pages[ESPFIX_MAX_PAGES]; -static __page_aligned_bss pud_t espfix_pud_page[PTRS_PER_PUD] - __aligned(PAGE_SIZE); +static __page_aligned_rodata pud_t espfix_pud_page[PTRS_PER_PUD]; +static __page_aligned_rodata pmd_t espfix_pmd_page[PTRS_PER_PMD]; +static __page_aligned_rodata pte_t espfix_pte_page[PTRS_PER_PTE]; +static __page_aligned_rodata char espfix_stack_page[ESPFIX_MAX_PAGES][PAGE_SIZE]; static unsigned int page_random, slot_random; @@ -122,10 +125,19 @@ static void init_espfix_random(void) void __init init_espfix_bsp(void) { pgd_t *pgd_p; + pud_t *pud_p; + unsigned long index = pgd_index(ESPFIX_BASE_ADDR); /* Install the espfix pud into the kernel page directory */ - pgd_p = &init_level4_pgt[pgd_index(ESPFIX_BASE_ADDR)]; - pgd_populate(&init_mm, pgd_p, (pud_t *)espfix_pud_page); + pgd_p = &init_level4_pgt[index]; + pud_p = espfix_pud_page; + paravirt_alloc_pud(&init_mm, __pa(pud_p) >> PAGE_SHIFT); + set_pgd(pgd_p, __pgd(PGTABLE_PROT | __pa(pud_p))); + +#ifdef CONFIG_PAX_PER_CPU_PGD + clone_pgd_range(get_cpu_pgd(0, kernel) + index, swapper_pg_dir + index, 1); + clone_pgd_range(get_cpu_pgd(0, user) + index, swapper_pg_dir + index, 1); +#endif /* Randomize the locations */ init_espfix_random(); @@ -170,35 +182,39 @@ void init_espfix_ap(int cpu) pud_p = &espfix_pud_page[pud_index(addr)]; pud = *pud_p; if (!pud_present(pud)) { - struct page *page = alloc_pages_node(node, PGALLOC_GFP, 0); - - pmd_p = (pmd_t *)page_address(page); + if (cpu) + pmd_p = page_address(alloc_pages_node(node, PGALLOC_GFP, 0)); + else + pmd_p = espfix_pmd_page; pud = __pud(__pa(pmd_p) | (PGTABLE_PROT & ptemask)); paravirt_alloc_pmd(&init_mm, __pa(pmd_p) >> PAGE_SHIFT); for (n = 0; n < ESPFIX_PUD_CLONES; n++) set_pud(&pud_p[n], pud); - } + } else + BUG_ON(!cpu); pmd_p = pmd_offset(&pud, addr); pmd = *pmd_p; if (!pmd_present(pmd)) { - struct page *page = alloc_pages_node(node, PGALLOC_GFP, 0); - - pte_p = (pte_t *)page_address(page); + if (cpu) + pte_p = page_address(alloc_pages_node(node, PGALLOC_GFP, 0)); + else + pte_p = espfix_pte_page; pmd = __pmd(__pa(pte_p) | (PGTABLE_PROT & ptemask)); paravirt_alloc_pte(&init_mm, __pa(pte_p) >> PAGE_SHIFT); for (n = 0; n < ESPFIX_PMD_CLONES; n++) set_pmd(&pmd_p[n], pmd); - } + } else + BUG_ON(!cpu); pte_p = pte_offset_kernel(&pmd, addr); - stack_page = page_address(alloc_pages_node(node, GFP_KERNEL, 0)); + stack_page = espfix_stack_page[page]; pte = __pte(__pa(stack_page) | (__PAGE_KERNEL_RO & ptemask)); for (n = 0; n < ESPFIX_PTE_CLONES; n++) set_pte(&pte_p[n*PTE_STRIDE], pte); /* Job is done for this CPU and any CPU which shares this page */ - ACCESS_ONCE(espfix_pages[page]) = stack_page; + ACCESS_ONCE_RW(espfix_pages[page]) = stack_page; unlock_done: mutex_unlock(&espfix_init_mutex); diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index d25097c..e2df353 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -127,7 +127,7 @@ void __kernel_fpu_end(void) struct fpu *fpu = ¤t->thread.fpu; if (fpu->fpregs_active) - copy_kernel_to_fpregs(&fpu->state); + copy_kernel_to_fpregs(fpu->state); else __fpregs_deactivate_hw(); @@ -238,7 +238,7 @@ static void fpu_copy(struct fpu *dst_fpu, struct fpu *src_fpu) * leak into the child task: */ if (use_eager_fpu()) - memset(&dst_fpu->state.xsave, 0, xstate_size); + memset(&dst_fpu->state->xsave, 0, xstate_size); /* * Save current FPU registers directly into the child @@ -258,7 +258,7 @@ static void fpu_copy(struct fpu *dst_fpu, struct fpu *src_fpu) */ preempt_disable(); if (!copy_fpregs_to_fpstate(dst_fpu)) { - memcpy(&src_fpu->state, &dst_fpu->state, xstate_size); + memcpy(src_fpu->state, dst_fpu->state, xstate_size); fpregs_deactivate(src_fpu); } preempt_enable(); @@ -285,7 +285,7 @@ void fpu__activate_curr(struct fpu *fpu) WARN_ON_FPU(fpu != ¤t->thread.fpu); if (!fpu->fpstate_active) { - fpstate_init(&fpu->state); + fpstate_init(fpu->state); /* Safe to do for the current task: */ fpu->fpstate_active = 1; @@ -311,7 +311,7 @@ void fpu__activate_fpstate_read(struct fpu *fpu) fpu__save(fpu); } else { if (!fpu->fpstate_active) { - fpstate_init(&fpu->state); + fpstate_init(fpu->state); /* Safe to do for current and for stopped child tasks: */ fpu->fpstate_active = 1; @@ -344,7 +344,7 @@ void fpu__activate_fpstate_write(struct fpu *fpu) /* Invalidate any lazy state: */ fpu->last_cpu = -1; } else { - fpstate_init(&fpu->state); + fpstate_init(fpu->state); /* Safe to do for stopped child tasks: */ fpu->fpstate_active = 1; @@ -368,7 +368,7 @@ void fpu__restore(struct fpu *fpu) /* Avoid __kernel_fpu_begin() right after fpregs_activate() */ kernel_fpu_disable(); fpregs_activate(fpu); - copy_kernel_to_fpregs(&fpu->state); + copy_kernel_to_fpregs(fpu->state); fpu->counter++; kernel_fpu_enable(); } @@ -442,25 +442,25 @@ void fpu__clear(struct fpu *fpu) static inline unsigned short get_fpu_cwd(struct fpu *fpu) { if (cpu_has_fxsr) { - return fpu->state.fxsave.cwd; + return fpu->state->fxsave.cwd; } else { - return (unsigned short)fpu->state.fsave.cwd; + return (unsigned short)fpu->state->fsave.cwd; } } static inline unsigned short get_fpu_swd(struct fpu *fpu) { if (cpu_has_fxsr) { - return fpu->state.fxsave.swd; + return fpu->state->fxsave.swd; } else { - return (unsigned short)fpu->state.fsave.swd; + return (unsigned short)fpu->state->fsave.swd; } } static inline unsigned short get_fpu_mxcsr(struct fpu *fpu) { if (cpu_has_xmm) { - return fpu->state.fxsave.mxcsr; + return fpu->state->fxsave.mxcsr; } else { return MXCSR_DEFAULT; } diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index d14e9ac..13442f0 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c @@ -42,7 +42,7 @@ static void fpu__init_cpu_generic(void) /* Flush out any pending x87 state: */ #ifdef CONFIG_MATH_EMULATION if (!cpu_has_fpu) - fpstate_init_soft(¤t->thread.fpu.state.soft); + fpstate_init_soft(¤t->thread.fpu.state->soft); else #endif asm volatile ("fninit"); @@ -143,42 +143,7 @@ static void __init fpu__init_system_generic(void) unsigned int xstate_size; EXPORT_SYMBOL_GPL(xstate_size); -/* Enforce that 'MEMBER' is the last field of 'TYPE': */ -#define CHECK_MEMBER_AT_END_OF(TYPE, MEMBER) \ - BUILD_BUG_ON(sizeof(TYPE) != offsetofend(TYPE, MEMBER)) - -/* - * We append the 'struct fpu' to the task_struct: - */ -static void __init fpu__init_task_struct_size(void) -{ - int task_size = sizeof(struct task_struct); - - /* - * Subtract off the static size of the register state. - * It potentially has a bunch of padding. - */ - task_size -= sizeof(((struct task_struct *)0)->thread.fpu.state); - - /* - * Add back the dynamically-calculated register state - * size. - */ - task_size += xstate_size; - - /* - * We dynamically size 'struct fpu', so we require that - * it be at the end of 'thread_struct' and that - * 'thread_struct' be at the end of 'task_struct'. If - * you hit a compile error here, check the structure to - * see if something got added to the end. - */ - CHECK_MEMBER_AT_END_OF(struct fpu, state); - CHECK_MEMBER_AT_END_OF(struct thread_struct, fpu); - CHECK_MEMBER_AT_END_OF(struct task_struct, thread); - - arch_task_struct_size = task_size; -} +union fpregs_state init_fpregs_state; /* * Set up the xstate_size based on the legacy FPU context size. @@ -331,7 +296,6 @@ void __init fpu__init_system(struct cpuinfo_x86 *c) fpu__init_system_generic(); fpu__init_system_xstate_size_legacy(); fpu__init_system_xstate(); - fpu__init_task_struct_size(); fpu__init_system_ctx_switch(); } diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c index dc60810..6c8a1fa 100644 --- a/arch/x86/kernel/fpu/regset.c +++ b/arch/x86/kernel/fpu/regset.c @@ -37,7 +37,7 @@ int xfpregs_get(struct task_struct *target, const struct user_regset *regset, fpstate_sanitize_xstate(fpu); return user_regset_copyout(&pos, &count, &kbuf, &ubuf, - &fpu->state.fxsave, 0, -1); + &fpu->state->fxsave, 0, -1); } int xfpregs_set(struct task_struct *target, const struct user_regset *regset, @@ -54,19 +54,19 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset, fpstate_sanitize_xstate(fpu); ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &fpu->state.fxsave, 0, -1); + &fpu->state->fxsave, 0, -1); /* * mxcsr reserved bits must be masked to zero for security reasons. */ - fpu->state.fxsave.mxcsr &= mxcsr_feature_mask; + fpu->state->fxsave.mxcsr &= mxcsr_feature_mask; /* * update the header bits in the xsave header, indicating the * presence of FP and SSE state. */ if (cpu_has_xsave) - fpu->state.xsave.header.xfeatures |= XSTATE_FPSSE; + fpu->state->xsave.header.xfeatures |= XSTATE_FPSSE; return ret; } @@ -84,7 +84,7 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset, fpu__activate_fpstate_read(fpu); - xsave = &fpu->state.xsave; + xsave = &fpu->state->xsave; /* * Copy the 48bytes defined by the software first into the xstate @@ -113,7 +113,7 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset, fpu__activate_fpstate_write(fpu); - xsave = &fpu->state.xsave; + xsave = &fpu->state->xsave; ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, xsave, 0, -1); /* @@ -204,7 +204,7 @@ static inline u32 twd_fxsr_to_i387(struct fxregs_state *fxsave) void convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk) { - struct fxregs_state *fxsave = &tsk->thread.fpu.state.fxsave; + struct fxregs_state *fxsave = &tsk->thread.fpu.state->fxsave; struct _fpreg *to = (struct _fpreg *) &env->st_space[0]; struct _fpxreg *from = (struct _fpxreg *) &fxsave->st_space[0]; int i; @@ -242,7 +242,7 @@ void convert_to_fxsr(struct task_struct *tsk, const struct user_i387_ia32_struct *env) { - struct fxregs_state *fxsave = &tsk->thread.fpu.state.fxsave; + struct fxregs_state *fxsave = &tsk->thread.fpu.state->fxsave; struct _fpreg *from = (struct _fpreg *) &env->st_space[0]; struct _fpxreg *to = (struct _fpxreg *) &fxsave->st_space[0]; int i; @@ -280,7 +280,7 @@ int fpregs_get(struct task_struct *target, const struct user_regset *regset, if (!cpu_has_fxsr) return user_regset_copyout(&pos, &count, &kbuf, &ubuf, - &fpu->state.fsave, 0, + &fpu->state->fsave, 0, -1); fpstate_sanitize_xstate(fpu); @@ -311,7 +311,7 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset, if (!cpu_has_fxsr) return user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &fpu->state.fsave, 0, + &fpu->state->fsave, 0, -1); if (pos > 0 || count < sizeof(env)) @@ -326,7 +326,7 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset, * presence of FP. */ if (cpu_has_xsave) - fpu->state.xsave.header.xfeatures |= XSTATE_FP; + fpu->state->xsave.header.xfeatures |= XSTATE_FP; return ret; } diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 6545e6d..32d7f10 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -54,7 +54,7 @@ static inline int check_for_xstate(struct fxregs_state __user *buf, static inline int save_fsave_header(struct task_struct *tsk, void __user *buf) { if (use_fxsr()) { - struct xregs_state *xsave = &tsk->thread.fpu.state.xsave; + struct xregs_state *xsave = &tsk->thread.fpu.state->xsave; struct user_i387_ia32_struct env; struct _fpstate_ia32 __user *fp = buf; @@ -83,18 +83,18 @@ static inline int save_xstate_epilog(void __user *buf, int ia32_frame) /* Setup the bytes not touched by the [f]xsave and reserved for SW. */ sw_bytes = ia32_frame ? &fx_sw_reserved_ia32 : &fx_sw_reserved; - err = __copy_to_user(&x->i387.sw_reserved, sw_bytes, sizeof(*sw_bytes)); + err = __copy_to_user(x->i387.sw_reserved, sw_bytes, sizeof(*sw_bytes)); if (!use_xsave()) return err; - err |= __put_user(FP_XSTATE_MAGIC2, (__u32 *)(buf + xstate_size)); + err |= __put_user(FP_XSTATE_MAGIC2, (__u32 __user *)(buf + xstate_size)); /* * Read the xfeatures which we copied (directly from the cpu or * from the state in task struct) to the user buffers. */ - err |= __get_user(xfeatures, (__u32 *)&x->header.xfeatures); + err |= __get_user(xfeatures, (__u32 __user *)&x->header.xfeatures); /* * For legacy compatible, we always set FP/SSE bits in the bit @@ -109,7 +109,7 @@ static inline int save_xstate_epilog(void __user *buf, int ia32_frame) */ xfeatures |= XSTATE_FPSSE; - err |= __put_user(xfeatures, (__u32 *)&x->header.xfeatures); + err |= __put_user(xfeatures, (__u32 __user *)&x->header.xfeatures); return err; } @@ -118,6 +118,7 @@ static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf) { int err; + buf = (struct xregs_state __user *)____m(buf); if (use_xsave()) err = copy_xregs_to_user(buf); else if (use_fxsr()) @@ -152,7 +153,7 @@ static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf) */ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size) { - struct xregs_state *xsave = ¤t->thread.fpu.state.xsave; + struct xregs_state *xsave = ¤t->thread.fpu.state->xsave; struct task_struct *tsk = current; int ia32_fxstate = (buf != buf_fx); @@ -195,7 +196,7 @@ sanitize_restored_xstate(struct task_struct *tsk, struct user_i387_ia32_struct *ia32_env, u64 xfeatures, int fx_only) { - struct xregs_state *xsave = &tsk->thread.fpu.state.xsave; + struct xregs_state *xsave = &tsk->thread.fpu.state->xsave; struct xstate_header *header = &xsave->header; if (use_xsave()) { @@ -228,6 +229,7 @@ sanitize_restored_xstate(struct task_struct *tsk, */ static inline int copy_user_to_fpregs_zeroing(void __user *buf, u64 xbv, int fx_only) { + buf = (void __user *)____m(buf); if (use_xsave()) { if ((unsigned long)buf % 64 || fx_only) { u64 init_bv = xfeatures_mask & ~XSTATE_FPSSE; @@ -308,9 +310,9 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) */ fpu__drop(fpu); - if (__copy_from_user(&fpu->state.xsave, buf_fx, state_size) || + if (__copy_from_user(&fpu->state->xsave, buf_fx, state_size) || __copy_from_user(&env, buf, sizeof(env))) { - fpstate_init(&fpu->state); + fpstate_init(fpu->state); err = -1; } else { sanitize_restored_xstate(tsk, &env, xfeatures, fx_only); diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 2c4ac07..099cbd7 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -93,14 +93,14 @@ EXPORT_SYMBOL_GPL(cpu_has_xfeatures); */ void fpstate_sanitize_xstate(struct fpu *fpu) { - struct fxregs_state *fx = &fpu->state.fxsave; + struct fxregs_state *fx = &fpu->state->fxsave; int feature_bit; u64 xfeatures; if (!use_xsaveopt()) return; - xfeatures = fpu->state.xsave.header.xfeatures; + xfeatures = fpu->state->xsave.header.xfeatures; /* * None of the feature bits are in init state. So nothing else @@ -456,5 +456,5 @@ const void *get_xsave_field_ptr(int xsave_state) */ fpu__save(fpu); - return get_xsave_addr(&fpu->state.xsave, xsave_state); + return get_xsave_addr(&fpu->state->xsave, xsave_state); } diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 8b7b0a5..02219db 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -89,7 +89,7 @@ static unsigned long text_ip_addr(unsigned long ip) * kernel identity mapping to modify code. */ if (within(ip, (unsigned long)_text, (unsigned long)_etext)) - ip = (unsigned long)__va(__pa_symbol(ip)); + ip = (unsigned long)__va(__pa_symbol(ktla_ktva(ip))); return ip; } @@ -105,6 +105,8 @@ ftrace_modify_code_direct(unsigned long ip, unsigned const char *old_code, { unsigned char replaced[MCOUNT_INSN_SIZE]; + ip = ktla_ktva(ip); + /* * Note: Due to modules and __init, code can * disappear and change, we need to protect against faulting @@ -230,7 +232,7 @@ static int update_ftrace_func(unsigned long ip, void *new) unsigned char old[MCOUNT_INSN_SIZE]; int ret; - memcpy(old, (void *)ip, MCOUNT_INSN_SIZE); + memcpy(old, (void *)ktla_ktva(ip), MCOUNT_INSN_SIZE); ftrace_update_func = ip; /* Make sure the breakpoints see the ftrace_update_func update */ @@ -311,7 +313,7 @@ static int add_break(unsigned long ip, const char *old) unsigned char replaced[MCOUNT_INSN_SIZE]; unsigned char brk = BREAKPOINT_INSTRUCTION; - if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE)) + if (probe_kernel_read(replaced, (void *)ktla_ktva(ip), MCOUNT_INSN_SIZE)) return -EFAULT; /* Make sure it is what we expect it to be */ @@ -670,11 +672,11 @@ static unsigned char *ftrace_jmp_replace(unsigned long ip, unsigned long addr) /* Module allocation simplifies allocating memory for code */ static inline void *alloc_tramp(unsigned long size) { - return module_alloc(size); + return module_alloc_exec(size); } static inline void tramp_free(void *tramp) { - module_memfree(tramp); + module_memfree_exec(tramp); } #else /* Trampolines can only be created if modules are supported */ @@ -753,7 +755,9 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size) *tramp_size = size + MCOUNT_INSN_SIZE + sizeof(void *); /* Copy ftrace_caller onto the trampoline memory */ + pax_open_kernel(); ret = probe_kernel_read(trampoline, (void *)start_offset, size); + pax_close_kernel(); if (WARN_ON(ret < 0)) { tramp_free(trampoline); return 0; @@ -763,6 +767,7 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size) /* The trampoline ends with a jmp to ftrace_return */ jmp = ftrace_jmp_replace(ip, (unsigned long)ftrace_return); + pax_open_kernel(); memcpy(trampoline + size, jmp, MCOUNT_INSN_SIZE); /* @@ -775,6 +780,7 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size) ptr = (unsigned long *)(trampoline + size + MCOUNT_INSN_SIZE); *ptr = (unsigned long)ops; + pax_close_kernel(); op_offset -= start_offset; memcpy(&op_ptr, trampoline + op_offset, OP_REF_SIZE); @@ -792,7 +798,9 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size) op_ptr.offset = offset; /* put in the new offset to the ftrace_ops */ + pax_open_kernel(); memcpy(trampoline + op_offset, &op_ptr, OP_REF_SIZE); + pax_close_kernel(); /* ALLOC_TRAMP flags lets us know we created it */ ops->flags |= FTRACE_OPS_FL_ALLOC_TRAMP; diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index f129a9a..af8f6da 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -68,12 +68,12 @@ again: pgd = *pgd_p; /* - * The use of __START_KERNEL_map rather than __PAGE_OFFSET here is - * critical -- __PAGE_OFFSET would point us back into the dynamic + * The use of __early_va rather than __va here is critical: + * __va would point us back into the dynamic * range and we might end up looping forever... */ if (pgd) - pud_p = (pudval_t *)((pgd & PTE_PFN_MASK) + __START_KERNEL_map - phys_base); + pud_p = (pudval_t *)(__early_va(pgd & PTE_PFN_MASK)); else { if (next_early_pgt >= EARLY_DYNAMIC_PAGE_TABLES) { reset_early_page_tables(); @@ -83,13 +83,13 @@ again: pud_p = (pudval_t *)early_dynamic_pgts[next_early_pgt++]; for (i = 0; i < PTRS_PER_PUD; i++) pud_p[i] = 0; - *pgd_p = (pgdval_t)pud_p - __START_KERNEL_map + phys_base + _KERNPG_TABLE; + *pgd_p = (pgdval_t)__pa(pud_p) + _KERNPG_TABLE; } pud_p += pud_index(address); pud = *pud_p; if (pud) - pmd_p = (pmdval_t *)((pud & PTE_PFN_MASK) + __START_KERNEL_map - phys_base); + pmd_p = (pmdval_t *)(__early_va(pud & PTE_PFN_MASK)); else { if (next_early_pgt >= EARLY_DYNAMIC_PAGE_TABLES) { reset_early_page_tables(); @@ -99,7 +99,7 @@ again: pmd_p = (pmdval_t *)early_dynamic_pgts[next_early_pgt++]; for (i = 0; i < PTRS_PER_PMD; i++) pmd_p[i] = 0; - *pud_p = (pudval_t)pmd_p - __START_KERNEL_map + phys_base + _KERNPG_TABLE; + *pud_p = (pudval_t)__pa(pmd_p) + _KERNPG_TABLE; } pmd = (physaddr & PMD_MASK) + early_pmd_flags; pmd_p[pmd_index(address)] = pmd; @@ -163,8 +163,6 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data) clear_bss(); - clear_page(init_level4_pgt); - kasan_early_init(); for (i = 0; i < NUM_EXCEPTION_VECTORS; i++) diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index 0e2d96f..5889003 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S @@ -27,6 +27,12 @@ /* Physical address */ #define pa(X) ((X) - __PAGE_OFFSET) +#ifdef CONFIG_PAX_KERNEXEC +#define ta(X) (X) +#else +#define ta(X) ((X) - __PAGE_OFFSET) +#endif + /* * References to members of the new_cpu_data structure. */ @@ -56,11 +62,7 @@ * and small than max_low_pfn, otherwise will waste some page table entries */ -#if PTRS_PER_PMD > 1 -#define PAGE_TABLE_SIZE(pages) (((pages) / PTRS_PER_PMD) + PTRS_PER_PGD) -#else -#define PAGE_TABLE_SIZE(pages) ((pages) / PTRS_PER_PGD) -#endif +#define PAGE_TABLE_SIZE(pages) ((pages) / PTRS_PER_PTE) /* * Number of possible pages in the lowmem region. @@ -86,6 +88,12 @@ INIT_MAP_SIZE = PAGE_TABLE_SIZE(KERNEL_PAGES) * PAGE_SIZE RESERVE_BRK(pagetables, INIT_MAP_SIZE) /* + * Real beginning of normal "text" segment + */ +ENTRY(stext) +ENTRY(_stext) + +/* * 32-bit kernel entrypoint; only used by the boot CPU. On entry, * %esi points to the real-mode code as a 32-bit pointer. * CS and DS must be 4 GB flat segments, but we don't depend on @@ -93,6 +101,13 @@ RESERVE_BRK(pagetables, INIT_MAP_SIZE) * can. */ __HEAD + +#ifdef CONFIG_PAX_KERNEXEC + jmp startup_32 +/* PaX: fill first page in .text with int3 to catch NULL derefs in kernel mode */ +.fill PAGE_SIZE-5,1,0xcc +#endif + ENTRY(startup_32) movl pa(stack_start),%ecx @@ -114,6 +129,66 @@ ENTRY(startup_32) 2: leal -__PAGE_OFFSET(%ecx),%esp +#ifdef CONFIG_SMP + movl $pa(cpu_gdt_table),%edi + movl $__per_cpu_load,%eax + movw %ax,GDT_ENTRY_PERCPU * 8 + 2(%edi) + rorl $16,%eax + movb %al,GDT_ENTRY_PERCPU * 8 + 4(%edi) + movb %ah,GDT_ENTRY_PERCPU * 8 + 7(%edi) + movl $__per_cpu_end - 1,%eax + subl $__per_cpu_start,%eax + cmpl $0x100000,%eax + jb 1f + shrl $PAGE_SHIFT,%eax + orb $0x80,GDT_ENTRY_PERCPU * 8 + 6(%edi) +1: + movw %ax,GDT_ENTRY_PERCPU * 8 + 0(%edi) + shrl $16,%eax + orb %al,GDT_ENTRY_PERCPU * 8 + 6(%edi) +#endif + +#ifdef CONFIG_PAX_MEMORY_UDEREF + movl $NR_CPUS,%ecx + movl $pa(cpu_gdt_table),%edi +1: + movl $((((__PAGE_OFFSET-1) & 0xf0000000) >> 12) | 0x00c09700),GDT_ENTRY_KERNEL_DS * 8 + 4(%edi) + movl $((((__PAGE_OFFSET-1) & 0xf0000000) >> 12) | 0x00c0fb00),GDT_ENTRY_DEFAULT_USER_CS * 8 + 4(%edi) + movl $((((__PAGE_OFFSET-1) & 0xf0000000) >> 12) | 0x00c0f300),GDT_ENTRY_DEFAULT_USER_DS * 8 + 4(%edi) + addl $PAGE_SIZE_asm,%edi + loop 1b +#endif + +#ifdef CONFIG_PAX_KERNEXEC + movl $pa(boot_gdt),%edi + movl $__LOAD_PHYSICAL_ADDR,%eax + movw %ax,GDT_ENTRY_BOOT_CS * 8 + 2(%edi) + rorl $16,%eax + movb %al,GDT_ENTRY_BOOT_CS * 8 + 4(%edi) + movb %ah,GDT_ENTRY_BOOT_CS * 8 + 7(%edi) + rorl $16,%eax + + ljmp $(__BOOT_CS),$1f +1: + + movl $NR_CPUS,%ecx + movl $pa(cpu_gdt_table),%edi + addl $__PAGE_OFFSET,%eax +1: + movb $0xc0,GDT_ENTRY_KERNEL_CS * 8 + 6(%edi) + movb $0xc0,GDT_ENTRY_KERNEXEC_KERNEL_CS * 8 + 6(%edi) + movw %ax,GDT_ENTRY_KERNEL_CS * 8 + 2(%edi) + movw %ax,GDT_ENTRY_KERNEXEC_KERNEL_CS * 8 + 2(%edi) + rorl $16,%eax + movb %al,GDT_ENTRY_KERNEL_CS * 8 + 4(%edi) + movb %al,GDT_ENTRY_KERNEXEC_KERNEL_CS * 8 + 4(%edi) + movb %ah,GDT_ENTRY_KERNEL_CS * 8 + 7(%edi) + movb %ah,GDT_ENTRY_KERNEXEC_KERNEL_CS * 8 + 7(%edi) + rorl $16,%eax + addl $PAGE_SIZE_asm,%edi + loop 1b +#endif + /* * Clear BSS first so that there are no surprises... */ @@ -209,8 +284,11 @@ ENTRY(startup_32) movl %eax, pa(max_pfn_mapped) /* Do early initialization of the fixmap area */ - movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax - movl %eax,pa(initial_pg_pmd+0x1000*KPMDS-8) +#ifdef CONFIG_COMPAT_VDSO + movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR+_PAGE_USER,pa(initial_pg_pmd+0x1000*KPMDS-8) +#else + movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,pa(initial_pg_pmd+0x1000*KPMDS-8) +#endif #else /* Not PAE */ page_pde_offset = (__PAGE_OFFSET >> 20); @@ -240,8 +318,11 @@ page_pde_offset = (__PAGE_OFFSET >> 20); movl %eax, pa(max_pfn_mapped) /* Do early initialization of the fixmap area */ - movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax - movl %eax,pa(initial_page_table+0xffc) +#ifdef CONFIG_COMPAT_VDSO + movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR+_PAGE_USER,pa(initial_page_table+0xffc) +#else + movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,pa(initial_page_table+0xffc) +#endif #endif #ifdef CONFIG_PARAVIRT @@ -255,9 +336,7 @@ page_pde_offset = (__PAGE_OFFSET >> 20); cmpl $num_subarch_entries, %eax jae bad_subarch - movl pa(subarch_entries)(,%eax,4), %eax - subl $__PAGE_OFFSET, %eax - jmp *%eax + jmp *pa(subarch_entries)(,%eax,4) bad_subarch: WEAK(lguest_entry) @@ -269,10 +348,10 @@ WEAK(xen_entry) __INITDATA subarch_entries: - .long default_entry /* normal x86/PC */ - .long lguest_entry /* lguest hypervisor */ - .long xen_entry /* Xen hypervisor */ - .long default_entry /* Moorestown MID */ + .long ta(default_entry) /* normal x86/PC */ + .long ta(lguest_entry) /* lguest hypervisor */ + .long ta(xen_entry) /* Xen hypervisor */ + .long ta(default_entry) /* Moorestown MID */ num_subarch_entries = (. - subarch_entries) / 4 .previous #else @@ -362,6 +441,7 @@ default_entry: movl pa(mmu_cr4_features),%eax movl %eax,%cr4 +#ifdef CONFIG_X86_PAE testb $X86_CR4_PAE, %al # check if PAE is enabled jz enable_paging @@ -390,6 +470,9 @@ default_entry: /* Make changes effective */ wrmsr + btsl $_PAGE_BIT_NX-32,pa(__supported_pte_mask+4) +#endif + enable_paging: /* @@ -457,14 +540,20 @@ is486: 1: movl $(__KERNEL_DS),%eax # reload all the segment registers movl %eax,%ss # after changing gdt. - movl $(__USER_DS),%eax # DS/ES contains default USER segment +# movl $(__KERNEL_DS),%eax # DS/ES contains default KERNEL segment movl %eax,%ds movl %eax,%es movl $(__KERNEL_PERCPU), %eax movl %eax,%fs # set this cpu's percpu +#ifdef CONFIG_CC_STACKPROTECTOR movl $(__KERNEL_STACK_CANARY),%eax +#elif defined(CONFIG_PAX_MEMORY_UDEREF) + movl $(__USER_DS),%eax +#else + xorl %eax,%eax +#endif movl %eax,%gs xorl %eax,%eax # Clear LDT @@ -521,8 +610,11 @@ setup_once: * relocation. Manually set base address in stack canary * segment descriptor. */ - movl $gdt_page,%eax + movl $cpu_gdt_table,%eax movl $stack_canary,%ecx +#ifdef CONFIG_SMP + addl $__per_cpu_load,%ecx +#endif movw %cx, 8 * GDT_ENTRY_STACK_CANARY + 2(%eax) shrl $16, %ecx movb %cl, 8 * GDT_ENTRY_STACK_CANARY + 4(%eax) @@ -559,7 +651,7 @@ early_idt_handler_common: cmpl $2,(%esp) # X86_TRAP_NMI je .Lis_nmi # Ignore NMI - cmpl $2,%ss:early_recursion_flag + cmpl $1,%ss:early_recursion_flag je hlt_loop incl %ss:early_recursion_flag @@ -597,8 +689,8 @@ early_idt_handler_common: pushl (20+6*4)(%esp) /* trapno */ pushl $fault_msg call printk -#endif call dump_stack +#endif hlt_loop: hlt jmp hlt_loop @@ -618,8 +710,11 @@ ENDPROC(early_idt_handler_common) /* This is the default interrupt "handler" :-) */ ALIGN ignore_int: - cld #ifdef CONFIG_PRINTK + cmpl $2,%ss:early_recursion_flag + je hlt_loop + incl %ss:early_recursion_flag + cld pushl %eax pushl %ecx pushl %edx @@ -628,9 +723,6 @@ ignore_int: movl $(__KERNEL_DS),%eax movl %eax,%ds movl %eax,%es - cmpl $2,early_recursion_flag - je hlt_loop - incl early_recursion_flag pushl 16(%esp) pushl 24(%esp) pushl 32(%esp) @@ -664,29 +756,34 @@ ENTRY(setup_once_ref) /* * BSS section */ -__PAGE_ALIGNED_BSS - .align PAGE_SIZE #ifdef CONFIG_X86_PAE +.section .initial_pg_pmd,"a",@progbits initial_pg_pmd: .fill 1024*KPMDS,4,0 #else +.section .initial_page_table,"a",@progbits ENTRY(initial_page_table) .fill 1024,4,0 #endif +.section .initial_pg_fixmap,"a",@progbits initial_pg_fixmap: .fill 1024,4,0 +.section .empty_zero_page,"a",@progbits ENTRY(empty_zero_page) .fill 4096,1,0 +.section .swapper_pg_dir,"a",@progbits ENTRY(swapper_pg_dir) +#ifdef CONFIG_X86_PAE + .fill 4,8,0 +#else .fill 1024,4,0 +#endif /* * This starts the data section. */ #ifdef CONFIG_X86_PAE -__PAGE_ALIGNED_DATA - /* Page-aligned for the benefit of paravirt? */ - .align PAGE_SIZE +.section .initial_page_table,"a",@progbits ENTRY(initial_page_table) .long pa(initial_pg_pmd+PGD_IDENT_ATTR),0 /* low identity map */ # if KPMDS == 3 @@ -705,12 +802,20 @@ ENTRY(initial_page_table) # error "Kernel PMDs should be 1, 2 or 3" # endif .align PAGE_SIZE /* needs to be page-sized too */ + +#ifdef CONFIG_PAX_PER_CPU_PGD +ENTRY(cpu_pgd) + .rept 2*NR_CPUS + .fill 4,8,0 + .endr +#endif + #endif .data .balign 4 ENTRY(stack_start) - .long init_thread_union+THREAD_SIZE + .long init_thread_union+THREAD_SIZE-8 __INITRODATA int_msg: @@ -738,7 +843,7 @@ fault_msg: * segment size, and 32-bit linear address value: */ - .data +.section .rodata,"a",@progbits .globl boot_gdt_descr .globl idt_descr @@ -747,7 +852,7 @@ fault_msg: .word 0 # 32 bit align gdt_desc.address boot_gdt_descr: .word __BOOT_DS+7 - .long boot_gdt - __PAGE_OFFSET + .long pa(boot_gdt) .word 0 # 32-bit align idt_desc.address idt_descr: @@ -758,7 +863,7 @@ idt_descr: .word 0 # 32 bit align gdt_desc.address ENTRY(early_gdt_descr) .word GDT_ENTRIES*8-1 - .long gdt_page /* Overwritten for secondary CPUs */ + .long cpu_gdt_table /* Overwritten for secondary CPUs */ /* * The boot_gdt must mirror the equivalent in setup.S and is @@ -767,5 +872,65 @@ ENTRY(early_gdt_descr) .align L1_CACHE_BYTES ENTRY(boot_gdt) .fill GDT_ENTRY_BOOT_CS,8,0 - .quad 0x00cf9a000000ffff /* kernel 4GB code at 0x00000000 */ - .quad 0x00cf92000000ffff /* kernel 4GB data at 0x00000000 */ + .quad 0x00cf9b000000ffff /* kernel 4GB code at 0x00000000 */ + .quad 0x00cf93000000ffff /* kernel 4GB data at 0x00000000 */ + + .align PAGE_SIZE_asm +ENTRY(cpu_gdt_table) + .rept NR_CPUS + .quad 0x0000000000000000 /* NULL descriptor */ + .quad 0x0000000000000000 /* 0x0b reserved */ + .quad 0x0000000000000000 /* 0x13 reserved */ + .quad 0x0000000000000000 /* 0x1b reserved */ + +#ifdef CONFIG_PAX_KERNEXEC + .quad 0x00cf9b000000ffff /* 0x20 alternate kernel 4GB code at 0x00000000 */ +#else + .quad 0x0000000000000000 /* 0x20 unused */ +#endif + + .quad 0x0000000000000000 /* 0x28 unused */ + .quad 0x0000000000000000 /* 0x33 TLS entry 1 */ + .quad 0x0000000000000000 /* 0x3b TLS entry 2 */ + .quad 0x0000000000000000 /* 0x43 TLS entry 3 */ + .quad 0x0000000000000000 /* 0x4b reserved */ + .quad 0x0000000000000000 /* 0x53 reserved */ + .quad 0x0000000000000000 /* 0x5b reserved */ + + .quad 0x00cf9b000000ffff /* 0x60 kernel 4GB code at 0x00000000 */ + .quad 0x00cf93000000ffff /* 0x68 kernel 4GB data at 0x00000000 */ + .quad 0x00cffb000000ffff /* 0x73 user 4GB code at 0x00000000 */ + .quad 0x00cff3000000ffff /* 0x7b user 4GB data at 0x00000000 */ + + .quad 0x0000000000000000 /* 0x80 TSS descriptor */ + .quad 0x0000000000000000 /* 0x88 LDT descriptor */ + + /* + * Segments used for calling PnP BIOS have byte granularity. + * The code segments and data segments have fixed 64k limits, + * the transfer segment sizes are set at run time. + */ + .quad 0x00409b000000ffff /* 0x90 32-bit code */ + .quad 0x00009b000000ffff /* 0x98 16-bit code */ + .quad 0x000093000000ffff /* 0xa0 16-bit data */ + .quad 0x0000930000000000 /* 0xa8 16-bit data */ + .quad 0x0000930000000000 /* 0xb0 16-bit data */ + + /* + * The APM segments have byte granularity and their bases + * are set at run time. All have 64k limits. + */ + .quad 0x00409b000000ffff /* 0xb8 APM CS code */ + .quad 0x00009b000000ffff /* 0xc0 APM CS 16 code (16 bit) */ + .quad 0x004093000000ffff /* 0xc8 APM DS data */ + + .quad 0x00c093000000ffff /* 0xd0 - ESPFIX SS */ + .quad 0x0040930000000000 /* 0xd8 - PERCPU */ + .quad 0x0040910000000017 /* 0xe0 - STACK_CANARY */ + .quad 0x0000000000000000 /* 0xe8 - PCIBIOS_CS */ + .quad 0x0000000000000000 /* 0xf0 - PCIBIOS_DS */ + .quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */ + + /* Be sure this is zeroed to avoid false validations in Xen */ + .fill PAGE_SIZE_asm - GDT_SIZE,1,0 + .endr diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index ffdc0e8..f429d4f 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -20,6 +20,8 @@ #include #include #include +#include +#include #ifdef CONFIG_PARAVIRT #include @@ -41,6 +43,12 @@ L4_PAGE_OFFSET = pgd_index(__PAGE_OFFSET) L3_PAGE_OFFSET = pud_index(__PAGE_OFFSET) L4_START_KERNEL = pgd_index(__START_KERNEL_map) L3_START_KERNEL = pud_index(__START_KERNEL_map) +L4_VMALLOC_START = pgd_index(VMALLOC_START) +L3_VMALLOC_START = pud_index(VMALLOC_START) +L4_VMALLOC_END = pgd_index(VMALLOC_END) +L3_VMALLOC_END = pud_index(VMALLOC_END) +L4_VMEMMAP_START = pgd_index(VMEMMAP_START) +L3_VMEMMAP_START = pud_index(VMEMMAP_START) .text __HEAD @@ -92,11 +100,33 @@ startup_64: * Fixup the physical addresses in the page table */ addq %rbp, early_level4_pgt + (L4_START_KERNEL*8)(%rip) + addq %rbp, init_level4_pgt + (L4_PAGE_OFFSET*8)(%rip) + addq %rbp, init_level4_pgt + (L4_VMALLOC_START*8)(%rip) + addq %rbp, init_level4_pgt + (L4_VMALLOC_END*8)(%rip) + addq %rbp, init_level4_pgt + (L4_VMEMMAP_START*8)(%rip) + addq %rbp, init_level4_pgt + (L4_START_KERNEL*8)(%rip) - addq %rbp, level3_kernel_pgt + (510*8)(%rip) - addq %rbp, level3_kernel_pgt + (511*8)(%rip) + addq %rbp, level3_ident_pgt + (0*8)(%rip) +#ifndef CONFIG_XEN + addq %rbp, level3_ident_pgt + (1*8)(%rip) +#endif + addq %rbp, level3_vmemmap_pgt + (L3_VMEMMAP_START*8)(%rip) + + addq %rbp, level3_kernel_pgt + (L3_START_KERNEL*8)(%rip) + addq %rbp, level3_kernel_pgt + ((L3_START_KERNEL+1)*8)(%rip) + + addq %rbp, level2_ident_pgt + (0*8)(%rip) + + addq %rbp, level2_fixmap_pgt + (0*8)(%rip) + addq %rbp, level2_fixmap_pgt + (1*8)(%rip) + addq %rbp, level2_fixmap_pgt + (2*8)(%rip) + addq %rbp, level2_fixmap_pgt + (3*8)(%rip) + + addq %rbp, level2_fixmap_pgt + (504*8)(%rip) + addq %rbp, level2_fixmap_pgt + (505*8)(%rip) addq %rbp, level2_fixmap_pgt + (506*8)(%rip) + addq %rbp, level2_fixmap_pgt + (507*8)(%rip) /* * Set up the identity mapping for the switchover. These @@ -180,11 +210,12 @@ ENTRY(secondary_startup_64) /* Sanitize CPU configuration */ call verify_cpu + orq $-1, %rbp movq $(init_level4_pgt - __START_KERNEL_map), %rax 1: - /* Enable PAE mode and PGE */ - movl $(X86_CR4_PAE | X86_CR4_PGE), %ecx + /* Enable PAE mode and PSE/PGE */ + movl $(X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE), %ecx movq %rcx, %cr4 /* Setup early boot stage 4 level pagetables. */ @@ -205,10 +236,21 @@ ENTRY(secondary_startup_64) movl $MSR_EFER, %ecx rdmsr btsl $_EFER_SCE, %eax /* Enable System Call */ - btl $20,%edi /* No Execute supported? */ + btl $(X86_FEATURE_NX & 31),%edi /* No Execute supported? */ jnc 1f btsl $_EFER_NX, %eax + cmpq $-1, %rbp + je 1f btsq $_PAGE_BIT_NX,early_pmd_flags(%rip) + btsq $_PAGE_BIT_NX, init_level4_pgt + 8*L4_PAGE_OFFSET(%rip) + btsq $_PAGE_BIT_NX, init_level4_pgt + 8*L4_VMALLOC_START(%rip) + btsq $_PAGE_BIT_NX, init_level4_pgt + 8*L4_VMALLOC_END(%rip) + btsq $_PAGE_BIT_NX, init_level4_pgt + 8*L4_VMEMMAP_START(%rip) + btsq $_PAGE_BIT_NX, level2_fixmap_pgt + 8*504(%rip) + btsq $_PAGE_BIT_NX, level2_fixmap_pgt + 8*505(%rip) + btsq $_PAGE_BIT_NX, level2_fixmap_pgt + 8*506(%rip) + btsq $_PAGE_BIT_NX, level2_fixmap_pgt + 8*507(%rip) + btsq $_PAGE_BIT_NX, __supported_pte_mask(%rip) 1: wrmsr /* Make changes effective */ /* Setup cr0 */ @@ -288,6 +330,7 @@ ENTRY(secondary_startup_64) * REX.W + FF /5 JMP m16:64 Jump far, absolute indirect, * address given in m16:64. */ + pax_set_fptr_mask movq initial_code(%rip),%rax pushq $0 # fake return address to stop unwinder pushq $__KERNEL_CS # set correct cs @@ -321,7 +364,7 @@ ENDPROC(start_cpu0) .quad INIT_PER_CPU_VAR(irq_stack_union) GLOBAL(stack_start) - .quad init_thread_union+THREAD_SIZE-8 + .quad init_thread_union+THREAD_SIZE-16 .word 0 __FINITDATA @@ -401,7 +444,7 @@ early_idt_handler_common: call dump_stack #ifdef CONFIG_KALLSYMS leaq early_idt_ripmsg(%rip),%rdi - movq 40(%rsp),%rsi # %rip again + movq 88(%rsp),%rsi # %rip again call __print_symbol #endif #endif /* EARLY_PRINTK */ @@ -430,6 +473,7 @@ ENDPROC(early_idt_handler_common) early_recursion_flag: .long 0 + .section .rodata,"a",@progbits #ifdef CONFIG_EARLY_PRINTK early_idt_msg: .asciz "PANIC: early exception %02lx rip %lx:%lx error %lx cr2 %lx\n" @@ -452,40 +496,67 @@ GLOBAL(name) __INITDATA NEXT_PAGE(early_level4_pgt) .fill 511,8,0 - .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE + .quad level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE NEXT_PAGE(early_dynamic_pgts) .fill 512*EARLY_DYNAMIC_PAGE_TABLES,8,0 - .data + .section .rodata,"a",@progbits -#ifndef CONFIG_XEN NEXT_PAGE(init_level4_pgt) - .fill 512,8,0 -#else -NEXT_PAGE(init_level4_pgt) - .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE .org init_level4_pgt + L4_PAGE_OFFSET*8, 0 .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE + .org init_level4_pgt + L4_VMALLOC_START*8, 0 + .quad level3_vmalloc_start_pgt - __START_KERNEL_map + _KERNPG_TABLE + .org init_level4_pgt + L4_VMALLOC_END*8, 0 + .quad level3_vmalloc_end_pgt - __START_KERNEL_map + _KERNPG_TABLE + .org init_level4_pgt + L4_VMEMMAP_START*8, 0 + .quad level3_vmemmap_pgt - __START_KERNEL_map + _KERNPG_TABLE .org init_level4_pgt + L4_START_KERNEL*8, 0 /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ - .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE + .quad level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE + +#ifdef CONFIG_PAX_PER_CPU_PGD +NEXT_PAGE(cpu_pgd) + .rept 2*NR_CPUS + .fill 512,8,0 + .endr +#endif NEXT_PAGE(level3_ident_pgt) .quad level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE +#ifdef CONFIG_XEN .fill 511, 8, 0 +#else + .quad level2_ident_pgt + PAGE_SIZE - __START_KERNEL_map + _KERNPG_TABLE + .fill 510,8,0 +#endif + +NEXT_PAGE(level3_vmalloc_start_pgt) + .fill 512,8,0 + +NEXT_PAGE(level3_vmalloc_end_pgt) + .fill 512,8,0 + +NEXT_PAGE(level3_vmemmap_pgt) + .fill L3_VMEMMAP_START,8,0 + .quad level2_vmemmap_pgt - __START_KERNEL_map + _KERNPG_TABLE + NEXT_PAGE(level2_ident_pgt) - /* Since I easily can, map the first 1G. + .quad level1_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE + /* Since I easily can, map the first 2G. * Don't set NX because code runs from these pages. */ - PMDS(0, __PAGE_KERNEL_IDENT_LARGE_EXEC, PTRS_PER_PMD) -#endif + PMDS(PMD_SIZE, __PAGE_KERNEL_IDENT_LARGE_EXEC, 2*PTRS_PER_PMD - 1) NEXT_PAGE(level3_kernel_pgt) .fill L3_START_KERNEL,8,0 /* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */ .quad level2_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE - .quad level2_fixmap_pgt - __START_KERNEL_map + _PAGE_TABLE + .quad level2_fixmap_pgt - __START_KERNEL_map + _KERNPG_TABLE + +NEXT_PAGE(level2_vmemmap_pgt) + .fill 512,8,0 NEXT_PAGE(level2_kernel_pgt) /* @@ -502,31 +573,79 @@ NEXT_PAGE(level2_kernel_pgt) KERNEL_IMAGE_SIZE/PMD_SIZE) NEXT_PAGE(level2_fixmap_pgt) - .fill 506,8,0 - .quad level1_fixmap_pgt - __START_KERNEL_map + _PAGE_TABLE - /* 8MB reserved for vsyscalls + a 2MB hole = 4 + 1 entries */ - .fill 5,8,0 + .quad level1_modules_pgt - __START_KERNEL_map + 0 * PAGE_SIZE + _KERNPG_TABLE + .quad level1_modules_pgt - __START_KERNEL_map + 1 * PAGE_SIZE + _KERNPG_TABLE + .quad level1_modules_pgt - __START_KERNEL_map + 2 * PAGE_SIZE + _KERNPG_TABLE + .quad level1_modules_pgt - __START_KERNEL_map + 3 * PAGE_SIZE + _KERNPG_TABLE + .fill 500,8,0 + .quad level1_fixmap_pgt - __START_KERNEL_map + 0 * PAGE_SIZE + _KERNPG_TABLE + .quad level1_fixmap_pgt - __START_KERNEL_map + 1 * PAGE_SIZE + _KERNPG_TABLE + .quad level1_fixmap_pgt - __START_KERNEL_map + 2 * PAGE_SIZE + _KERNPG_TABLE + .quad level1_vsyscall_pgt - __START_KERNEL_map + _KERNPG_TABLE + /* 6MB reserved for vsyscalls + a 2MB hole = 3 + 1 entries */ + .fill 4,8,0 + +NEXT_PAGE(level1_ident_pgt) + .fill 512,8,0 + +NEXT_PAGE(level1_modules_pgt) + .fill 4*512,8,0 NEXT_PAGE(level1_fixmap_pgt) + .fill 3*512,8,0 + +NEXT_PAGE(level1_vsyscall_pgt) .fill 512,8,0 #undef PMDS - .data + .align PAGE_SIZE +ENTRY(cpu_gdt_table) + .rept NR_CPUS + .quad 0x0000000000000000 /* NULL descriptor */ + .quad 0x00cf9b000000ffff /* __KERNEL32_CS */ + .quad 0x00af9b000000ffff /* __KERNEL_CS */ + .quad 0x00cf93000000ffff /* __KERNEL_DS */ + .quad 0x00cffb000000ffff /* __USER32_CS */ + .quad 0x00cff3000000ffff /* __USER_DS, __USER32_DS */ + .quad 0x00affb000000ffff /* __USER_CS */ + +#ifdef CONFIG_PAX_KERNEXEC + .quad 0x00af9b000000ffff /* __KERNEXEC_KERNEL_CS */ +#else + .quad 0x0 /* unused */ +#endif + + .quad 0,0 /* TSS */ + .quad 0,0 /* LDT */ + .quad 0,0,0 /* three TLS descriptors */ + .quad 0x0000f40000000000 /* node/CPU stored in limit */ + /* asm/segment.h:GDT_ENTRIES must match this */ + +#ifdef CONFIG_PAX_MEMORY_UDEREF + .quad 0x00cf93000000ffff /* __UDEREF_KERNEL_DS */ +#else + .quad 0x0 /* unused */ +#endif + + /* zero the remaining page */ + .fill PAGE_SIZE / 8 - GDT_ENTRIES,8,0 + .endr + .align 16 .globl early_gdt_descr early_gdt_descr: .word GDT_ENTRIES*8-1 early_gdt_descr_base: - .quad INIT_PER_CPU_VAR(gdt_page) + .quad cpu_gdt_table ENTRY(phys_base) /* This must match the first entry in level2_kernel_pgt */ .quad 0x0000000000000000 #include "../../x86/xen/xen-head.S" - - __PAGE_ALIGNED_BSS + + .section .rodata,"a",@progbits NEXT_PAGE(empty_zero_page) .skip PAGE_SIZE diff --git a/arch/x86/kernel/i386_ksyms_32.c b/arch/x86/kernel/i386_ksyms_32.c index 64341aa..b1e6632 100644 --- a/arch/x86/kernel/i386_ksyms_32.c +++ b/arch/x86/kernel/i386_ksyms_32.c @@ -20,8 +20,12 @@ extern void cmpxchg8b_emu(void); EXPORT_SYMBOL(cmpxchg8b_emu); #endif +EXPORT_SYMBOL_GPL(cpu_gdt_table); + /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy_generic); +EXPORT_SYMBOL(csum_partial_copy_generic_to_user); +EXPORT_SYMBOL(csum_partial_copy_generic_from_user); EXPORT_SYMBOL(__get_user_1); EXPORT_SYMBOL(__get_user_2); @@ -42,3 +46,11 @@ EXPORT_SYMBOL(empty_zero_page); EXPORT_SYMBOL(___preempt_schedule); EXPORT_SYMBOL(___preempt_schedule_notrace); #endif + +#ifdef CONFIG_PAX_KERNEXEC +EXPORT_SYMBOL(__LOAD_PHYSICAL_ADDR); +#endif + +#ifdef CONFIG_PAX_PER_CPU_PGD +EXPORT_SYMBOL(cpu_pgd); +#endif diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c index be22f5a..c5d0e1f 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) static void make_8259A_irq(unsigned int irq) { disable_irq_nosync(irq); - io_apic_irqs &= ~(1< #include #include +#include #include #include #include @@ -30,6 +31,12 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) return -EINVAL; if (turn_on && !capable(CAP_SYS_RAWIO)) return -EPERM; +#ifdef CONFIG_GRKERNSEC_IO + if (turn_on && grsec_disable_privio) { + gr_handle_ioperm(); + return -ENODEV; + } +#endif /* * If it's the first ioperm() call in this thread's lifetime, set the @@ -54,7 +61,7 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) * because the ->io_bitmap_max value must match the bitmap * contents: */ - tss = &per_cpu(cpu_tss, get_cpu()); + tss = cpu_tss + get_cpu(); if (turn_on) bitmap_clear(t->io_bitmap_ptr, from, num); @@ -105,6 +112,12 @@ SYSCALL_DEFINE1(iopl, unsigned int, level) if (level > old) { if (!capable(CAP_SYS_RAWIO)) return -EPERM; +#ifdef CONFIG_GRKERNSEC_IO + if (grsec_disable_privio) { + gr_handle_iopl(); + return -ENODEV; + } +#endif } regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | (level << 12); t->iopl = level << 12; diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index f8062aa..c37b60f 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -28,7 +28,7 @@ EXPORT_PER_CPU_SYMBOL(irq_stat); DEFINE_PER_CPU(struct pt_regs *, irq_regs); EXPORT_PER_CPU_SYMBOL(irq_regs); -atomic_t irq_err_count; +atomic_unchecked_t irq_err_count; /* Function pointer for generic interrupt vector handling */ void (*x86_platform_ipi_callback)(void) = NULL; @@ -147,9 +147,9 @@ int arch_show_interrupts(struct seq_file *p, int prec) seq_puts(p, " Hypervisor callback interrupts\n"); } #endif - seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count)); + seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read_unchecked(&irq_err_count)); #if defined(CONFIG_X86_IO_APIC) - seq_printf(p, "%*s: %10u\n", prec, "MIS", atomic_read(&irq_mis_count)); + seq_printf(p, "%*s: %10u\n", prec, "MIS", atomic_read_unchecked(&irq_mis_count)); #endif #ifdef CONFIG_HAVE_KVM seq_printf(p, "%*s: ", prec, "PIN"); @@ -201,7 +201,7 @@ u64 arch_irq_stat_cpu(unsigned int cpu) u64 arch_irq_stat(void) { - u64 sum = atomic_read(&irq_err_count); + u64 sum = atomic_read_unchecked(&irq_err_count); return sum; } diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c index 38da8f2..5653e36 100644 --- a/arch/x86/kernel/irq_32.c +++ b/arch/x86/kernel/irq_32.c @@ -23,6 +23,8 @@ #ifdef CONFIG_DEBUG_STACKOVERFLOW +extern void gr_handle_kernel_exploit(void); + int sysctl_panic_on_stackoverflow __read_mostly; /* Debugging check for stack overflow: is there less than 1KB free? */ @@ -33,13 +35,14 @@ static int check_stack_overflow(void) __asm__ __volatile__("andl %%esp,%0" : "=r" (sp) : "0" (THREAD_SIZE - 1)); - return sp < (sizeof(struct thread_info) + STACK_WARN); + return sp < STACK_WARN; } static void print_stack_overflow(void) { printk(KERN_WARNING "low stack detected by irq handler\n"); dump_stack(); + gr_handle_kernel_exploit(); if (sysctl_panic_on_stackoverflow) panic("low stack detected by irq handler - check messages\n"); } @@ -70,10 +73,9 @@ static inline void *current_stack(void) static inline int execute_on_irq_stack(int overflow, struct irq_desc *desc) { - struct irq_stack *curstk, *irqstk; + struct irq_stack *irqstk; u32 *isp, *prev_esp, arg1; - curstk = (struct irq_stack *) current_stack(); irqstk = __this_cpu_read(hardirq_stack); /* @@ -82,15 +84,19 @@ static inline int execute_on_irq_stack(int overflow, struct irq_desc *desc) * handler) we can't do that and just have to keep using the * current stack (which is the irq stack already after all) */ - if (unlikely(curstk == irqstk)) + if (unlikely((void *)current_stack_pointer - (void *)irqstk < THREAD_SIZE)) return 0; - isp = (u32 *) ((char *)irqstk + sizeof(*irqstk)); + isp = (u32 *) ((char *)irqstk + sizeof(*irqstk) - 8); /* Save the next esp at the bottom of the stack */ prev_esp = (u32 *)irqstk; *prev_esp = current_stack_pointer(); +#ifdef CONFIG_PAX_MEMORY_UDEREF + __set_fs(MAKE_MM_SEG(0)); +#endif + if (unlikely(overflow)) call_on_stack(print_stack_overflow, isp); @@ -101,6 +107,11 @@ static inline int execute_on_irq_stack(int overflow, struct irq_desc *desc) : "0" (desc), "1" (isp), "D" (desc->handle_irq) : "memory", "cc", "ecx"); + +#ifdef CONFIG_PAX_MEMORY_UDEREF + __set_fs(current_thread_info()->addr_limit); +#endif + return 1; } @@ -109,32 +120,18 @@ static inline int execute_on_irq_stack(int overflow, struct irq_desc *desc) */ void irq_ctx_init(int cpu) { - struct irq_stack *irqstk; - if (per_cpu(hardirq_stack, cpu)) return; - irqstk = page_address(alloc_pages_node(cpu_to_node(cpu), - THREADINFO_GFP, - THREAD_SIZE_ORDER)); - per_cpu(hardirq_stack, cpu) = irqstk; - - irqstk = page_address(alloc_pages_node(cpu_to_node(cpu), - THREADINFO_GFP, - THREAD_SIZE_ORDER)); - per_cpu(softirq_stack, cpu) = irqstk; - - printk(KERN_DEBUG "CPU %u irqstacks, hard=%p soft=%p\n", - cpu, per_cpu(hardirq_stack, cpu), per_cpu(softirq_stack, cpu)); + per_cpu(hardirq_stack, cpu) = page_address(alloc_pages_node(cpu_to_node(cpu), THREADINFO_GFP, THREAD_SIZE_ORDER)); + per_cpu(softirq_stack, cpu) = page_address(alloc_pages_node(cpu_to_node(cpu), THREADINFO_GFP, THREAD_SIZE_ORDER)); } void do_softirq_own_stack(void) { - struct thread_info *curstk; struct irq_stack *irqstk; u32 *isp, *prev_esp; - curstk = current_stack(); irqstk = __this_cpu_read(softirq_stack); /* build the stack frame on the softirq stack */ @@ -144,7 +141,16 @@ void do_softirq_own_stack(void) prev_esp = (u32 *)irqstk; *prev_esp = current_stack_pointer(); +#ifdef CONFIG_PAX_MEMORY_UDEREF + __set_fs(MAKE_MM_SEG(0)); +#endif + call_on_stack(__do_softirq, isp); + +#ifdef CONFIG_PAX_MEMORY_UDEREF + __set_fs(current_thread_info()->addr_limit); +#endif + } bool handle_irq(struct irq_desc *desc, struct pt_regs *regs) diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c index c767cf2..425a7ec 100644 --- a/arch/x86/kernel/irq_64.c +++ b/arch/x86/kernel/irq_64.c @@ -20,6 +20,8 @@ #include #include +extern void gr_handle_kernel_exploit(void); + int sysctl_panic_on_stackoverflow; /* @@ -63,6 +65,8 @@ static inline void stack_overflow_check(struct pt_regs *regs) irq_stack_top, irq_stack_bottom, estack_top, estack_bottom); + gr_handle_kernel_exploit(); + if (sysctl_panic_on_stackoverflow) panic("low stack detected by irq handler - check messages\n"); #endif diff --git a/arch/x86/kernel/jump_label.c b/arch/x86/kernel/jump_label.c index e565e0e..fdfeb45 100644 --- a/arch/x86/kernel/jump_label.c +++ b/arch/x86/kernel/jump_label.c @@ -31,6 +31,8 @@ static void bug_at(unsigned char *ip, int line) * Something went wrong. Crash the box, as something could be * corrupting the kernel. */ + ip = (unsigned char *)ktla_ktva((unsigned long)ip); + pr_warning("Unexpected op at %pS [%p] %s:%d\n", ip, ip, __FILE__, line); pr_warning("Unexpected op at %pS [%p] (%02x %02x %02x %02x %02x) %s:%d\n", ip, ip, ip[0], ip[1], ip[2], ip[3], ip[4], __FILE__, line); BUG(); @@ -51,7 +53,7 @@ static void __jump_label_transform(struct jump_entry *entry, * Jump label is enabled for the first time. * So we expect a default_nop... */ - if (unlikely(memcmp((void *)entry->code, default_nop, 5) + if (unlikely(memcmp((void *)ktla_ktva(entry->code), default_nop, 5) != 0)) bug_at((void *)entry->code, __LINE__); } else { @@ -59,7 +61,7 @@ static void __jump_label_transform(struct jump_entry *entry, * ...otherwise expect an ideal_nop. Otherwise * something went horribly wrong. */ - if (unlikely(memcmp((void *)entry->code, ideal_nop, 5) + if (unlikely(memcmp((void *)ktla_ktva(entry->code), ideal_nop, 5) != 0)) bug_at((void *)entry->code, __LINE__); } @@ -75,13 +77,13 @@ static void __jump_label_transform(struct jump_entry *entry, * are converting the default nop to the ideal nop. */ if (init) { - if (unlikely(memcmp((void *)entry->code, default_nop, 5) != 0)) + if (unlikely(memcmp((void *)ktla_ktva(entry->code), default_nop, 5) != 0)) bug_at((void *)entry->code, __LINE__); } else { code.jump = 0xe9; code.offset = entry->target - (entry->code + JUMP_LABEL_NOP_SIZE); - if (unlikely(memcmp((void *)entry->code, &code, 5) != 0)) + if (unlikely(memcmp((void *)ktla_ktva(entry->code), &code, 5) != 0)) bug_at((void *)entry->code, __LINE__); } memcpy(&code, ideal_nops[NOP_ATOMIC5], JUMP_LABEL_NOP_SIZE); diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index d6178d9..598681f 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -228,7 +228,10 @@ static void kgdb_correct_hw_break(void) bp->attr.bp_addr = breakinfo[breakno].addr; bp->attr.bp_len = breakinfo[breakno].len; bp->attr.bp_type = breakinfo[breakno].type; - info->address = breakinfo[breakno].addr; + if (breakinfo[breakno].type == X86_BREAKPOINT_EXECUTE) + info->address = ktla_ktva(breakinfo[breakno].addr); + else + info->address = breakinfo[breakno].addr; info->len = breakinfo[breakno].len; info->type = breakinfo[breakno].type; val = arch_install_hw_breakpoint(bp); @@ -475,12 +478,12 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, case 'k': /* clear the trace bit */ linux_regs->flags &= ~X86_EFLAGS_TF; - atomic_set(&kgdb_cpu_doing_single_step, -1); + atomic_set_unchecked(&kgdb_cpu_doing_single_step, -1); /* set the trace bit if we're stepping */ if (remcomInBuffer[0] == 's') { linux_regs->flags |= X86_EFLAGS_TF; - atomic_set(&kgdb_cpu_doing_single_step, + atomic_set_unchecked(&kgdb_cpu_doing_single_step, raw_smp_processor_id()); } @@ -545,7 +548,7 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd) switch (cmd) { case DIE_DEBUG: - if (atomic_read(&kgdb_cpu_doing_single_step) != -1) { + if (atomic_read_unchecked(&kgdb_cpu_doing_single_step) != -1) { if (user_mode(regs)) return single_step_cont(regs, args); break; @@ -750,11 +753,11 @@ int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) #endif /* CONFIG_DEBUG_RODATA */ bpt->type = BP_BREAKPOINT; - err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr, + err = probe_kernel_read(bpt->saved_instr, (const void *)ktla_ktva(bpt->bpt_addr), BREAK_INSTR_SIZE); if (err) return err; - err = probe_kernel_write((char *)bpt->bpt_addr, + err = probe_kernel_write((void *)ktla_ktva(bpt->bpt_addr), arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE); #ifdef CONFIG_DEBUG_RODATA if (!err) @@ -767,7 +770,7 @@ int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) return -EBUSY; text_poke((void *)bpt->bpt_addr, arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE); - err = probe_kernel_read(opc, (char *)bpt->bpt_addr, BREAK_INSTR_SIZE); + err = probe_kernel_read(opc, ktla_ktva((char *)bpt->bpt_addr), BREAK_INSTR_SIZE); if (err) return err; if (memcmp(opc, arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE)) @@ -792,13 +795,13 @@ int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt) if (mutex_is_locked(&text_mutex)) goto knl_write; text_poke((void *)bpt->bpt_addr, bpt->saved_instr, BREAK_INSTR_SIZE); - err = probe_kernel_read(opc, (char *)bpt->bpt_addr, BREAK_INSTR_SIZE); + err = probe_kernel_read(opc, ktla_ktva((char *)bpt->bpt_addr), BREAK_INSTR_SIZE); if (err || memcmp(opc, bpt->saved_instr, BREAK_INSTR_SIZE)) goto knl_write; return err; knl_write: #endif /* CONFIG_DEBUG_RODATA */ - return probe_kernel_write((char *)bpt->bpt_addr, + return probe_kernel_write((void *)ktla_ktva(bpt->bpt_addr), (char *)bpt->saved_instr, BREAK_INSTR_SIZE); } diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 1deffe6..3be342a 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -120,9 +120,12 @@ __synthesize_relative_insn(void *from, void *to, u8 op) s32 raddr; } __packed *insn; - insn = (struct __arch_relative_insn *)from; + insn = (struct __arch_relative_insn *)ktla_ktva((unsigned long)from); + + pax_open_kernel(); insn->raddr = (s32)((long)(to) - ((long)(from) + 5)); insn->op = op; + pax_close_kernel(); } /* Insert a jump instruction at address 'from', which jumps to address 'to'.*/ @@ -168,7 +171,7 @@ int can_boost(kprobe_opcode_t *opcodes) kprobe_opcode_t opcode; kprobe_opcode_t *orig_opcodes = opcodes; - if (search_exception_tables((unsigned long)opcodes)) + if (search_exception_tables(ktva_ktla((unsigned long)opcodes))) return 0; /* Page fault may occur on this address. */ retry: @@ -260,12 +263,12 @@ __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr) * Fortunately, we know that the original code is the ideal 5-byte * long NOP. */ - memcpy(buf, (void *)addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); + memcpy(buf, (void *)ktla_ktva(addr), MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); if (faddr) memcpy(buf, ideal_nops[NOP_ATOMIC5], 5); else buf[0] = kp->opcode; - return (unsigned long)buf; + return ktva_ktla((unsigned long)buf); } /* @@ -367,7 +370,9 @@ int __copy_instruction(u8 *dest, u8 *src) /* Another subsystem puts a breakpoint, failed to recover */ if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION) return 0; + pax_open_kernel(); memcpy(dest, insn.kaddr, length); + pax_close_kernel(); #ifdef CONFIG_X86_64 if (insn_rip_relative(&insn)) { @@ -394,7 +399,9 @@ int __copy_instruction(u8 *dest, u8 *src) return 0; } disp = (u8 *) dest + insn_offset_displacement(&insn); + pax_open_kernel(); *(s32 *) disp = (s32) newdisp; + pax_close_kernel(); } #endif return length; @@ -536,7 +543,7 @@ static void setup_singlestep(struct kprobe *p, struct pt_regs *regs, * nor set current_kprobe, because it doesn't use single * stepping. */ - regs->ip = (unsigned long)p->ainsn.insn; + regs->ip = ktva_ktla((unsigned long)p->ainsn.insn); preempt_enable_no_resched(); return; } @@ -553,9 +560,9 @@ static void setup_singlestep(struct kprobe *p, struct pt_regs *regs, regs->flags &= ~X86_EFLAGS_IF; /* single step inline if the instruction is an int3 */ if (p->opcode == BREAKPOINT_INSTRUCTION) - regs->ip = (unsigned long)p->addr; + regs->ip = ktla_ktva((unsigned long)p->addr); else - regs->ip = (unsigned long)p->ainsn.insn; + regs->ip = ktva_ktla((unsigned long)p->ainsn.insn); } NOKPROBE_SYMBOL(setup_singlestep); @@ -640,7 +647,7 @@ int kprobe_int3_handler(struct pt_regs *regs) setup_singlestep(p, regs, kcb, 0); return 1; } - } else if (*addr != BREAKPOINT_INSTRUCTION) { + } else if (*(kprobe_opcode_t *)ktla_ktva((unsigned long)addr) != BREAKPOINT_INSTRUCTION) { /* * The breakpoint instruction was removed right * after we hit it. Another cpu has removed @@ -687,6 +694,9 @@ static void __used kretprobe_trampoline_holder(void) " movq %rax, 152(%rsp)\n" RESTORE_REGS_STRING " popfq\n" +#ifdef KERNEXEC_PLUGIN + " btsq $63,(%rsp)\n" +#endif #else " pushf\n" SAVE_REGS_STRING @@ -827,7 +837,7 @@ static void resume_execution(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) { unsigned long *tos = stack_addr(regs); - unsigned long copy_ip = (unsigned long)p->ainsn.insn; + unsigned long copy_ip = ktva_ktla((unsigned long)p->ainsn.insn); unsigned long orig_ip = (unsigned long)p->addr; kprobe_opcode_t *insn = p->ainsn.insn; diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c index 7b3b9d1..e2478b91 100644 --- a/arch/x86/kernel/kprobes/opt.c +++ b/arch/x86/kernel/kprobes/opt.c @@ -79,6 +79,7 @@ found: /* Insert a move instruction which sets a pointer to eax/rdi (1st arg). */ static void synthesize_set_arg1(kprobe_opcode_t *addr, unsigned long val) { + pax_open_kernel(); #ifdef CONFIG_X86_64 *addr++ = 0x48; *addr++ = 0xbf; @@ -86,6 +87,7 @@ static void synthesize_set_arg1(kprobe_opcode_t *addr, unsigned long val) *addr++ = 0xb8; #endif *(unsigned long *)addr = val; + pax_close_kernel(); } asm ( @@ -342,7 +344,7 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, * Verify if the address gap is in 2GB range, because this uses * a relative jump. */ - rel = (long)op->optinsn.insn - (long)op->kp.addr + RELATIVEJUMP_SIZE; + rel = (long)op->optinsn.insn - ktla_ktva((long)op->kp.addr) + RELATIVEJUMP_SIZE; if (abs(rel) > 0x7fffffff) { __arch_remove_optimized_kprobe(op, 0); return -ERANGE; @@ -359,16 +361,18 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, op->optinsn.size = ret; /* Copy arch-dep-instance from template */ - memcpy(buf, &optprobe_template_entry, TMPL_END_IDX); + pax_open_kernel(); + memcpy(buf, ktla_ktva(&optprobe_template_entry), TMPL_END_IDX); + pax_close_kernel(); /* Set probe information */ synthesize_set_arg1(buf + TMPL_MOVE_IDX, (unsigned long)op); /* Set probe function call */ - synthesize_relcall(buf + TMPL_CALL_IDX, optimized_callback); + synthesize_relcall(ktva_ktla(buf) + TMPL_CALL_IDX, optimized_callback); /* Set returning jmp instruction at the tail of out-of-line buffer */ - synthesize_reljump(buf + TMPL_END_IDX + op->optinsn.size, + synthesize_reljump(ktva_ktla(buf) + TMPL_END_IDX + op->optinsn.size, (u8 *)op->kp.addr + op->optinsn.size); flush_icache_range((unsigned long) buf, @@ -393,7 +397,7 @@ void arch_optimize_kprobes(struct list_head *oplist) WARN_ON(kprobe_disabled(&op->kp)); /* Backup instructions which will be replaced by jump address */ - memcpy(op->optinsn.copied_insn, op->kp.addr + INT3_SIZE, + memcpy(op->optinsn.copied_insn, ktla_ktva(op->kp.addr) + INT3_SIZE, RELATIVE_ADDR_SIZE); insn_buf[0] = RELATIVEJUMP_OPCODE; @@ -441,7 +445,7 @@ int setup_detour_execution(struct kprobe *p, struct pt_regs *regs, int reenter) /* This kprobe is really able to run optimized path. */ op = container_of(p, struct optimized_kprobe, kp); /* Detour through copied instructions */ - regs->ip = (unsigned long)op->optinsn.insn + TMPL_END_IDX; + regs->ip = ktva_ktla((unsigned long)op->optinsn.insn) + TMPL_END_IDX; if (!reenter) reset_current_kprobe(); preempt_enable_no_resched(); diff --git a/arch/x86/kernel/ksysfs.c b/arch/x86/kernel/ksysfs.c index c2bedae..25e7ab60 100644 --- a/arch/x86/kernel/ksysfs.c +++ b/arch/x86/kernel/ksysfs.c @@ -184,7 +184,7 @@ out: static struct kobj_attribute type_attr = __ATTR_RO(type); -static struct bin_attribute data_attr = { +static bin_attribute_no_const data_attr __read_only = { .attr = { .name = "data", .mode = S_IRUGO, diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c index 2c7aafa..7ac2af2 100644 --- a/arch/x86/kernel/kvmclock.c +++ b/arch/x86/kernel/kvmclock.c @@ -29,7 +29,7 @@ #include #include -static int kvmclock = 1; +static int kvmclock __read_only = 1; static int msr_kvm_system_time = MSR_KVM_SYSTEM_TIME; static int msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK; @@ -41,7 +41,7 @@ static int parse_no_kvmclock(char *arg) early_param("no-kvmclock", parse_no_kvmclock); /* The hypervisor will put information about time periodically here */ -static struct pvclock_vsyscall_time_info *hv_clock; +static struct pvclock_vsyscall_time_info hv_clock[NR_CPUS] __page_aligned_bss; static struct pvclock_wall_clock wall_clock; /* @@ -132,7 +132,7 @@ bool kvm_check_and_clear_guest_paused(void) struct pvclock_vcpu_time_info *src; int cpu = smp_processor_id(); - if (!hv_clock) + if (!kvmclock) return ret; src = &hv_clock[cpu].pvti; @@ -159,7 +159,7 @@ int kvm_register_clock(char *txt) int low, high, ret; struct pvclock_vcpu_time_info *src; - if (!hv_clock) + if (!kvmclock) return 0; src = &hv_clock[cpu].pvti; @@ -219,7 +219,6 @@ static void kvm_shutdown(void) void __init kvmclock_init(void) { struct pvclock_vcpu_time_info *vcpu_time; - unsigned long mem; int size, cpu; u8 flags; @@ -237,15 +236,8 @@ void __init kvmclock_init(void) printk(KERN_INFO "kvm-clock: Using msrs %x and %x", msr_kvm_system_time, msr_kvm_wall_clock); - mem = memblock_alloc(size, PAGE_SIZE); - if (!mem) - return; - hv_clock = __va(mem); - memset(hv_clock, 0, size); - if (kvm_register_clock("primary cpu clock")) { - hv_clock = NULL; - memblock_free(mem, size); + kvmclock = 0; return; } pv_time_ops.sched_clock = kvm_clock_read; @@ -286,7 +278,7 @@ int __init kvm_setup_vsyscall_timeinfo(void) struct pvclock_vcpu_time_info *vcpu_time; unsigned int size; - if (!hv_clock) + if (!kvmclock) return 0; size = PAGE_ALIGN(sizeof(struct pvclock_vsyscall_time_info)*NR_CPUS); diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c index 6acc9dd..f72931d 100644 --- a/arch/x86/kernel/ldt.c +++ b/arch/x86/kernel/ldt.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,14 @@ #include #include +#ifdef CONFIG_GRKERNSEC +int sysctl_modify_ldt __read_only = 0; +#elif defined(CONFIG_DEFAULT_MODIFY_LDT_SYSCALL) +int sysctl_modify_ldt __read_only = 1; +#else +int sysctl_modify_ldt __read_only = 0; +#endif + /* context.lock is held for us, so we don't need any locking. */ static void flush_ldt(void *current_mm) { @@ -109,6 +118,23 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm) struct mm_struct *old_mm; int retval = 0; + if (tsk == current) { + mm->context.vdso = 0; + +#ifdef CONFIG_X86_32 +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) + mm->context.user_cs_base = 0UL; + mm->context.user_cs_limit = ~0UL; + +#if defined(CONFIG_PAX_PAGEEXEC) && defined(CONFIG_SMP) + cpumask_clear(&mm->context.cpu_user_cs_mask); +#endif + +#endif +#endif + + } + mutex_init(&mm->context.lock); old_mm = current->mm; if (!old_mm) { @@ -235,6 +261,14 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) /* The user wants to clear the entry. */ memset(&ldt, 0, sizeof(ldt)); } else { + +#ifdef CONFIG_PAX_SEGMEXEC + if ((mm->pax_flags & MF_PAX_SEGMEXEC) && (ldt_info.contents & MODIFY_LDT_CONTENTS_CODE)) { + error = -EINVAL; + goto out; + } +#endif + if (!IS_ENABLED(CONFIG_X86_16BIT) && !ldt_info.seg_32bit) { error = -EINVAL; goto out; @@ -276,6 +310,15 @@ asmlinkage int sys_modify_ldt(int func, void __user *ptr, { int ret = -ENOSYS; + if (!sysctl_modify_ldt) { + printk_ratelimited(KERN_INFO + "Denied a call to modify_ldt() from %s[%d] (uid: %d)." + " Adjust sysctl if this was not an exploit attempt.\n", + current->comm, task_pid_nr(current), + from_kuid_munged(current_user_ns(), current_uid())); + return ret; + } + switch (func) { case 0: ret = read_ldt(ptr, bytecount); diff --git a/arch/x86/kernel/livepatch.c b/arch/x86/kernel/livepatch.c index ff3c3101d..d7c0cd8 100644 --- a/arch/x86/kernel/livepatch.c +++ b/arch/x86/kernel/livepatch.c @@ -41,9 +41,10 @@ int klp_write_module_reloc(struct module *mod, unsigned long type, int ret, numpages, size = 4; bool readonly; unsigned long val; - unsigned long core = (unsigned long)mod->module_core; - unsigned long core_ro_size = mod->core_ro_size; - unsigned long core_size = mod->core_size; + unsigned long core_rx = (unsigned long)mod->module_core_rx; + unsigned long core_rw = (unsigned long)mod->module_core_rw; + unsigned long core_size_rx = mod->core_size_rx; + unsigned long core_size_rw = mod->core_size_rw; switch (type) { case R_X86_64_NONE: @@ -66,11 +67,12 @@ int klp_write_module_reloc(struct module *mod, unsigned long type, return -EINVAL; } - if (loc < core || loc >= core + core_size) + if ((loc < core_rx || loc >= core_rx + core_size_rx) && + (loc < core_rw || loc >= core_rw + core_size_rw)) /* loc does not point to any symbol inside the module */ return -EINVAL; - if (loc < core + core_ro_size) + if (loc < core_rx + core_size_rx) readonly = true; else readonly = false; diff --git a/arch/x86/kernel/machine_kexec_32.c b/arch/x86/kernel/machine_kexec_32.c index 469b23d..5449cfe 100644 --- a/arch/x86/kernel/machine_kexec_32.c +++ b/arch/x86/kernel/machine_kexec_32.c @@ -26,7 +26,7 @@ #include #include -static void set_idt(void *newidt, __u16 limit) +static void set_idt(struct desc_struct *newidt, __u16 limit) { struct desc_ptr curidt; @@ -38,7 +38,7 @@ static void set_idt(void *newidt, __u16 limit) } -static void set_gdt(void *newgdt, __u16 limit) +static void set_gdt(struct desc_struct *newgdt, __u16 limit) { struct desc_ptr curgdt; @@ -216,7 +216,7 @@ void machine_kexec(struct kimage *image) } control_page = page_address(image->control_code_page); - memcpy(control_page, relocate_kernel, KEXEC_CONTROL_CODE_MAX_SIZE); + memcpy(control_page, (void *)ktla_ktva((unsigned long)relocate_kernel), KEXEC_CONTROL_CODE_MAX_SIZE); relocate_kernel_ptr = control_page; page_list[PA_CONTROL_PAGE] = __pa(control_page); diff --git a/arch/x86/kernel/mcount_64.S b/arch/x86/kernel/mcount_64.S index 94ea120..4154cea 100644 --- a/arch/x86/kernel/mcount_64.S +++ b/arch/x86/kernel/mcount_64.S @@ -7,7 +7,7 @@ #include #include #include - +#include .code64 .section .entry.text, "ax" @@ -148,8 +148,9 @@ #ifdef CONFIG_DYNAMIC_FTRACE ENTRY(function_hook) + pax_force_retaddr retq -END(function_hook) +ENDPROC(function_hook) ENTRY(ftrace_caller) /* save_mcount_regs fills in first two parameters */ @@ -181,8 +182,9 @@ GLOBAL(ftrace_graph_call) #endif GLOBAL(ftrace_stub) + pax_force_retaddr retq -END(ftrace_caller) +ENDPROC(ftrace_caller) ENTRY(ftrace_regs_caller) /* Save the current flags before any operations that can change them */ @@ -253,7 +255,7 @@ GLOBAL(ftrace_regs_caller_end) jmp ftrace_return -END(ftrace_regs_caller) +ENDPROC(ftrace_regs_caller) #else /* ! CONFIG_DYNAMIC_FTRACE */ @@ -272,18 +274,20 @@ fgraph_trace: #endif GLOBAL(ftrace_stub) + pax_force_retaddr retq trace: /* save_mcount_regs fills in first two parameters */ save_mcount_regs + pax_force_fptr ftrace_trace_function call *ftrace_trace_function restore_mcount_regs jmp fgraph_trace -END(function_hook) +ENDPROC(function_hook) #endif /* CONFIG_DYNAMIC_FTRACE */ #endif /* CONFIG_FUNCTION_TRACER */ @@ -305,8 +309,9 @@ ENTRY(ftrace_graph_caller) restore_mcount_regs + pax_force_retaddr retq -END(ftrace_graph_caller) +ENDPROC(ftrace_graph_caller) GLOBAL(return_to_handler) subq $24, %rsp @@ -322,5 +327,7 @@ GLOBAL(return_to_handler) movq 8(%rsp), %rdx movq (%rsp), %rax addq $24, %rsp + pax_force_fptr %rdi jmp *%rdi +ENDPROC(return_to_handler) #endif diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index 005c03e..7000fe4 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -75,17 +75,17 @@ static unsigned long int get_module_load_offset(void) } #endif -void *module_alloc(unsigned long size) +static inline void *__module_alloc(unsigned long size, pgprot_t prot) { void *p; - if (PAGE_ALIGN(size) > MODULES_LEN) + if (!size || PAGE_ALIGN(size) > MODULES_LEN) return NULL; p = __vmalloc_node_range(size, MODULE_ALIGN, MODULES_VADDR + get_module_load_offset(), - MODULES_END, GFP_KERNEL | __GFP_HIGHMEM, - PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE, + MODULES_END, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, + prot, 0, NUMA_NO_NODE, __builtin_return_address(0)); if (p && (kasan_module_alloc(p, size) < 0)) { vfree(p); @@ -95,6 +95,51 @@ void *module_alloc(unsigned long size) return p; } +void *module_alloc(unsigned long size) +{ + +#ifdef CONFIG_PAX_KERNEXEC + return __module_alloc(size, PAGE_KERNEL); +#else + return __module_alloc(size, PAGE_KERNEL_EXEC); +#endif + +} + +#ifdef CONFIG_PAX_KERNEXEC +#ifdef CONFIG_X86_32 +void *module_alloc_exec(unsigned long size) +{ + struct vm_struct *area; + + if (size == 0) + return NULL; + + area = __get_vm_area(size, VM_ALLOC, (unsigned long)&MODULES_EXEC_VADDR, (unsigned long)&MODULES_EXEC_END); +return area ? area->addr : NULL; +} +EXPORT_SYMBOL(module_alloc_exec); + +void module_memfree_exec(void *module_region) +{ + vunmap(module_region); +} +EXPORT_SYMBOL(module_memfree_exec); +#else +void module_memfree_exec(void *module_region) +{ + module_memfree(module_region); +} +EXPORT_SYMBOL(module_memfree_exec); + +void *module_alloc_exec(unsigned long size) +{ + return __module_alloc(size, PAGE_KERNEL_RX); +} +EXPORT_SYMBOL(module_alloc_exec); +#endif +#endif + #ifdef CONFIG_X86_32 int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, @@ -105,14 +150,16 @@ int apply_relocate(Elf32_Shdr *sechdrs, unsigned int i; Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; Elf32_Sym *sym; - uint32_t *location; + uint32_t *plocation, location; DEBUGP("Applying relocate section %u to %u\n", relsec, sechdrs[relsec].sh_info); for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { /* This is where to make the change */ - location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr - + rel[i].r_offset; + plocation = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[i].r_offset; + location = (uint32_t)plocation; + if (sechdrs[sechdrs[relsec].sh_info].sh_flags & SHF_EXECINSTR) + plocation = (uint32_t *)ktla_ktva((unsigned long)plocation); /* This is the symbol it is referring to. Note that all undefined symbols have been resolved. */ sym = (Elf32_Sym *)sechdrs[symindex].sh_addr @@ -121,11 +168,15 @@ int apply_relocate(Elf32_Shdr *sechdrs, switch (ELF32_R_TYPE(rel[i].r_info)) { case R_386_32: /* We add the value into the location given */ - *location += sym->st_value; + pax_open_kernel(); + *plocation += sym->st_value; + pax_close_kernel(); break; case R_386_PC32: /* Add the value, subtract its position */ - *location += sym->st_value - (uint32_t)location; + pax_open_kernel(); + *plocation += sym->st_value - location; + pax_close_kernel(); break; default: pr_err("%s: Unknown relocation: %u\n", @@ -170,21 +221,30 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, case R_X86_64_NONE: break; case R_X86_64_64: + pax_open_kernel(); *(u64 *)loc = val; + pax_close_kernel(); break; case R_X86_64_32: + pax_open_kernel(); *(u32 *)loc = val; + pax_close_kernel(); if (val != *(u32 *)loc) goto overflow; break; case R_X86_64_32S: + pax_open_kernel(); *(s32 *)loc = val; + pax_close_kernel(); if ((s64)val != *(s32 *)loc) goto overflow; break; case R_X86_64_PC32: val -= (u64)loc; + pax_open_kernel(); *(u32 *)loc = val; + pax_close_kernel(); + #if 0 if ((s64)val != *(s32 *)loc) goto overflow; diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c index 113e707..0a690e1 100644 --- a/arch/x86/kernel/msr.c +++ b/arch/x86/kernel/msr.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -105,6 +106,11 @@ static ssize_t msr_write(struct file *file, const char __user *buf, int err = 0; ssize_t bytes = 0; +#ifdef CONFIG_GRKERNSEC_KMEM + gr_handle_msr_write(); + return -EPERM; +#endif + if (count % 8) return -EINVAL; /* Invalid chunk size */ @@ -152,6 +158,10 @@ static long msr_ioctl(struct file *file, unsigned int ioc, unsigned long arg) err = -EBADF; break; } +#ifdef CONFIG_GRKERNSEC_KMEM + gr_handle_msr_write(); + return -EPERM; +#endif if (copy_from_user(®s, uregs, sizeof regs)) { err = -EFAULT; break; @@ -235,7 +245,7 @@ static int msr_class_cpu_callback(struct notifier_block *nfb, return notifier_from_errno(err); } -static struct notifier_block __refdata msr_class_cpu_notifier = { +static struct notifier_block msr_class_cpu_notifier = { .notifier_call = msr_class_cpu_callback, }; diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c index 697f90d..8b1c639 100644 --- a/arch/x86/kernel/nmi.c +++ b/arch/x86/kernel/nmi.c @@ -98,16 +98,16 @@ fs_initcall(nmi_warning_debugfs); static void nmi_max_handler(struct irq_work *w) { - struct nmiaction *a = container_of(w, struct nmiaction, irq_work); + struct nmiwork *n = container_of(w, struct nmiwork, irq_work); int remainder_ns, decimal_msecs; - u64 whole_msecs = ACCESS_ONCE(a->max_duration); + u64 whole_msecs = ACCESS_ONCE(n->max_duration); remainder_ns = do_div(whole_msecs, (1000 * 1000)); decimal_msecs = remainder_ns / 1000; printk_ratelimited(KERN_INFO "INFO: NMI handler (%ps) took too long to run: %lld.%03d msecs\n", - a->handler, whole_msecs, decimal_msecs); + n->action->handler, whole_msecs, decimal_msecs); } static int nmi_handle(unsigned int type, struct pt_regs *regs) @@ -134,11 +134,11 @@ static int nmi_handle(unsigned int type, struct pt_regs *regs) delta = sched_clock() - delta; trace_nmi_handler(a->handler, (int)delta, thishandled); - if (delta < nmi_longest_ns || delta < a->max_duration) + if (delta < nmi_longest_ns || delta < a->work->max_duration) continue; - a->max_duration = delta; - irq_work_queue(&a->irq_work); + a->work->max_duration = delta; + irq_work_queue(&a->work->irq_work); } rcu_read_unlock(); @@ -148,7 +148,7 @@ static int nmi_handle(unsigned int type, struct pt_regs *regs) } NOKPROBE_SYMBOL(nmi_handle); -int __register_nmi_handler(unsigned int type, struct nmiaction *action) +int __register_nmi_handler(unsigned int type, const struct nmiaction *action) { struct nmi_desc *desc = nmi_to_desc(type); unsigned long flags; @@ -156,7 +156,8 @@ int __register_nmi_handler(unsigned int type, struct nmiaction *action) if (!action->handler) return -EINVAL; - init_irq_work(&action->irq_work, nmi_max_handler); + action->work->action = action; + init_irq_work(&action->work->irq_work, nmi_max_handler); spin_lock_irqsave(&desc->lock, flags); @@ -174,9 +175,9 @@ int __register_nmi_handler(unsigned int type, struct nmiaction *action) * event confuses some handlers (kdump uses this flag) */ if (action->flags & NMI_FLAG_FIRST) - list_add_rcu(&action->list, &desc->head); + pax_list_add_rcu((struct list_head *)&action->list, &desc->head); else - list_add_tail_rcu(&action->list, &desc->head); + pax_list_add_tail_rcu((struct list_head *)&action->list, &desc->head); spin_unlock_irqrestore(&desc->lock, flags); return 0; @@ -199,7 +200,7 @@ void unregister_nmi_handler(unsigned int type, const char *name) if (!strcmp(n->name, name)) { WARN(in_nmi(), "Trying to free NMI (%s) from NMI context!\n", n->name); - list_del_rcu(&n->list); + pax_list_del_rcu((struct list_head *)&n->list); break; } } @@ -481,6 +482,17 @@ static DEFINE_PER_CPU(int, update_debug_stack); dotraplinkage notrace void do_nmi(struct pt_regs *regs, long error_code) { + +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) + if (!user_mode(regs)) { + unsigned long cs = regs->cs & 0xFFFF; + unsigned long ip = ktva_ktla(regs->ip); + + if ((cs == __KERNEL_CS || cs == __KERNEXEC_KERNEL_CS) && ip <= (unsigned long)_etext) + regs->ip = ip; + } +#endif + if (this_cpu_read(nmi_state) != NMI_NOT_RUNNING) { this_cpu_write(nmi_state, NMI_LATCHED); return; diff --git a/arch/x86/kernel/nmi_selftest.c b/arch/x86/kernel/nmi_selftest.c index 6d9582e..f746287 100644 --- a/arch/x86/kernel/nmi_selftest.c +++ b/arch/x86/kernel/nmi_selftest.c @@ -43,7 +43,7 @@ static void __init init_nmi_testsuite(void) { /* trap all the unknown NMIs we may generate */ register_nmi_handler(NMI_UNKNOWN, nmi_unk_cb, 0, "nmi_selftest_unk", - __initdata); + __initconst); } static void __init cleanup_nmi_testsuite(void) @@ -66,7 +66,7 @@ static void __init test_nmi_ipi(struct cpumask *mask) unsigned long timeout; if (register_nmi_handler(NMI_LOCAL, test_nmi_ipi_callback, - NMI_FLAG_FIRST, "nmi_selftest", __initdata)) { + NMI_FLAG_FIRST, "nmi_selftest", __initconst)) { nmi_fail = FAILURE; return; } diff --git a/arch/x86/kernel/paravirt-spinlocks.c b/arch/x86/kernel/paravirt-spinlocks.c index 33ee3e0..da3519a 100644 --- a/arch/x86/kernel/paravirt-spinlocks.c +++ b/arch/x86/kernel/paravirt-spinlocks.c @@ -23,7 +23,7 @@ bool pv_is_native_spin_unlock(void) } #endif -struct pv_lock_ops pv_lock_ops = { +struct pv_lock_ops pv_lock_ops __read_only = { #ifdef CONFIG_SMP #ifdef CONFIG_QUEUED_SPINLOCKS .queued_spin_lock_slowpath = native_queued_spin_lock_slowpath, diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index c2130ae..d52ca15 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c @@ -64,6 +64,9 @@ u64 _paravirt_ident_64(u64 x) { return x; } +#if defined(CONFIG_X86_32) && defined(CONFIG_X86_PAE) +PV_CALLEE_SAVE_REGS_THUNK(_paravirt_ident_64); +#endif void __init default_banner(void) { @@ -150,16 +153,20 @@ unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf, if (opfunc == NULL) /* If there's no function, patch it with a ud2a (BUG) */ - ret = paravirt_patch_insns(insnbuf, len, ud2a, ud2a+sizeof(ud2a)); - else if (opfunc == _paravirt_nop) + ret = paravirt_patch_insns(insnbuf, len, (const char *)ktva_ktla((unsigned long)ud2a), ud2a+sizeof(ud2a)); + else if (opfunc == (void *)_paravirt_nop) /* If the operation is a nop, then nop the callsite */ ret = paravirt_patch_nop(); /* identity functions just return their single argument */ - else if (opfunc == _paravirt_ident_32) + else if (opfunc == (void *)_paravirt_ident_32) ret = paravirt_patch_ident_32(insnbuf, len); - else if (opfunc == _paravirt_ident_64) + else if (opfunc == (void *)_paravirt_ident_64) ret = paravirt_patch_ident_64(insnbuf, len); +#if defined(CONFIG_X86_32) && defined(CONFIG_X86_PAE) + else if (opfunc == (void *)__raw_callee_save__paravirt_ident_64) + ret = paravirt_patch_ident_64(insnbuf, len); +#endif else if (type == PARAVIRT_PATCH(pv_cpu_ops.iret) || #ifdef CONFIG_X86_32 @@ -186,7 +193,7 @@ unsigned paravirt_patch_insns(void *insnbuf, unsigned len, if (insn_len > len || start == NULL) insn_len = len; else - memcpy(insnbuf, start, insn_len); + memcpy(insnbuf, (const char *)ktla_ktva((unsigned long)start), insn_len); return insn_len; } @@ -310,7 +317,7 @@ enum paravirt_lazy_mode paravirt_get_lazy_mode(void) return this_cpu_read(paravirt_lazy_mode); } -struct pv_info pv_info = { +struct pv_info pv_info __read_only = { .name = "bare hardware", .paravirt_enabled = 0, .kernel_rpl = 0, @@ -321,16 +328,16 @@ struct pv_info pv_info = { #endif }; -struct pv_init_ops pv_init_ops = { +struct pv_init_ops pv_init_ops __read_only = { .patch = native_patch, }; -struct pv_time_ops pv_time_ops = { +struct pv_time_ops pv_time_ops __read_only = { .sched_clock = native_sched_clock, .steal_clock = native_steal_clock, }; -__visible struct pv_irq_ops pv_irq_ops = { +__visible struct pv_irq_ops pv_irq_ops __read_only = { .save_fl = __PV_IS_CALLEE_SAVE(native_save_fl), .restore_fl = __PV_IS_CALLEE_SAVE(native_restore_fl), .irq_disable = __PV_IS_CALLEE_SAVE(native_irq_disable), @@ -342,7 +349,7 @@ __visible struct pv_irq_ops pv_irq_ops = { #endif }; -__visible struct pv_cpu_ops pv_cpu_ops = { +__visible struct pv_cpu_ops pv_cpu_ops __read_only = { .cpuid = native_cpuid, .get_debugreg = native_get_debugreg, .set_debugreg = native_set_debugreg, @@ -403,21 +410,26 @@ NOKPROBE_SYMBOL(native_get_debugreg); NOKPROBE_SYMBOL(native_set_debugreg); NOKPROBE_SYMBOL(native_load_idt); -struct pv_apic_ops pv_apic_ops = { +struct pv_apic_ops pv_apic_ops __read_only= { #ifdef CONFIG_X86_LOCAL_APIC .startup_ipi_hook = paravirt_nop, #endif }; -#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_PAE) +#ifdef CONFIG_X86_32 +#ifdef CONFIG_X86_PAE +/* 64-bit pagetable entries */ +#define PTE_IDENT PV_CALLEE_SAVE(_paravirt_ident_64) +#else /* 32-bit pagetable entries */ #define PTE_IDENT __PV_IS_CALLEE_SAVE(_paravirt_ident_32) +#endif #else /* 64-bit pagetable entries */ #define PTE_IDENT __PV_IS_CALLEE_SAVE(_paravirt_ident_64) #endif -struct pv_mmu_ops pv_mmu_ops = { +struct pv_mmu_ops pv_mmu_ops __read_only = { .read_cr2 = native_read_cr2, .write_cr2 = native_write_cr2, @@ -467,6 +479,7 @@ struct pv_mmu_ops pv_mmu_ops = { .make_pud = PTE_IDENT, .set_pgd = native_set_pgd, + .set_pgd_batched = native_set_pgd_batched, #endif #endif /* CONFIG_PGTABLE_LEVELS >= 3 */ @@ -487,6 +500,12 @@ struct pv_mmu_ops pv_mmu_ops = { }, .set_fixmap = native_set_fixmap, + +#ifdef CONFIG_PAX_KERNEXEC + .pax_open_kernel = native_pax_open_kernel, + .pax_close_kernel = native_pax_close_kernel, +#endif + }; EXPORT_SYMBOL_GPL(pv_time_ops); diff --git a/arch/x86/kernel/paravirt_patch_64.c b/arch/x86/kernel/paravirt_patch_64.c index 8aa0558..465512e 100644 --- a/arch/x86/kernel/paravirt_patch_64.c +++ b/arch/x86/kernel/paravirt_patch_64.c @@ -9,7 +9,11 @@ DEF_NATIVE(pv_irq_ops, save_fl, "pushfq; popq %rax"); DEF_NATIVE(pv_mmu_ops, read_cr2, "movq %cr2, %rax"); DEF_NATIVE(pv_mmu_ops, read_cr3, "movq %cr3, %rax"); DEF_NATIVE(pv_mmu_ops, write_cr3, "movq %rdi, %cr3"); + +#ifndef CONFIG_PAX_MEMORY_UDEREF DEF_NATIVE(pv_mmu_ops, flush_tlb_single, "invlpg (%rdi)"); +#endif + DEF_NATIVE(pv_cpu_ops, clts, "clts"); DEF_NATIVE(pv_cpu_ops, wbinvd, "wbinvd"); @@ -62,7 +66,11 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf, PATCH_SITE(pv_mmu_ops, read_cr3); PATCH_SITE(pv_mmu_ops, write_cr3); PATCH_SITE(pv_cpu_ops, clts); + +#ifndef CONFIG_PAX_MEMORY_UDEREF PATCH_SITE(pv_mmu_ops, flush_tlb_single); +#endif + PATCH_SITE(pv_cpu_ops, wbinvd); #if defined(CONFIG_PARAVIRT_SPINLOCKS) && defined(CONFIG_QUEUED_SPINLOCKS) case PARAVIRT_PATCH(pv_lock_ops.queued_spin_unlock): diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index 0497f71..7186c0d 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c @@ -1347,7 +1347,7 @@ static void __init get_tce_space_from_tar(void) tce_space = be64_to_cpu(readq(target)); tce_space = tce_space & TAR_SW_BITS; - tce_space = tce_space & (~specified_table_size); + tce_space = tce_space & (~(unsigned long)specified_table_size); info->tce_space = (u64 *)__va(tce_space); } } diff --git a/arch/x86/kernel/pci-iommu_table.c b/arch/x86/kernel/pci-iommu_table.c index 35ccf75..7a15747 100644 --- a/arch/x86/kernel/pci-iommu_table.c +++ b/arch/x86/kernel/pci-iommu_table.c @@ -2,7 +2,7 @@ #include #include #include - +#include #define DEBUG 1 diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c index adf0392..88a7576 100644 --- a/arch/x86/kernel/pci-swiotlb.c +++ b/arch/x86/kernel/pci-swiotlb.c @@ -40,7 +40,7 @@ void x86_swiotlb_free_coherent(struct device *dev, size_t size, struct dma_attrs *attrs) { if (is_swiotlb_buffer(dma_to_phys(dev, dma_addr))) - swiotlb_free_coherent(dev, size, vaddr, dma_addr); + swiotlb_free_coherent(dev, size, vaddr, dma_addr, attrs); else dma_generic_free_coherent(dev, size, vaddr, dma_addr, attrs); } diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 9f7c21c..854f412 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -39,7 +40,8 @@ * section. Since TSS's are completely CPU-local, we want them * on exact cacheline boundaries, to eliminate cacheline ping-pong. */ -__visible DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss) = { +struct tss_struct cpu_tss[NR_CPUS] __visible ____cacheline_internodealigned_in_smp = { + [0 ... NR_CPUS-1] = { .x86_tss = { .sp0 = TOP_OF_INIT_STACK, #ifdef CONFIG_X86_32 @@ -57,6 +59,7 @@ __visible DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss) = { */ .io_bitmap = { [0 ... IO_BITMAP_LONGS] = ~0 }, #endif +} }; EXPORT_PER_CPU_SYMBOL(cpu_tss); @@ -77,13 +80,26 @@ void idle_notifier_unregister(struct notifier_block *n) EXPORT_SYMBOL_GPL(idle_notifier_unregister); #endif +struct kmem_cache *fpregs_state_cachep; +EXPORT_SYMBOL(fpregs_state_cachep); + +void __init arch_task_cache_init(void) +{ + /* create a slab on which task_structs can be allocated */ + fpregs_state_cachep = + kmem_cache_create("fpregs_state", xstate_size, + ARCH_MIN_TASKALIGN, SLAB_PANIC | SLAB_NOTRACK | SLAB_USERCOPY, NULL); +} + /* * this gets called so that we can store lazy state into memory and copy the * current task into the new thread. */ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) { - memcpy(dst, src, arch_task_struct_size); + *dst = *src; + dst->thread.fpu.state = kmem_cache_alloc_node(fpregs_state_cachep, GFP_KERNEL, tsk_fork_get_node(src)); + memcpy(dst->thread.fpu.state, src->thread.fpu.state, xstate_size); #ifdef CONFIG_VM86 dst->thread.vm86 = NULL; #endif @@ -91,6 +107,12 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) return fpu__copy(&dst->thread.fpu, &src->thread.fpu); } +void arch_release_task_struct(struct task_struct *tsk) +{ + kmem_cache_free(fpregs_state_cachep, tsk->thread.fpu.state); + tsk->thread.fpu.state = NULL; +} + /* * Free current thread data structures etc.. */ @@ -102,7 +124,7 @@ void exit_thread(void) struct fpu *fpu = &t->fpu; if (bp) { - struct tss_struct *tss = &per_cpu(cpu_tss, get_cpu()); + struct tss_struct *tss = cpu_tss + get_cpu(); t->io_bitmap_ptr = NULL; clear_thread_flag(TIF_IO_BITMAP); @@ -124,6 +146,9 @@ void flush_thread(void) { struct task_struct *tsk = current; +#if defined(CONFIG_X86_32) && !defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_PAX_MEMORY_UDEREF) + loadsegment(gs, 0); +#endif flush_ptrace_hw_breakpoint(tsk); memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); @@ -265,7 +290,7 @@ static void __exit_idle(void) void exit_idle(void) { /* idle loop has pid 0 */ - if (current->pid) + if (task_pid_nr(current)) return; __exit_idle(); } @@ -318,7 +343,7 @@ bool xen_set_default_idle(void) return ret; } #endif -void stop_this_cpu(void *dummy) +__noreturn void stop_this_cpu(void *dummy) { local_irq_disable(); /* @@ -496,13 +521,6 @@ static int __init idle_setup(char *str) } early_param("idle", idle_setup); -unsigned long arch_align_stack(unsigned long sp) -{ - if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) - sp -= get_random_int() % 8192; - return sp & ~0xf; -} - unsigned long arch_randomize_brk(struct mm_struct *mm) { unsigned long range_end = mm->brk + 0x02000000; @@ -534,9 +552,7 @@ unsigned long get_wchan(struct task_struct *p) * PADDING * ----------- top = topmax - TOP_OF_KERNEL_STACK_PADDING * stack - * ----------- bottom = start + sizeof(thread_info) - * thread_info - * ----------- start + * ----------- bottom = start * * The tasks stack pointer points at the location where the * framepointer is stored. The data on the stack is: @@ -547,7 +563,7 @@ unsigned long get_wchan(struct task_struct *p) */ top = start + THREAD_SIZE - TOP_OF_KERNEL_STACK_PADDING; top -= 2 * sizeof(unsigned long); - bottom = start + sizeof(struct thread_info); + bottom = start; sp = READ_ONCE(p->thread.sp); if (sp < bottom || sp > top) @@ -564,3 +580,35 @@ unsigned long get_wchan(struct task_struct *p) } while (count++ < 16 && p->state != TASK_RUNNING); return 0; } + +#ifdef CONFIG_PAX_RANDKSTACK +void pax_randomize_kstack(struct pt_regs *regs) +{ + struct thread_struct *thread = ¤t->thread; + unsigned long time; + + if (!randomize_va_space) + return; + + if (v8086_mode(regs)) + return; + + time = rdtsc(); + + /* P4 seems to return a 0 LSB, ignore it */ +#ifdef CONFIG_MPENTIUM4 + time &= 0x3EUL; + time <<= 2; +#elif defined(CONFIG_X86_64) + time &= 0xFUL; + time <<= 4; +#else + time &= 0x1FUL; + time <<= 3; +#endif + + thread->sp0 ^= time; + load_sp0(cpu_tss + smp_processor_id(), thread); + this_cpu_write(cpu_current_top_of_stack, thread->sp0); +} +#endif diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 737527b..ebf7a85 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -64,6 +64,7 @@ asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread"); unsigned long thread_saved_pc(struct task_struct *tsk) { return ((unsigned long *)tsk->thread.sp)[3]; +//XXX return tsk->thread.eip; } void __show_regs(struct pt_regs *regs, int all) @@ -76,16 +77,15 @@ void __show_regs(struct pt_regs *regs, int all) if (user_mode(regs)) { sp = regs->sp; ss = regs->ss & 0xffff; - gs = get_user_gs(regs); } else { sp = kernel_stack_pointer(regs); savesegment(ss, ss); - savesegment(gs, gs); } + gs = get_user_gs(regs); printk(KERN_DEFAULT "EIP: %04x:[<%08lx>] EFLAGS: %08lx CPU: %d\n", (u16)regs->cs, regs->ip, regs->flags, - smp_processor_id()); + raw_smp_processor_id()); print_symbol("EIP is at %s\n", regs->ip); printk(KERN_DEFAULT "EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", @@ -132,21 +132,22 @@ void release_thread(struct task_struct *dead_task) int copy_thread_tls(unsigned long clone_flags, unsigned long sp, unsigned long arg, struct task_struct *p, unsigned long tls) { - struct pt_regs *childregs = task_pt_regs(p); + struct pt_regs *childregs = task_stack_page(p) + THREAD_SIZE - sizeof(struct pt_regs) - 8; struct task_struct *tsk; int err; p->thread.sp = (unsigned long) childregs; p->thread.sp0 = (unsigned long) (childregs+1); + p->tinfo.lowest_stack = (unsigned long)task_stack_page(p) + 2 * sizeof(unsigned long); memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); if (unlikely(p->flags & PF_KTHREAD)) { /* kernel thread */ memset(childregs, 0, sizeof(struct pt_regs)); p->thread.ip = (unsigned long) ret_from_kernel_thread; - task_user_gs(p) = __KERNEL_STACK_CANARY; - childregs->ds = __USER_DS; - childregs->es = __USER_DS; + savesegment(gs, childregs->gs); + childregs->ds = __KERNEL_DS; + childregs->es = __KERNEL_DS; childregs->fs = __KERNEL_PERCPU; childregs->bx = sp; /* function */ childregs->bp = arg; @@ -246,7 +247,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) struct fpu *prev_fpu = &prev->fpu; struct fpu *next_fpu = &next->fpu; int cpu = smp_processor_id(); - struct tss_struct *tss = &per_cpu(cpu_tss, cpu); + struct tss_struct *tss = cpu_tss + cpu; fpu_switch_t fpu_switch; /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ @@ -265,6 +266,10 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) */ lazy_save_gs(prev->gs); +#ifdef CONFIG_PAX_MEMORY_UDEREF + __set_fs(task_thread_info(next_p)->addr_limit); +#endif + /* * Load the per-thread Thread-Local Storage descriptor. */ @@ -308,9 +313,9 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) * current_thread_info(). */ load_sp0(tss, next); - this_cpu_write(cpu_current_top_of_stack, - (unsigned long)task_stack_page(next_p) + - THREAD_SIZE); + this_cpu_write(current_task, next_p); + this_cpu_write(current_tinfo, &next_p->tinfo); + this_cpu_write(cpu_current_top_of_stack, next->sp0); /* * Restore %gs if needed (which is common) @@ -320,7 +325,5 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) switch_fpu_finish(next_fpu, fpu_switch); - this_cpu_write(current_task, next_p); - return prev_p; } diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index b35921a..c995d0b 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -159,9 +159,10 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long sp, struct pt_regs *childregs; struct task_struct *me = current; - p->thread.sp0 = (unsigned long)task_stack_page(p) + THREAD_SIZE; + p->thread.sp0 = (unsigned long)task_stack_page(p) + THREAD_SIZE - 16; childregs = task_pt_regs(p); p->thread.sp = (unsigned long) childregs; + p->tinfo.lowest_stack = (unsigned long)task_stack_page(p) + 2 * sizeof(unsigned long); set_tsk_thread_flag(p, TIF_FORK); p->thread.io_bitmap_ptr = NULL; @@ -171,6 +172,8 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long sp, p->thread.fs = p->thread.fsindex ? 0 : me->thread.fs; savesegment(es, p->thread.es); savesegment(ds, p->thread.ds); + savesegment(ss, p->thread.ss); + BUG_ON(p->thread.ss == __UDEREF_KERNEL_DS); memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); if (unlikely(p->flags & PF_KTHREAD)) { @@ -278,7 +281,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) struct fpu *prev_fpu = &prev->fpu; struct fpu *next_fpu = &next->fpu; int cpu = smp_processor_id(); - struct tss_struct *tss = &per_cpu(cpu_tss, cpu); + struct tss_struct *tss = cpu_tss + cpu; unsigned fsindex, gsindex; fpu_switch_t fpu_switch; @@ -329,6 +332,10 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) if (unlikely(next->ds | prev->ds)) loadsegment(ds, next->ds); + savesegment(ss, prev->ss); + if (unlikely(next->ss != prev->ss)) + loadsegment(ss, next->ss); + /* * Switch FS and GS. * @@ -400,6 +407,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) * Switch the PDA and FPU contexts. */ this_cpu_write(current_task, next_p); + this_cpu_write(current_tinfo, &next_p->tinfo); /* * If it were not for PREEMPT_ACTIVE we could guarantee that the @@ -412,6 +420,8 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) /* Reload esp0 and ss1. This changes current_thread_info(). */ load_sp0(tss, next); + this_cpu_write(cpu_current_top_of_stack, next->sp0); + /* * Now maybe reload the debug registers and handle I/O bitmaps */ diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 558f50e..2312c52 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -184,10 +184,10 @@ unsigned long kernel_stack_pointer(struct pt_regs *regs) unsigned long sp = (unsigned long)®s->sp; u32 *prev_esp; - if (context == (sp & ~(THREAD_SIZE - 1))) + if (context == ((sp + 8) & ~(THREAD_SIZE - 1))) return sp; - prev_esp = (u32 *)(context); + prev_esp = *(u32 **)(context); if (prev_esp) return (unsigned long)prev_esp; @@ -444,6 +444,20 @@ static int putreg(struct task_struct *child, if (child->thread.gs != value) return do_arch_prctl(child, ARCH_SET_GS, value); return 0; + + case offsetof(struct user_regs_struct,ip): + /* + * Protect against any attempt to set ip to an + * impossible address. There are dragons lurking if the + * address is noncanonical. (This explicitly allows + * setting ip to TASK_SIZE_MAX, because user code can do + * that all by itself by running off the end of its + * address space. + */ + if (value > TASK_SIZE_MAX) + return -EIO; + break; + #endif } @@ -580,7 +594,7 @@ static void ptrace_triggered(struct perf_event *bp, static unsigned long ptrace_get_dr7(struct perf_event *bp[]) { int i; - int dr7 = 0; + unsigned long dr7 = 0; struct arch_hw_breakpoint *info; for (i = 0; i < HBP_NUM; i++) { @@ -814,7 +828,7 @@ long arch_ptrace(struct task_struct *child, long request, unsigned long addr, unsigned long data) { int ret; - unsigned long __user *datap = (unsigned long __user *)data; + unsigned long __user *datap = (__force unsigned long __user *)data; switch (request) { /* read the word at location addr in the USER area. */ @@ -899,14 +913,14 @@ long arch_ptrace(struct task_struct *child, long request, if ((int) addr < 0) return -EIO; ret = do_get_thread_area(child, addr, - (struct user_desc __user *)data); + (__force struct user_desc __user *) data); break; case PTRACE_SET_THREAD_AREA: if ((int) addr < 0) return -EIO; ret = do_set_thread_area(child, addr, - (struct user_desc __user *)data, 0); + (__force struct user_desc __user *) data, 0); break; #endif @@ -1294,7 +1308,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, #ifdef CONFIG_X86_64 -static struct user_regset x86_64_regsets[] __read_mostly = { +static user_regset_no_const x86_64_regsets[] __read_only = { [REGSET_GENERAL] = { .core_note_type = NT_PRSTATUS, .n = sizeof(struct user_regs_struct) / sizeof(long), @@ -1335,7 +1349,7 @@ static const struct user_regset_view user_x86_64_view = { #endif /* CONFIG_X86_64 */ #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION -static struct user_regset x86_32_regsets[] __read_mostly = { +static user_regset_no_const x86_32_regsets[] __read_only = { [REGSET_GENERAL] = { .core_note_type = NT_PRSTATUS, .n = sizeof(struct user_regs_struct32) / sizeof(u32), @@ -1388,7 +1402,7 @@ static const struct user_regset_view user_x86_32_view = { */ u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS]; -void update_regset_xstate_info(unsigned int size, u64 xstate_mask) +void __init update_regset_xstate_info(unsigned int size, u64 xstate_mask) { #ifdef CONFIG_X86_64 x86_64_regsets[REGSET_XSTATE].n = size / sizeof(u64); @@ -1423,7 +1437,7 @@ static void fill_sigtrap_info(struct task_struct *tsk, memset(info, 0, sizeof(*info)); info->si_signo = SIGTRAP; info->si_code = si_code; - info->si_addr = user_mode(regs) ? (void __user *)regs->ip : NULL; + info->si_addr = user_mode(regs) ? (__force void __user *)regs->ip : NULL; } void user_single_step_siginfo(struct task_struct *tsk, diff --git a/arch/x86/kernel/pvclock.c b/arch/x86/kernel/pvclock.c index 2f355d2..e75ed0a 100644 --- a/arch/x86/kernel/pvclock.c +++ b/arch/x86/kernel/pvclock.c @@ -51,11 +51,11 @@ void pvclock_touch_watchdogs(void) reset_hung_task_detector(); } -static atomic64_t last_value = ATOMIC64_INIT(0); +static atomic64_unchecked_t last_value = ATOMIC64_INIT(0); void pvclock_resume(void) { - atomic64_set(&last_value, 0); + atomic64_set_unchecked(&last_value, 0); } u8 pvclock_read_flags(struct pvclock_vcpu_time_info *src) @@ -105,11 +105,11 @@ cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src) * updating at the same time, and one of them could be slightly behind, * making the assumption that last_value always go forward fail to hold. */ - last = atomic64_read(&last_value); + last = atomic64_read_unchecked(&last_value); do { if (ret < last) return last; - last = atomic64_cmpxchg(&last_value, last, ret); + last = atomic64_cmpxchg_unchecked(&last_value, last, ret); } while (unlikely(last != ret)); return ret; diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 02693dd..33a1546 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -70,6 +70,11 @@ static int __init set_bios_reboot(const struct dmi_system_id *d) void __noreturn machine_real_restart(unsigned int type) { + +#if defined(CONFIG_X86_32) && (defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF)) + struct desc_struct *gdt; +#endif + local_irq_disable(); /* @@ -97,7 +102,29 @@ void __noreturn machine_real_restart(unsigned int type) /* Jump to the identity-mapped low memory code */ #ifdef CONFIG_X86_32 - asm volatile("jmpl *%0" : : + +#if defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) + gdt = get_cpu_gdt_table(smp_processor_id()); + pax_open_kernel(); +#ifdef CONFIG_PAX_MEMORY_UDEREF + gdt[GDT_ENTRY_KERNEL_DS].type = 3; + gdt[GDT_ENTRY_KERNEL_DS].limit = 0xf; + loadsegment(ds, __KERNEL_DS); + loadsegment(es, __KERNEL_DS); + loadsegment(ss, __KERNEL_DS); +#endif +#ifdef CONFIG_PAX_KERNEXEC + gdt[GDT_ENTRY_KERNEL_CS].base0 = 0; + gdt[GDT_ENTRY_KERNEL_CS].base1 = 0; + gdt[GDT_ENTRY_KERNEL_CS].base2 = 0; + gdt[GDT_ENTRY_KERNEL_CS].limit0 = 0xffff; + gdt[GDT_ENTRY_KERNEL_CS].limit = 0xf; + gdt[GDT_ENTRY_KERNEL_CS].g = 1; +#endif + pax_close_kernel(); +#endif + + asm volatile("ljmpl *%0" : : "rm" (real_mode_header->machine_real_restart_asm), "a" (type)); #else @@ -137,7 +164,7 @@ static int __init set_kbd_reboot(const struct dmi_system_id *d) /* * This is a single dmi_table handling all reboot quirks. */ -static struct dmi_system_id __initdata reboot_dmi_table[] = { +static const struct dmi_system_id __initconst reboot_dmi_table[] = { /* Acer */ { /* Handle reboot issue on Acer Aspire one */ @@ -511,7 +538,7 @@ void __attribute__((weak)) mach_reboot_fixups(void) * This means that this function can never return, it can misbehave * by not rebooting properly and hanging. */ -static void native_machine_emergency_restart(void) +static void __noreturn native_machine_emergency_restart(void) { int i; int attempt = 0; @@ -631,13 +658,13 @@ void native_machine_shutdown(void) #endif } -static void __machine_emergency_restart(int emergency) +static void __noreturn __machine_emergency_restart(int emergency) { reboot_emergency = emergency; machine_ops.emergency_restart(); } -static void native_machine_restart(char *__unused) +static void __noreturn native_machine_restart(char *__unused) { pr_notice("machine restart\n"); @@ -646,7 +673,7 @@ static void native_machine_restart(char *__unused) __machine_emergency_restart(0); } -static void native_machine_halt(void) +static void __noreturn native_machine_halt(void) { /* Stop other cpus and apics */ machine_shutdown(); @@ -656,7 +683,7 @@ static void native_machine_halt(void) stop_this_cpu(NULL); } -static void native_machine_power_off(void) +static void __noreturn native_machine_power_off(void) { if (pm_power_off) { if (!reboot_force) @@ -665,9 +692,10 @@ static void native_machine_power_off(void) } /* A fallback in case there is no PM info available */ tboot_shutdown(TB_SHUTDOWN_HALT); + unreachable(); } -struct machine_ops machine_ops = { +struct machine_ops machine_ops __read_only = { .power_off = native_machine_power_off, .shutdown = native_machine_shutdown, .emergency_restart = native_machine_emergency_restart, diff --git a/arch/x86/kernel/reboot_fixups_32.c b/arch/x86/kernel/reboot_fixups_32.c index c8e41e9..64049ef 100644 --- a/arch/x86/kernel/reboot_fixups_32.c +++ b/arch/x86/kernel/reboot_fixups_32.c @@ -57,7 +57,7 @@ struct device_fixup { unsigned int vendor; unsigned int device; void (*reboot_fixup)(struct pci_dev *); -}; +} __do_const; /* * PCI ids solely used for fixups_table go here diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S index 98111b3..73ca125 100644 --- a/arch/x86/kernel/relocate_kernel_64.S +++ b/arch/x86/kernel/relocate_kernel_64.S @@ -96,8 +96,7 @@ relocate_kernel: /* jump to identity mapped page */ addq $(identity_mapped - relocate_kernel), %r8 - pushq %r8 - ret + jmp *%r8 identity_mapped: /* set return address to 0 if not preserving context */ diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 37c8ea8..c0e8efa 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -111,6 +111,7 @@ #include #include #include +#include /* * max_low_pfn_mapped: highest direct mapped pfn under 4GB @@ -206,10 +207,12 @@ EXPORT_SYMBOL(boot_cpu_data); #endif -#if !defined(CONFIG_X86_PAE) || defined(CONFIG_X86_64) -__visible unsigned long mmu_cr4_features; +#ifdef CONFIG_X86_64 +__visible unsigned long mmu_cr4_features __read_only = X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE; +#elif defined(CONFIG_X86_PAE) +__visible unsigned long mmu_cr4_features __read_only = X86_CR4_PAE; #else -__visible unsigned long mmu_cr4_features = X86_CR4_PAE; +__visible unsigned long mmu_cr4_features __read_only; #endif /* Boot loader ID and version as integers, for the benefit of proc_dointvec */ @@ -752,7 +755,7 @@ static void __init trim_bios_range(void) * area (640->1Mb) as ram even though it is not. * take them out. */ - e820_remove_range(BIOS_BEGIN, BIOS_END - BIOS_BEGIN, E820_RAM, 1); + e820_remove_range(ISA_START_ADDRESS, ISA_END_ADDRESS - ISA_START_ADDRESS, E820_RAM, 1); sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); } @@ -760,7 +763,7 @@ static void __init trim_bios_range(void) /* called before trim_bios_range() to spare extra sanitize */ static void __init e820_add_kernel_range(void) { - u64 start = __pa_symbol(_text); + u64 start = __pa_symbol(ktla_ktva((unsigned long)_text)); u64 size = __pa_symbol(_end) - start; /* @@ -841,8 +844,8 @@ dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p) void __init setup_arch(char **cmdline_p) { - memblock_reserve(__pa_symbol(_text), - (unsigned long)__bss_stop - (unsigned long)_text); + memblock_reserve(__pa_symbol(ktla_ktva((unsigned long)_text)), + (unsigned long)__bss_stop - ktla_ktva((unsigned long)_text)); early_reserve_initrd(); @@ -935,16 +938,16 @@ void __init setup_arch(char **cmdline_p) if (!boot_params.hdr.root_flags) root_mountflags &= ~MS_RDONLY; - init_mm.start_code = (unsigned long) _text; - init_mm.end_code = (unsigned long) _etext; - init_mm.end_data = (unsigned long) _edata; + init_mm.start_code = ktla_ktva((unsigned long)_text); + init_mm.end_code = ktla_ktva((unsigned long)_etext); + init_mm.end_data = (unsigned long)_edata; init_mm.brk = _brk_end; mpx_mm_init(&init_mm); - code_resource.start = __pa_symbol(_text); - code_resource.end = __pa_symbol(_etext)-1; - data_resource.start = __pa_symbol(_etext); + code_resource.start = __pa_symbol(ktla_ktva((unsigned long)_text)); + code_resource.end = __pa_symbol(ktla_ktva((unsigned long)_etext))-1; + data_resource.start = __pa_symbol(_sdata); data_resource.end = __pa_symbol(_edata)-1; bss_resource.start = __pa_symbol(__bss_start); bss_resource.end = __pa_symbol(__bss_stop)-1; diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index e4fcb87..9c06c55 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c @@ -21,19 +21,17 @@ #include #include -DEFINE_PER_CPU_READ_MOSTLY(int, cpu_number); +#ifdef CONFIG_SMP +DEFINE_PER_CPU_READ_MOSTLY(unsigned int, cpu_number); EXPORT_PER_CPU_SYMBOL(cpu_number); +#endif -#ifdef CONFIG_X86_64 #define BOOT_PERCPU_OFFSET ((unsigned long)__per_cpu_load) -#else -#define BOOT_PERCPU_OFFSET 0 -#endif DEFINE_PER_CPU_READ_MOSTLY(unsigned long, this_cpu_off) = BOOT_PERCPU_OFFSET; EXPORT_PER_CPU_SYMBOL(this_cpu_off); -unsigned long __per_cpu_offset[NR_CPUS] __read_mostly = { +unsigned long __per_cpu_offset[NR_CPUS] __read_only = { [0 ... NR_CPUS-1] = BOOT_PERCPU_OFFSET, }; EXPORT_SYMBOL(__per_cpu_offset); @@ -66,7 +64,7 @@ static bool __init pcpu_need_numa(void) { #ifdef CONFIG_NEED_MULTIPLE_NODES pg_data_t *last = NULL; - unsigned int cpu; + int cpu; for_each_possible_cpu(cpu) { int node = early_cpu_to_node(cpu); @@ -155,10 +153,10 @@ static inline void setup_percpu_segment(int cpu) { #ifdef CONFIG_X86_32 struct desc_struct gdt; + unsigned long base = per_cpu_offset(cpu); - pack_descriptor(&gdt, per_cpu_offset(cpu), 0xFFFFF, - 0x2 | DESCTYPE_S, 0x8); - gdt.s = 1; + pack_descriptor(&gdt, base, (VMALLOC_END - base - 1) >> PAGE_SHIFT, + 0x83 | DESCTYPE_S, 0xC); write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_PERCPU, &gdt, DESCTYPE_S); #endif @@ -219,6 +217,11 @@ void __init setup_per_cpu_areas(void) /* alrighty, percpu areas up and running */ delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; for_each_possible_cpu(cpu) { +#ifdef CONFIG_CC_STACKPROTECTOR +#ifdef CONFIG_X86_32 + unsigned long canary = per_cpu(stack_canary.canary, cpu); +#endif +#endif per_cpu_offset(cpu) = delta + pcpu_unit_offsets[cpu]; per_cpu(this_cpu_off, cpu) = per_cpu_offset(cpu); per_cpu(cpu_number, cpu) = cpu; @@ -259,6 +262,12 @@ void __init setup_per_cpu_areas(void) */ set_cpu_numa_node(cpu, early_cpu_to_node(cpu)); #endif +#ifdef CONFIG_CC_STACKPROTECTOR +#ifdef CONFIG_X86_32 + if (!cpu) + per_cpu(stack_canary.canary, cpu) = canary; +#endif +#endif /* * Up to this point, the boot CPU has been using .init.data * area. Reload any changed state for the boot CPU. diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index da52e6b..8c18d64 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -189,7 +189,7 @@ static unsigned long align_sigframe(unsigned long sp) * Align the stack pointer according to the i386 ABI, * i.e. so that on function entry ((sp + 4) & 15) == 0. */ - sp = ((sp + 4) & -16ul) - 4; + sp = ((sp - 12) & -16ul) - 4; #else /* !CONFIG_X86_32 */ sp = round_down(sp, 16) - 8; #endif @@ -298,10 +298,9 @@ __setup_frame(int sig, struct ksignal *ksig, sigset_t *set, } if (current->mm->context.vdso) - restorer = current->mm->context.vdso + - selected_vdso32->sym___kernel_sigreturn; + restorer = (void __force_user *)(current->mm->context.vdso + selected_vdso32->sym___kernel_sigreturn); else - restorer = &frame->retcode; + restorer = (void __user *)&frame->retcode; if (ksig->ka.sa.sa_flags & SA_RESTORER) restorer = ksig->ka.sa.sa_restorer; @@ -315,7 +314,7 @@ __setup_frame(int sig, struct ksignal *ksig, sigset_t *set, * reasons and because gdb uses it as a signature to notice * signal handler stack frames. */ - err |= __put_user(*((u64 *)&retcode), (u64 *)frame->retcode); + err |= __put_user(*((u64 *)&retcode), (u64 __user *)frame->retcode); if (err) return -EFAULT; @@ -362,8 +361,10 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig, save_altstack_ex(&frame->uc.uc_stack, regs->sp); /* Set up to return from userspace. */ - restorer = current->mm->context.vdso + - selected_vdso32->sym___kernel_rt_sigreturn; + if (current->mm->context.vdso) + restorer = (void __force_user *)(current->mm->context.vdso + selected_vdso32->sym___kernel_rt_sigreturn); + else + restorer = (void __user *)&frame->retcode; if (ksig->ka.sa.sa_flags & SA_RESTORER) restorer = ksig->ka.sa.sa_restorer; put_user_ex(restorer, &frame->pretcode); @@ -375,7 +376,7 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig, * reasons and because gdb uses it as a signature to notice * signal handler stack frames. */ - put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode); + put_user_ex(*((u64 *)&rt_retcode), (u64 __user *)frame->retcode); } put_user_catch(err); err |= copy_siginfo_to_user(&frame->info, &ksig->info); @@ -611,7 +612,12 @@ setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs) { int usig = ksig->sig; sigset_t *set = sigmask_to_save(); - compat_sigset_t *cset = (compat_sigset_t *) set; + sigset_t sigcopy; + compat_sigset_t *cset; + + sigcopy = *set; + + cset = (compat_sigset_t *) &sigcopy; /* Set up the stack frame */ if (is_ia32_frame()) { @@ -622,7 +628,7 @@ setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs) } else if (is_x32_frame()) { return x32_setup_rt_frame(ksig, cset, regs); } else { - return __setup_rt_frame(ksig->sig, ksig, set, regs); + return __setup_rt_frame(ksig->sig, ksig, &sigcopy, regs); } } diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index 12c8286..aa65d13 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c @@ -336,7 +336,7 @@ static int __init nonmi_ipi_setup(char *str) __setup("nonmi_ipi", nonmi_ipi_setup); -struct smp_ops smp_ops = { +struct smp_ops smp_ops __read_only = { .smp_prepare_boot_cpu = native_smp_prepare_boot_cpu, .smp_prepare_cpus = native_smp_prepare_cpus, .smp_cpus_done = native_smp_cpus_done, diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 892ee2e5..be6b3f6 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -213,14 +213,17 @@ static void notrace start_secondary(void *unused) enable_start_cpu0 = 0; -#ifdef CONFIG_X86_32 + /* otherwise gcc will move up smp_processor_id before the cpu_init */ + barrier(); + /* switch away from the initial page table */ +#ifdef CONFIG_PAX_PER_CPU_PGD + load_cr3(get_cpu_pgd(smp_processor_id(), kernel)); +#else load_cr3(swapper_pg_dir); +#endif __flush_tlb_all(); -#endif - /* otherwise gcc will move up smp_processor_id before the cpu_init */ - barrier(); /* * Check TSC synchronization with the BP: */ @@ -809,16 +812,15 @@ void common_cpu_up(unsigned int cpu, struct task_struct *idle) alternatives_enable_smp(); per_cpu(current_task, cpu) = idle; + per_cpu(current_tinfo, cpu) = &idle->tinfo; #ifdef CONFIG_X86_32 - /* Stack for startup_32 can be just as for start_secondary onwards */ irq_ctx_init(cpu); - per_cpu(cpu_current_top_of_stack, cpu) = - (unsigned long)task_stack_page(idle) + THREAD_SIZE; #else clear_tsk_thread_flag(idle, TIF_FORK); initial_gs = per_cpu_offset(cpu); #endif + per_cpu(cpu_current_top_of_stack, cpu) = (unsigned long)task_stack_page(idle) - 16 + THREAD_SIZE; } /* @@ -839,9 +841,11 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle) unsigned long timeout; idle->thread.sp = (unsigned long) (((struct pt_regs *) - (THREAD_SIZE + task_stack_page(idle))) - 1); + (THREAD_SIZE - 16 + task_stack_page(idle))) - 1); + pax_open_kernel(); early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu); + pax_close_kernel(); initial_code = (unsigned long)start_secondary; stack_start = idle->thread.sp; @@ -989,6 +993,15 @@ int native_cpu_up(unsigned int cpu, struct task_struct *tidle) common_cpu_up(cpu, tidle); +#ifdef CONFIG_PAX_PER_CPU_PGD + clone_pgd_range(get_cpu_pgd(cpu, kernel) + KERNEL_PGD_BOUNDARY, + swapper_pg_dir + KERNEL_PGD_BOUNDARY, + KERNEL_PGD_PTRS); + clone_pgd_range(get_cpu_pgd(cpu, user) + KERNEL_PGD_BOUNDARY, + swapper_pg_dir + KERNEL_PGD_BOUNDARY, + KERNEL_PGD_PTRS); +#endif + /* * We have to walk the irq descriptors to setup the vector * space for the cpu which comes online. Prevent irq diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c index c9a0738..f0ab628 100644 --- a/arch/x86/kernel/step.c +++ b/arch/x86/kernel/step.c @@ -45,7 +45,8 @@ unsigned long convert_ip_to_linear(struct task_struct *child, struct pt_regs *re addr += base; } mutex_unlock(&child->mm->context.lock); - } + } else if (seg == __KERNEL_CS || seg == __KERNEXEC_KERNEL_CS) + addr = ktla_ktva(addr); #endif return addr; @@ -57,6 +58,9 @@ static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs) unsigned char opcode[15]; unsigned long addr = convert_ip_to_linear(child, regs); + if (addr == -EINVAL) + return 0; + copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0); for (i = 0; i < copied; i++) { switch (opcode[i]) { diff --git a/arch/x86/kernel/sys_i386_32.c b/arch/x86/kernel/sys_i386_32.c new file mode 100644 index 0000000..5877189 --- /dev/null +++ b/arch/x86/kernel/sys_i386_32.c @@ -0,0 +1,189 @@ +/* + * This file contains various random system calls that + * have a non-standard calling sequence on the Linux/i386 + * platform. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +int i386_mmap_check(unsigned long addr, unsigned long len, unsigned long flags) +{ + unsigned long pax_task_size = TASK_SIZE; + +#ifdef CONFIG_PAX_SEGMEXEC + if (current->mm->pax_flags & MF_PAX_SEGMEXEC) + pax_task_size = SEGMEXEC_TASK_SIZE; +#endif + + if (flags & MAP_FIXED) + if (len > pax_task_size || addr > pax_task_size - len) + return -EINVAL; + + return 0; +} + +/* + * Align a virtual address to avoid aliasing in the I$ on AMD F15h. + */ +static unsigned long get_align_mask(void) +{ + if (va_align.flags < 0 || !(va_align.flags & ALIGN_VA_32)) + return 0; + + if (!(current->flags & PF_RANDOMIZE)) + return 0; + + return va_align.mask; +} + +unsigned long +arch_get_unmapped_area(struct file *filp, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long flags) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + unsigned long pax_task_size = TASK_SIZE; + struct vm_unmapped_area_info info; + unsigned long offset = gr_rand_threadstack_offset(mm, filp, flags); + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) + pax_task_size = SEGMEXEC_TASK_SIZE; +#endif + + pax_task_size -= PAGE_SIZE; + + if (len > pax_task_size) + return -ENOMEM; + + if (flags & MAP_FIXED) + return addr; + +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + + if (addr) { + addr = PAGE_ALIGN(addr); + if (pax_task_size - len >= addr) { + vma = find_vma(mm, addr); + if (check_heap_stack_gap(vma, addr, len, offset)) + return addr; + } + } + + info.flags = 0; + info.length = len; + info.align_mask = filp ? get_align_mask() : 0; + info.align_offset = pgoff << PAGE_SHIFT; + info.threadstack_offset = offset; + +#ifdef CONFIG_PAX_PAGEEXEC + if (!(__supported_pte_mask & _PAGE_NX) && (mm->pax_flags & MF_PAX_PAGEEXEC) && (flags & MAP_EXECUTABLE)) { + info.low_limit = 0x00110000UL; + info.high_limit = mm->start_code; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + info.low_limit += mm->delta_mmap & 0x03FFF000UL; +#endif + + if (info.low_limit < info.high_limit) { + addr = vm_unmapped_area(&info); + if (!IS_ERR_VALUE(addr)) + return addr; + } + } else +#endif + + info.low_limit = mm->mmap_base; + info.high_limit = pax_task_size; + + return vm_unmapped_area(&info); +} + +unsigned long +arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, + const unsigned long len, const unsigned long pgoff, + const unsigned long flags) +{ + struct vm_area_struct *vma; + struct mm_struct *mm = current->mm; + unsigned long addr = addr0, pax_task_size = TASK_SIZE; + struct vm_unmapped_area_info info; + unsigned long offset = gr_rand_threadstack_offset(mm, filp, flags); + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) + pax_task_size = SEGMEXEC_TASK_SIZE; +#endif + + pax_task_size -= PAGE_SIZE; + + /* requested length too big for entire address space */ + if (len > pax_task_size) + return -ENOMEM; + + if (flags & MAP_FIXED) + return addr; + +#ifdef CONFIG_PAX_PAGEEXEC + if (!(__supported_pte_mask & _PAGE_NX) && (mm->pax_flags & MF_PAX_PAGEEXEC) && (flags & MAP_EXECUTABLE)) + goto bottomup; +#endif + +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + + /* requesting a specific address */ + if (addr) { + addr = PAGE_ALIGN(addr); + if (pax_task_size - len >= addr) { + vma = find_vma(mm, addr); + if (check_heap_stack_gap(vma, addr, len, offset)) + return addr; + } + } + + info.flags = VM_UNMAPPED_AREA_TOPDOWN; + info.length = len; + info.low_limit = PAGE_SIZE; + info.high_limit = mm->mmap_base; + info.align_mask = filp ? get_align_mask() : 0; + info.align_offset = pgoff << PAGE_SHIFT; + info.threadstack_offset = offset; + + addr = vm_unmapped_area(&info); + if (!(addr & ~PAGE_MASK)) + return addr; + VM_BUG_ON(addr != -ENOMEM); + +bottomup: + /* + * A failed mmap() very likely causes application failure, + * so fall back to the bottom-up function here. This scenario + * can happen with large stack limits and large mmap() + * allocations. + */ + return arch_get_unmapped_area(filp, addr0, len, pgoff, flags); +} diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c index 10e0272..b4bb9a7 100644 --- a/arch/x86/kernel/sys_x86_64.c +++ b/arch/x86/kernel/sys_x86_64.c @@ -97,8 +97,8 @@ out: return error; } -static void find_start_end(unsigned long flags, unsigned long *begin, - unsigned long *end) +static void find_start_end(struct mm_struct *mm, unsigned long flags, + unsigned long *begin, unsigned long *end) { if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT)) { unsigned long new_begin; @@ -117,7 +117,7 @@ static void find_start_end(unsigned long flags, unsigned long *begin, *begin = new_begin; } } else { - *begin = current->mm->mmap_legacy_base; + *begin = mm->mmap_legacy_base; *end = TASK_SIZE; } } @@ -130,20 +130,24 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, struct vm_area_struct *vma; struct vm_unmapped_area_info info; unsigned long begin, end; + unsigned long offset = gr_rand_threadstack_offset(mm, filp, flags); if (flags & MAP_FIXED) return addr; - find_start_end(flags, &begin, &end); + find_start_end(mm, flags, &begin, &end); if (len > end) return -ENOMEM; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + if (addr) { addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (end - len >= addr && - (!vma || addr + len <= vma->vm_start)) + if (end - len >= addr && check_heap_stack_gap(vma, addr, len, offset)) return addr; } @@ -157,6 +161,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, info.align_mask = get_align_mask(); info.align_offset += get_align_bits(); } + info.threadstack_offset = offset; return vm_unmapped_area(&info); } @@ -169,6 +174,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, struct mm_struct *mm = current->mm; unsigned long addr = addr0; struct vm_unmapped_area_info info; + unsigned long offset = gr_rand_threadstack_offset(mm, filp, flags); /* requested length too big for entire address space */ if (len > TASK_SIZE) @@ -181,12 +187,15 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT)) goto bottomup; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + /* requesting a specific address */ if (addr) { addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + if (TASK_SIZE - len >= addr && check_heap_stack_gap(vma, addr, len, offset)) return addr; } @@ -200,6 +209,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, info.align_mask = get_align_mask(); info.align_offset += get_align_bits(); } + info.threadstack_offset = offset; addr = vm_unmapped_area(&info); if (!(addr & ~PAGE_MASK)) return addr; diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c index 91a4496..6414b5c 100644 --- a/arch/x86/kernel/tboot.c +++ b/arch/x86/kernel/tboot.c @@ -44,6 +44,7 @@ #include #include #include +#include #include "../realmode/rm/wakeup.h" @@ -151,6 +152,10 @@ static int map_tboot_pages(unsigned long vaddr, unsigned long start_pfn, if (!tboot_pg_dir) return -1; + clone_pgd_range(tboot_pg_dir + KERNEL_PGD_BOUNDARY, + swapper_pg_dir + KERNEL_PGD_BOUNDARY, + KERNEL_PGD_PTRS); + for (; nr > 0; nr--, vaddr += PAGE_SIZE, start_pfn++) { if (map_tboot_page(vaddr, start_pfn, PAGE_KERNEL_EXEC)) return -1; @@ -221,8 +226,6 @@ static int tboot_setup_sleep(void) void tboot_shutdown(u32 shutdown_type) { - void (*shutdown)(void); - if (!tboot_enabled()) return; @@ -242,9 +245,12 @@ void tboot_shutdown(u32 shutdown_type) tboot->shutdown_type = shutdown_type; switch_to_tboot_pt(); + __write_cr4(__read_cr4() & ~X86_CR4_PCIDE); - shutdown = (void(*)(void))(unsigned long)tboot->shutdown_entry; - shutdown(); + /* + * PaX: can't be a C indirect function call due to KERNEXEC + */ + asm volatile("jmp *%0" : : "r"((unsigned long)tboot->shutdown_entry)); /* should not reach here */ while (1) @@ -310,7 +316,7 @@ static int tboot_extended_sleep(u8 sleep_state, u32 val_a, u32 val_b) return -ENODEV; } -static atomic_t ap_wfs_count; +static atomic_unchecked_t ap_wfs_count; static int tboot_wait_for_aps(int num_aps) { @@ -334,9 +340,9 @@ static int tboot_cpu_callback(struct notifier_block *nfb, unsigned long action, { switch (action) { case CPU_DYING: - atomic_inc(&ap_wfs_count); + atomic_inc_unchecked(&ap_wfs_count); if (num_online_cpus() == 1) - if (tboot_wait_for_aps(atomic_read(&ap_wfs_count))) + if (tboot_wait_for_aps(atomic_read_unchecked(&ap_wfs_count))) return NOTIFY_BAD; break; } @@ -422,7 +428,7 @@ static __init int tboot_late_init(void) tboot_create_trampoline(); - atomic_set(&ap_wfs_count, 0); + atomic_set_unchecked(&ap_wfs_count, 0); register_hotcpu_notifier(&tboot_cpu_notifier); #ifdef CONFIG_DEBUG_FS diff --git a/arch/x86/kernel/time.c b/arch/x86/kernel/time.c index d39c091..1df4349 100644 --- a/arch/x86/kernel/time.c +++ b/arch/x86/kernel/time.c @@ -32,7 +32,7 @@ unsigned long profile_pc(struct pt_regs *regs) if (!user_mode(regs) && in_lock_functions(pc)) { #ifdef CONFIG_FRAME_POINTER - return *(unsigned long *)(regs->bp + sizeof(long)); + return ktla_ktva(*(unsigned long *)(regs->bp + sizeof(long))); #else unsigned long *sp = (unsigned long *)kernel_stack_pointer(regs); @@ -41,11 +41,17 @@ unsigned long profile_pc(struct pt_regs *regs) * or above a saved flags. Eflags has bits 22-31 zero, * kernel addresses don't. */ + +#ifdef CONFIG_PAX_KERNEXEC + return ktla_ktva(sp[0]); +#else if (sp[0] >> 22) return sp[0]; if (sp[1] >> 22) return sp[1]; #endif + +#endif } return pc; } diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c index 7fc5e84..c6e445a 100644 --- a/arch/x86/kernel/tls.c +++ b/arch/x86/kernel/tls.c @@ -139,6 +139,11 @@ int do_set_thread_area(struct task_struct *p, int idx, if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) return -EINVAL; +#ifdef CONFIG_PAX_SEGMEXEC + if ((p->mm->pax_flags & MF_PAX_SEGMEXEC) && (info.contents & MODIFY_LDT_CONTENTS_CODE)) + return -EINVAL; +#endif + set_tls_desc(p, idx, &info, 1); return 0; @@ -256,7 +261,7 @@ int regset_tls_set(struct task_struct *target, const struct user_regset *regset, if (kbuf) info = kbuf; - else if (__copy_from_user(infobuf, ubuf, count)) + else if (count > sizeof infobuf || __copy_from_user(infobuf, ubuf, count)) return -EFAULT; else info = infobuf; diff --git a/arch/x86/kernel/tracepoint.c b/arch/x86/kernel/tracepoint.c index 1c113db..287b42e 100644 --- a/arch/x86/kernel/tracepoint.c +++ b/arch/x86/kernel/tracepoint.c @@ -9,11 +9,11 @@ #include atomic_t trace_idt_ctr = ATOMIC_INIT(0); -struct desc_ptr trace_idt_descr = { NR_VECTORS * 16 - 1, +const struct desc_ptr trace_idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) trace_idt_table }; /* No need to be aligned, but done to keep all IDTs defined the same way. */ -gate_desc trace_idt_table[NR_VECTORS] __page_aligned_bss; +gate_desc trace_idt_table[NR_VECTORS] __page_aligned_rodata; static int trace_irq_vector_refcount; static DEFINE_MUTEX(irq_vector_mutex); diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 346eec7..d98e7a6 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -70,7 +70,7 @@ #include /* No need to be aligned, but done to keep all IDTs defined the same way. */ -gate_desc debug_idt_table[NR_VECTORS] __page_aligned_bss; +gate_desc debug_idt_table[NR_VECTORS] __page_aligned_rodata; #else #include #include @@ -78,7 +78,7 @@ gate_desc debug_idt_table[NR_VECTORS] __page_aligned_bss; #endif /* Must be page-aligned because the real IDT is used in a fixmap. */ -gate_desc idt_table[NR_VECTORS] __page_aligned_bss; +gate_desc idt_table[NR_VECTORS] __page_aligned_rodata; DECLARE_BITMAP(used_vectors, NR_VECTORS); EXPORT_SYMBOL_GPL(used_vectors); @@ -165,7 +165,7 @@ void ist_begin_non_atomic(struct pt_regs *regs) * will catch asm bugs and any attempt to use ist_preempt_enable * from double_fault. */ - BUG_ON((unsigned long)(current_top_of_stack() - + BUG_ON((unsigned long)(current_top_of_stack(smp_processor_id()) - current_stack_pointer()) >= THREAD_SIZE); preempt_count_sub(HARDIRQ_OFFSET); @@ -182,7 +182,7 @@ void ist_end_non_atomic(void) } static nokprobe_inline int -do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str, +do_trap_no_signal(struct task_struct *tsk, int trapnr, const char *str, struct pt_regs *regs, long error_code) { if (v8086_mode(regs)) { @@ -202,8 +202,20 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str, if (!fixup_exception(regs)) { tsk->thread.error_code = error_code; tsk->thread.trap_nr = trapnr; + +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) + if (trapnr == X86_TRAP_SS && ((regs->cs & 0xFFFF) == __KERNEL_CS || (regs->cs & 0xFFFF) == __KERNEXEC_KERNEL_CS)) + str = "PAX: suspicious stack segment fault"; +#endif + die(str, regs, error_code); } + +#ifdef CONFIG_PAX_REFCOUNT + if (trapnr == X86_TRAP_OF) + pax_report_refcount_overflow(regs); +#endif + return 0; } @@ -242,7 +254,7 @@ static siginfo_t *fill_trap_info(struct pt_regs *regs, int signr, int trapnr, } static void -do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, +do_trap(int trapnr, int signr, const char *str, struct pt_regs *regs, long error_code, siginfo_t *info) { struct task_struct *tsk = current; @@ -266,7 +278,7 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, if (show_unhandled_signals && unhandled_signal(tsk, signr) && printk_ratelimit()) { pr_info("%s[%d] trap %s ip:%lx sp:%lx error:%lx", - tsk->comm, tsk->pid, str, + tsk->comm, task_pid_nr(tsk), str, regs->ip, regs->sp, error_code); print_vma_addr(" in ", regs->ip); pr_cont("\n"); @@ -347,6 +359,11 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) tsk->thread.error_code = error_code; tsk->thread.trap_nr = X86_TRAP_DF; +#ifdef CONFIG_GRKERNSEC_KSTACKOVERFLOW + if ((unsigned long)tsk->stack - regs->sp <= PAGE_SIZE) + die("grsec: kernel stack overflow detected", regs, error_code); +#endif + #ifdef CONFIG_DOUBLEFAULT df_debug(regs, error_code); #endif @@ -459,11 +476,35 @@ do_general_protection(struct pt_regs *regs, long error_code) tsk->thread.error_code = error_code; tsk->thread.trap_nr = X86_TRAP_GP; if (notify_die(DIE_GPF, "general protection fault", regs, error_code, - X86_TRAP_GP, SIGSEGV) != NOTIFY_STOP) + X86_TRAP_GP, SIGSEGV) != NOTIFY_STOP) { + +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) + if ((regs->cs & 0xFFFF) == __KERNEL_CS || (regs->cs & 0xFFFF) == __KERNEXEC_KERNEL_CS) + die("PAX: suspicious general protection fault", regs, error_code); + else +#endif + die("general protection fault", regs, error_code); + } return; } +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_PAGEEXEC) + if (!(__supported_pte_mask & _PAGE_NX) && tsk->mm && (tsk->mm->pax_flags & MF_PAX_PAGEEXEC)) { + struct mm_struct *mm = tsk->mm; + unsigned long limit; + + down_write(&mm->mmap_sem); + limit = mm->context.user_cs_limit; + if (limit < TASK_SIZE) { + track_exec_limit(mm, limit, TASK_SIZE, VM_EXEC); + up_write(&mm->mmap_sem); + return; + } + up_write(&mm->mmap_sem); + } +#endif + tsk->thread.error_code = error_code; tsk->thread.trap_nr = X86_TRAP_GP; @@ -559,6 +600,9 @@ struct bad_iret_stack *fixup_bad_iret(struct bad_iret_stack *s) container_of(task_pt_regs(current), struct bad_iret_stack, regs); + if ((current->thread.sp0 ^ (unsigned long)s) < THREAD_SIZE) + new_stack = s; + /* Copy the IRET target to the new stack. */ memmove(&new_stack->regs.ip, (void *)s->regs.sp, 5*8); diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index c3f7602..f6033e1 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -151,7 +151,7 @@ static void cyc2ns_write_end(int cpu, struct cyc2ns_data *data) */ smp_wmb(); - ACCESS_ONCE(c2n->head) = data; + ACCESS_ONCE_RW(c2n->head) = data; } /* diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index bf4db6e..d491400 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c @@ -978,7 +978,7 @@ arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs if (nleft != rasize) { pr_err("uprobe: return address clobbered: pid=%d, %%sp=%#lx, " - "%%ip=%#lx\n", current->pid, regs->sp, regs->ip); + "%%ip=%#lx\n", task_pid_nr(current), regs->sp, regs->ip); force_sig_info(SIGSEGV, SEND_SIG_FORCED, current); } diff --git a/arch/x86/kernel/verify_cpu.S b/arch/x86/kernel/verify_cpu.S index 4cf401f..ae8c9cf 100644 --- a/arch/x86/kernel/verify_cpu.S +++ b/arch/x86/kernel/verify_cpu.S @@ -20,6 +20,7 @@ * arch/x86/boot/compressed/head_64.S: Boot cpu verification * arch/x86/kernel/trampoline_64.S: secondary processor verification * arch/x86/kernel/head_32.S: processor startup + * arch/x86/kernel/acpi/realmode/wakeup.S: 32bit processor resume * * verify_cpu, returns the status of longmode and SSE in register %eax. * 0: Success 1: Failure diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index 5246193..c6bed42 100644 --- a/arch/x86/kernel/vm86_32.c +++ b/arch/x86/kernel/vm86_32.c @@ -144,7 +144,7 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval) do_exit(SIGSEGV); } - tss = &per_cpu(cpu_tss, get_cpu()); + tss = cpu_tss + get_cpu(); tsk->thread.sp0 = vm86->saved_sp0; tsk->thread.sysenter_cs = __KERNEL_CS; load_sp0(tss, &tsk->thread); @@ -259,6 +259,13 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus) return -EPERM; } +#ifdef CONFIG_GRKERNSEC_VM86 + if (!capable(CAP_SYS_RAWIO)) { + gr_handle_vm86(); + return -EPERM; + } +#endif + if (!vm86) { if (!(vm86 = kzalloc(sizeof(*vm86), GFP_KERNEL))) return -ENOMEM; @@ -354,7 +361,7 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus) vm86->saved_sp0 = tsk->thread.sp0; lazy_save_gs(vm86->regs32.gs); - tss = &per_cpu(cpu_tss, get_cpu()); + tss = cpu_tss + get_cpu(); /* make room for real-mode segments */ tsk->thread.sp0 += 16; if (cpu_has_sep) @@ -535,7 +542,7 @@ static void do_int(struct kernel_vm86_regs *regs, int i, goto cannot_handle; if (i == 0x21 && is_revectored(AH(regs), &vm86->int21_revectored)) goto cannot_handle; - intr_ptr = (unsigned long __user *) (i << 2); + intr_ptr = (unsigned long __force_user *) (i << 2); if (get_user(segoffs, intr_ptr)) goto cannot_handle; if ((segoffs >> 16) == BIOSSEG) @@ -828,6 +835,14 @@ static inline int get_and_reset_irq(int irqnumber) static int do_vm86_irq_handling(int subfunction, int irqnumber) { int ret; + +#ifdef CONFIG_GRKERNSEC_VM86 + if (!capable(CAP_SYS_RAWIO)) { + gr_handle_vm86(); + return -EPERM; + } +#endif + switch (subfunction) { case VM86_GET_AND_RESET_IRQ: { return get_and_reset_irq(irqnumber); diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 74e4bf1..a9a6168 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -26,6 +26,13 @@ #include #include #include +#include + +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) +#define __KERNEL_TEXT_OFFSET (LOAD_OFFSET + ____LOAD_PHYSICAL_ADDR) +#else +#define __KERNEL_TEXT_OFFSET 0 +#endif #undef i386 /* in case the preprocessor is a 32bit one */ @@ -69,30 +76,43 @@ jiffies_64 = jiffies; PHDRS { text PT_LOAD FLAGS(5); /* R_E */ +#ifdef CONFIG_X86_32 + module PT_LOAD FLAGS(5); /* R_E */ +#endif +#ifdef CONFIG_XEN + rodata PT_LOAD FLAGS(5); /* R_E */ +#else + rodata PT_LOAD FLAGS(4); /* R__ */ +#endif data PT_LOAD FLAGS(6); /* RW_ */ -#ifdef CONFIG_X86_64 + init.begin PT_LOAD FLAGS(6); /* RW_ */ #ifdef CONFIG_SMP percpu PT_LOAD FLAGS(6); /* RW_ */ #endif - init PT_LOAD FLAGS(7); /* RWE */ -#endif + text.init PT_LOAD FLAGS(5); /* R_E */ + text.exit PT_LOAD FLAGS(5); /* R_E */ + init PT_LOAD FLAGS(6); /* RW_ */ note PT_NOTE FLAGS(0); /* ___ */ } SECTIONS { #ifdef CONFIG_X86_32 - . = LOAD_OFFSET + LOAD_PHYSICAL_ADDR; - phys_startup_32 = startup_32 - LOAD_OFFSET; + . = LOAD_OFFSET + ____LOAD_PHYSICAL_ADDR; #else - . = __START_KERNEL; - phys_startup_64 = startup_64 - LOAD_OFFSET; + . = __START_KERNEL; #endif /* Text and read-only data */ - .text : AT(ADDR(.text) - LOAD_OFFSET) { - _text = .; + .text (. - __KERNEL_TEXT_OFFSET): AT(ADDR(.text) - LOAD_OFFSET + __KERNEL_TEXT_OFFSET) { /* bootstrapping code */ +#ifdef CONFIG_X86_32 + phys_startup_32 = startup_32 - LOAD_OFFSET + __KERNEL_TEXT_OFFSET; +#else + phys_startup_64 = startup_64 - LOAD_OFFSET + __KERNEL_TEXT_OFFSET; +#endif + __LOAD_PHYSICAL_ADDR = . - LOAD_OFFSET + __KERNEL_TEXT_OFFSET; + _text = .; HEAD_TEXT . = ALIGN(8); _stext = .; @@ -104,13 +124,47 @@ SECTIONS IRQENTRY_TEXT *(.fixup) *(.gnu.warning) - /* End of text section */ - _etext = .; } :text = 0x9090 - NOTES :text :note + . += __KERNEL_TEXT_OFFSET; - EXCEPTION_TABLE(16) :text = 0x9090 +#ifdef CONFIG_X86_32 + . = ALIGN(PAGE_SIZE); + .module.text : AT(ADDR(.module.text) - LOAD_OFFSET) { + +#ifdef CONFIG_PAX_KERNEXEC + MODULES_EXEC_VADDR = .; + BYTE(0) + . += (CONFIG_PAX_KERNEXEC_MODULE_TEXT * 1024 * 1024); + . = ALIGN(HPAGE_SIZE) - 1; + MODULES_EXEC_END = .; +#endif + + } :module +#endif + + .text.end : AT(ADDR(.text.end) - LOAD_OFFSET) { + /* End of text section */ + BYTE(0) + _etext = . - __KERNEL_TEXT_OFFSET; + } + +#ifdef CONFIG_X86_32 + . = ALIGN(PAGE_SIZE); + .rodata.page_aligned : AT(ADDR(.rodata.page_aligned) - LOAD_OFFSET) { + . = ALIGN(PAGE_SIZE); + *(.empty_zero_page) + *(.initial_pg_fixmap) + *(.initial_pg_pmd) + *(.initial_page_table) + *(.swapper_pg_dir) + } :rodata +#endif + + . = ALIGN(PAGE_SIZE); + NOTES :rodata :note + + EXCEPTION_TABLE(16) :rodata #if defined(CONFIG_DEBUG_RODATA) /* .text should occupy whole number of pages */ @@ -122,16 +176,20 @@ SECTIONS /* Data */ .data : AT(ADDR(.data) - LOAD_OFFSET) { + +#ifdef CONFIG_PAX_KERNEXEC + . = ALIGN(HPAGE_SIZE); +#else + . = ALIGN(PAGE_SIZE); +#endif + /* Start of data section */ _sdata = .; /* init_task */ INIT_TASK_DATA(THREAD_SIZE) -#ifdef CONFIG_X86_32 - /* 32 bit has nosave before _edata */ NOSAVE_DATA -#endif PAGE_ALIGNED_DATA(PAGE_SIZE) @@ -174,12 +232,19 @@ SECTIONS . = ALIGN(__vvar_page + PAGE_SIZE, PAGE_SIZE); /* Init code and data - will be freed after init */ - . = ALIGN(PAGE_SIZE); .init.begin : AT(ADDR(.init.begin) - LOAD_OFFSET) { + BYTE(0) + +#ifdef CONFIG_PAX_KERNEXEC + . = ALIGN(HPAGE_SIZE); +#else + . = ALIGN(PAGE_SIZE); +#endif + __init_begin = .; /* paired with __init_end */ - } + } :init.begin -#if defined(CONFIG_X86_64) && defined(CONFIG_SMP) +#ifdef CONFIG_SMP /* * percpu offsets are zero-based on SMP. PERCPU_VADDR() changes the * output PHDR, so the next output section - .init.text - should @@ -190,12 +255,33 @@ SECTIONS "per-CPU data too large - increase CONFIG_PHYSICAL_START") #endif - INIT_TEXT_SECTION(PAGE_SIZE) -#ifdef CONFIG_X86_64 - :init + . = ALIGN(PAGE_SIZE); + init_begin = .; + .init.text (. - __KERNEL_TEXT_OFFSET): AT(init_begin - LOAD_OFFSET) { + VMLINUX_SYMBOL(_sinittext) = .; + INIT_TEXT + . = ALIGN(PAGE_SIZE); + } :text.init + + /* + * .exit.text is discard at runtime, not link time, to deal with + * references from .altinstructions and .eh_frame + */ + .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET + __KERNEL_TEXT_OFFSET) { + EXIT_TEXT + VMLINUX_SYMBOL(_einittext) = .; + +#ifdef CONFIG_PAX_KERNEXEC + . = ALIGN(HPAGE_SIZE); +#else + . = ALIGN(16); #endif - INIT_DATA_SECTION(16) + } :text.exit + . = init_begin + SIZEOF(.init.text) + SIZEOF(.exit.text); + + . = ALIGN(PAGE_SIZE); + INIT_DATA_SECTION(16) :init .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) { __x86_cpu_dev_start = .; @@ -266,19 +352,12 @@ SECTIONS } . = ALIGN(8); - /* - * .exit.text is discard at runtime, not link time, to deal with - * references from .altinstructions and .eh_frame - */ - .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { - EXIT_TEXT - } .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { EXIT_DATA } -#if !defined(CONFIG_X86_64) || !defined(CONFIG_SMP) +#ifndef CONFIG_SMP PERCPU_SECTION(INTERNODE_CACHE_BYTES) #endif @@ -297,16 +376,10 @@ SECTIONS .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) { __smp_locks = .; *(.smp_locks) - . = ALIGN(PAGE_SIZE); __smp_locks_end = .; + . = ALIGN(PAGE_SIZE); } -#ifdef CONFIG_X86_64 - .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { - NOSAVE_DATA - } -#endif - /* BSS */ . = ALIGN(PAGE_SIZE); .bss : AT(ADDR(.bss) - LOAD_OFFSET) { @@ -322,6 +395,7 @@ SECTIONS __brk_base = .; . += 64 * 1024; /* 64k alignment slop space */ *(.brk_reservation) /* areas brk users have reserved */ + . = ALIGN(HPAGE_SIZE); __brk_limit = .; } @@ -348,13 +422,12 @@ SECTIONS * for the boot processor. */ #define INIT_PER_CPU(x) init_per_cpu__##x = x + __per_cpu_load -INIT_PER_CPU(gdt_page); INIT_PER_CPU(irq_stack_union); /* * Build-time check on the image size: */ -. = ASSERT((_end - _text <= KERNEL_IMAGE_SIZE), +. = ASSERT((_end - _text - __KERNEL_TEXT_OFFSET <= KERNEL_IMAGE_SIZE), "kernel image bigger than KERNEL_IMAGE_SIZE"); #ifdef CONFIG_SMP diff --git a/arch/x86/kernel/x8664_ksyms_64.c b/arch/x86/kernel/x8664_ksyms_64.c index a0695be..33e180c 100644 --- a/arch/x86/kernel/x8664_ksyms_64.c +++ b/arch/x86/kernel/x8664_ksyms_64.c @@ -34,8 +34,6 @@ EXPORT_SYMBOL(copy_user_generic_string); EXPORT_SYMBOL(copy_user_generic_unrolled); EXPORT_SYMBOL(copy_user_enhanced_fast_string); EXPORT_SYMBOL(__copy_user_nocache); -EXPORT_SYMBOL(_copy_from_user); -EXPORT_SYMBOL(_copy_to_user); EXPORT_SYMBOL(copy_page); EXPORT_SYMBOL(clear_page); @@ -77,3 +75,7 @@ EXPORT_SYMBOL(native_load_gs_index); EXPORT_SYMBOL(___preempt_schedule); EXPORT_SYMBOL(___preempt_schedule_notrace); #endif + +#ifdef CONFIG_PAX_PER_CPU_PGD +EXPORT_SYMBOL(cpu_pgd); +#endif diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index 3839628..2e5b5b35 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c @@ -92,7 +92,7 @@ struct x86_cpuinit_ops x86_cpuinit = { static void default_nmi_init(void) { }; static int default_i8042_detect(void) { return 1; }; -struct x86_platform_ops x86_platform = { +struct x86_platform_ops x86_platform __read_only = { .calibrate_tsc = native_calibrate_tsc, .get_wallclock = mach_get_cmos_time, .set_wallclock = mach_set_rtc_mmss, @@ -108,7 +108,7 @@ struct x86_platform_ops x86_platform = { EXPORT_SYMBOL_GPL(x86_platform); #if defined(CONFIG_PCI_MSI) -struct x86_msi_ops x86_msi = { +struct x86_msi_ops x86_msi __read_only = { .setup_msi_irqs = native_setup_msi_irqs, .teardown_msi_irq = native_teardown_msi_irq, .teardown_msi_irqs = default_teardown_msi_irqs, @@ -137,7 +137,7 @@ void arch_restore_msi_irqs(struct pci_dev *dev) } #endif -struct x86_io_apic_ops x86_io_apic_ops = { +struct x86_io_apic_ops x86_io_apic_ops __read_only = { .read = native_io_apic_read, .disable = native_disable_io_apic, }; diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 2fbea25..9e0f8c7 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -206,15 +206,20 @@ int kvm_vcpu_ioctl_set_cpuid2(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid, struct kvm_cpuid_entry2 __user *entries) { - int r; + int r, i; r = -E2BIG; if (cpuid->nent > KVM_MAX_CPUID_ENTRIES) goto out; r = -EFAULT; - if (copy_from_user(&vcpu->arch.cpuid_entries, entries, - cpuid->nent * sizeof(struct kvm_cpuid_entry2))) + if (!access_ok(VERIFY_READ, entries, cpuid->nent * sizeof(struct kvm_cpuid_entry2))) goto out; + for (i = 0; i < cpuid->nent; ++i) { + struct kvm_cpuid_entry2 cpuid_entry; + if (__copy_from_user(&cpuid_entry, entries + i, sizeof(cpuid_entry))) + goto out; + vcpu->arch.cpuid_entries[i] = cpuid_entry; + } vcpu->arch.cpuid_nent = cpuid->nent; kvm_apic_set_version(vcpu); kvm_x86_ops->cpuid_update(vcpu); @@ -227,15 +232,19 @@ int kvm_vcpu_ioctl_get_cpuid2(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid, struct kvm_cpuid_entry2 __user *entries) { - int r; + int r, i; r = -E2BIG; if (cpuid->nent < vcpu->arch.cpuid_nent) goto out; r = -EFAULT; - if (copy_to_user(entries, &vcpu->arch.cpuid_entries, - vcpu->arch.cpuid_nent * sizeof(struct kvm_cpuid_entry2))) + if (!access_ok(VERIFY_WRITE, entries, vcpu->arch.cpuid_nent * sizeof(struct kvm_cpuid_entry2))) goto out; + for (i = 0; i < vcpu->arch.cpuid_nent; ++i) { + struct kvm_cpuid_entry2 cpuid_entry = vcpu->arch.cpuid_entries[i]; + if (__copy_to_user(entries + i, &cpuid_entry, sizeof(cpuid_entry))) + goto out; + } return 0; out: diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 1505587..0f0516c 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -1881,7 +1881,7 @@ static int em_push_sreg(struct x86_emulate_ctxt *ctxt) static int em_pop_sreg(struct x86_emulate_ctxt *ctxt) { int seg = ctxt->src2.val; - unsigned long selector; + u16 selector; int rc; rc = emulate_pop(ctxt, &selector, 2); @@ -1893,7 +1893,7 @@ static int em_pop_sreg(struct x86_emulate_ctxt *ctxt) if (ctxt->op_bytes > 2) rsp_increment(ctxt, ctxt->op_bytes - 2); - rc = load_segment_descriptor(ctxt, (u16)selector, seg); + rc = load_segment_descriptor(ctxt, selector, seg); return rc; } @@ -3870,7 +3870,7 @@ static int check_cr_write(struct x86_emulate_ctxt *ctxt) int cr = ctxt->modrm_reg; u64 efer = 0; - static u64 cr_reserved_bits[] = { + static const u64 cr_reserved_bits[] = { 0xffffffff00000000ULL, 0, 0, 0, /* CR3 checked later */ CR4_RESERVED_BITS, diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c index 7cc2360..6ae1236 100644 --- a/arch/x86/kvm/i8259.c +++ b/arch/x86/kvm/i8259.c @@ -39,14 +39,14 @@ static void pic_irq_request(struct kvm *kvm, int level); +static void pic_lock(struct kvm_pic *s) __acquires(&s->lock); static void pic_lock(struct kvm_pic *s) - __acquires(&s->lock) { spin_lock(&s->lock); } +static void pic_unlock(struct kvm_pic *s) __releases(&s->lock); static void pic_unlock(struct kvm_pic *s) - __releases(&s->lock) { bool wakeup = s->wakeup_needed; struct kvm_vcpu *vcpu, *found = NULL; @@ -72,6 +72,7 @@ static void pic_unlock(struct kvm_pic *s) } } +static void pic_clear_isr(struct kvm_kpic_state *s, int irq) __must_hold(s->pics_state); static void pic_clear_isr(struct kvm_kpic_state *s, int irq) { s->isr &= ~(1 << irq); @@ -219,6 +220,7 @@ void kvm_pic_clear_all(struct kvm_pic *s, int irq_source_id) /* * acknowledge interrupt 'irq' */ +static inline void pic_intack(struct kvm_kpic_state *s, int irq) __must_hold(s); static inline void pic_intack(struct kvm_kpic_state *s, int irq) { s->isr |= 1 << irq; @@ -273,6 +275,7 @@ int kvm_pic_read_irq(struct kvm *kvm) return intno; } +void kvm_pic_reset(struct kvm_kpic_state *s) __must_hold(s); void kvm_pic_reset(struct kvm_kpic_state *s) { int irq, i; @@ -307,6 +310,7 @@ void kvm_pic_reset(struct kvm_kpic_state *s) pic_clear_isr(s, irq); } +static void pic_ioport_write(void *opaque, u32 addr, u32 val) __must_hold(opaque); static void pic_ioport_write(void *opaque, u32 addr, u32 val) { struct kvm_kpic_state *s = opaque; @@ -400,6 +404,7 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val) } } +static u32 pic_poll_read(struct kvm_kpic_state *s, u32 addr1) __must_hold(s); static u32 pic_poll_read(struct kvm_kpic_state *s, u32 addr1) { int ret; @@ -422,6 +427,7 @@ static u32 pic_poll_read(struct kvm_kpic_state *s, u32 addr1) return ret; } +static u32 pic_ioport_read(void *opaque, u32 addr1) __must_hold(opaque); static u32 pic_ioport_read(void *opaque, u32 addr1) { struct kvm_kpic_state *s = opaque; diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c index 856f791..bfc7694 100644 --- a/arch/x86/kvm/ioapic.c +++ b/arch/x86/kvm/ioapic.c @@ -422,6 +422,8 @@ static void kvm_ioapic_eoi_inject_work(struct work_struct *work) #define IOAPIC_SUCCESSIVE_IRQ_MAX_COUNT 10000 static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, + struct kvm_ioapic *ioapic, int vector, int trigger_mode) __must_hold(&ioapic->lock); +static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, struct kvm_ioapic *ioapic, int vector, int trigger_mode) { int i; diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index ae4483a..0eac8a1 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -56,7 +56,7 @@ #define APIC_BUS_CYCLE_NS 1 /* #define apic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */ -#define apic_debug(fmt, arg...) +#define apic_debug(fmt, arg...) do {} while (0) #define APIC_LVT_NUM 6 /* 14 is the version for Xeon and Pentium 8.4.8*/ diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 736e6ab..b2e3094 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -335,7 +335,7 @@ retry_walk: if (unlikely(kvm_is_error_hva(host_addr))) goto error; - ptep_user = (pt_element_t __user *)((void *)host_addr + offset); + ptep_user = (pt_element_t __force_user *)((void *)host_addr + offset); if (unlikely(__copy_from_user(&pte, ptep_user, sizeof(pte)))) goto error; walker->ptep_user[walker->level - 1] = ptep_user; diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index d7f8938..bc95a50 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -1108,6 +1108,7 @@ static void init_vmcb(struct vcpu_svm *svm) set_exception_intercept(svm, UD_VECTOR); set_exception_intercept(svm, MC_VECTOR); set_exception_intercept(svm, AC_VECTOR); + set_exception_intercept(svm, DB_VECTOR); set_intercept(svm, INTERCEPT_INTR); set_intercept(svm, INTERCEPT_NMI); @@ -1642,20 +1643,13 @@ static void svm_set_segment(struct kvm_vcpu *vcpu, mark_dirty(svm->vmcb, VMCB_SEG); } -static void update_db_bp_intercept(struct kvm_vcpu *vcpu) +static void update_bp_intercept(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); - clr_exception_intercept(svm, DB_VECTOR); clr_exception_intercept(svm, BP_VECTOR); - if (svm->nmi_singlestep) - set_exception_intercept(svm, DB_VECTOR); - if (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) { - if (vcpu->guest_debug & - (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) - set_exception_intercept(svm, DB_VECTOR); if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) set_exception_intercept(svm, BP_VECTOR); } else @@ -1761,7 +1755,6 @@ static int db_interception(struct vcpu_svm *svm) if (!(svm->vcpu.guest_debug & KVM_GUESTDBG_SINGLESTEP)) svm->vmcb->save.rflags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF); - update_db_bp_intercept(&svm->vcpu); } if (svm->vcpu.guest_debug & @@ -3595,7 +3588,11 @@ static void reload_tss(struct kvm_vcpu *vcpu) int cpu = raw_smp_processor_id(); struct svm_cpu_data *sd = per_cpu(svm_data, cpu); + + pax_open_kernel(); sd->tss_desc->type = 9; /* available 32/64-bit TSS */ + pax_close_kernel(); + load_TR_desc(); } @@ -3761,7 +3758,6 @@ static void enable_nmi_window(struct kvm_vcpu *vcpu) */ svm->nmi_singlestep = true; svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF); - update_db_bp_intercept(vcpu); } static int svm_set_tss_addr(struct kvm *kvm, unsigned int addr) @@ -3991,6 +3987,10 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) #endif #endif +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_MEMORY_UDEREF) + __set_fs(current_thread_info()->addr_limit); +#endif + reload_tss(vcpu); local_irq_disable(); @@ -4364,7 +4364,7 @@ static void svm_sched_in(struct kvm_vcpu *vcpu, int cpu) { } -static struct kvm_x86_ops svm_x86_ops = { +static struct kvm_x86_ops svm_x86_ops __read_only = { .cpu_has_kvm_support = has_svm, .disabled_by_bios = is_disabled, .hardware_setup = svm_hardware_setup, @@ -4383,7 +4383,7 @@ static struct kvm_x86_ops svm_x86_ops = { .vcpu_load = svm_vcpu_load, .vcpu_put = svm_vcpu_put, - .update_db_bp_intercept = update_db_bp_intercept, + .update_db_bp_intercept = update_bp_intercept, .get_msr = svm_get_msr, .set_msr = svm_set_msr, .get_segment_base = svm_get_segment_base, diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 343d369..95ade96 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -1440,12 +1440,12 @@ static void vmcs_write64(unsigned long field, u64 value) #endif } -static void vmcs_clear_bits(unsigned long field, u32 mask) +static void vmcs_clear_bits(unsigned long field, unsigned long mask) { vmcs_writel(field, vmcs_readl(field) & ~mask); } -static void vmcs_set_bits(unsigned long field, u32 mask) +static void vmcs_set_bits(unsigned long field, unsigned long mask) { vmcs_writel(field, vmcs_readl(field) | mask); } @@ -1705,7 +1705,11 @@ static void reload_tss(void) struct desc_struct *descs; descs = (void *)gdt->address; + + pax_open_kernel(); descs[GDT_ENTRY_TSS].type = 9; /* available TSS */ + pax_close_kernel(); + load_TR_desc(); } @@ -1941,6 +1945,10 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) vmcs_writel(HOST_TR_BASE, kvm_read_tr_base()); /* 22.2.4 */ vmcs_writel(HOST_GDTR_BASE, gdt->address); /* 22.2.4 */ +#ifdef CONFIG_PAX_PER_CPU_PGD + vmcs_writel(HOST_CR3, read_cr3()); /* 22.2.3 FIXME: shadow tables */ +#endif + rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp); vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */ vmx->loaded_vmcs->cpu = cpu; @@ -2232,7 +2240,7 @@ static void setup_msrs(struct vcpu_vmx *vmx) * reads and returns guest's timestamp counter "register" * guest_tsc = host_tsc + tsc_offset -- 21.3 */ -static u64 guest_read_tsc(void) +static u64 __intentional_overflow(-1) guest_read_tsc(void) { u64 host_tsc, tsc_offset; @@ -4450,7 +4458,10 @@ static void vmx_set_constant_host_state(struct vcpu_vmx *vmx) unsigned long cr4; vmcs_writel(HOST_CR0, read_cr0() & ~X86_CR0_TS); /* 22.2.3 */ + +#ifndef CONFIG_PAX_PER_CPU_PGD vmcs_writel(HOST_CR3, read_cr3()); /* 22.2.3 FIXME: shadow tables */ +#endif /* Save the most likely value for this task's CR4 in the VMCS. */ cr4 = cr4_read_shadow(); @@ -4477,7 +4488,7 @@ static void vmx_set_constant_host_state(struct vcpu_vmx *vmx) vmcs_writel(HOST_IDTR_BASE, dt.address); /* 22.2.4 */ vmx->host_idt_base = dt.address; - vmcs_writel(HOST_RIP, vmx_return); /* 22.2.5 */ + vmcs_writel(HOST_RIP, ktla_ktva(vmx_return)); /* 22.2.5 */ rdmsr(MSR_IA32_SYSENTER_CS, low32, high32); vmcs_write32(HOST_IA32_SYSENTER_CS, low32); @@ -6015,11 +6026,17 @@ static __init int hardware_setup(void) * page upon invalidation. No need to do anything if not * using the APIC_ACCESS_ADDR VMCS field. */ - if (!flexpriority_enabled) + if (!flexpriority_enabled) { + pax_open_kernel(); kvm_x86_ops->set_apic_access_page_addr = NULL; + pax_close_kernel(); + } - if (!cpu_has_vmx_tpr_shadow()) + if (!cpu_has_vmx_tpr_shadow()) { + pax_open_kernel(); kvm_x86_ops->update_cr8_intercept = NULL; + pax_close_kernel(); + } if (enable_ept && !cpu_has_vmx_ept_2m_page()) kvm_disable_largepages(); @@ -6030,6 +6047,7 @@ static __init int hardware_setup(void) if (!cpu_has_vmx_apicv()) enable_apicv = 0; + pax_open_kernel(); if (enable_apicv) kvm_x86_ops->update_cr8_intercept = NULL; else { @@ -6038,6 +6056,7 @@ static __init int hardware_setup(void) kvm_x86_ops->deliver_posted_interrupt = NULL; kvm_x86_ops->sync_pir_to_irr = vmx_sync_pir_to_irr_dummy; } + pax_close_kernel(); vmx_disable_intercept_for_msr(MSR_FS_BASE, false); vmx_disable_intercept_for_msr(MSR_GS_BASE, false); @@ -6092,10 +6111,12 @@ static __init int hardware_setup(void) enable_pml = 0; if (!enable_pml) { + pax_open_kernel(); kvm_x86_ops->slot_enable_log_dirty = NULL; kvm_x86_ops->slot_disable_log_dirty = NULL; kvm_x86_ops->flush_log_dirty = NULL; kvm_x86_ops->enable_log_dirty_pt_masked = NULL; + pax_close_kernel(); } return alloc_kvm_area(); @@ -8351,6 +8372,12 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) "jmp 2f \n\t" "1: " __ex(ASM_VMX_VMRESUME) "\n\t" "2: " + +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) + "ljmp %[cs],$3f\n\t" + "3: " +#endif + /* Save guest registers, load host registers, keep flags */ "mov %0, %c[wordsize](%%" _ASM_SP ") \n\t" "pop %0 \n\t" @@ -8403,6 +8430,11 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) #endif [cr2]"i"(offsetof(struct vcpu_vmx, vcpu.arch.cr2)), [wordsize]"i"(sizeof(ulong)) + +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) + ,[cs]"i"(__KERNEL_CS) +#endif + : "cc", "memory" #ifdef CONFIG_X86_64 , "rax", "rbx", "rdi", "rsi" @@ -8416,7 +8448,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) if (debugctlmsr) update_debugctlmsr(debugctlmsr); -#ifndef CONFIG_X86_64 +#ifdef CONFIG_X86_32 /* * The sysexit path does not restore ds/es, so we must set them to * a reasonable value ourselves. @@ -8425,8 +8457,18 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) * may be executed in interrupt context, which saves and restore segments * around it, nullifying its effect. */ - loadsegment(ds, __USER_DS); - loadsegment(es, __USER_DS); + loadsegment(ds, __KERNEL_DS); + loadsegment(es, __KERNEL_DS); + loadsegment(ss, __KERNEL_DS); + +#ifdef CONFIG_PAX_KERNEXEC + loadsegment(fs, __KERNEL_PERCPU); +#endif + +#ifdef CONFIG_PAX_MEMORY_UDEREF + __set_fs(current_thread_info()->addr_limit); +#endif + #endif vcpu->arch.regs_avail = ~((1 << VCPU_REGS_RIP) | (1 << VCPU_REGS_RSP) @@ -10280,7 +10322,7 @@ static void vmx_enable_log_dirty_pt_masked(struct kvm *kvm, kvm_mmu_clear_dirty_pt_masked(kvm, memslot, offset, mask); } -static struct kvm_x86_ops vmx_x86_ops = { +static struct kvm_x86_ops vmx_x86_ops __read_only = { .cpu_has_kvm_support = cpu_has_kvm_support, .disabled_by_bios = vmx_disabled_by_bios, .hardware_setup = hardware_setup, diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 43609af..f8b7b2c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1828,8 +1828,8 @@ static int xen_hvm_config(struct kvm_vcpu *vcpu, u64 data) { struct kvm *kvm = vcpu->kvm; int lm = is_long_mode(vcpu); - u8 *blob_addr = lm ? (u8 *)(long)kvm->arch.xen_hvm_config.blob_addr_64 - : (u8 *)(long)kvm->arch.xen_hvm_config.blob_addr_32; + u8 __user *blob_addr = lm ? (u8 __user *)(long)kvm->arch.xen_hvm_config.blob_addr_64 + : (u8 __user *)(long)kvm->arch.xen_hvm_config.blob_addr_32; u8 blob_size = lm ? kvm->arch.xen_hvm_config.blob_size_64 : kvm->arch.xen_hvm_config.blob_size_32; u32 page_num = data & ~PAGE_MASK; @@ -2530,6 +2530,8 @@ long kvm_arch_dev_ioctl(struct file *filp, if (n < msr_list.nmsrs) goto out; r = -EFAULT; + if (num_msrs_to_save > ARRAY_SIZE(msrs_to_save)) + goto out; if (copy_to_user(user_msr_list->indices, &msrs_to_save, num_msrs_to_save * sizeof(u32))) goto out; @@ -2890,7 +2892,7 @@ static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu, static void fill_xsave(u8 *dest, struct kvm_vcpu *vcpu) { - struct xregs_state *xsave = &vcpu->arch.guest_fpu.state.xsave; + struct xregs_state *xsave = &vcpu->arch.guest_fpu.state->xsave; u64 xstate_bv = xsave->header.xfeatures; u64 valid; @@ -2926,7 +2928,7 @@ static void fill_xsave(u8 *dest, struct kvm_vcpu *vcpu) static void load_xsave(struct kvm_vcpu *vcpu, u8 *src) { - struct xregs_state *xsave = &vcpu->arch.guest_fpu.state.xsave; + struct xregs_state *xsave = &vcpu->arch.guest_fpu.state->xsave; u64 xstate_bv = *(u64 *)(src + XSAVE_HDR_OFFSET); u64 valid; @@ -2970,7 +2972,7 @@ static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu, fill_xsave((u8 *) guest_xsave->region, vcpu); } else { memcpy(guest_xsave->region, - &vcpu->arch.guest_fpu.state.fxsave, + &vcpu->arch.guest_fpu.state->fxsave, sizeof(struct fxregs_state)); *(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)] = XSTATE_FPSSE; @@ -2995,7 +2997,7 @@ static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu, } else { if (xstate_bv & ~XSTATE_FPSSE) return -EINVAL; - memcpy(&vcpu->arch.guest_fpu.state.fxsave, + memcpy(&vcpu->arch.guest_fpu.state->fxsave, guest_xsave->region, sizeof(struct fxregs_state)); } return 0; @@ -6214,6 +6216,7 @@ void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm, * exiting to the userspace. Otherwise, the value will be returned to the * userspace. */ +static int vcpu_enter_guest(struct kvm_vcpu *vcpu) __must_hold(&vcpu->kvm->srcu); static int vcpu_enter_guest(struct kvm_vcpu *vcpu) { int r; @@ -6437,6 +6440,7 @@ out: return r; } +static inline int vcpu_block(struct kvm *kvm, struct kvm_vcpu *vcpu) __must_hold(&kvm->srcu); static inline int vcpu_block(struct kvm *kvm, struct kvm_vcpu *vcpu) { if (!kvm_arch_vcpu_runnable(vcpu)) { @@ -6976,7 +6980,7 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) { struct fxregs_state *fxsave = - &vcpu->arch.guest_fpu.state.fxsave; + &vcpu->arch.guest_fpu.state->fxsave; memcpy(fpu->fpr, fxsave->st_space, 128); fpu->fcw = fxsave->cwd; @@ -6993,7 +6997,7 @@ int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) { struct fxregs_state *fxsave = - &vcpu->arch.guest_fpu.state.fxsave; + &vcpu->arch.guest_fpu.state->fxsave; memcpy(fxsave->st_space, fpu->fpr, 128); fxsave->cwd = fpu->fcw; @@ -7009,9 +7013,9 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) static void fx_init(struct kvm_vcpu *vcpu) { - fpstate_init(&vcpu->arch.guest_fpu.state); + fpstate_init(vcpu->arch.guest_fpu.state); if (cpu_has_xsaves) - vcpu->arch.guest_fpu.state.xsave.header.xcomp_bv = + vcpu->arch.guest_fpu.state->xsave.header.xcomp_bv = host_xcr0 | XSTATE_COMPACTION_ENABLED; /* @@ -7035,7 +7039,7 @@ void kvm_load_guest_fpu(struct kvm_vcpu *vcpu) kvm_put_guest_xcr0(vcpu); vcpu->guest_fpu_loaded = 1; __kernel_fpu_begin(); - __copy_kernel_to_fpregs(&vcpu->arch.guest_fpu.state); + __copy_kernel_to_fpregs(vcpu->arch.guest_fpu.state); trace_kvm_fpu(1); } @@ -7324,6 +7328,8 @@ bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu) struct static_key kvm_no_apic_vcpu __read_mostly; +extern struct kmem_cache *fpregs_state_cachep; + int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) { struct page *page; @@ -7340,11 +7346,14 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) else vcpu->arch.mp_state = KVM_MP_STATE_UNINITIALIZED; - page = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (!page) { - r = -ENOMEM; + r = -ENOMEM; + vcpu->arch.guest_fpu.state = kmem_cache_alloc(fpregs_state_cachep, GFP_KERNEL); + if (!vcpu->arch.guest_fpu.state) goto fail; - } + + page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!page) + goto fail_free_fpregs; vcpu->arch.pio_data = page_address(page); kvm_set_tsc_khz(vcpu, max_tsc_khz); @@ -7398,6 +7407,9 @@ fail_mmu_destroy: kvm_mmu_destroy(vcpu); fail_free_pio_data: free_page((unsigned long)vcpu->arch.pio_data); +fail_free_fpregs: + kmem_cache_free(fpregs_state_cachep, vcpu->arch.guest_fpu.state); + vcpu->arch.guest_fpu.state = NULL; fail: return r; } @@ -7415,6 +7427,8 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) free_page((unsigned long)vcpu->arch.pio_data); if (!irqchip_in_kernel(vcpu->kvm)) static_key_slow_dec(&kvm_no_apic_vcpu); + kmem_cache_free(fpregs_state_cachep, vcpu->arch.guest_fpu.state); + vcpu->arch.guest_fpu.state = NULL; } void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index a0d09f6..92ede76 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -1336,9 +1336,10 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count) * Rebooting also tells the Host we're finished, but the RESTART flag tells the * Launcher to reboot us. */ -static void lguest_restart(char *reason) +static __noreturn void lguest_restart(char *reason) { hcall(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART, 0, 0); + BUG(); } /*G:050 diff --git a/arch/x86/lib/atomic64_386_32.S b/arch/x86/lib/atomic64_386_32.S index 9b0ca8f..bb4af41 100644 --- a/arch/x86/lib/atomic64_386_32.S +++ b/arch/x86/lib/atomic64_386_32.S @@ -45,6 +45,10 @@ BEGIN(read) movl (v), %eax movl 4(v), %edx RET_ENDP +BEGIN(read_unchecked) + movl (v), %eax + movl 4(v), %edx +RET_ENDP #undef v #define v %esi @@ -52,6 +56,10 @@ BEGIN(set) movl %ebx, (v) movl %ecx, 4(v) RET_ENDP +BEGIN(set_unchecked) + movl %ebx, (v) + movl %ecx, 4(v) +RET_ENDP #undef v #define v %esi @@ -67,6 +75,20 @@ RET_ENDP BEGIN(add) addl %eax, (v) adcl %edx, 4(v) + +#ifdef CONFIG_PAX_REFCOUNT + jno 0f + subl %eax, (v) + sbbl %edx, 4(v) + int $4 +0: + _ASM_EXTABLE(0b, 0b) +#endif + +RET_ENDP +BEGIN(add_unchecked) + addl %eax, (v) + adcl %edx, 4(v) RET_ENDP #undef v @@ -74,6 +96,24 @@ RET_ENDP BEGIN(add_return) addl (v), %eax adcl 4(v), %edx + +#ifdef CONFIG_PAX_REFCOUNT + into +1234: + _ASM_EXTABLE(1234b, 2f) +#endif + + movl %eax, (v) + movl %edx, 4(v) + +#ifdef CONFIG_PAX_REFCOUNT +2: +#endif + +RET_ENDP +BEGIN(add_return_unchecked) + addl (v), %eax + adcl 4(v), %edx movl %eax, (v) movl %edx, 4(v) RET_ENDP @@ -83,6 +123,20 @@ RET_ENDP BEGIN(sub) subl %eax, (v) sbbl %edx, 4(v) + +#ifdef CONFIG_PAX_REFCOUNT + jno 0f + addl %eax, (v) + adcl %edx, 4(v) + int $4 +0: + _ASM_EXTABLE(0b, 0b) +#endif + +RET_ENDP +BEGIN(sub_unchecked) + subl %eax, (v) + sbbl %edx, 4(v) RET_ENDP #undef v @@ -93,6 +147,27 @@ BEGIN(sub_return) sbbl $0, %edx addl (v), %eax adcl 4(v), %edx + +#ifdef CONFIG_PAX_REFCOUNT + into +1234: + _ASM_EXTABLE(1234b, 2f) +#endif + + movl %eax, (v) + movl %edx, 4(v) + +#ifdef CONFIG_PAX_REFCOUNT +2: +#endif + +RET_ENDP +BEGIN(sub_return_unchecked) + negl %edx + negl %eax + sbbl $0, %edx + addl (v), %eax + adcl 4(v), %edx movl %eax, (v) movl %edx, 4(v) RET_ENDP @@ -102,6 +177,20 @@ RET_ENDP BEGIN(inc) addl $1, (v) adcl $0, 4(v) + +#ifdef CONFIG_PAX_REFCOUNT + jno 0f + subl $1, (v) + sbbl $0, 4(v) + int $4 +0: + _ASM_EXTABLE(0b, 0b) +#endif + +RET_ENDP +BEGIN(inc_unchecked) + addl $1, (v) + adcl $0, 4(v) RET_ENDP #undef v @@ -111,6 +200,26 @@ BEGIN(inc_return) movl 4(v), %edx addl $1, %eax adcl $0, %edx + +#ifdef CONFIG_PAX_REFCOUNT + into +1234: + _ASM_EXTABLE(1234b, 2f) +#endif + + movl %eax, (v) + movl %edx, 4(v) + +#ifdef CONFIG_PAX_REFCOUNT +2: +#endif + +RET_ENDP +BEGIN(inc_return_unchecked) + movl (v), %eax + movl 4(v), %edx + addl $1, %eax + adcl $0, %edx movl %eax, (v) movl %edx, 4(v) RET_ENDP @@ -120,6 +229,20 @@ RET_ENDP BEGIN(dec) subl $1, (v) sbbl $0, 4(v) + +#ifdef CONFIG_PAX_REFCOUNT + jno 0f + addl $1, (v) + adcl $0, 4(v) + int $4 +0: + _ASM_EXTABLE(0b, 0b) +#endif + +RET_ENDP +BEGIN(dec_unchecked) + subl $1, (v) + sbbl $0, 4(v) RET_ENDP #undef v @@ -129,6 +252,26 @@ BEGIN(dec_return) movl 4(v), %edx subl $1, %eax sbbl $0, %edx + +#ifdef CONFIG_PAX_REFCOUNT + into +1234: + _ASM_EXTABLE(1234b, 2f) +#endif + + movl %eax, (v) + movl %edx, 4(v) + +#ifdef CONFIG_PAX_REFCOUNT +2: +#endif + +RET_ENDP +BEGIN(dec_return_unchecked) + movl (v), %eax + movl 4(v), %edx + subl $1, %eax + sbbl $0, %edx movl %eax, (v) movl %edx, 4(v) RET_ENDP @@ -140,6 +283,13 @@ BEGIN(add_unless) adcl %edx, %edi addl (v), %eax adcl 4(v), %edx + +#ifdef CONFIG_PAX_REFCOUNT + into +1234: + _ASM_EXTABLE(1234b, 2f) +#endif + cmpl %eax, %ecx je 3f 1: @@ -165,6 +315,13 @@ BEGIN(inc_not_zero) 1: addl $1, %eax adcl $0, %edx + +#ifdef CONFIG_PAX_REFCOUNT + into +1234: + _ASM_EXTABLE(1234b, 2f) +#endif + movl %eax, (v) movl %edx, 4(v) movl $1, %eax @@ -183,6 +340,13 @@ BEGIN(dec_if_positive) movl 4(v), %edx subl $1, %eax sbbl $0, %edx + +#ifdef CONFIG_PAX_REFCOUNT + into +1234: + _ASM_EXTABLE(1234b, 1f) +#endif + js 1f movl %eax, (v) movl %edx, 4(v) diff --git a/arch/x86/lib/atomic64_cx8_32.S b/arch/x86/lib/atomic64_cx8_32.S index db3ae854..b8ad0de 100644 --- a/arch/x86/lib/atomic64_cx8_32.S +++ b/arch/x86/lib/atomic64_cx8_32.S @@ -22,9 +22,16 @@ ENTRY(atomic64_read_cx8) read64 %ecx + pax_force_retaddr ret ENDPROC(atomic64_read_cx8) +ENTRY(atomic64_read_unchecked_cx8) + read64 %ecx + pax_force_retaddr + ret +ENDPROC(atomic64_read_unchecked_cx8) + ENTRY(atomic64_set_cx8) 1: /* we don't need LOCK_PREFIX since aligned 64-bit writes @@ -32,20 +39,33 @@ ENTRY(atomic64_set_cx8) cmpxchg8b (%esi) jne 1b + pax_force_retaddr ret ENDPROC(atomic64_set_cx8) +ENTRY(atomic64_set_unchecked_cx8) +1: +/* we don't need LOCK_PREFIX since aligned 64-bit writes + * are atomic on 586 and newer */ + cmpxchg8b (%esi) + jne 1b + + pax_force_retaddr + ret +ENDPROC(atomic64_set_unchecked_cx8) + ENTRY(atomic64_xchg_cx8) 1: LOCK_PREFIX cmpxchg8b (%esi) jne 1b + pax_force_retaddr ret ENDPROC(atomic64_xchg_cx8) -.macro addsub_return func ins insc -ENTRY(atomic64_\func\()_return_cx8) +.macro addsub_return func ins insc unchecked="" +ENTRY(atomic64_\func\()_return\unchecked\()_cx8) pushl %ebp pushl %ebx pushl %esi @@ -61,26 +81,43 @@ ENTRY(atomic64_\func\()_return_cx8) movl %edx, %ecx \ins\()l %esi, %ebx \insc\()l %edi, %ecx + +.ifb \unchecked +#ifdef CONFIG_PAX_REFCOUNT + into +2: + _ASM_EXTABLE(2b, 3f) +#endif +.endif + LOCK_PREFIX cmpxchg8b (%ebp) jne 1b - -10: movl %ebx, %eax movl %ecx, %edx + +.ifb \unchecked +#ifdef CONFIG_PAX_REFCOUNT +3: +#endif +.endif + popl %edi popl %esi popl %ebx popl %ebp + pax_force_retaddr ret -ENDPROC(atomic64_\func\()_return_cx8) +ENDPROC(atomic64_\func\()_return\unchecked\()_cx8) .endm addsub_return add add adc addsub_return sub sub sbb +addsub_return add add adc _unchecked +addsub_return sub sub sbb _unchecked -.macro incdec_return func ins insc -ENTRY(atomic64_\func\()_return_cx8) +.macro incdec_return func ins insc unchecked="" +ENTRY(atomic64_\func\()_return\unchecked\()_cx8) pushl %ebx read64 %esi @@ -89,20 +126,37 @@ ENTRY(atomic64_\func\()_return_cx8) movl %edx, %ecx \ins\()l $1, %ebx \insc\()l $0, %ecx + +.ifb \unchecked +#ifdef CONFIG_PAX_REFCOUNT + into +2: + _ASM_EXTABLE(2b, 3f) +#endif +.endif + LOCK_PREFIX cmpxchg8b (%esi) jne 1b - -10: movl %ebx, %eax movl %ecx, %edx + +.ifb \unchecked +#ifdef CONFIG_PAX_REFCOUNT +3: +#endif +.endif + popl %ebx + pax_force_retaddr ret -ENDPROC(atomic64_\func\()_return_cx8) +ENDPROC(atomic64_\func\()_return\unchecked\()_cx8) .endm incdec_return inc add adc incdec_return dec sub sbb +incdec_return inc add adc _unchecked +incdec_return dec sub sbb _unchecked ENTRY(atomic64_dec_if_positive_cx8) pushl %ebx @@ -113,6 +167,13 @@ ENTRY(atomic64_dec_if_positive_cx8) movl %edx, %ecx subl $1, %ebx sbb $0, %ecx + +#ifdef CONFIG_PAX_REFCOUNT + into +1234: + _ASM_EXTABLE(1234b, 2f) +#endif + js 2f LOCK_PREFIX cmpxchg8b (%esi) @@ -122,6 +183,7 @@ ENTRY(atomic64_dec_if_positive_cx8) movl %ebx, %eax movl %ecx, %edx popl %ebx + pax_force_retaddr ret ENDPROC(atomic64_dec_if_positive_cx8) @@ -144,6 +206,13 @@ ENTRY(atomic64_add_unless_cx8) movl %edx, %ecx addl %ebp, %ebx adcl %edi, %ecx + +#ifdef CONFIG_PAX_REFCOUNT + into +1234: + _ASM_EXTABLE(1234b, 3f) +#endif + LOCK_PREFIX cmpxchg8b (%esi) jne 1b @@ -153,6 +222,7 @@ ENTRY(atomic64_add_unless_cx8) addl $8, %esp popl %ebx popl %ebp + pax_force_retaddr ret 4: cmpl %edx, 4(%esp) @@ -173,6 +243,13 @@ ENTRY(atomic64_inc_not_zero_cx8) xorl %ecx, %ecx addl $1, %ebx adcl %edx, %ecx + +#ifdef CONFIG_PAX_REFCOUNT + into +1234: + _ASM_EXTABLE(1234b, 3f) +#endif + LOCK_PREFIX cmpxchg8b (%esi) jne 1b @@ -180,5 +257,6 @@ ENTRY(atomic64_inc_not_zero_cx8) movl $1, %eax 3: popl %ebx + pax_force_retaddr ret ENDPROC(atomic64_inc_not_zero_cx8) diff --git a/arch/x86/lib/checksum_32.S b/arch/x86/lib/checksum_32.S index c1e6232..ebbeba7 100644 --- a/arch/x86/lib/checksum_32.S +++ b/arch/x86/lib/checksum_32.S @@ -28,7 +28,8 @@ #include #include #include - +#include + /* * computes a partial checksum, e.g. for TCP/UDP fragments */ @@ -280,7 +281,22 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst, #define ARGBASE 16 #define FP 12 - + +ENTRY(csum_partial_copy_generic_to_user) + +#ifdef CONFIG_PAX_MEMORY_UDEREF + pushl %gs + popl %es + jmp csum_partial_copy_generic +#endif + +ENTRY(csum_partial_copy_generic_from_user) + +#ifdef CONFIG_PAX_MEMORY_UDEREF + pushl %gs + popl %ds +#endif + ENTRY(csum_partial_copy_generic) subl $4,%esp pushl %edi @@ -299,7 +315,7 @@ ENTRY(csum_partial_copy_generic) jmp 4f SRC(1: movw (%esi), %bx ) addl $2, %esi -DST( movw %bx, (%edi) ) +DST( movw %bx, %es:(%edi) ) addl $2, %edi addw %bx, %ax adcl $0, %eax @@ -311,30 +327,30 @@ DST( movw %bx, (%edi) ) SRC(1: movl (%esi), %ebx ) SRC( movl 4(%esi), %edx ) adcl %ebx, %eax -DST( movl %ebx, (%edi) ) +DST( movl %ebx, %es:(%edi) ) adcl %edx, %eax -DST( movl %edx, 4(%edi) ) +DST( movl %edx, %es:4(%edi) ) SRC( movl 8(%esi), %ebx ) SRC( movl 12(%esi), %edx ) adcl %ebx, %eax -DST( movl %ebx, 8(%edi) ) +DST( movl %ebx, %es:8(%edi) ) adcl %edx, %eax -DST( movl %edx, 12(%edi) ) +DST( movl %edx, %es:12(%edi) ) SRC( movl 16(%esi), %ebx ) SRC( movl 20(%esi), %edx ) adcl %ebx, %eax -DST( movl %ebx, 16(%edi) ) +DST( movl %ebx, %es:16(%edi) ) adcl %edx, %eax -DST( movl %edx, 20(%edi) ) +DST( movl %edx, %es:20(%edi) ) SRC( movl 24(%esi), %ebx ) SRC( movl 28(%esi), %edx ) adcl %ebx, %eax -DST( movl %ebx, 24(%edi) ) +DST( movl %ebx, %es:24(%edi) ) adcl %edx, %eax -DST( movl %edx, 28(%edi) ) +DST( movl %edx, %es:28(%edi) ) lea 32(%esi), %esi lea 32(%edi), %edi @@ -348,7 +364,7 @@ DST( movl %edx, 28(%edi) ) shrl $2, %edx # This clears CF SRC(3: movl (%esi), %ebx ) adcl %ebx, %eax -DST( movl %ebx, (%edi) ) +DST( movl %ebx, %es:(%edi) ) lea 4(%esi), %esi lea 4(%edi), %edi dec %edx @@ -360,12 +376,12 @@ DST( movl %ebx, (%edi) ) jb 5f SRC( movw (%esi), %cx ) leal 2(%esi), %esi -DST( movw %cx, (%edi) ) +DST( movw %cx, %es:(%edi) ) leal 2(%edi), %edi je 6f shll $16,%ecx SRC(5: movb (%esi), %cl ) -DST( movb %cl, (%edi) ) +DST( movb %cl, %es:(%edi) ) 6: addl %ecx, %eax adcl $0, %eax 7: @@ -376,7 +392,7 @@ DST( movb %cl, (%edi) ) 6001: movl ARGBASE+20(%esp), %ebx # src_err_ptr - movl $-EFAULT, (%ebx) + movl $-EFAULT, %ss:(%ebx) # zero the complete destination - computing the rest # is too much work @@ -389,34 +405,58 @@ DST( movb %cl, (%edi) ) 6002: movl ARGBASE+24(%esp), %ebx # dst_err_ptr - movl $-EFAULT,(%ebx) + movl $-EFAULT,%ss:(%ebx) jmp 5000b .previous +#ifdef CONFIG_PAX_MEMORY_UDEREF + pushl %ss + popl %ds + pushl %ss + popl %es +#endif + popl %ebx popl %esi popl %edi popl %ecx # equivalent to addl $4,%esp ret -ENDPROC(csum_partial_copy_generic) +ENDPROC(csum_partial_copy_generic_to_user) #else /* Version for PentiumII/PPro */ #define ROUND1(x) \ + nop; nop; nop; \ SRC(movl x(%esi), %ebx ) ; \ addl %ebx, %eax ; \ - DST(movl %ebx, x(%edi) ) ; + DST(movl %ebx, %es:x(%edi)) ; #define ROUND(x) \ + nop; nop; nop; \ SRC(movl x(%esi), %ebx ) ; \ adcl %ebx, %eax ; \ - DST(movl %ebx, x(%edi) ) ; + DST(movl %ebx, %es:x(%edi)) ; #define ARGBASE 12 - + +ENTRY(csum_partial_copy_generic_to_user) + +#ifdef CONFIG_PAX_MEMORY_UDEREF + pushl %gs + popl %es + jmp csum_partial_copy_generic +#endif + +ENTRY(csum_partial_copy_generic_from_user) + +#ifdef CONFIG_PAX_MEMORY_UDEREF + pushl %gs + popl %ds +#endif + ENTRY(csum_partial_copy_generic) pushl %ebx pushl %edi @@ -435,7 +475,7 @@ ENTRY(csum_partial_copy_generic) subl %ebx, %edi lea -1(%esi),%edx andl $-32,%edx - lea 3f(%ebx,%ebx), %ebx + lea 3f(%ebx,%ebx,2), %ebx testl %esi, %esi jmp *%ebx 1: addl $64,%esi @@ -456,19 +496,19 @@ ENTRY(csum_partial_copy_generic) jb 5f SRC( movw (%esi), %dx ) leal 2(%esi), %esi -DST( movw %dx, (%edi) ) +DST( movw %dx, %es:(%edi) ) leal 2(%edi), %edi je 6f shll $16,%edx 5: SRC( movb (%esi), %dl ) -DST( movb %dl, (%edi) ) +DST( movb %dl, %es:(%edi) ) 6: addl %edx, %eax adcl $0, %eax 7: .section .fixup, "ax" 6001: movl ARGBASE+20(%esp), %ebx # src_err_ptr - movl $-EFAULT, (%ebx) + movl $-EFAULT, %ss:(%ebx) # zero the complete destination (computing the rest is too much work) movl ARGBASE+8(%esp),%edi # dst movl ARGBASE+12(%esp),%ecx # len @@ -476,15 +516,22 @@ DST( movb %dl, (%edi) ) rep; stosb jmp 7b 6002: movl ARGBASE+24(%esp), %ebx # dst_err_ptr - movl $-EFAULT, (%ebx) + movl $-EFAULT, %ss:(%ebx) jmp 7b .previous +#ifdef CONFIG_PAX_MEMORY_UDEREF + pushl %ss + popl %ds + pushl %ss + popl %es +#endif + popl %esi popl %edi popl %ebx ret -ENDPROC(csum_partial_copy_generic) +ENDPROC(csum_partial_copy_generic_to_user) #undef ROUND #undef ROUND1 diff --git a/arch/x86/lib/clear_page_64.S b/arch/x86/lib/clear_page_64.S index a2fe51b..507dab0 100644 --- a/arch/x86/lib/clear_page_64.S +++ b/arch/x86/lib/clear_page_64.S @@ -21,6 +21,7 @@ ENTRY(clear_page) movl $4096/8,%ecx xorl %eax,%eax rep stosq + pax_force_retaddr ret ENDPROC(clear_page) @@ -43,6 +44,7 @@ ENTRY(clear_page_orig) leaq 64(%rdi),%rdi jnz .Lloop nop + pax_force_retaddr ret ENDPROC(clear_page_orig) @@ -50,5 +52,6 @@ ENTRY(clear_page_c_e) movl $4096,%ecx xorl %eax,%eax rep stosb + pax_force_retaddr ret ENDPROC(clear_page_c_e) diff --git a/arch/x86/lib/cmpxchg16b_emu.S b/arch/x86/lib/cmpxchg16b_emu.S index 9b33024..e52ee44 100644 --- a/arch/x86/lib/cmpxchg16b_emu.S +++ b/arch/x86/lib/cmpxchg16b_emu.S @@ -7,6 +7,7 @@ */ #include #include +#include .text @@ -43,11 +44,13 @@ ENTRY(this_cpu_cmpxchg16b_emu) popfq mov $1, %al + pax_force_retaddr ret .Lnot_same: popfq xor %al,%al + pax_force_retaddr ret ENDPROC(this_cpu_cmpxchg16b_emu) diff --git a/arch/x86/lib/copy_page_64.S b/arch/x86/lib/copy_page_64.S index 009f982..9b3db5e 100644 --- a/arch/x86/lib/copy_page_64.S +++ b/arch/x86/lib/copy_page_64.S @@ -15,13 +15,14 @@ ENTRY(copy_page) ALTERNATIVE "jmp copy_page_regs", "", X86_FEATURE_REP_GOOD movl $4096/8, %ecx rep movsq + pax_force_retaddr ret ENDPROC(copy_page) ENTRY(copy_page_regs) subq $2*8, %rsp movq %rbx, (%rsp) - movq %r12, 1*8(%rsp) + movq %r13, 1*8(%rsp) movl $(4096/64)-5, %ecx .p2align 4 @@ -34,7 +35,7 @@ ENTRY(copy_page_regs) movq 0x8*4(%rsi), %r9 movq 0x8*5(%rsi), %r10 movq 0x8*6(%rsi), %r11 - movq 0x8*7(%rsi), %r12 + movq 0x8*7(%rsi), %r13 prefetcht0 5*64(%rsi) @@ -45,7 +46,7 @@ ENTRY(copy_page_regs) movq %r9, 0x8*4(%rdi) movq %r10, 0x8*5(%rdi) movq %r11, 0x8*6(%rdi) - movq %r12, 0x8*7(%rdi) + movq %r13, 0x8*7(%rdi) leaq 64 (%rsi), %rsi leaq 64 (%rdi), %rdi @@ -64,7 +65,7 @@ ENTRY(copy_page_regs) movq 0x8*4(%rsi), %r9 movq 0x8*5(%rsi), %r10 movq 0x8*6(%rsi), %r11 - movq 0x8*7(%rsi), %r12 + movq 0x8*7(%rsi), %r13 movq %rax, 0x8*0(%rdi) movq %rbx, 0x8*1(%rdi) @@ -73,14 +74,15 @@ ENTRY(copy_page_regs) movq %r9, 0x8*4(%rdi) movq %r10, 0x8*5(%rdi) movq %r11, 0x8*6(%rdi) - movq %r12, 0x8*7(%rdi) + movq %r13, 0x8*7(%rdi) leaq 64(%rdi), %rdi leaq 64(%rsi), %rsi jnz .Loop2 movq (%rsp), %rbx - movq 1*8(%rsp), %r12 + movq 1*8(%rsp), %r13 addq $2*8, %rsp + pax_force_retaddr ret ENDPROC(copy_page_regs) diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S index 982ce34..8e14731 100644 --- a/arch/x86/lib/copy_user_64.S +++ b/arch/x86/lib/copy_user_64.S @@ -14,50 +14,7 @@ #include #include #include - -/* Standard copy_to_user with segment limit checking */ -ENTRY(_copy_to_user) - GET_THREAD_INFO(%rax) - movq %rdi,%rcx - addq %rdx,%rcx - jc bad_to_user - cmpq TI_addr_limit(%rax),%rcx - ja bad_to_user - ALTERNATIVE_2 "jmp copy_user_generic_unrolled", \ - "jmp copy_user_generic_string", \ - X86_FEATURE_REP_GOOD, \ - "jmp copy_user_enhanced_fast_string", \ - X86_FEATURE_ERMS -ENDPROC(_copy_to_user) - -/* Standard copy_from_user with segment limit checking */ -ENTRY(_copy_from_user) - GET_THREAD_INFO(%rax) - movq %rsi,%rcx - addq %rdx,%rcx - jc bad_from_user - cmpq TI_addr_limit(%rax),%rcx - ja bad_from_user - ALTERNATIVE_2 "jmp copy_user_generic_unrolled", \ - "jmp copy_user_generic_string", \ - X86_FEATURE_REP_GOOD, \ - "jmp copy_user_enhanced_fast_string", \ - X86_FEATURE_ERMS -ENDPROC(_copy_from_user) - - .section .fixup,"ax" - /* must zero dest */ -ENTRY(bad_from_user) -bad_from_user: - movl %edx,%ecx - xorl %eax,%eax - rep - stosb -bad_to_user: - movl %edx,%eax - ret -ENDPROC(bad_from_user) - .previous +#include /* * copy_user_generic_unrolled - memory copy with exception handling. @@ -73,6 +30,7 @@ ENDPROC(bad_from_user) * eax uncopied bytes or 0 if successful. */ ENTRY(copy_user_generic_unrolled) + ASM_PAX_OPEN_USERLAND ASM_STAC cmpl $8,%edx jb 20f /* less then 8 bytes, go to byte copy loop */ @@ -122,6 +80,8 @@ ENTRY(copy_user_generic_unrolled) jnz 21b 23: xor %eax,%eax ASM_CLAC + ASM_PAX_CLOSE_USERLAND + pax_force_retaddr ret .section .fixup,"ax" @@ -175,6 +135,7 @@ ENDPROC(copy_user_generic_unrolled) * eax uncopied bytes or 0 if successful. */ ENTRY(copy_user_generic_string) + ASM_PAX_OPEN_USERLAND ASM_STAC cmpl $8,%edx jb 2f /* less than 8 bytes, go to byte copy loop */ @@ -189,6 +150,8 @@ ENTRY(copy_user_generic_string) movsb xorl %eax,%eax ASM_CLAC + ASM_PAX_CLOSE_USERLAND + pax_force_retaddr ret .section .fixup,"ax" @@ -214,12 +177,15 @@ ENDPROC(copy_user_generic_string) * eax uncopied bytes or 0 if successful. */ ENTRY(copy_user_enhanced_fast_string) + ASM_PAX_OPEN_USERLAND ASM_STAC movl %edx,%ecx 1: rep movsb xorl %eax,%eax ASM_CLAC + ASM_PAX_CLOSE_USERLAND + pax_force_retaddr ret .section .fixup,"ax" @@ -235,6 +201,16 @@ ENDPROC(copy_user_enhanced_fast_string) * This will force destination/source out of cache for more performance. */ ENTRY(__copy_user_nocache) + +#ifdef CONFIG_PAX_MEMORY_UDEREF + mov pax_user_shadow_base,%rcx + cmp %rcx,%rsi + jae 1f + add %rcx,%rsi +1: +#endif + + ASM_PAX_OPEN_USERLAND ASM_STAC cmpl $8,%edx jb 20f /* less then 8 bytes, go to byte copy loop */ @@ -284,7 +260,9 @@ ENTRY(__copy_user_nocache) jnz 21b 23: xorl %eax,%eax ASM_CLAC + ASM_PAX_CLOSE_USERLAND sfence + pax_force_retaddr ret .section .fixup,"ax" diff --git a/arch/x86/lib/csum-copy_64.S b/arch/x86/lib/csum-copy_64.S index 7e48807..cc966ff 100644 --- a/arch/x86/lib/csum-copy_64.S +++ b/arch/x86/lib/csum-copy_64.S @@ -8,6 +8,7 @@ #include #include #include +#include /* * Checksum copy with exception handling. @@ -52,7 +53,7 @@ ENTRY(csum_partial_copy_generic) .Lignore: subq $7*8, %rsp movq %rbx, 2*8(%rsp) - movq %r12, 3*8(%rsp) + movq %r15, 3*8(%rsp) movq %r14, 4*8(%rsp) movq %r13, 5*8(%rsp) movq %rbp, 6*8(%rsp) @@ -64,16 +65,16 @@ ENTRY(csum_partial_copy_generic) movl %edx, %ecx xorl %r9d, %r9d - movq %rcx, %r12 + movq %rcx, %r15 - shrq $6, %r12 + shrq $6, %r15 jz .Lhandle_tail /* < 64 */ clc /* main loop. clear in 64 byte blocks */ /* r9: zero, r8: temp2, rbx: temp1, rax: sum, rcx: saved length */ - /* r11: temp3, rdx: temp4, r12 loopcnt */ + /* r11: temp3, rdx: temp4, r15 loopcnt */ /* r10: temp5, rbp: temp6, r14 temp7, r13 temp8 */ .p2align 4 .Lloop: @@ -107,7 +108,7 @@ ENTRY(csum_partial_copy_generic) adcq %r14, %rax adcq %r13, %rax - decl %r12d + decl %r15d dest movq %rbx, (%rsi) @@ -200,11 +201,12 @@ ENTRY(csum_partial_copy_generic) .Lende: movq 2*8(%rsp), %rbx - movq 3*8(%rsp), %r12 + movq 3*8(%rsp), %r15 movq 4*8(%rsp), %r14 movq 5*8(%rsp), %r13 movq 6*8(%rsp), %rbp addq $7*8, %rsp + pax_force_retaddr ret /* Exception handlers. Very simple, zeroing is done in the wrappers */ diff --git a/arch/x86/lib/csum-wrappers_64.c b/arch/x86/lib/csum-wrappers_64.c index 1318f75..44c30fd 100644 --- a/arch/x86/lib/csum-wrappers_64.c +++ b/arch/x86/lib/csum-wrappers_64.c @@ -52,10 +52,12 @@ csum_partial_copy_from_user(const void __user *src, void *dst, len -= 2; } } + pax_open_userland(); stac(); - isum = csum_partial_copy_generic((__force const void *)src, + isum = csum_partial_copy_generic((const void __force_kernel *)____m(src), dst, len, isum, errp, NULL); clac(); + pax_close_userland(); if (unlikely(*errp)) goto out_err; @@ -109,10 +111,12 @@ csum_partial_copy_to_user(const void *src, void __user *dst, } *errp = 0; + pax_open_userland(); stac(); - ret = csum_partial_copy_generic(src, (void __force *)dst, + ret = csum_partial_copy_generic(src, (void __force_kernel *)____m(dst), len, isum, NULL, errp); clac(); + pax_close_userland(); return ret; } EXPORT_SYMBOL(csum_partial_copy_to_user); diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S index 46668cd..a3bdfb9 100644 --- a/arch/x86/lib/getuser.S +++ b/arch/x86/lib/getuser.S @@ -32,42 +32,93 @@ #include #include #include +#include +#include +#include + +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_MEMORY_UDEREF) +#define __copyuser_seg gs; +#else +#define __copyuser_seg +#endif .text ENTRY(__get_user_1) + +#if !defined(CONFIG_X86_32) || !defined(CONFIG_PAX_MEMORY_UDEREF) GET_THREAD_INFO(%_ASM_DX) cmp TI_addr_limit(%_ASM_DX),%_ASM_AX jae bad_get_user + +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) + mov pax_user_shadow_base,%_ASM_DX + cmp %_ASM_DX,%_ASM_AX + jae 1234f + add %_ASM_DX,%_ASM_AX +1234: +#endif + +#endif + ASM_STAC -1: movzbl (%_ASM_AX),%edx +1: __copyuser_seg movzbl (%_ASM_AX),%edx xor %eax,%eax ASM_CLAC + pax_force_retaddr ret ENDPROC(__get_user_1) ENTRY(__get_user_2) add $1,%_ASM_AX + +#if !defined(CONFIG_X86_32) || !defined(CONFIG_PAX_MEMORY_UDEREF) jc bad_get_user GET_THREAD_INFO(%_ASM_DX) cmp TI_addr_limit(%_ASM_DX),%_ASM_AX jae bad_get_user + +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) + mov pax_user_shadow_base,%_ASM_DX + cmp %_ASM_DX,%_ASM_AX + jae 1234f + add %_ASM_DX,%_ASM_AX +1234: +#endif + +#endif + ASM_STAC -2: movzwl -1(%_ASM_AX),%edx +2: __copyuser_seg movzwl -1(%_ASM_AX),%edx xor %eax,%eax ASM_CLAC + pax_force_retaddr ret ENDPROC(__get_user_2) ENTRY(__get_user_4) add $3,%_ASM_AX + +#if !defined(CONFIG_X86_32) || !defined(CONFIG_PAX_MEMORY_UDEREF) jc bad_get_user GET_THREAD_INFO(%_ASM_DX) cmp TI_addr_limit(%_ASM_DX),%_ASM_AX jae bad_get_user + +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) + mov pax_user_shadow_base,%_ASM_DX + cmp %_ASM_DX,%_ASM_AX + jae 1234f + add %_ASM_DX,%_ASM_AX +1234: +#endif + +#endif + ASM_STAC -3: movl -3(%_ASM_AX),%edx +3: __copyuser_seg movl -3(%_ASM_AX),%edx xor %eax,%eax ASM_CLAC + pax_force_retaddr ret ENDPROC(__get_user_4) @@ -78,10 +129,20 @@ ENTRY(__get_user_8) GET_THREAD_INFO(%_ASM_DX) cmp TI_addr_limit(%_ASM_DX),%_ASM_AX jae bad_get_user + +#ifdef CONFIG_PAX_MEMORY_UDEREF + mov pax_user_shadow_base,%_ASM_DX + cmp %_ASM_DX,%_ASM_AX + jae 1234f + add %_ASM_DX,%_ASM_AX +1234: +#endif + ASM_STAC 4: movq -7(%_ASM_AX),%rdx xor %eax,%eax ASM_CLAC + pax_force_retaddr ret #else add $7,%_ASM_AX @@ -90,10 +151,11 @@ ENTRY(__get_user_8) cmp TI_addr_limit(%_ASM_DX),%_ASM_AX jae bad_get_user_8 ASM_STAC -4: movl -7(%_ASM_AX),%edx -5: movl -3(%_ASM_AX),%ecx +4: __copyuser_seg movl -7(%_ASM_AX),%edx +5: __copyuser_seg movl -3(%_ASM_AX),%ecx xor %eax,%eax ASM_CLAC + pax_force_retaddr ret #endif ENDPROC(__get_user_8) @@ -103,6 +165,7 @@ bad_get_user: xor %edx,%edx mov $(-EFAULT),%_ASM_AX ASM_CLAC + pax_force_retaddr ret END(bad_get_user) @@ -112,6 +175,7 @@ bad_get_user_8: xor %ecx,%ecx mov $(-EFAULT),%_ASM_AX ASM_CLAC + pax_force_retaddr ret END(bad_get_user_8) #endif diff --git a/arch/x86/lib/insn.c b/arch/x86/lib/insn.c index 8f72b33..4667a46 100644 --- a/arch/x86/lib/insn.c +++ b/arch/x86/lib/insn.c @@ -20,8 +20,10 @@ #ifdef __KERNEL__ #include +#include #else #include +#define ktla_ktva(addr) addr #endif #include #include @@ -60,9 +62,9 @@ void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64) buf_len = MAX_INSN_SIZE; memset(insn, 0, sizeof(*insn)); - insn->kaddr = kaddr; - insn->end_kaddr = kaddr + buf_len; - insn->next_byte = kaddr; + insn->kaddr = (void *)ktla_ktva((unsigned long)kaddr); + insn->end_kaddr = insn->kaddr + buf_len; + insn->next_byte = insn->kaddr; insn->x86_64 = x86_64 ? 1 : 0; insn->opnd_bytes = 4; if (x86_64) diff --git a/arch/x86/lib/iomap_copy_64.S b/arch/x86/lib/iomap_copy_64.S index 33147fe..12a8815 100644 --- a/arch/x86/lib/iomap_copy_64.S +++ b/arch/x86/lib/iomap_copy_64.S @@ -16,6 +16,7 @@ */ #include +#include /* * override generic version in lib/iomap_copy.c @@ -23,5 +24,6 @@ ENTRY(__iowrite32_copy) movl %edx,%ecx rep movsd + pax_force_retaddr ret ENDPROC(__iowrite32_copy) diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S index 16698bb..971d300 100644 --- a/arch/x86/lib/memcpy_64.S +++ b/arch/x86/lib/memcpy_64.S @@ -36,6 +36,7 @@ ENTRY(memcpy) rep movsq movl %edx, %ecx rep movsb + pax_force_retaddr ret ENDPROC(memcpy) ENDPROC(__memcpy) @@ -48,6 +49,7 @@ ENTRY(memcpy_erms) movq %rdi, %rax movq %rdx, %rcx rep movsb + pax_force_retaddr ret ENDPROC(memcpy_erms) @@ -132,6 +134,7 @@ ENTRY(memcpy_orig) movq %r9, 1*8(%rdi) movq %r10, -2*8(%rdi, %rdx) movq %r11, -1*8(%rdi, %rdx) + pax_force_retaddr retq .p2align 4 .Lless_16bytes: @@ -144,6 +147,7 @@ ENTRY(memcpy_orig) movq -1*8(%rsi, %rdx), %r9 movq %r8, 0*8(%rdi) movq %r9, -1*8(%rdi, %rdx) + pax_force_retaddr retq .p2align 4 .Lless_8bytes: @@ -157,6 +161,7 @@ ENTRY(memcpy_orig) movl -4(%rsi, %rdx), %r8d movl %ecx, (%rdi) movl %r8d, -4(%rdi, %rdx) + pax_force_retaddr retq .p2align 4 .Lless_3bytes: @@ -175,5 +180,6 @@ ENTRY(memcpy_orig) movb %cl, (%rdi) .Lend: + pax_force_retaddr retq ENDPROC(memcpy_orig) diff --git a/arch/x86/lib/memmove_64.S b/arch/x86/lib/memmove_64.S index ca2afdd..2e474fa 100644 --- a/arch/x86/lib/memmove_64.S +++ b/arch/x86/lib/memmove_64.S @@ -41,7 +41,7 @@ ENTRY(__memmove) jg 2f .Lmemmove_begin_forward: - ALTERNATIVE "", "movq %rdx, %rcx; rep movsb; retq", X86_FEATURE_ERMS + ALTERNATIVE "", "movq %rdx, %rcx; rep movsb; pax_force_retaddr; retq", X86_FEATURE_ERMS /* * movsq instruction have many startup latency @@ -204,6 +204,7 @@ ENTRY(__memmove) movb (%rsi), %r11b movb %r11b, (%rdi) 13: + pax_force_retaddr retq ENDPROC(__memmove) ENDPROC(memmove) diff --git a/arch/x86/lib/memset_64.S b/arch/x86/lib/memset_64.S index 2661fad..b584d5c 100644 --- a/arch/x86/lib/memset_64.S +++ b/arch/x86/lib/memset_64.S @@ -40,6 +40,7 @@ ENTRY(__memset) movl %edx,%ecx rep stosb movq %r9,%rax + pax_force_retaddr ret ENDPROC(memset) ENDPROC(__memset) @@ -61,6 +62,7 @@ ENTRY(memset_erms) movq %rdx,%rcx rep stosb movq %r9,%rax + pax_force_retaddr ret ENDPROC(memset_erms) @@ -123,6 +125,7 @@ ENTRY(memset_orig) .Lende: movq %r10,%rax + pax_force_retaddr ret .Lbad_alignment: diff --git a/arch/x86/lib/mmx_32.c b/arch/x86/lib/mmx_32.c index e5e3ed8..d7c08c2 100644 --- a/arch/x86/lib/mmx_32.c +++ b/arch/x86/lib/mmx_32.c @@ -29,6 +29,7 @@ void *_mmx_memcpy(void *to, const void *from, size_t len) { void *p; int i; + unsigned long cr0; if (unlikely(in_interrupt())) return __memcpy(to, from, len); @@ -39,44 +40,72 @@ void *_mmx_memcpy(void *to, const void *from, size_t len) kernel_fpu_begin(); __asm__ __volatile__ ( - "1: prefetch (%0)\n" /* This set is 28 bytes */ - " prefetch 64(%0)\n" - " prefetch 128(%0)\n" - " prefetch 192(%0)\n" - " prefetch 256(%0)\n" + "1: prefetch (%1)\n" /* This set is 28 bytes */ + " prefetch 64(%1)\n" + " prefetch 128(%1)\n" + " prefetch 192(%1)\n" + " prefetch 256(%1)\n" "2: \n" ".section .fixup, \"ax\"\n" - "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + "3: \n" + +#ifdef CONFIG_PAX_KERNEXEC + " movl %%cr0, %0\n" + " movl %0, %%eax\n" + " andl $0xFFFEFFFF, %%eax\n" + " movl %%eax, %%cr0\n" +#endif + + " movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + +#ifdef CONFIG_PAX_KERNEXEC + " movl %0, %%cr0\n" +#endif + " jmp 2b\n" ".previous\n" _ASM_EXTABLE(1b, 3b) - : : "r" (from)); + : "=&r" (cr0) : "r" (from) : "ax"); for ( ; i > 5; i--) { __asm__ __volatile__ ( - "1: prefetch 320(%0)\n" - "2: movq (%0), %%mm0\n" - " movq 8(%0), %%mm1\n" - " movq 16(%0), %%mm2\n" - " movq 24(%0), %%mm3\n" - " movq %%mm0, (%1)\n" - " movq %%mm1, 8(%1)\n" - " movq %%mm2, 16(%1)\n" - " movq %%mm3, 24(%1)\n" - " movq 32(%0), %%mm0\n" - " movq 40(%0), %%mm1\n" - " movq 48(%0), %%mm2\n" - " movq 56(%0), %%mm3\n" - " movq %%mm0, 32(%1)\n" - " movq %%mm1, 40(%1)\n" - " movq %%mm2, 48(%1)\n" - " movq %%mm3, 56(%1)\n" + "1: prefetch 320(%1)\n" + "2: movq (%1), %%mm0\n" + " movq 8(%1), %%mm1\n" + " movq 16(%1), %%mm2\n" + " movq 24(%1), %%mm3\n" + " movq %%mm0, (%2)\n" + " movq %%mm1, 8(%2)\n" + " movq %%mm2, 16(%2)\n" + " movq %%mm3, 24(%2)\n" + " movq 32(%1), %%mm0\n" + " movq 40(%1), %%mm1\n" + " movq 48(%1), %%mm2\n" + " movq 56(%1), %%mm3\n" + " movq %%mm0, 32(%2)\n" + " movq %%mm1, 40(%2)\n" + " movq %%mm2, 48(%2)\n" + " movq %%mm3, 56(%2)\n" ".section .fixup, \"ax\"\n" - "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + "3:\n" + +#ifdef CONFIG_PAX_KERNEXEC + " movl %%cr0, %0\n" + " movl %0, %%eax\n" + " andl $0xFFFEFFFF, %%eax\n" + " movl %%eax, %%cr0\n" +#endif + + " movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + +#ifdef CONFIG_PAX_KERNEXEC + " movl %0, %%cr0\n" +#endif + " jmp 2b\n" ".previous\n" _ASM_EXTABLE(1b, 3b) - : : "r" (from), "r" (to) : "memory"); + : "=&r" (cr0) : "r" (from), "r" (to) : "memory", "ax"); from += 64; to += 64; @@ -158,6 +187,7 @@ static void fast_clear_page(void *page) static void fast_copy_page(void *to, void *from) { int i; + unsigned long cr0; kernel_fpu_begin(); @@ -166,42 +196,70 @@ static void fast_copy_page(void *to, void *from) * but that is for later. -AV */ __asm__ __volatile__( - "1: prefetch (%0)\n" - " prefetch 64(%0)\n" - " prefetch 128(%0)\n" - " prefetch 192(%0)\n" - " prefetch 256(%0)\n" + "1: prefetch (%1)\n" + " prefetch 64(%1)\n" + " prefetch 128(%1)\n" + " prefetch 192(%1)\n" + " prefetch 256(%1)\n" "2: \n" ".section .fixup, \"ax\"\n" - "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + "3: \n" + +#ifdef CONFIG_PAX_KERNEXEC + " movl %%cr0, %0\n" + " movl %0, %%eax\n" + " andl $0xFFFEFFFF, %%eax\n" + " movl %%eax, %%cr0\n" +#endif + + " movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + +#ifdef CONFIG_PAX_KERNEXEC + " movl %0, %%cr0\n" +#endif + " jmp 2b\n" ".previous\n" - _ASM_EXTABLE(1b, 3b) : : "r" (from)); + _ASM_EXTABLE(1b, 3b) : "=&r" (cr0) : "r" (from) : "ax"); for (i = 0; i < (4096-320)/64; i++) { __asm__ __volatile__ ( - "1: prefetch 320(%0)\n" - "2: movq (%0), %%mm0\n" - " movntq %%mm0, (%1)\n" - " movq 8(%0), %%mm1\n" - " movntq %%mm1, 8(%1)\n" - " movq 16(%0), %%mm2\n" - " movntq %%mm2, 16(%1)\n" - " movq 24(%0), %%mm3\n" - " movntq %%mm3, 24(%1)\n" - " movq 32(%0), %%mm4\n" - " movntq %%mm4, 32(%1)\n" - " movq 40(%0), %%mm5\n" - " movntq %%mm5, 40(%1)\n" - " movq 48(%0), %%mm6\n" - " movntq %%mm6, 48(%1)\n" - " movq 56(%0), %%mm7\n" - " movntq %%mm7, 56(%1)\n" + "1: prefetch 320(%1)\n" + "2: movq (%1), %%mm0\n" + " movntq %%mm0, (%2)\n" + " movq 8(%1), %%mm1\n" + " movntq %%mm1, 8(%2)\n" + " movq 16(%1), %%mm2\n" + " movntq %%mm2, 16(%2)\n" + " movq 24(%1), %%mm3\n" + " movntq %%mm3, 24(%2)\n" + " movq 32(%1), %%mm4\n" + " movntq %%mm4, 32(%2)\n" + " movq 40(%1), %%mm5\n" + " movntq %%mm5, 40(%2)\n" + " movq 48(%1), %%mm6\n" + " movntq %%mm6, 48(%2)\n" + " movq 56(%1), %%mm7\n" + " movntq %%mm7, 56(%2)\n" ".section .fixup, \"ax\"\n" - "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + "3:\n" + +#ifdef CONFIG_PAX_KERNEXEC + " movl %%cr0, %0\n" + " movl %0, %%eax\n" + " andl $0xFFFEFFFF, %%eax\n" + " movl %%eax, %%cr0\n" +#endif + + " movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + +#ifdef CONFIG_PAX_KERNEXEC + " movl %0, %%cr0\n" +#endif + " jmp 2b\n" ".previous\n" - _ASM_EXTABLE(1b, 3b) : : "r" (from), "r" (to) : "memory"); + _ASM_EXTABLE(1b, 3b) : "=&r" (cr0) : "r" (from), "r" (to) : "memory", "ax"); from += 64; to += 64; @@ -280,47 +338,76 @@ static void fast_clear_page(void *page) static void fast_copy_page(void *to, void *from) { int i; + unsigned long cr0; kernel_fpu_begin(); __asm__ __volatile__ ( - "1: prefetch (%0)\n" - " prefetch 64(%0)\n" - " prefetch 128(%0)\n" - " prefetch 192(%0)\n" - " prefetch 256(%0)\n" + "1: prefetch (%1)\n" + " prefetch 64(%1)\n" + " prefetch 128(%1)\n" + " prefetch 192(%1)\n" + " prefetch 256(%1)\n" "2: \n" ".section .fixup, \"ax\"\n" - "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + "3: \n" + +#ifdef CONFIG_PAX_KERNEXEC + " movl %%cr0, %0\n" + " movl %0, %%eax\n" + " andl $0xFFFEFFFF, %%eax\n" + " movl %%eax, %%cr0\n" +#endif + + " movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + +#ifdef CONFIG_PAX_KERNEXEC + " movl %0, %%cr0\n" +#endif + " jmp 2b\n" ".previous\n" - _ASM_EXTABLE(1b, 3b) : : "r" (from)); + _ASM_EXTABLE(1b, 3b) : "=&r" (cr0) : "r" (from) : "ax"); for (i = 0; i < 4096/64; i++) { __asm__ __volatile__ ( - "1: prefetch 320(%0)\n" - "2: movq (%0), %%mm0\n" - " movq 8(%0), %%mm1\n" - " movq 16(%0), %%mm2\n" - " movq 24(%0), %%mm3\n" - " movq %%mm0, (%1)\n" - " movq %%mm1, 8(%1)\n" - " movq %%mm2, 16(%1)\n" - " movq %%mm3, 24(%1)\n" - " movq 32(%0), %%mm0\n" - " movq 40(%0), %%mm1\n" - " movq 48(%0), %%mm2\n" - " movq 56(%0), %%mm3\n" - " movq %%mm0, 32(%1)\n" - " movq %%mm1, 40(%1)\n" - " movq %%mm2, 48(%1)\n" - " movq %%mm3, 56(%1)\n" + "1: prefetch 320(%1)\n" + "2: movq (%1), %%mm0\n" + " movq 8(%1), %%mm1\n" + " movq 16(%1), %%mm2\n" + " movq 24(%1), %%mm3\n" + " movq %%mm0, (%2)\n" + " movq %%mm1, 8(%2)\n" + " movq %%mm2, 16(%2)\n" + " movq %%mm3, 24(%2)\n" + " movq 32(%1), %%mm0\n" + " movq 40(%1), %%mm1\n" + " movq 48(%1), %%mm2\n" + " movq 56(%1), %%mm3\n" + " movq %%mm0, 32(%2)\n" + " movq %%mm1, 40(%2)\n" + " movq %%mm2, 48(%2)\n" + " movq %%mm3, 56(%2)\n" ".section .fixup, \"ax\"\n" - "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + "3:\n" + +#ifdef CONFIG_PAX_KERNEXEC + " movl %%cr0, %0\n" + " movl %0, %%eax\n" + " andl $0xFFFEFFFF, %%eax\n" + " movl %%eax, %%cr0\n" +#endif + + " movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + +#ifdef CONFIG_PAX_KERNEXEC + " movl %0, %%cr0\n" +#endif + " jmp 2b\n" ".previous\n" _ASM_EXTABLE(1b, 3b) - : : "r" (from), "r" (to) : "memory"); + : "=&r" (cr0) : "r" (from), "r" (to) : "memory", "ax"); from += 64; to += 64; diff --git a/arch/x86/lib/msr-reg.S b/arch/x86/lib/msr-reg.S index c815564..303dcfa 100644 --- a/arch/x86/lib/msr-reg.S +++ b/arch/x86/lib/msr-reg.S @@ -2,6 +2,7 @@ #include #include #include +#include #ifdef CONFIG_X86_64 /* @@ -34,6 +35,7 @@ ENTRY(\op\()_safe_regs) movl %edi, 28(%r10) popq %rbp popq %rbx + pax_force_retaddr ret 3: movl $-EIO, %r11d diff --git a/arch/x86/lib/putuser.S b/arch/x86/lib/putuser.S index e0817a1..bc9cf66 100644 --- a/arch/x86/lib/putuser.S +++ b/arch/x86/lib/putuser.S @@ -15,7 +15,9 @@ #include #include #include - +#include +#include +#include /* * __put_user_X @@ -29,55 +31,124 @@ * as they get called from within inline assembly. */ -#define ENTER GET_THREAD_INFO(%_ASM_BX) -#define EXIT ASM_CLAC ; \ +#define ENTER +#define EXIT ASM_CLAC ; \ + pax_force_retaddr ; \ ret +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) +#define _DEST %_ASM_CX,%_ASM_BX +#else +#define _DEST %_ASM_CX +#endif + +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_MEMORY_UDEREF) +#define __copyuser_seg gs; +#else +#define __copyuser_seg +#endif + .text ENTRY(__put_user_1) ENTER + +#if !defined(CONFIG_X86_32) || !defined(CONFIG_PAX_MEMORY_UDEREF) + GET_THREAD_INFO(%_ASM_BX) cmp TI_addr_limit(%_ASM_BX),%_ASM_CX jae bad_put_user + +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) + mov pax_user_shadow_base,%_ASM_BX + cmp %_ASM_BX,%_ASM_CX + jb 1234f + xor %ebx,%ebx +1234: +#endif + +#endif + ASM_STAC -1: movb %al,(%_ASM_CX) +1: __copyuser_seg movb %al,(_DEST) xor %eax,%eax EXIT ENDPROC(__put_user_1) ENTRY(__put_user_2) ENTER + +#if !defined(CONFIG_X86_32) || !defined(CONFIG_PAX_MEMORY_UDEREF) + GET_THREAD_INFO(%_ASM_BX) mov TI_addr_limit(%_ASM_BX),%_ASM_BX sub $1,%_ASM_BX cmp %_ASM_BX,%_ASM_CX jae bad_put_user + +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) + mov pax_user_shadow_base,%_ASM_BX + cmp %_ASM_BX,%_ASM_CX + jb 1234f + xor %ebx,%ebx +1234: +#endif + +#endif + ASM_STAC -2: movw %ax,(%_ASM_CX) +2: __copyuser_seg movw %ax,(_DEST) xor %eax,%eax EXIT ENDPROC(__put_user_2) ENTRY(__put_user_4) ENTER + +#if !defined(CONFIG_X86_32) || !defined(CONFIG_PAX_MEMORY_UDEREF) + GET_THREAD_INFO(%_ASM_BX) mov TI_addr_limit(%_ASM_BX),%_ASM_BX sub $3,%_ASM_BX cmp %_ASM_BX,%_ASM_CX jae bad_put_user + +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) + mov pax_user_shadow_base,%_ASM_BX + cmp %_ASM_BX,%_ASM_CX + jb 1234f + xor %ebx,%ebx +1234: +#endif + +#endif + ASM_STAC -3: movl %eax,(%_ASM_CX) +3: __copyuser_seg movl %eax,(_DEST) xor %eax,%eax EXIT ENDPROC(__put_user_4) ENTRY(__put_user_8) ENTER + +#if !defined(CONFIG_X86_32) || !defined(CONFIG_PAX_MEMORY_UDEREF) + GET_THREAD_INFO(%_ASM_BX) mov TI_addr_limit(%_ASM_BX),%_ASM_BX sub $7,%_ASM_BX cmp %_ASM_BX,%_ASM_CX jae bad_put_user + +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) + mov pax_user_shadow_base,%_ASM_BX + cmp %_ASM_BX,%_ASM_CX + jb 1234f + xor %ebx,%ebx +1234: +#endif + +#endif + ASM_STAC -4: mov %_ASM_AX,(%_ASM_CX) +4: __copyuser_seg mov %_ASM_AX,(_DEST) #ifdef CONFIG_X86_32 -5: movl %edx,4(%_ASM_CX) +5: __copyuser_seg movl %edx,4(_DEST) #endif xor %eax,%eax EXIT diff --git a/arch/x86/lib/rwsem.S b/arch/x86/lib/rwsem.S index 40027db..37bb69d 100644 --- a/arch/x86/lib/rwsem.S +++ b/arch/x86/lib/rwsem.S @@ -90,6 +90,7 @@ ENTRY(call_rwsem_down_read_failed) call rwsem_down_read_failed __ASM_SIZE(pop,) %__ASM_REG(dx) restore_common_regs + pax_force_retaddr ret ENDPROC(call_rwsem_down_read_failed) @@ -98,6 +99,7 @@ ENTRY(call_rwsem_down_write_failed) movq %rax,%rdi call rwsem_down_write_failed restore_common_regs + pax_force_retaddr ret ENDPROC(call_rwsem_down_write_failed) @@ -109,7 +111,8 @@ ENTRY(call_rwsem_wake) movq %rax,%rdi call rwsem_wake restore_common_regs -1: ret +1: pax_force_retaddr + ret ENDPROC(call_rwsem_wake) ENTRY(call_rwsem_downgrade_wake) @@ -119,5 +122,6 @@ ENTRY(call_rwsem_downgrade_wake) call rwsem_downgrade_wake __ASM_SIZE(pop,) %__ASM_REG(dx) restore_common_regs + pax_force_retaddr ret ENDPROC(call_rwsem_downgrade_wake) diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c index 91d93b9..4b22130 100644 --- a/arch/x86/lib/usercopy_32.c +++ b/arch/x86/lib/usercopy_32.c @@ -42,11 +42,13 @@ do { \ int __d0; \ might_fault(); \ __asm__ __volatile__( \ + __COPYUSER_SET_ES \ ASM_STAC "\n" \ "0: rep; stosl\n" \ " movl %2,%0\n" \ "1: rep; stosb\n" \ "2: " ASM_CLAC "\n" \ + __COPYUSER_RESTORE_ES \ ".section .fixup,\"ax\"\n" \ "3: lea 0(%2,%0,4),%0\n" \ " jmp 2b\n" \ @@ -98,7 +100,7 @@ EXPORT_SYMBOL(__clear_user); #ifdef CONFIG_X86_INTEL_USERCOPY static unsigned long -__copy_user_intel(void __user *to, const void *from, unsigned long size) +__generic_copy_to_user_intel(void __user *to, const void *from, unsigned long size) { int d0, d1; __asm__ __volatile__( @@ -110,36 +112,36 @@ __copy_user_intel(void __user *to, const void *from, unsigned long size) " .align 2,0x90\n" "3: movl 0(%4), %%eax\n" "4: movl 4(%4), %%edx\n" - "5: movl %%eax, 0(%3)\n" - "6: movl %%edx, 4(%3)\n" + "5: "__copyuser_seg" movl %%eax, 0(%3)\n" + "6: "__copyuser_seg" movl %%edx, 4(%3)\n" "7: movl 8(%4), %%eax\n" "8: movl 12(%4),%%edx\n" - "9: movl %%eax, 8(%3)\n" - "10: movl %%edx, 12(%3)\n" + "9: "__copyuser_seg" movl %%eax, 8(%3)\n" + "10: "__copyuser_seg" movl %%edx, 12(%3)\n" "11: movl 16(%4), %%eax\n" "12: movl 20(%4), %%edx\n" - "13: movl %%eax, 16(%3)\n" - "14: movl %%edx, 20(%3)\n" + "13: "__copyuser_seg" movl %%eax, 16(%3)\n" + "14: "__copyuser_seg" movl %%edx, 20(%3)\n" "15: movl 24(%4), %%eax\n" "16: movl 28(%4), %%edx\n" - "17: movl %%eax, 24(%3)\n" - "18: movl %%edx, 28(%3)\n" + "17: "__copyuser_seg" movl %%eax, 24(%3)\n" + "18: "__copyuser_seg" movl %%edx, 28(%3)\n" "19: movl 32(%4), %%eax\n" "20: movl 36(%4), %%edx\n" - "21: movl %%eax, 32(%3)\n" - "22: movl %%edx, 36(%3)\n" + "21: "__copyuser_seg" movl %%eax, 32(%3)\n" + "22: "__copyuser_seg" movl %%edx, 36(%3)\n" "23: movl 40(%4), %%eax\n" "24: movl 44(%4), %%edx\n" - "25: movl %%eax, 40(%3)\n" - "26: movl %%edx, 44(%3)\n" + "25: "__copyuser_seg" movl %%eax, 40(%3)\n" + "26: "__copyuser_seg" movl %%edx, 44(%3)\n" "27: movl 48(%4), %%eax\n" "28: movl 52(%4), %%edx\n" - "29: movl %%eax, 48(%3)\n" - "30: movl %%edx, 52(%3)\n" + "29: "__copyuser_seg" movl %%eax, 48(%3)\n" + "30: "__copyuser_seg" movl %%edx, 52(%3)\n" "31: movl 56(%4), %%eax\n" "32: movl 60(%4), %%edx\n" - "33: movl %%eax, 56(%3)\n" - "34: movl %%edx, 60(%3)\n" + "33: "__copyuser_seg" movl %%eax, 56(%3)\n" + "34: "__copyuser_seg" movl %%edx, 60(%3)\n" " addl $-64, %0\n" " addl $64, %4\n" " addl $64, %3\n" @@ -149,10 +151,116 @@ __copy_user_intel(void __user *to, const void *from, unsigned long size) " shrl $2, %0\n" " andl $3, %%eax\n" " cld\n" + __COPYUSER_SET_ES "99: rep; movsl\n" "36: movl %%eax, %0\n" "37: rep; movsb\n" "100:\n" + __COPYUSER_RESTORE_ES + ".section .fixup,\"ax\"\n" + "101: lea 0(%%eax,%0,4),%0\n" + " jmp 100b\n" + ".previous\n" + _ASM_EXTABLE(1b,100b) + _ASM_EXTABLE(2b,100b) + _ASM_EXTABLE(3b,100b) + _ASM_EXTABLE(4b,100b) + _ASM_EXTABLE(5b,100b) + _ASM_EXTABLE(6b,100b) + _ASM_EXTABLE(7b,100b) + _ASM_EXTABLE(8b,100b) + _ASM_EXTABLE(9b,100b) + _ASM_EXTABLE(10b,100b) + _ASM_EXTABLE(11b,100b) + _ASM_EXTABLE(12b,100b) + _ASM_EXTABLE(13b,100b) + _ASM_EXTABLE(14b,100b) + _ASM_EXTABLE(15b,100b) + _ASM_EXTABLE(16b,100b) + _ASM_EXTABLE(17b,100b) + _ASM_EXTABLE(18b,100b) + _ASM_EXTABLE(19b,100b) + _ASM_EXTABLE(20b,100b) + _ASM_EXTABLE(21b,100b) + _ASM_EXTABLE(22b,100b) + _ASM_EXTABLE(23b,100b) + _ASM_EXTABLE(24b,100b) + _ASM_EXTABLE(25b,100b) + _ASM_EXTABLE(26b,100b) + _ASM_EXTABLE(27b,100b) + _ASM_EXTABLE(28b,100b) + _ASM_EXTABLE(29b,100b) + _ASM_EXTABLE(30b,100b) + _ASM_EXTABLE(31b,100b) + _ASM_EXTABLE(32b,100b) + _ASM_EXTABLE(33b,100b) + _ASM_EXTABLE(34b,100b) + _ASM_EXTABLE(35b,100b) + _ASM_EXTABLE(36b,100b) + _ASM_EXTABLE(37b,100b) + _ASM_EXTABLE(99b,101b) + : "=&c"(size), "=&D" (d0), "=&S" (d1) + : "1"(to), "2"(from), "0"(size) + : "eax", "edx", "memory"); + return size; +} + +static unsigned long +__generic_copy_from_user_intel(void *to, const void __user *from, unsigned long size) +{ + int d0, d1; + __asm__ __volatile__( + " .align 2,0x90\n" + "1: "__copyuser_seg" movl 32(%4), %%eax\n" + " cmpl $67, %0\n" + " jbe 3f\n" + "2: "__copyuser_seg" movl 64(%4), %%eax\n" + " .align 2,0x90\n" + "3: "__copyuser_seg" movl 0(%4), %%eax\n" + "4: "__copyuser_seg" movl 4(%4), %%edx\n" + "5: movl %%eax, 0(%3)\n" + "6: movl %%edx, 4(%3)\n" + "7: "__copyuser_seg" movl 8(%4), %%eax\n" + "8: "__copyuser_seg" movl 12(%4),%%edx\n" + "9: movl %%eax, 8(%3)\n" + "10: movl %%edx, 12(%3)\n" + "11: "__copyuser_seg" movl 16(%4), %%eax\n" + "12: "__copyuser_seg" movl 20(%4), %%edx\n" + "13: movl %%eax, 16(%3)\n" + "14: movl %%edx, 20(%3)\n" + "15: "__copyuser_seg" movl 24(%4), %%eax\n" + "16: "__copyuser_seg" movl 28(%4), %%edx\n" + "17: movl %%eax, 24(%3)\n" + "18: movl %%edx, 28(%3)\n" + "19: "__copyuser_seg" movl 32(%4), %%eax\n" + "20: "__copyuser_seg" movl 36(%4), %%edx\n" + "21: movl %%eax, 32(%3)\n" + "22: movl %%edx, 36(%3)\n" + "23: "__copyuser_seg" movl 40(%4), %%eax\n" + "24: "__copyuser_seg" movl 44(%4), %%edx\n" + "25: movl %%eax, 40(%3)\n" + "26: movl %%edx, 44(%3)\n" + "27: "__copyuser_seg" movl 48(%4), %%eax\n" + "28: "__copyuser_seg" movl 52(%4), %%edx\n" + "29: movl %%eax, 48(%3)\n" + "30: movl %%edx, 52(%3)\n" + "31: "__copyuser_seg" movl 56(%4), %%eax\n" + "32: "__copyuser_seg" movl 60(%4), %%edx\n" + "33: movl %%eax, 56(%3)\n" + "34: movl %%edx, 60(%3)\n" + " addl $-64, %0\n" + " addl $64, %4\n" + " addl $64, %3\n" + " cmpl $63, %0\n" + " ja 1b\n" + "35: movl %0, %%eax\n" + " shrl $2, %0\n" + " andl $3, %%eax\n" + " cld\n" + "99: rep; "__copyuser_seg" movsl\n" + "36: movl %%eax, %0\n" + "37: rep; "__copyuser_seg" movsb\n" + "100:\n" ".section .fixup,\"ax\"\n" "101: lea 0(%%eax,%0,4),%0\n" " jmp 100b\n" @@ -207,41 +315,41 @@ __copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size) int d0, d1; __asm__ __volatile__( " .align 2,0x90\n" - "0: movl 32(%4), %%eax\n" + "0: "__copyuser_seg" movl 32(%4), %%eax\n" " cmpl $67, %0\n" " jbe 2f\n" - "1: movl 64(%4), %%eax\n" + "1: "__copyuser_seg" movl 64(%4), %%eax\n" " .align 2,0x90\n" - "2: movl 0(%4), %%eax\n" - "21: movl 4(%4), %%edx\n" + "2: "__copyuser_seg" movl 0(%4), %%eax\n" + "21: "__copyuser_seg" movl 4(%4), %%edx\n" " movl %%eax, 0(%3)\n" " movl %%edx, 4(%3)\n" - "3: movl 8(%4), %%eax\n" - "31: movl 12(%4),%%edx\n" + "3: "__copyuser_seg" movl 8(%4), %%eax\n" + "31: "__copyuser_seg" movl 12(%4),%%edx\n" " movl %%eax, 8(%3)\n" " movl %%edx, 12(%3)\n" - "4: movl 16(%4), %%eax\n" - "41: movl 20(%4), %%edx\n" + "4: "__copyuser_seg" movl 16(%4), %%eax\n" + "41: "__copyuser_seg" movl 20(%4), %%edx\n" " movl %%eax, 16(%3)\n" " movl %%edx, 20(%3)\n" - "10: movl 24(%4), %%eax\n" - "51: movl 28(%4), %%edx\n" + "10: "__copyuser_seg" movl 24(%4), %%eax\n" + "51: "__copyuser_seg" movl 28(%4), %%edx\n" " movl %%eax, 24(%3)\n" " movl %%edx, 28(%3)\n" - "11: movl 32(%4), %%eax\n" - "61: movl 36(%4), %%edx\n" + "11: "__copyuser_seg" movl 32(%4), %%eax\n" + "61: "__copyuser_seg" movl 36(%4), %%edx\n" " movl %%eax, 32(%3)\n" " movl %%edx, 36(%3)\n" - "12: movl 40(%4), %%eax\n" - "71: movl 44(%4), %%edx\n" + "12: "__copyuser_seg" movl 40(%4), %%eax\n" + "71: "__copyuser_seg" movl 44(%4), %%edx\n" " movl %%eax, 40(%3)\n" " movl %%edx, 44(%3)\n" - "13: movl 48(%4), %%eax\n" - "81: movl 52(%4), %%edx\n" + "13: "__copyuser_seg" movl 48(%4), %%eax\n" + "81: "__copyuser_seg" movl 52(%4), %%edx\n" " movl %%eax, 48(%3)\n" " movl %%edx, 52(%3)\n" - "14: movl 56(%4), %%eax\n" - "91: movl 60(%4), %%edx\n" + "14: "__copyuser_seg" movl 56(%4), %%eax\n" + "91: "__copyuser_seg" movl 60(%4), %%edx\n" " movl %%eax, 56(%3)\n" " movl %%edx, 60(%3)\n" " addl $-64, %0\n" @@ -253,9 +361,9 @@ __copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size) " shrl $2, %0\n" " andl $3, %%eax\n" " cld\n" - "6: rep; movsl\n" + "6: rep; "__copyuser_seg" movsl\n" " movl %%eax,%0\n" - "7: rep; movsb\n" + "7: rep; "__copyuser_seg" movsb\n" "8:\n" ".section .fixup,\"ax\"\n" "9: lea 0(%%eax,%0,4),%0\n" @@ -305,41 +413,41 @@ static unsigned long __copy_user_zeroing_intel_nocache(void *to, __asm__ __volatile__( " .align 2,0x90\n" - "0: movl 32(%4), %%eax\n" + "0: "__copyuser_seg" movl 32(%4), %%eax\n" " cmpl $67, %0\n" " jbe 2f\n" - "1: movl 64(%4), %%eax\n" + "1: "__copyuser_seg" movl 64(%4), %%eax\n" " .align 2,0x90\n" - "2: movl 0(%4), %%eax\n" - "21: movl 4(%4), %%edx\n" + "2: "__copyuser_seg" movl 0(%4), %%eax\n" + "21: "__copyuser_seg" movl 4(%4), %%edx\n" " movnti %%eax, 0(%3)\n" " movnti %%edx, 4(%3)\n" - "3: movl 8(%4), %%eax\n" - "31: movl 12(%4),%%edx\n" + "3: "__copyuser_seg" movl 8(%4), %%eax\n" + "31: "__copyuser_seg" movl 12(%4),%%edx\n" " movnti %%eax, 8(%3)\n" " movnti %%edx, 12(%3)\n" - "4: movl 16(%4), %%eax\n" - "41: movl 20(%4), %%edx\n" + "4: "__copyuser_seg" movl 16(%4), %%eax\n" + "41: "__copyuser_seg" movl 20(%4), %%edx\n" " movnti %%eax, 16(%3)\n" " movnti %%edx, 20(%3)\n" - "10: movl 24(%4), %%eax\n" - "51: movl 28(%4), %%edx\n" + "10: "__copyuser_seg" movl 24(%4), %%eax\n" + "51: "__copyuser_seg" movl 28(%4), %%edx\n" " movnti %%eax, 24(%3)\n" " movnti %%edx, 28(%3)\n" - "11: movl 32(%4), %%eax\n" - "61: movl 36(%4), %%edx\n" + "11: "__copyuser_seg" movl 32(%4), %%eax\n" + "61: "__copyuser_seg" movl 36(%4), %%edx\n" " movnti %%eax, 32(%3)\n" " movnti %%edx, 36(%3)\n" - "12: movl 40(%4), %%eax\n" - "71: movl 44(%4), %%edx\n" + "12: "__copyuser_seg" movl 40(%4), %%eax\n" + "71: "__copyuser_seg" movl 44(%4), %%edx\n" " movnti %%eax, 40(%3)\n" " movnti %%edx, 44(%3)\n" - "13: movl 48(%4), %%eax\n" - "81: movl 52(%4), %%edx\n" + "13: "__copyuser_seg" movl 48(%4), %%eax\n" + "81: "__copyuser_seg" movl 52(%4), %%edx\n" " movnti %%eax, 48(%3)\n" " movnti %%edx, 52(%3)\n" - "14: movl 56(%4), %%eax\n" - "91: movl 60(%4), %%edx\n" + "14: "__copyuser_seg" movl 56(%4), %%eax\n" + "91: "__copyuser_seg" movl 60(%4), %%edx\n" " movnti %%eax, 56(%3)\n" " movnti %%edx, 60(%3)\n" " addl $-64, %0\n" @@ -352,9 +460,9 @@ static unsigned long __copy_user_zeroing_intel_nocache(void *to, " shrl $2, %0\n" " andl $3, %%eax\n" " cld\n" - "6: rep; movsl\n" + "6: rep; "__copyuser_seg" movsl\n" " movl %%eax,%0\n" - "7: rep; movsb\n" + "7: rep; "__copyuser_seg" movsb\n" "8:\n" ".section .fixup,\"ax\"\n" "9: lea 0(%%eax,%0,4),%0\n" @@ -399,41 +507,41 @@ static unsigned long __copy_user_intel_nocache(void *to, __asm__ __volatile__( " .align 2,0x90\n" - "0: movl 32(%4), %%eax\n" + "0: "__copyuser_seg" movl 32(%4), %%eax\n" " cmpl $67, %0\n" " jbe 2f\n" - "1: movl 64(%4), %%eax\n" + "1: "__copyuser_seg" movl 64(%4), %%eax\n" " .align 2,0x90\n" - "2: movl 0(%4), %%eax\n" - "21: movl 4(%4), %%edx\n" + "2: "__copyuser_seg" movl 0(%4), %%eax\n" + "21: "__copyuser_seg" movl 4(%4), %%edx\n" " movnti %%eax, 0(%3)\n" " movnti %%edx, 4(%3)\n" - "3: movl 8(%4), %%eax\n" - "31: movl 12(%4),%%edx\n" + "3: "__copyuser_seg" movl 8(%4), %%eax\n" + "31: "__copyuser_seg" movl 12(%4),%%edx\n" " movnti %%eax, 8(%3)\n" " movnti %%edx, 12(%3)\n" - "4: movl 16(%4), %%eax\n" - "41: movl 20(%4), %%edx\n" + "4: "__copyuser_seg" movl 16(%4), %%eax\n" + "41: "__copyuser_seg" movl 20(%4), %%edx\n" " movnti %%eax, 16(%3)\n" " movnti %%edx, 20(%3)\n" - "10: movl 24(%4), %%eax\n" - "51: movl 28(%4), %%edx\n" + "10: "__copyuser_seg" movl 24(%4), %%eax\n" + "51: "__copyuser_seg" movl 28(%4), %%edx\n" " movnti %%eax, 24(%3)\n" " movnti %%edx, 28(%3)\n" - "11: movl 32(%4), %%eax\n" - "61: movl 36(%4), %%edx\n" + "11: "__copyuser_seg" movl 32(%4), %%eax\n" + "61: "__copyuser_seg" movl 36(%4), %%edx\n" " movnti %%eax, 32(%3)\n" " movnti %%edx, 36(%3)\n" - "12: movl 40(%4), %%eax\n" - "71: movl 44(%4), %%edx\n" + "12: "__copyuser_seg" movl 40(%4), %%eax\n" + "71: "__copyuser_seg" movl 44(%4), %%edx\n" " movnti %%eax, 40(%3)\n" " movnti %%edx, 44(%3)\n" - "13: movl 48(%4), %%eax\n" - "81: movl 52(%4), %%edx\n" + "13: "__copyuser_seg" movl 48(%4), %%eax\n" + "81: "__copyuser_seg" movl 52(%4), %%edx\n" " movnti %%eax, 48(%3)\n" " movnti %%edx, 52(%3)\n" - "14: movl 56(%4), %%eax\n" - "91: movl 60(%4), %%edx\n" + "14: "__copyuser_seg" movl 56(%4), %%eax\n" + "91: "__copyuser_seg" movl 60(%4), %%edx\n" " movnti %%eax, 56(%3)\n" " movnti %%edx, 60(%3)\n" " addl $-64, %0\n" @@ -446,9 +554,9 @@ static unsigned long __copy_user_intel_nocache(void *to, " shrl $2, %0\n" " andl $3, %%eax\n" " cld\n" - "6: rep; movsl\n" + "6: rep; "__copyuser_seg" movsl\n" " movl %%eax,%0\n" - "7: rep; movsb\n" + "7: rep; "__copyuser_seg" movsb\n" "8:\n" ".section .fixup,\"ax\"\n" "9: lea 0(%%eax,%0,4),%0\n" @@ -488,32 +596,36 @@ static unsigned long __copy_user_intel_nocache(void *to, */ unsigned long __copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size); -unsigned long __copy_user_intel(void __user *to, const void *from, +unsigned long __generic_copy_to_user_intel(void __user *to, const void *from, + unsigned long size); +unsigned long __generic_copy_from_user_intel(void *to, const void __user *from, unsigned long size); unsigned long __copy_user_zeroing_intel_nocache(void *to, const void __user *from, unsigned long size); #endif /* CONFIG_X86_INTEL_USERCOPY */ /* Generic arbitrary sized copy. */ -#define __copy_user(to, from, size) \ +#define __copy_user(to, from, size, prefix, set, restore) \ do { \ int __d0, __d1, __d2; \ __asm__ __volatile__( \ + set \ " cmp $7,%0\n" \ " jbe 1f\n" \ " movl %1,%0\n" \ " negl %0\n" \ " andl $7,%0\n" \ " subl %0,%3\n" \ - "4: rep; movsb\n" \ + "4: rep; "prefix"movsb\n" \ " movl %3,%0\n" \ " shrl $2,%0\n" \ " andl $3,%3\n" \ " .align 2,0x90\n" \ - "0: rep; movsl\n" \ + "0: rep; "prefix"movsl\n" \ " movl %3,%0\n" \ - "1: rep; movsb\n" \ + "1: rep; "prefix"movsb\n" \ "2:\n" \ + restore \ ".section .fixup,\"ax\"\n" \ "5: addl %3,%0\n" \ " jmp 2b\n" \ @@ -538,14 +650,14 @@ do { \ " negl %0\n" \ " andl $7,%0\n" \ " subl %0,%3\n" \ - "4: rep; movsb\n" \ + "4: rep; "__copyuser_seg"movsb\n" \ " movl %3,%0\n" \ " shrl $2,%0\n" \ " andl $3,%3\n" \ " .align 2,0x90\n" \ - "0: rep; movsl\n" \ + "0: rep; "__copyuser_seg"movsl\n" \ " movl %3,%0\n" \ - "1: rep; movsb\n" \ + "1: rep; "__copyuser_seg"movsb\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ "5: addl %3,%0\n" \ @@ -572,9 +684,9 @@ unsigned long __copy_to_user_ll(void __user *to, const void *from, { stac(); if (movsl_is_ok(to, from, n)) - __copy_user(to, from, n); + __copy_user(to, from, n, "", __COPYUSER_SET_ES, __COPYUSER_RESTORE_ES); else - n = __copy_user_intel(to, from, n); + n = __generic_copy_to_user_intel(to, from, n); clac(); return n; } @@ -598,10 +710,9 @@ unsigned long __copy_from_user_ll_nozero(void *to, const void __user *from, { stac(); if (movsl_is_ok(to, from, n)) - __copy_user(to, from, n); + __copy_user(to, from, n, __copyuser_seg, "", ""); else - n = __copy_user_intel((void __user *)to, - (const void *)from, n); + n = __generic_copy_from_user_intel(to, from, n); clac(); return n; } @@ -632,60 +743,38 @@ unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *fr if (n > 64 && cpu_has_xmm2) n = __copy_user_intel_nocache(to, from, n); else - __copy_user(to, from, n); + __copy_user(to, from, n, __copyuser_seg, "", ""); #else - __copy_user(to, from, n); + __copy_user(to, from, n, __copyuser_seg, "", ""); #endif clac(); return n; } EXPORT_SYMBOL(__copy_from_user_ll_nocache_nozero); -/** - * copy_to_user: - Copy a block of data into user space. - * @to: Destination address, in user space. - * @from: Source address, in kernel space. - * @n: Number of bytes to copy. - * - * Context: User context only. This function may sleep if pagefaults are - * enabled. - * - * Copy data from kernel space to user space. - * - * Returns number of bytes that could not be copied. - * On success, this will be zero. - */ -unsigned long _copy_to_user(void __user *to, const void *from, unsigned n) +#ifdef CONFIG_PAX_MEMORY_UDEREF +void __set_fs(mm_segment_t x) { - if (access_ok(VERIFY_WRITE, to, n)) - n = __copy_to_user(to, from, n); - return n; + switch (x.seg) { + case 0: + loadsegment(gs, 0); + break; + case TASK_SIZE_MAX: + loadsegment(gs, __USER_DS); + break; + case -1UL: + loadsegment(gs, __KERNEL_DS); + break; + default: + BUG(); + } } -EXPORT_SYMBOL(_copy_to_user); +EXPORT_SYMBOL(__set_fs); -/** - * copy_from_user: - Copy a block of data from user space. - * @to: Destination address, in kernel space. - * @from: Source address, in user space. - * @n: Number of bytes to copy. - * - * Context: User context only. This function may sleep if pagefaults are - * enabled. - * - * Copy data from user space to kernel space. - * - * Returns number of bytes that could not be copied. - * On success, this will be zero. - * - * If some data could not be copied, this function will pad the copied - * data to the requested size using zero bytes. - */ -unsigned long _copy_from_user(void *to, const void __user *from, unsigned n) +void set_fs(mm_segment_t x) { - if (access_ok(VERIFY_READ, from, n)) - n = __copy_from_user(to, from, n); - else - memset(to, 0, n); - return n; + current_thread_info()->addr_limit = x; + __set_fs(x); } -EXPORT_SYMBOL(_copy_from_user); +EXPORT_SYMBOL(set_fs); +#endif diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c index 0a42327..45c0063 100644 --- a/arch/x86/lib/usercopy_64.c +++ b/arch/x86/lib/usercopy_64.c @@ -18,6 +18,7 @@ unsigned long __clear_user(void __user *addr, unsigned long size) might_fault(); /* no memory constraint because it doesn't change any memory gcc knows about */ + pax_open_userland(); stac(); asm volatile( " testq %[size8],%[size8]\n" @@ -39,9 +40,10 @@ unsigned long __clear_user(void __user *addr, unsigned long size) _ASM_EXTABLE(0b,3b) _ASM_EXTABLE(1b,2b) : [size8] "=&c"(size), [dst] "=&D" (__d0) - : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr), + : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(____m(addr)), [zero] "r" (0UL), [eight] "r" (8UL)); clac(); + pax_close_userland(); return size; } EXPORT_SYMBOL(__clear_user); @@ -54,12 +56,11 @@ unsigned long clear_user(void __user *to, unsigned long n) } EXPORT_SYMBOL(clear_user); -unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len) +unsigned long copy_in_user(void __user *to, const void __user *from, unsigned long len) { - if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) { - return copy_user_generic((__force void *)to, (__force void *)from, len); - } - return len; + if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) + return copy_user_generic((void __force_kernel *)____m(to), (void __force_kernel *)____m(from), len); + return len; } EXPORT_SYMBOL(copy_in_user); @@ -69,8 +70,10 @@ EXPORT_SYMBOL(copy_in_user); * it is not necessary to optimize tail handling. */ __visible unsigned long -copy_user_handle_tail(char *to, char *from, unsigned len) +copy_user_handle_tail(char __user *to, char __user *from, unsigned long len) { + clac(); + pax_close_userland(); for (; len; --len, to++) { char c; @@ -79,10 +82,9 @@ copy_user_handle_tail(char *to, char *from, unsigned len) if (__put_user_nocheck(c, to, sizeof(char))) break; } - clac(); /* If the destination is a kernel buffer, we always clear the end */ - if (!__addr_ok(to)) - memset(to, 0, len); + if (!__addr_ok(to) && (unsigned long)to >= TASK_SIZE_MAX + pax_user_shadow_base) + memset((void __force_kernel *)to, 0, len); return len; } diff --git a/arch/x86/math-emu/fpu_aux.c b/arch/x86/math-emu/fpu_aux.c index dd76a05..df65688 100644 --- a/arch/x86/math-emu/fpu_aux.c +++ b/arch/x86/math-emu/fpu_aux.c @@ -52,7 +52,7 @@ void fpstate_init_soft(struct swregs_state *soft) void finit(void) { - fpstate_init_soft(¤t->thread.fpu.state.soft); + fpstate_init_soft(¤t->thread.fpu.state->soft); } /* diff --git a/arch/x86/math-emu/fpu_entry.c b/arch/x86/math-emu/fpu_entry.c index 3d8f2e4..ef7cf4e 100644 --- a/arch/x86/math-emu/fpu_entry.c +++ b/arch/x86/math-emu/fpu_entry.c @@ -677,7 +677,7 @@ int fpregs_soft_set(struct task_struct *target, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { - struct swregs_state *s387 = &target->thread.fpu.state.soft; + struct swregs_state *s387 = &target->thread.fpu.state->soft; void *space = s387->st_space; int ret; int offset, other, i, tags, regnr, tag, newtop; @@ -729,7 +729,7 @@ int fpregs_soft_get(struct task_struct *target, unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) { - struct swregs_state *s387 = &target->thread.fpu.state.soft; + struct swregs_state *s387 = &target->thread.fpu.state->soft; const void *space = s387->st_space; int ret; int offset = (S387->ftop & 7) * 10, other = 80 - offset; diff --git a/arch/x86/math-emu/fpu_system.h b/arch/x86/math-emu/fpu_system.h index 5e044d5..d342fce 100644 --- a/arch/x86/math-emu/fpu_system.h +++ b/arch/x86/math-emu/fpu_system.h @@ -46,7 +46,7 @@ static inline struct desc_struct FPU_get_ldt_descriptor(unsigned seg) #define SEG_EXPAND_DOWN(s) (((s).b & ((1 << 11) | (1 << 10))) \ == (1 << 10)) -#define I387 (¤t->thread.fpu.state) +#define I387 (current->thread.fpu.state) #define FPU_info (I387->soft.info) #define FPU_CS (*(unsigned short *) &(FPU_info->regs->cs)) diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index a482d10..1a6edb5 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile @@ -33,3 +33,7 @@ obj-$(CONFIG_ACPI_NUMA) += srat.o obj-$(CONFIG_NUMA_EMU) += numa_emulation.o obj-$(CONFIG_X86_INTEL_MPX) += mpx.o + +quote:=" +obj-$(CONFIG_X86_64) += uderef_64.o +CFLAGS_uderef_64.o := $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS)) -fcall-saved-rax diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c index 903ec1e..41b4708 100644 --- a/arch/x86/mm/extable.c +++ b/arch/x86/mm/extable.c @@ -2,16 +2,29 @@ #include #include #include +#include static inline unsigned long ex_insn_addr(const struct exception_table_entry *x) { - return (unsigned long)&x->insn + x->insn; + unsigned long reloc = 0; + +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) + reloc = ____LOAD_PHYSICAL_ADDR - LOAD_PHYSICAL_ADDR; +#endif + + return (unsigned long)&x->insn + x->insn + reloc; } static inline unsigned long ex_fixup_addr(const struct exception_table_entry *x) { - return (unsigned long)&x->fixup + x->fixup; + unsigned long reloc = 0; + +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) + reloc = ____LOAD_PHYSICAL_ADDR - LOAD_PHYSICAL_ADDR; +#endif + + return (unsigned long)&x->fixup + x->fixup + reloc; } int fixup_exception(struct pt_regs *regs) @@ -20,7 +33,7 @@ int fixup_exception(struct pt_regs *regs) unsigned long new_ip; #ifdef CONFIG_PNPBIOS - if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) { + if (unlikely(!v8086_mode(regs) && SEGMENT_IS_PNP_CODE(regs->cs))) { extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp; extern u32 pnp_bios_is_utter_crap; pnp_bios_is_utter_crap = 1; @@ -145,6 +158,13 @@ void sort_extable(struct exception_table_entry *start, i += 4; p->fixup -= i; i += 4; + +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) + BUILD_BUG_ON(!IS_ENABLED(CONFIG_BUILDTIME_EXTABLE_SORT)); + p->insn -= ____LOAD_PHYSICAL_ADDR - LOAD_PHYSICAL_ADDR; + p->fixup -= ____LOAD_PHYSICAL_ADDR - LOAD_PHYSICAL_ADDR; +#endif + } } diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index eef44d9..79b0e58 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -14,6 +14,8 @@ #include /* prefetchw */ #include /* exception_enter(), ... */ #include /* faulthandler_disabled() */ +#include +#include #include /* dotraplinkage, ... */ #include /* pgd_*(), ... */ @@ -21,6 +23,11 @@ #include /* VSYSCALL_ADDR */ #include /* emulate_vsyscall */ #include /* struct vm86 */ +#include + +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) +#include +#endif #define CREATE_TRACE_POINTS #include @@ -122,7 +129,10 @@ check_prefetch_opcode(struct pt_regs *regs, unsigned char *instr, return !instr_lo || (instr_lo>>1) == 1; case 0x00: /* Prefetch instruction is 0x0F0D or 0x0F18 */ - if (probe_kernel_address(instr, opcode)) + if (user_mode(regs)) { + if (__copy_from_user_inatomic(&opcode, (unsigned char __force_user *)(instr), 1)) + return 0; + } else if (probe_kernel_address(instr, opcode)) return 0; *prefetch = (instr_lo == 0xF) && @@ -156,7 +166,10 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr) while (instr < max_instr) { unsigned char opcode; - if (probe_kernel_address(instr, opcode)) + if (user_mode(regs)) { + if (__copy_from_user_inatomic(&opcode, (unsigned char __force_user *)(instr), 1)) + break; + } else if (probe_kernel_address(instr, opcode)) break; instr++; @@ -187,6 +200,34 @@ force_sig_info_fault(int si_signo, int si_code, unsigned long address, force_sig_info(si_signo, &info, tsk); } +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) +static bool pax_is_fetch_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address); +#endif + +#ifdef CONFIG_PAX_EMUTRAMP +static int pax_handle_fetch_fault(struct pt_regs *regs); +#endif + +#ifdef CONFIG_PAX_PAGEEXEC +static inline pmd_t * pax_get_pmd(struct mm_struct *mm, unsigned long address) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + + pgd = pgd_offset(mm, address); + if (!pgd_present(*pgd)) + return NULL; + pud = pud_offset(pgd, address); + if (!pud_present(*pud)) + return NULL; + pmd = pmd_offset(pud, address); + if (!pmd_present(*pmd)) + return NULL; + return pmd; +} +#endif + DEFINE_SPINLOCK(pgd_lock); LIST_HEAD(pgd_list); @@ -237,10 +278,27 @@ void vmalloc_sync_all(void) for (address = VMALLOC_START & PMD_MASK; address >= TASK_SIZE && address < FIXADDR_TOP; address += PMD_SIZE) { + +#ifdef CONFIG_PAX_PER_CPU_PGD + unsigned long cpu; +#else struct page *page; +#endif spin_lock(&pgd_lock); + +#ifdef CONFIG_PAX_PER_CPU_PGD + for (cpu = 0; cpu < nr_cpu_ids; ++cpu) { + pgd_t *pgd = get_cpu_pgd(cpu, user); + pmd_t *ret; + + ret = vmalloc_sync_one(pgd, address); + if (!ret) + break; + pgd = get_cpu_pgd(cpu, kernel); +#else list_for_each_entry(page, &pgd_list, lru) { + pgd_t *pgd; spinlock_t *pgt_lock; pmd_t *ret; @@ -248,8 +306,14 @@ void vmalloc_sync_all(void) pgt_lock = &pgd_page_get_mm(page)->page_table_lock; spin_lock(pgt_lock); - ret = vmalloc_sync_one(page_address(page), address); + pgd = page_address(page); +#endif + + ret = vmalloc_sync_one(pgd, address); + +#ifndef CONFIG_PAX_PER_CPU_PGD spin_unlock(pgt_lock); +#endif if (!ret) break; @@ -283,6 +347,12 @@ static noinline int vmalloc_fault(unsigned long address) * an interrupt in the middle of a task switch.. */ pgd_paddr = read_cr3(); + +#ifdef CONFIG_PAX_PER_CPU_PGD + BUG_ON(__pa(get_cpu_pgd(smp_processor_id(), kernel)) != (pgd_paddr & __PHYSICAL_MASK)); + vmalloc_sync_one(__va(pgd_paddr + PAGE_SIZE), address); +#endif + pmd_k = vmalloc_sync_one(__va(pgd_paddr), address); if (!pmd_k) return -1; @@ -381,11 +451,25 @@ static noinline int vmalloc_fault(unsigned long address) * happen within a race in page table update. In the later * case just flush: */ - pgd = pgd_offset(current->active_mm, address); + pgd_ref = pgd_offset_k(address); if (pgd_none(*pgd_ref)) return -1; +#ifdef CONFIG_PAX_PER_CPU_PGD + BUG_ON(__pa(get_cpu_pgd(smp_processor_id(), kernel)) != (read_cr3() & __PHYSICAL_MASK)); + pgd = pgd_offset_cpu(smp_processor_id(), user, address); + if (pgd_none(*pgd)) { + set_pgd(pgd, *pgd_ref); + arch_flush_lazy_mmu_mode(); + } else { + BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref)); + } + pgd = pgd_offset_cpu(smp_processor_id(), kernel, address); +#else + pgd = pgd_offset(current->active_mm, address); +#endif + if (pgd_none(*pgd)) { set_pgd(pgd, *pgd_ref); arch_flush_lazy_mmu_mode(); @@ -552,7 +636,7 @@ static int is_errata93(struct pt_regs *regs, unsigned long address) static int is_errata100(struct pt_regs *regs, unsigned long address) { #ifdef CONFIG_X86_64 - if ((regs->cs == __USER32_CS || (regs->cs & (1<<2))) && (address >> 32)) + if ((regs->cs == __USER32_CS || (regs->cs & SEGMENT_LDT)) && (address >> 32)) return 1; #endif return 0; @@ -579,9 +663,9 @@ static int is_f00f_bug(struct pt_regs *regs, unsigned long address) } static const char nx_warning[] = KERN_CRIT -"kernel tried to execute NX-protected page - exploit attempt? (uid: %d)\n"; +"kernel tried to execute NX-protected page - exploit attempt? (uid: %d, task: %s, pid: %d)\n"; static const char smep_warning[] = KERN_CRIT -"unable to execute userspace code (SMEP?) (uid: %d)\n"; +"unable to execute userspace code (SMEP?) (uid: %d, task: %s, pid: %d)\n"; static void show_fault_oops(struct pt_regs *regs, unsigned long error_code, @@ -590,7 +674,7 @@ show_fault_oops(struct pt_regs *regs, unsigned long error_code, if (!oops_may_print()) return; - if (error_code & PF_INSTR) { + if ((__supported_pte_mask & _PAGE_NX) && (error_code & PF_INSTR)) { unsigned int level; pgd_t *pgd; pte_t *pte; @@ -601,13 +685,25 @@ show_fault_oops(struct pt_regs *regs, unsigned long error_code, pte = lookup_address_in_pgd(pgd, address, &level); if (pte && pte_present(*pte) && !pte_exec(*pte)) - printk(nx_warning, from_kuid(&init_user_ns, current_uid())); + printk(nx_warning, from_kuid_munged(&init_user_ns, current_uid()), current->comm, task_pid_nr(current)); if (pte && pte_present(*pte) && pte_exec(*pte) && (pgd_flags(*pgd) & _PAGE_USER) && (__read_cr4() & X86_CR4_SMEP)) - printk(smep_warning, from_kuid(&init_user_ns, current_uid())); + printk(smep_warning, from_kuid(&init_user_ns, current_uid()), current->comm, task_pid_nr(current)); } +#ifdef CONFIG_PAX_KERNEXEC + if (init_mm.start_code <= address && address < init_mm.end_code) { + if (current->signal->curr_ip) + printk(KERN_EMERG "PAX: From %pI4: %s:%d, uid/euid: %u/%u, attempted to modify kernel code\n", + ¤t->signal->curr_ip, current->comm, task_pid_nr(current), + from_kuid_munged(&init_user_ns, current_uid()), from_kuid_munged(&init_user_ns, current_euid())); + else + printk(KERN_EMERG "PAX: %s:%d, uid/euid: %u/%u, attempted to modify kernel code\n", current->comm, task_pid_nr(current), + from_kuid_munged(&init_user_ns, current_uid()), from_kuid_munged(&init_user_ns, current_euid())); + } +#endif + printk(KERN_ALERT "BUG: unable to handle kernel "); if (address < PAGE_SIZE) printk(KERN_CONT "NULL pointer dereference"); @@ -786,6 +882,22 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, return; } #endif + +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) + if (pax_is_fetch_fault(regs, error_code, address)) { + +#ifdef CONFIG_PAX_EMUTRAMP + switch (pax_handle_fetch_fault(regs)) { + case 2: + return; + } +#endif + + pax_report_fault(regs, (void *)regs->ip, (void *)regs->sp); + do_group_exit(SIGKILL); + } +#endif + /* Kernel addresses are always protection faults: */ if (address >= TASK_SIZE) error_code |= PF_PROT; @@ -868,7 +980,7 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) { printk(KERN_ERR "MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n", - tsk->comm, tsk->pid, address); + tsk->comm, task_pid_nr(tsk), address); code = BUS_MCEERR_AR; } #endif @@ -920,6 +1032,107 @@ static int spurious_fault_check(unsigned long error_code, pte_t *pte) return 1; } +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_PAGEEXEC) +static inline unsigned long get_limit(unsigned long segment) +{ + unsigned long __limit; + + asm("lsll %1,%0" : "=r" (__limit) : "r" (segment)); + return __limit + 1; +} + +static int pax_handle_pageexec_fault(struct pt_regs *regs, struct mm_struct *mm, unsigned long address, unsigned long error_code) +{ + pte_t *pte; + pmd_t *pmd; + spinlock_t *ptl; + unsigned char pte_mask; + + if ((__supported_pte_mask & _PAGE_NX) || (error_code & (PF_PROT|PF_USER)) != (PF_PROT|PF_USER) || v8086_mode(regs) || + !(mm->pax_flags & MF_PAX_PAGEEXEC)) + return 0; + + /* PaX: it's our fault, let's handle it if we can */ + + /* PaX: take a look at read faults before acquiring any locks */ + if (unlikely(!(error_code & PF_WRITE) && (regs->ip == address))) { + /* instruction fetch attempt from a protected page in user mode */ + up_read(&mm->mmap_sem); + +#ifdef CONFIG_PAX_EMUTRAMP + switch (pax_handle_fetch_fault(regs)) { + case 2: + return 1; + } +#endif + + pax_report_fault(regs, (void *)regs->ip, (void *)regs->sp); + do_group_exit(SIGKILL); + } + + pmd = pax_get_pmd(mm, address); + if (unlikely(!pmd)) + return 0; + + pte = pte_offset_map_lock(mm, pmd, address, &ptl); + if (unlikely(!(pte_val(*pte) & _PAGE_PRESENT) || pte_user(*pte))) { + pte_unmap_unlock(pte, ptl); + return 0; + } + + if (unlikely((error_code & PF_WRITE) && !pte_write(*pte))) { + /* write attempt to a protected page in user mode */ + pte_unmap_unlock(pte, ptl); + return 0; + } + +#ifdef CONFIG_SMP + if (likely(address > get_limit(regs->cs) && cpumask_test_cpu(smp_processor_id(), &mm->context.cpu_user_cs_mask))) +#else + if (likely(address > get_limit(regs->cs))) +#endif + { + set_pte(pte, pte_mkread(*pte)); + __flush_tlb_one(address); + pte_unmap_unlock(pte, ptl); + up_read(&mm->mmap_sem); + return 1; + } + + pte_mask = _PAGE_ACCESSED | _PAGE_USER | ((error_code & PF_WRITE) << (_PAGE_BIT_DIRTY-1)); + + /* + * PaX: fill DTLB with user rights and retry + */ + __asm__ __volatile__ ( + "orb %2,(%1)\n" +#if defined(CONFIG_M586) || defined(CONFIG_M586TSC) +/* + * PaX: let this uncommented 'invlpg' remind us on the behaviour of Intel's + * (and AMD's) TLBs. namely, they do not cache PTEs that would raise *any* + * page fault when examined during a TLB load attempt. this is true not only + * for PTEs holding a non-present entry but also present entries that will + * raise a page fault (such as those set up by PaX, or the copy-on-write + * mechanism). in effect it means that we do *not* need to flush the TLBs + * for our target pages since their PTEs are simply not in the TLBs at all. + + * the best thing in omitting it is that we gain around 15-20% speed in the + * fast path of the page fault handler and can get rid of tracing since we + * can no longer flush unintended entries. + */ + "invlpg (%0)\n" +#endif + __copyuser_seg"testb $0,(%0)\n" + "xorb %3,(%1)\n" + : + : "r" (address), "r" (pte), "q" (pte_mask), "i" (_PAGE_USER) + : "memory", "cc"); + pte_unmap_unlock(pte, ptl); + up_read(&mm->mmap_sem); + return 1; +} +#endif + /* * Handle a spurious fault caused by a stale TLB entry. * @@ -1005,6 +1218,9 @@ int show_unhandled_signals = 1; static inline int access_error(unsigned long error_code, struct vm_area_struct *vma) { + if ((__supported_pte_mask & _PAGE_NX) && (error_code & PF_INSTR) && !(vma->vm_flags & VM_EXEC)) + return 1; + if (error_code & PF_WRITE) { /* write, present and write, not present: */ if (unlikely(!(vma->vm_flags & VM_WRITE))) @@ -1067,6 +1283,22 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, tsk = current; mm = tsk->mm; +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) + if (!user_mode(regs) && address < 2 * pax_user_shadow_base) { + if (!search_exception_tables(regs->ip)) { + printk(KERN_EMERG "PAX: please report this to pageexec@freemail.hu\n"); + bad_area_nosemaphore(regs, error_code, address); + return; + } + if (address < pax_user_shadow_base) { + printk(KERN_EMERG "PAX: please report this to pageexec@freemail.hu\n"); + printk(KERN_EMERG "PAX: faulting IP: %pS\n", (void *)regs->ip); + show_trace_log_lvl(NULL, NULL, (void *)regs->sp, regs->bp, KERN_EMERG); + } else + address -= pax_user_shadow_base; + } +#endif + /* * Detect and handle instructions that would cause a page fault for * both a tracked kernel page and a userspace page. @@ -1191,6 +1423,11 @@ retry: might_sleep(); } +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_PAGEEXEC) + if (pax_handle_pageexec_fault(regs, mm, address, error_code)) + return; +#endif + vma = find_vma(mm, address); if (unlikely(!vma)) { bad_area(regs, error_code, address); @@ -1202,18 +1439,24 @@ retry: bad_area(regs, error_code, address); return; } - if (error_code & PF_USER) { - /* - * Accessing the stack below %sp is always a bug. - * The large cushion allows instructions like enter - * and pusha to work. ("enter $65535, $31" pushes - * 32 pointers and then decrements %sp by 65535.) - */ - if (unlikely(address + 65536 + 32 * sizeof(unsigned long) < regs->sp)) { - bad_area(regs, error_code, address); - return; - } + /* + * Accessing the stack below %sp is always a bug. + * The large cushion allows instructions like enter + * and pusha to work. ("enter $65535, $31" pushes + * 32 pointers and then decrements %sp by 65535.) + */ + if (unlikely(address + 65536 + 32 * sizeof(unsigned long) < task_pt_regs(tsk)->sp)) { + bad_area(regs, error_code, address); + return; } + +#ifdef CONFIG_PAX_SEGMEXEC + if (unlikely((mm->pax_flags & MF_PAX_SEGMEXEC) && vma->vm_end - SEGMEXEC_TASK_SIZE - 1 < address - SEGMEXEC_TASK_SIZE - 1)) { + bad_area(regs, error_code, address); + return; + } +#endif + if (unlikely(expand_stack(vma, address))) { bad_area(regs, error_code, address); return; @@ -1333,3 +1576,292 @@ trace_do_page_fault(struct pt_regs *regs, unsigned long error_code) } NOKPROBE_SYMBOL(trace_do_page_fault); #endif /* CONFIG_TRACING */ + +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) +static bool pax_is_fetch_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address) +{ + struct mm_struct *mm = current->mm; + unsigned long ip = regs->ip; + + if (v8086_mode(regs)) + ip = ((regs->cs & 0xffff) << 4) + (ip & 0xffff); + +#ifdef CONFIG_PAX_PAGEEXEC + if (mm->pax_flags & MF_PAX_PAGEEXEC) { + if ((__supported_pte_mask & _PAGE_NX) && (error_code & PF_INSTR)) + return true; + if (!(error_code & (PF_PROT | PF_WRITE)) && ip == address) + return true; + return false; + } +#endif + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) { + if (!(error_code & (PF_PROT | PF_WRITE)) && (ip + SEGMEXEC_TASK_SIZE == address)) + return true; + return false; + } +#endif + + return false; +} +#endif + +#ifdef CONFIG_PAX_EMUTRAMP +static int pax_handle_fetch_fault_32(struct pt_regs *regs) +{ + int err; + + do { /* PaX: libffi trampoline emulation */ + unsigned char mov, jmp; + unsigned int addr1, addr2; + +#ifdef CONFIG_X86_64 + if ((regs->ip + 9) >> 32) + break; +#endif + + err = get_user(mov, (unsigned char __user *)regs->ip); + err |= get_user(addr1, (unsigned int __user *)(regs->ip + 1)); + err |= get_user(jmp, (unsigned char __user *)(regs->ip + 5)); + err |= get_user(addr2, (unsigned int __user *)(regs->ip + 6)); + + if (err) + break; + + if (mov == 0xB8 && jmp == 0xE9) { + regs->ax = addr1; + regs->ip = (unsigned int)(regs->ip + addr2 + 10); + return 2; + } + } while (0); + + do { /* PaX: gcc trampoline emulation #1 */ + unsigned char mov1, mov2; + unsigned short jmp; + unsigned int addr1, addr2; + +#ifdef CONFIG_X86_64 + if ((regs->ip + 11) >> 32) + break; +#endif + + err = get_user(mov1, (unsigned char __user *)regs->ip); + err |= get_user(addr1, (unsigned int __user *)(regs->ip + 1)); + err |= get_user(mov2, (unsigned char __user *)(regs->ip + 5)); + err |= get_user(addr2, (unsigned int __user *)(regs->ip + 6)); + err |= get_user(jmp, (unsigned short __user *)(regs->ip + 10)); + + if (err) + break; + + if (mov1 == 0xB9 && mov2 == 0xB8 && jmp == 0xE0FF) { + regs->cx = addr1; + regs->ax = addr2; + regs->ip = addr2; + return 2; + } + } while (0); + + do { /* PaX: gcc trampoline emulation #2 */ + unsigned char mov, jmp; + unsigned int addr1, addr2; + +#ifdef CONFIG_X86_64 + if ((regs->ip + 9) >> 32) + break; +#endif + + err = get_user(mov, (unsigned char __user *)regs->ip); + err |= get_user(addr1, (unsigned int __user *)(regs->ip + 1)); + err |= get_user(jmp, (unsigned char __user *)(regs->ip + 5)); + err |= get_user(addr2, (unsigned int __user *)(regs->ip + 6)); + + if (err) + break; + + if (mov == 0xB9 && jmp == 0xE9) { + regs->cx = addr1; + regs->ip = (unsigned int)(regs->ip + addr2 + 10); + return 2; + } + } while (0); + + return 1; /* PaX in action */ +} + +#ifdef CONFIG_X86_64 +static int pax_handle_fetch_fault_64(struct pt_regs *regs) +{ + int err; + + do { /* PaX: libffi trampoline emulation */ + unsigned short mov1, mov2, jmp1; + unsigned char stcclc, jmp2; + unsigned long addr1, addr2; + + err = get_user(mov1, (unsigned short __user *)regs->ip); + err |= get_user(addr1, (unsigned long __user *)(regs->ip + 2)); + err |= get_user(mov2, (unsigned short __user *)(regs->ip + 10)); + err |= get_user(addr2, (unsigned long __user *)(regs->ip + 12)); + err |= get_user(stcclc, (unsigned char __user *)(regs->ip + 20)); + err |= get_user(jmp1, (unsigned short __user *)(regs->ip + 21)); + err |= get_user(jmp2, (unsigned char __user *)(regs->ip + 23)); + + if (err) + break; + + if (mov1 == 0xBB49 && mov2 == 0xBA49 && (stcclc == 0xF8 || stcclc == 0xF9) && jmp1 == 0xFF49 && jmp2 == 0xE3) { + regs->r11 = addr1; + regs->r10 = addr2; + if (stcclc == 0xF8) + regs->flags &= ~X86_EFLAGS_CF; + else + regs->flags |= X86_EFLAGS_CF; + regs->ip = addr1; + return 2; + } + } while (0); + + do { /* PaX: gcc trampoline emulation #1 */ + unsigned short mov1, mov2, jmp1; + unsigned char jmp2; + unsigned int addr1; + unsigned long addr2; + + err = get_user(mov1, (unsigned short __user *)regs->ip); + err |= get_user(addr1, (unsigned int __user *)(regs->ip + 2)); + err |= get_user(mov2, (unsigned short __user *)(regs->ip + 6)); + err |= get_user(addr2, (unsigned long __user *)(regs->ip + 8)); + err |= get_user(jmp1, (unsigned short __user *)(regs->ip + 16)); + err |= get_user(jmp2, (unsigned char __user *)(regs->ip + 18)); + + if (err) + break; + + if (mov1 == 0xBB41 && mov2 == 0xBA49 && jmp1 == 0xFF49 && jmp2 == 0xE3) { + regs->r11 = addr1; + regs->r10 = addr2; + regs->ip = addr1; + return 2; + } + } while (0); + + do { /* PaX: gcc trampoline emulation #2 */ + unsigned short mov1, mov2, jmp1; + unsigned char jmp2; + unsigned long addr1, addr2; + + err = get_user(mov1, (unsigned short __user *)regs->ip); + err |= get_user(addr1, (unsigned long __user *)(regs->ip + 2)); + err |= get_user(mov2, (unsigned short __user *)(regs->ip + 10)); + err |= get_user(addr2, (unsigned long __user *)(regs->ip + 12)); + err |= get_user(jmp1, (unsigned short __user *)(regs->ip + 20)); + err |= get_user(jmp2, (unsigned char __user *)(regs->ip + 22)); + + if (err) + break; + + if (mov1 == 0xBB49 && mov2 == 0xBA49 && jmp1 == 0xFF49 && jmp2 == 0xE3) { + regs->r11 = addr1; + regs->r10 = addr2; + regs->ip = addr1; + return 2; + } + } while (0); + + return 1; /* PaX in action */ +} +#endif + +/* + * PaX: decide what to do with offenders (regs->ip = fault address) + * + * returns 1 when task should be killed + * 2 when gcc trampoline was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + if (v8086_mode(regs)) + return 1; + + if (!(current->mm->pax_flags & MF_PAX_EMUTRAMP)) + return 1; + +#ifdef CONFIG_X86_32 + return pax_handle_fetch_fault_32(regs); +#else + if (regs->cs == __USER32_CS || (regs->cs & SEGMENT_LDT)) + return pax_handle_fetch_fault_32(regs); + else + return pax_handle_fetch_fault_64(regs); +#endif +} +#endif + +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) +void pax_report_insns(struct pt_regs *regs, void *pc, void *sp) +{ + long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 20; i++) { + unsigned char c; + if (get_user(c, (unsigned char __force_user *)pc+i)) + printk(KERN_CONT "?? "); + else + printk(KERN_CONT "%02x ", c); + } + printk("\n"); + + printk(KERN_ERR "PAX: bytes at SP-%lu: ", (unsigned long)sizeof(long)); + for (i = -1; i < 80 / (long)sizeof(long); i++) { + unsigned long c; + if (get_user(c, (unsigned long __force_user *)sp+i)) { +#ifdef CONFIG_X86_32 + printk(KERN_CONT "???????? "); +#else + if ((regs->cs == __USER32_CS || (regs->cs & SEGMENT_LDT))) + printk(KERN_CONT "???????? ???????? "); + else + printk(KERN_CONT "???????????????? "); +#endif + } else { +#ifdef CONFIG_X86_64 + if ((regs->cs == __USER32_CS || (regs->cs & SEGMENT_LDT))) { + printk(KERN_CONT "%08x ", (unsigned int)c); + printk(KERN_CONT "%08x ", (unsigned int)(c >> 32)); + } else +#endif + printk(KERN_CONT "%0*lx ", 2 * (int)sizeof(long), c); + } + } + printk("\n"); +} +#endif + +/** + * probe_kernel_write(): safely attempt to write to a location + * @dst: address to write to + * @src: pointer to the data that shall be written + * @size: size of the data chunk + * + * Safely write to address @dst from the buffer at @src. If a kernel fault + * happens, handle that and return -EFAULT. + */ +long notrace probe_kernel_write(void *dst, const void *src, size_t size) +{ + long ret; + mm_segment_t old_fs = get_fs(); + + set_fs(KERNEL_DS); + pagefault_disable(); + pax_open_kernel(); + ret = __copy_to_user_inatomic((void __force_user *)dst, src, size); + pax_close_kernel(); + pagefault_enable(); + set_fs(old_fs); + + return ret ? -EFAULT : 0; +} diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c index 81bf3d2..7ef25c2 100644 --- a/arch/x86/mm/gup.c +++ b/arch/x86/mm/gup.c @@ -268,7 +268,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write, addr = start; len = (unsigned long) nr_pages << PAGE_SHIFT; end = start + len; - if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ, + if (unlikely(!access_ok_noprefault(write ? VERIFY_WRITE : VERIFY_READ, (void __user *)start, len))) return 0; @@ -344,6 +344,10 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write, goto slow_irqon; #endif + if (unlikely(!access_ok_noprefault(write ? VERIFY_WRITE : VERIFY_READ, + (void __user *)start, len))) + return 0; + /* * XXX: batch / limit 'nr', to avoid large irq off latency * needs some instrumenting to determine the common sizes used by diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c index eecb207a..e76b7f4 100644 --- a/arch/x86/mm/highmem_32.c +++ b/arch/x86/mm/highmem_32.c @@ -35,6 +35,8 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) unsigned long vaddr; int idx, type; + BUG_ON(pgprot_val(prot) & _PAGE_USER); + preempt_disable(); pagefault_disable(); @@ -45,7 +47,11 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) idx = type + KM_TYPE_NR*smp_processor_id(); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); BUG_ON(!pte_none(*(kmap_pte-idx))); + + pax_open_kernel(); set_pte(kmap_pte-idx, mk_pte(page, prot)); + pax_close_kernel(); + arch_flush_lazy_mmu_mode(); return (void *)vaddr; diff --git a/arch/x86/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c index 42982b2..7168fc3 100644 --- a/arch/x86/mm/hugetlbpage.c +++ b/arch/x86/mm/hugetlbpage.c @@ -74,23 +74,24 @@ int pud_huge(pud_t pud) #ifdef CONFIG_HUGETLB_PAGE static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *file, unsigned long addr, unsigned long len, - unsigned long pgoff, unsigned long flags) + unsigned long pgoff, unsigned long flags, unsigned long offset) { struct hstate *h = hstate_file(file); struct vm_unmapped_area_info info; - + info.flags = 0; info.length = len; info.low_limit = current->mm->mmap_legacy_base; info.high_limit = TASK_SIZE; info.align_mask = PAGE_MASK & ~huge_page_mask(h); info.align_offset = 0; + info.threadstack_offset = offset; return vm_unmapped_area(&info); } static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file, unsigned long addr0, unsigned long len, - unsigned long pgoff, unsigned long flags) + unsigned long pgoff, unsigned long flags, unsigned long offset) { struct hstate *h = hstate_file(file); struct vm_unmapped_area_info info; @@ -102,6 +103,7 @@ static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file, info.high_limit = current->mm->mmap_base; info.align_mask = PAGE_MASK & ~huge_page_mask(h); info.align_offset = 0; + info.threadstack_offset = offset; addr = vm_unmapped_area(&info); /* @@ -114,6 +116,12 @@ static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file, VM_BUG_ON(addr != -ENOMEM); info.flags = 0; info.low_limit = TASK_UNMAPPED_BASE; + +#ifdef CONFIG_PAX_RANDMMAP + if (current->mm->pax_flags & MF_PAX_RANDMMAP) + info.low_limit += current->mm->delta_mmap; +#endif + info.high_limit = TASK_SIZE; addr = vm_unmapped_area(&info); } @@ -128,10 +136,20 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, struct hstate *h = hstate_file(file); struct mm_struct *mm = current->mm; struct vm_area_struct *vma; + unsigned long pax_task_size = TASK_SIZE; + unsigned long offset = gr_rand_threadstack_offset(mm, file, flags); if (len & ~huge_page_mask(h)) return -EINVAL; - if (len > TASK_SIZE) + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) + pax_task_size = SEGMEXEC_TASK_SIZE; +#endif + + pax_task_size -= PAGE_SIZE; + + if (len > pax_task_size) return -ENOMEM; if (flags & MAP_FIXED) { @@ -140,19 +158,22 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, return addr; } +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + if (addr) { addr = ALIGN(addr, huge_page_size(h)); vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + if (pax_task_size - len >= addr && check_heap_stack_gap(vma, addr, len, offset)) return addr; } if (mm->get_unmapped_area == arch_get_unmapped_area) return hugetlb_get_unmapped_area_bottomup(file, addr, len, - pgoff, flags); + pgoff, flags, offset); else return hugetlb_get_unmapped_area_topdown(file, addr, len, - pgoff, flags); + pgoff, flags, offset); } #endif /* CONFIG_HUGETLB_PAGE */ diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 1d8a83d..e435d63 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -4,6 +4,7 @@ #include #include #include /* for max_low_pfn */ +#include #include #include @@ -17,6 +18,8 @@ #include #include /* for MAX_DMA_PFN */ #include +#include +#include /* * We need to define the tracepoints somewhere, and tlb.c @@ -618,7 +621,18 @@ void __init init_mem_mapping(void) early_ioremap_page_table_range_init(); #endif +#ifdef CONFIG_PAX_PER_CPU_PGD + clone_pgd_range(get_cpu_pgd(0, kernel) + KERNEL_PGD_BOUNDARY, + swapper_pg_dir + KERNEL_PGD_BOUNDARY, + KERNEL_PGD_PTRS); + clone_pgd_range(get_cpu_pgd(0, user) + KERNEL_PGD_BOUNDARY, + swapper_pg_dir + KERNEL_PGD_BOUNDARY, + KERNEL_PGD_PTRS); + load_cr3(get_cpu_pgd(0, kernel)); +#else load_cr3(swapper_pg_dir); +#endif + __flush_tlb_all(); early_memtest(0, max_pfn_mapped << PAGE_SHIFT); @@ -634,10 +648,40 @@ void __init init_mem_mapping(void) * Access has to be given to non-kernel-ram areas as well, these contain the PCI * mmio resources as well as potential bios/acpi data regions. */ + +#ifdef CONFIG_GRKERNSEC_KMEM +static unsigned int ebda_start __read_only; +static unsigned int ebda_end __read_only; +#endif + int devmem_is_allowed(unsigned long pagenr) { - if (pagenr < 256) +#ifdef CONFIG_GRKERNSEC_KMEM + /* allow BDA */ + if (!pagenr) return 1; + /* allow EBDA */ + if (pagenr >= ebda_start && pagenr < ebda_end) + return 1; + /* if tboot is in use, allow access to its hardcoded serial log range */ + if (tboot_enabled() && ((0x60000 >> PAGE_SHIFT) <= pagenr) && (pagenr < (0x68000 >> PAGE_SHIFT))) + return 1; +#else + if (!pagenr) + return 1; +#ifdef CONFIG_VM86 + if (pagenr < (ISA_START_ADDRESS >> PAGE_SHIFT)) + return 1; +#endif +#endif + + if ((ISA_START_ADDRESS >> PAGE_SHIFT) <= pagenr && pagenr < (ISA_END_ADDRESS >> PAGE_SHIFT)) + return 1; +#ifdef CONFIG_GRKERNSEC_KMEM + /* throw out everything else below 1MB */ + if (pagenr <= 256) + return 0; +#endif if (iomem_is_exclusive(pagenr << PAGE_SHIFT)) return 0; if (!page_is_ram(pagenr)) @@ -683,8 +727,127 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end) #endif } +#ifdef CONFIG_GRKERNSEC_KMEM +static inline void gr_init_ebda(void) +{ + unsigned int ebda_addr; + unsigned int ebda_size = 0; + + ebda_addr = get_bios_ebda(); + if (ebda_addr) { + ebda_size = *(unsigned char *)phys_to_virt(ebda_addr); + ebda_size <<= 10; + } + if (ebda_addr && ebda_size) { + ebda_start = ebda_addr >> PAGE_SHIFT; + ebda_end = min((unsigned int)PAGE_ALIGN(ebda_addr + ebda_size), (unsigned int)0xa0000) >> PAGE_SHIFT; + } else { + ebda_start = 0x9f000 >> PAGE_SHIFT; + ebda_end = 0xa0000 >> PAGE_SHIFT; + } +} +#else +static inline void gr_init_ebda(void) { } +#endif + void free_initmem(void) { +#ifdef CONFIG_PAX_KERNEXEC +#ifdef CONFIG_X86_32 + /* PaX: limit KERNEL_CS to actual size */ + unsigned long addr, limit; + struct desc_struct d; + int cpu; +#else + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + unsigned long addr, end; +#endif +#endif + + gr_init_ebda(); + +#ifdef CONFIG_PAX_KERNEXEC +#ifdef CONFIG_X86_32 + limit = paravirt_enabled() ? ktva_ktla(0xffffffff) : (unsigned long)&_etext; + limit = (limit - 1UL) >> PAGE_SHIFT; + + memset(__LOAD_PHYSICAL_ADDR + PAGE_OFFSET, POISON_FREE_INITMEM, PAGE_SIZE); + for (cpu = 0; cpu < nr_cpu_ids; cpu++) { + pack_descriptor(&d, get_desc_base(&get_cpu_gdt_table(cpu)[GDT_ENTRY_KERNEL_CS]), limit, 0x9B, 0xC); + write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_KERNEL_CS, &d, DESCTYPE_S); + write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_KERNEXEC_KERNEL_CS, &d, DESCTYPE_S); + } + + /* PaX: make KERNEL_CS read-only */ + addr = PFN_ALIGN(ktla_ktva((unsigned long)&_text)); + if (!paravirt_enabled()) + set_memory_ro(addr, (PFN_ALIGN(_sdata) - addr) >> PAGE_SHIFT); +/* + for (addr = ktla_ktva((unsigned long)&_text); addr < (unsigned long)&_sdata; addr += PMD_SIZE) { + pgd = pgd_offset_k(addr); + pud = pud_offset(pgd, addr); + pmd = pmd_offset(pud, addr); + set_pmd(pmd, __pmd(pmd_val(*pmd) & ~_PAGE_RW)); + } +*/ +#ifdef CONFIG_X86_PAE + set_memory_nx(PFN_ALIGN(__init_begin), (PFN_ALIGN(__init_end) - PFN_ALIGN(__init_begin)) >> PAGE_SHIFT); +/* + for (addr = (unsigned long)&__init_begin; addr < (unsigned long)&__init_end; addr += PMD_SIZE) { + pgd = pgd_offset_k(addr); + pud = pud_offset(pgd, addr); + pmd = pmd_offset(pud, addr); + set_pmd(pmd, __pmd(pmd_val(*pmd) | (_PAGE_NX & __supported_pte_mask))); + } +*/ +#endif + +#ifdef CONFIG_MODULES + set_memory_4k((unsigned long)MODULES_EXEC_VADDR, (MODULES_EXEC_END - MODULES_EXEC_VADDR) >> PAGE_SHIFT); +#endif + +#else + /* PaX: make kernel code/rodata read-only, rest non-executable */ + set_memory_ro((unsigned long)_text, ((unsigned long)(_sdata - _text) >> PAGE_SHIFT)); + set_memory_nx((unsigned long)_sdata, (__START_KERNEL_map + KERNEL_IMAGE_SIZE - (unsigned long)_sdata) >> PAGE_SHIFT); + + for (addr = __START_KERNEL_map; addr < __START_KERNEL_map + KERNEL_IMAGE_SIZE; addr += PMD_SIZE) { + pgd = pgd_offset_k(addr); + pud = pud_offset(pgd, addr); + pmd = pmd_offset(pud, addr); + if (!pmd_present(*pmd)) + continue; + if (addr >= (unsigned long)_text) + BUG_ON(!pmd_large(*pmd)); + if ((unsigned long)_text <= addr && addr < (unsigned long)_sdata) + BUG_ON(pmd_write(*pmd)); +// set_pmd(pmd, __pmd(pmd_val(*pmd) & ~_PAGE_RW)); + else + BUG_ON(!(pmd_flags(*pmd) & _PAGE_NX)); +// set_pmd(pmd, __pmd(pmd_val(*pmd) | (_PAGE_NX & __supported_pte_mask))); + } + + addr = (unsigned long)__va(__pa(__START_KERNEL_map)); + end = addr + KERNEL_IMAGE_SIZE; + for (; addr < end; addr += PMD_SIZE) { + pgd = pgd_offset_k(addr); + pud = pud_offset(pgd, addr); + pmd = pmd_offset(pud, addr); + if (!pmd_present(*pmd)) + continue; + if (addr >= (unsigned long)_text) + BUG_ON(!pmd_large(*pmd)); + if ((unsigned long)__va(__pa(_text)) <= addr && addr < (unsigned long)__va(__pa(_sdata))) + BUG_ON(pmd_write(*pmd)); +// set_pmd(pmd, __pmd(pmd_val(*pmd) & ~_PAGE_RW)); + } +#endif + + flush_tlb_all(); +#endif + free_init_pages("unused kernel", (unsigned long)(&__init_begin), (unsigned long)(&__init_end)); diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 7562f42..6859164 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c @@ -62,33 +62,6 @@ static noinline int do_test_wp_bit(void); bool __read_mostly __vmalloc_start_set = false; /* - * Creates a middle page table and puts a pointer to it in the - * given global directory entry. This only returns the gd entry - * in non-PAE compilation mode, since the middle layer is folded. - */ -static pmd_t * __init one_md_table_init(pgd_t *pgd) -{ - pud_t *pud; - pmd_t *pmd_table; - -#ifdef CONFIG_X86_PAE - if (!(pgd_val(*pgd) & _PAGE_PRESENT)) { - pmd_table = (pmd_t *)alloc_low_page(); - paravirt_alloc_pmd(&init_mm, __pa(pmd_table) >> PAGE_SHIFT); - set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); - pud = pud_offset(pgd, 0); - BUG_ON(pmd_table != pmd_offset(pud, 0)); - - return pmd_table; - } -#endif - pud = pud_offset(pgd, 0); - pmd_table = pmd_offset(pud, 0); - - return pmd_table; -} - -/* * Create a page table and place a pointer to it in a middle page * directory entry: */ @@ -98,13 +71,28 @@ static pte_t * __init one_page_table_init(pmd_t *pmd) pte_t *page_table = (pte_t *)alloc_low_page(); paravirt_alloc_pte(&init_mm, __pa(page_table) >> PAGE_SHIFT); +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) + set_pmd(pmd, __pmd(__pa(page_table) | _KERNPG_TABLE)); +#else set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); +#endif BUG_ON(page_table != pte_offset_kernel(pmd, 0)); } return pte_offset_kernel(pmd, 0); } +static pmd_t * __init one_md_table_init(pgd_t *pgd) +{ + pud_t *pud; + pmd_t *pmd_table; + + pud = pud_offset(pgd, 0); + pmd_table = pmd_offset(pud, 0); + + return pmd_table; +} + pmd_t * __init populate_extra_pmd(unsigned long vaddr) { int pgd_idx = pgd_index(vaddr); @@ -209,6 +197,7 @@ page_table_range_init(unsigned long start, unsigned long end, pgd_t *pgd_base) int pgd_idx, pmd_idx; unsigned long vaddr; pgd_t *pgd; + pud_t *pud; pmd_t *pmd; pte_t *pte = NULL; unsigned long count = page_table_range_init_count(start, end); @@ -223,8 +212,13 @@ page_table_range_init(unsigned long start, unsigned long end, pgd_t *pgd_base) pgd = pgd_base + pgd_idx; for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) { - pmd = one_md_table_init(pgd); - pmd = pmd + pmd_index(vaddr); + pud = pud_offset(pgd, vaddr); + pmd = pmd_offset(pud, vaddr); + +#ifdef CONFIG_X86_PAE + paravirt_alloc_pmd(&init_mm, __pa(pmd) >> PAGE_SHIFT); +#endif + for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) { pte = page_table_kmap_check(one_page_table_init(pmd), @@ -236,11 +230,20 @@ page_table_range_init(unsigned long start, unsigned long end, pgd_t *pgd_base) } } -static inline int is_kernel_text(unsigned long addr) +static inline int is_kernel_text(unsigned long start, unsigned long end) { - if (addr >= (unsigned long)_text && addr <= (unsigned long)__init_end) - return 1; - return 0; + if ((start >= ktla_ktva((unsigned long)_etext) || + end <= ktla_ktva((unsigned long)_stext)) && + (start >= ktla_ktva((unsigned long)_einittext) || + end <= ktla_ktva((unsigned long)_sinittext)) && + +#ifdef CONFIG_ACPI_SLEEP + (start >= (unsigned long)__va(acpi_wakeup_address) + 0x4000 || end <= (unsigned long)__va(acpi_wakeup_address)) && +#endif + + (start > (unsigned long)__va(0xfffff) || end <= (unsigned long)__va(0xc0000))) + return 0; + return 1; } /* @@ -257,9 +260,10 @@ kernel_physical_mapping_init(unsigned long start, unsigned long last_map_addr = end; unsigned long start_pfn, end_pfn; pgd_t *pgd_base = swapper_pg_dir; - int pgd_idx, pmd_idx, pte_ofs; + unsigned int pgd_idx, pmd_idx, pte_ofs; unsigned long pfn; pgd_t *pgd; + pud_t *pud; pmd_t *pmd; pte_t *pte; unsigned pages_2m, pages_4k; @@ -292,8 +296,13 @@ repeat: pfn = start_pfn; pgd_idx = pgd_index((pfn<> PAGE_SHIFT); +#endif if (pfn >= end_pfn) continue; @@ -305,14 +314,13 @@ repeat: #endif for (; pmd_idx < PTRS_PER_PMD && pfn < end_pfn; pmd++, pmd_idx++) { - unsigned int addr = pfn * PAGE_SIZE + PAGE_OFFSET; + unsigned long address = pfn * PAGE_SIZE + PAGE_OFFSET; /* * Map with big pages if possible, otherwise * create normal page tables: */ if (use_pse) { - unsigned int addr2; pgprot_t prot = PAGE_KERNEL_LARGE; /* * first pass will use the same initial @@ -323,11 +331,7 @@ repeat: _PAGE_PSE); pfn &= PMD_MASK >> PAGE_SHIFT; - addr2 = (pfn + PTRS_PER_PTE-1) * PAGE_SIZE + - PAGE_OFFSET + PAGE_SIZE-1; - - if (is_kernel_text(addr) || - is_kernel_text(addr2)) + if (is_kernel_text(address, address + PMD_SIZE)) prot = PAGE_KERNEL_LARGE_EXEC; pages_2m++; @@ -344,7 +348,7 @@ repeat: pte_ofs = pte_index((pfn<> 10, - (unsigned long)&_etext, (unsigned long)&_edata, - ((unsigned long)&_edata - (unsigned long)&_etext) >> 10, + (unsigned long)&_sdata, (unsigned long)&_edata, + ((unsigned long)&_edata - (unsigned long)&_sdata) >> 10, - (unsigned long)&_text, (unsigned long)&_etext, + ktla_ktva((unsigned long)&_text), ktla_ktva((unsigned long)&_etext), ((unsigned long)&_etext - (unsigned long)&_text) >> 10); /* @@ -885,6 +887,7 @@ void set_kernel_text_rw(void) if (!kernel_set_to_readonly) return; + start = ktla_ktva(start); pr_debug("Set kernel text: %lx - %lx for read write\n", start, start+size); @@ -899,6 +902,7 @@ void set_kernel_text_ro(void) if (!kernel_set_to_readonly) return; + start = ktla_ktva(start); pr_debug("Set kernel text: %lx - %lx for read only\n", start, start+size); @@ -927,6 +931,7 @@ void mark_rodata_ro(void) unsigned long start = PFN_ALIGN(_text); unsigned long size = PFN_ALIGN(_etext) - start; + start = ktla_ktva(start); set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); printk(KERN_INFO "Write protecting the kernel text: %luk\n", size >> 10); diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index df48430..0a2197b 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -136,7 +136,7 @@ int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page, * around without checking the pgd every time. */ -pteval_t __supported_pte_mask __read_mostly = ~0; +pteval_t __supported_pte_mask __read_only = ~_PAGE_NX; EXPORT_SYMBOL_GPL(__supported_pte_mask); int force_personality32; @@ -169,7 +169,12 @@ void sync_global_pgds(unsigned long start, unsigned long end, int removed) for (address = start; address <= end; address += PGDIR_SIZE) { const pgd_t *pgd_ref = pgd_offset_k(address); + +#ifdef CONFIG_PAX_PER_CPU_PGD + unsigned long cpu; +#else struct page *page; +#endif /* * When it is called after memory hot remove, pgd_none() @@ -180,6 +185,25 @@ void sync_global_pgds(unsigned long start, unsigned long end, int removed) continue; spin_lock(&pgd_lock); + +#ifdef CONFIG_PAX_PER_CPU_PGD + for (cpu = 0; cpu < nr_cpu_ids; ++cpu) { + pgd_t *pgd = pgd_offset_cpu(cpu, user, address); + + if (!pgd_none(*pgd_ref) && !pgd_none(*pgd)) + BUG_ON(pgd_page_vaddr(*pgd) + != pgd_page_vaddr(*pgd_ref)); + + if (removed) { + if (pgd_none(*pgd_ref) && !pgd_none(*pgd)) + pgd_clear(pgd); + } else { + if (pgd_none(*pgd)) + set_pgd(pgd, *pgd_ref); + } + + pgd = pgd_offset_cpu(cpu, kernel, address); +#else list_for_each_entry(page, &pgd_list, lru) { pgd_t *pgd; spinlock_t *pgt_lock; @@ -188,6 +212,7 @@ void sync_global_pgds(unsigned long start, unsigned long end, int removed) /* the pgt_lock only for Xen */ pgt_lock = &pgd_page_get_mm(page)->page_table_lock; spin_lock(pgt_lock); +#endif if (!pgd_none(*pgd_ref) && !pgd_none(*pgd)) BUG_ON(pgd_page_vaddr(*pgd) @@ -201,7 +226,10 @@ void sync_global_pgds(unsigned long start, unsigned long end, int removed) set_pgd(pgd, *pgd_ref); } +#ifndef CONFIG_PAX_PER_CPU_PGD spin_unlock(pgt_lock); +#endif + } spin_unlock(&pgd_lock); } @@ -234,7 +262,7 @@ static pud_t *fill_pud(pgd_t *pgd, unsigned long vaddr) { if (pgd_none(*pgd)) { pud_t *pud = (pud_t *)spp_getpage(); - pgd_populate(&init_mm, pgd, pud); + pgd_populate_kernel(&init_mm, pgd, pud); if (pud != pud_offset(pgd, 0)) printk(KERN_ERR "PAGETABLE BUG #00! %p <-> %p\n", pud, pud_offset(pgd, 0)); @@ -246,7 +274,7 @@ static pmd_t *fill_pmd(pud_t *pud, unsigned long vaddr) { if (pud_none(*pud)) { pmd_t *pmd = (pmd_t *) spp_getpage(); - pud_populate(&init_mm, pud, pmd); + pud_populate_kernel(&init_mm, pud, pmd); if (pmd != pmd_offset(pud, 0)) printk(KERN_ERR "PAGETABLE BUG #01! %p <-> %p\n", pmd, pmd_offset(pud, 0)); @@ -275,7 +303,9 @@ void set_pte_vaddr_pud(pud_t *pud_page, unsigned long vaddr, pte_t new_pte) pmd = fill_pmd(pud, vaddr); pte = fill_pte(pmd, vaddr); + pax_open_kernel(); set_pte(pte, new_pte); + pax_close_kernel(); /* * It's enough to flush this one mapping. @@ -337,14 +367,12 @@ static void __init __init_extra_mapping(unsigned long phys, unsigned long size, pgd = pgd_offset_k((unsigned long)__va(phys)); if (pgd_none(*pgd)) { pud = (pud_t *) spp_getpage(); - set_pgd(pgd, __pgd(__pa(pud) | _KERNPG_TABLE | - _PAGE_USER)); + set_pgd(pgd, __pgd(__pa(pud) | _PAGE_TABLE)); } pud = pud_offset(pgd, (unsigned long)__va(phys)); if (pud_none(*pud)) { pmd = (pmd_t *) spp_getpage(); - set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE | - _PAGE_USER)); + set_pud(pud, __pud(__pa(pmd) | _PAGE_TABLE)); } pmd = pmd_offset(pud, phys); BUG_ON(!pmd_none(*pmd)); @@ -585,7 +613,7 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end, prot); spin_lock(&init_mm.page_table_lock); - pud_populate(&init_mm, pud, pmd); + pud_populate_kernel(&init_mm, pud, pmd); spin_unlock(&init_mm.page_table_lock); } __flush_tlb_all(); @@ -626,7 +654,7 @@ kernel_physical_mapping_init(unsigned long start, page_size_mask); spin_lock(&init_mm.page_table_lock); - pgd_populate(&init_mm, pgd, pud); + pgd_populate_kernel(&init_mm, pgd, pud); spin_unlock(&init_mm.page_table_lock); pgd_changed = true; } diff --git a/arch/x86/mm/iomap_32.c b/arch/x86/mm/iomap_32.c index 9c0ff04..9020d5f 100644 --- a/arch/x86/mm/iomap_32.c +++ b/arch/x86/mm/iomap_32.c @@ -65,7 +65,11 @@ void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot) type = kmap_atomic_idx_push(); idx = type + KM_TYPE_NR * smp_processor_id(); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); + + pax_open_kernel(); set_pte(kmap_pte - idx, pfn_pte(pfn, prot)); + pax_close_kernel(); + arch_flush_lazy_mmu_mode(); return (void *)vaddr; diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index b9c78f3..c757af4 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -59,8 +59,8 @@ static int __ioremap_check_ram(unsigned long start_pfn, unsigned long nr_pages, unsigned long i; for (i = 0; i < nr_pages; ++i) - if (pfn_valid(start_pfn + i) && - !PageReserved(pfn_to_page(start_pfn + i))) + if (pfn_valid(start_pfn + i) && (start_pfn + i >= 0x100 || + !PageReserved(pfn_to_page(start_pfn + i)))) return 1; return 0; @@ -332,7 +332,7 @@ EXPORT_SYMBOL(ioremap_prot); * * Caller must ensure there is only one unmapping for the same pointer. */ -void iounmap(volatile void __iomem *addr) +void iounmap(const volatile void __iomem *addr) { struct vm_struct *p, *o; @@ -395,31 +395,37 @@ int __init arch_ioremap_pmd_supported(void) */ void *xlate_dev_mem_ptr(phys_addr_t phys) { - unsigned long start = phys & PAGE_MASK; - unsigned long offset = phys & ~PAGE_MASK; - void *vaddr; + phys_addr_t pfn = phys >> PAGE_SHIFT; - /* If page is RAM, we can use __va. Otherwise ioremap and unmap. */ - if (page_is_ram(start >> PAGE_SHIFT)) - return __va(phys); + if (page_is_ram(pfn)) { +#ifdef CONFIG_HIGHMEM + if (pfn >= max_low_pfn) + return kmap_high(pfn_to_page(pfn)); + else +#endif + return __va(phys); + } - vaddr = ioremap_cache(start, PAGE_SIZE); - /* Only add the offset on success and return NULL if the ioremap() failed: */ - if (vaddr) - vaddr += offset; - - return vaddr; + return (void __force *)ioremap_cache(phys, 1); } void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr) { - if (page_is_ram(phys >> PAGE_SHIFT)) + phys_addr_t pfn = phys >> PAGE_SHIFT; + + if (page_is_ram(pfn)) { +#ifdef CONFIG_HIGHMEM + if (pfn >= max_low_pfn) + kunmap_high(pfn_to_page(pfn)); +#endif return; + } - iounmap((void __iomem *)((unsigned long)addr & PAGE_MASK)); + iounmap((void __iomem __force *)addr); } -static pte_t bm_pte[PAGE_SIZE/sizeof(pte_t)] __page_aligned_bss; +static pte_t __bm_pte[PAGE_SIZE/sizeof(pte_t)] __page_aligned_rodata; +static pte_t *bm_pte __read_only = __bm_pte; static inline pmd_t * __init early_ioremap_pmd(unsigned long addr) { @@ -455,8 +461,14 @@ void __init early_ioremap_init(void) early_ioremap_setup(); pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)); - memset(bm_pte, 0, sizeof(bm_pte)); - pmd_populate_kernel(&init_mm, pmd, bm_pte); + if (pmd_none(*pmd)) +#ifdef CONFIG_COMPAT_VDSO + pmd_populate_user(&init_mm, pmd, __bm_pte); +#else + pmd_populate_kernel(&init_mm, pmd, __bm_pte); +#endif + else + bm_pte = (pte_t *)pmd_page_vaddr(*pmd); /* * The boot-ioremap range spans multiple pmds, for which diff --git a/arch/x86/mm/kmemcheck/kmemcheck.c b/arch/x86/mm/kmemcheck/kmemcheck.c index b4f2e7e..96c9c3e 100644 --- a/arch/x86/mm/kmemcheck/kmemcheck.c +++ b/arch/x86/mm/kmemcheck/kmemcheck.c @@ -628,9 +628,9 @@ bool kmemcheck_fault(struct pt_regs *regs, unsigned long address, * memory (e.g. tracked pages)? For now, we need this to avoid * invoking kmemcheck for PnP BIOS calls. */ - if (regs->flags & X86_VM_MASK) + if (v8086_mode(regs)) return false; - if (regs->cs != __KERNEL_CS) + if (regs->cs != __KERNEL_CS && regs->cs != __KERNEXEC_KERNEL_CS) return false; pte = kmemcheck_pte_lookup(address); diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c index 844b06d..f363c86 100644 --- a/arch/x86/mm/mmap.c +++ b/arch/x86/mm/mmap.c @@ -52,7 +52,7 @@ static unsigned long stack_maxrandom_size(void) * Leave an at least ~128 MB hole with possible stack randomization. */ #define MIN_GAP (128*1024*1024UL + stack_maxrandom_size()) -#define MAX_GAP (TASK_SIZE/6*5) +#define MAX_GAP (pax_task_size/6*5) static int mmap_is_legacy(void) { @@ -81,27 +81,40 @@ unsigned long arch_mmap_rnd(void) return rnd << PAGE_SHIFT; } -static unsigned long mmap_base(unsigned long rnd) +static unsigned long mmap_base(struct mm_struct *mm, unsigned long rnd) { unsigned long gap = rlimit(RLIMIT_STACK); + unsigned long pax_task_size = TASK_SIZE; + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) + pax_task_size = SEGMEXEC_TASK_SIZE; +#endif if (gap < MIN_GAP) gap = MIN_GAP; else if (gap > MAX_GAP) gap = MAX_GAP; - return PAGE_ALIGN(TASK_SIZE - gap - rnd); + return PAGE_ALIGN(pax_task_size - gap - rnd); } /* * Bottom-up (legacy) layout on X86_32 did not support randomization, X86_64 * does, but not when emulating X86_32 */ -static unsigned long mmap_legacy_base(unsigned long rnd) +static unsigned long mmap_legacy_base(struct mm_struct *mm, unsigned long rnd) { - if (mmap_is_ia32()) + if (mmap_is_ia32()) { + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) + return SEGMEXEC_TASK_UNMAPPED_BASE; + else +#endif + return TASK_UNMAPPED_BASE; - else + } else return TASK_UNMAPPED_BASE + rnd; } @@ -113,18 +126,29 @@ void arch_pick_mmap_layout(struct mm_struct *mm) { unsigned long random_factor = 0UL; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif if (current->flags & PF_RANDOMIZE) random_factor = arch_mmap_rnd(); - mm->mmap_legacy_base = mmap_legacy_base(random_factor); + mm->mmap_legacy_base = mmap_legacy_base(mm, random_factor); if (mmap_is_legacy()) { mm->mmap_base = mm->mmap_legacy_base; mm->get_unmapped_area = arch_get_unmapped_area; } else { - mm->mmap_base = mmap_base(random_factor); + mm->mmap_base = mmap_base(mm, random_factor); mm->get_unmapped_area = arch_get_unmapped_area_topdown; } + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) { + mm->mmap_legacy_base += mm->delta_mmap; + mm->mmap_base -= mm->delta_mmap + mm->delta_stack; + } +#endif + } const char *arch_vma_name(struct vm_area_struct *vma) diff --git a/arch/x86/mm/mmio-mod.c b/arch/x86/mm/mmio-mod.c index 0057a7acc..95c7edd 100644 --- a/arch/x86/mm/mmio-mod.c +++ b/arch/x86/mm/mmio-mod.c @@ -194,7 +194,7 @@ static void pre(struct kmmio_probe *p, struct pt_regs *regs, break; default: { - unsigned char *ip = (unsigned char *)instptr; + unsigned char *ip = (unsigned char *)ktla_ktva(instptr); my_trace->opcode = MMIO_UNKNOWN_OP; my_trace->width = 0; my_trace->value = (*ip) << 16 | *(ip + 1) << 8 | @@ -234,7 +234,7 @@ static void post(struct kmmio_probe *p, unsigned long condition, static void ioremap_trace_core(resource_size_t offset, unsigned long size, void __iomem *addr) { - static atomic_t next_id; + static atomic_unchecked_t next_id; struct remap_trace *trace = kmalloc(sizeof(*trace), GFP_KERNEL); /* These are page-unaligned. */ struct mmiotrace_map map = { @@ -258,7 +258,7 @@ static void ioremap_trace_core(resource_size_t offset, unsigned long size, .private = trace }, .phys = offset, - .id = atomic_inc_return(&next_id) + .id = atomic_inc_return_unchecked(&next_id) }; map.map_id = trace->id; @@ -290,7 +290,7 @@ void mmiotrace_ioremap(resource_size_t offset, unsigned long size, ioremap_trace_core(offset, size, addr); } -static void iounmap_trace_core(volatile void __iomem *addr) +static void iounmap_trace_core(const volatile void __iomem *addr) { struct mmiotrace_map map = { .phys = 0, @@ -328,7 +328,7 @@ not_enabled: } } -void mmiotrace_iounmap(volatile void __iomem *addr) +void mmiotrace_iounmap(const volatile void __iomem *addr) { might_sleep(); if (is_enabled()) /* recheck and proper locking in *_core() */ diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c index 71fc79a..7388ad7 100644 --- a/arch/x86/mm/mpx.c +++ b/arch/x86/mm/mpx.c @@ -292,11 +292,11 @@ siginfo_t *mpx_generate_siginfo(struct pt_regs *regs) * We were not able to extract an address from the instruction, * probably because there was something invalid in it. */ - if (info->si_addr == (void *)-1) { + if (info->si_addr == (void __user *)-1) { err = -EINVAL; goto err_out; } - trace_mpx_bounds_register_exception(info->si_addr, bndreg); + trace_mpx_bounds_register_exception((void __force_kernel *)info->si_addr, bndreg); return info; err_out: /* info might be NULL, but kfree() handles that */ diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index c3b3f65..8919a28 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -508,7 +508,7 @@ static void __init numa_clear_kernel_node_hotplug(void) } } -static int __init numa_register_memblks(struct numa_meminfo *mi) +static int __init __intentional_overflow(-1) numa_register_memblks(struct numa_meminfo *mi) { unsigned long uninitialized_var(pfn_align); int i, nid; diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 2c44c07..5c5e457 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -259,7 +259,7 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address, */ #ifdef CONFIG_PCI_BIOS if (pcibios_enabled && within(pfn, BIOS_BEGIN >> PAGE_SHIFT, BIOS_END >> PAGE_SHIFT)) - pgprot_val(forbidden) |= _PAGE_NX; + pgprot_val(forbidden) |= _PAGE_NX & __supported_pte_mask; #endif /* @@ -267,9 +267,10 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address, * Does not cover __inittext since that is gone later on. On * 64bit we do not enforce !NX on the low mapping */ - if (within(address, (unsigned long)_text, (unsigned long)_etext)) - pgprot_val(forbidden) |= _PAGE_NX; + if (within(address, ktla_ktva((unsigned long)_text), ktla_ktva((unsigned long)_etext))) + pgprot_val(forbidden) |= _PAGE_NX & __supported_pte_mask; +#ifdef CONFIG_DEBUG_RODATA /* * The .rodata section needs to be read-only. Using the pfn * catches all aliases. @@ -277,6 +278,7 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address, if (within(pfn, __pa_symbol(__start_rodata) >> PAGE_SHIFT, __pa_symbol(__end_rodata) >> PAGE_SHIFT)) pgprot_val(forbidden) |= _PAGE_RW; +#endif #if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA) /* @@ -315,6 +317,13 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address, } #endif +#ifdef CONFIG_PAX_KERNEXEC + if (within(pfn, __pa(ktla_ktva((unsigned long)&_text)), __pa((unsigned long)&_sdata))) { + pgprot_val(forbidden) |= _PAGE_RW; + pgprot_val(forbidden) |= _PAGE_NX & __supported_pte_mask; + } +#endif + prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden)); return prot; @@ -435,23 +444,37 @@ EXPORT_SYMBOL_GPL(slow_virt_to_phys); static void __set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte) { /* change init_mm */ + pax_open_kernel(); set_pte_atomic(kpte, pte); + #ifdef CONFIG_X86_32 if (!SHARED_KERNEL_PMD) { + +#ifdef CONFIG_PAX_PER_CPU_PGD + unsigned long cpu; +#else struct page *page; +#endif +#ifdef CONFIG_PAX_PER_CPU_PGD + for (cpu = 0; cpu < nr_cpu_ids; ++cpu) { + pgd_t *pgd = get_cpu_pgd(cpu, kernel); +#else list_for_each_entry(page, &pgd_list, lru) { - pgd_t *pgd; + pgd_t *pgd = (pgd_t *)page_address(page); +#endif + pud_t *pud; pmd_t *pmd; - pgd = (pgd_t *)page_address(page) + pgd_index(address); + pgd += pgd_index(address); pud = pud_offset(pgd, address); pmd = pmd_offset(pud, address); set_pte_atomic((pte_t *)pmd, pte); } } #endif + pax_close_kernel(); } static int @@ -504,7 +527,8 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, * up accordingly. */ old_pte = *kpte; - old_prot = req_prot = pgprot_large_2_4k(pte_pgprot(old_pte)); + old_prot = pte_pgprot(old_pte); + req_prot = pgprot_large_2_4k(old_prot); pgprot_val(req_prot) &= ~pgprot_val(cpa->mask_clr); pgprot_val(req_prot) |= pgprot_val(cpa->mask_set); @@ -674,6 +698,10 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address, return 0; } +#if debug_pagealloc == 0 +static int split_large_page(struct cpa_data *cpa, pte_t *kpte, + unsigned long address) __must_hold(&cpa_lock); +#endif static int split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address) { @@ -1117,6 +1145,9 @@ static int __cpa_process_fault(struct cpa_data *cpa, unsigned long vaddr, } } +#if debug_pagealloc == 0 +static int __change_page_attr(struct cpa_data *cpa, int primary) __must_hold(&cpa_lock); +#endif static int __change_page_attr(struct cpa_data *cpa, int primary) { unsigned long address; @@ -1175,7 +1206,9 @@ repeat: * Do we really change anything ? */ if (pte_val(old_pte) != pte_val(new_pte)) { + pax_open_kernel(); set_pte_atomic(kpte, new_pte); + pax_close_kernel(); cpa->flags |= CPA_FLUSHTLB; } cpa->numpages = 1; diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 188e3e0..5c75446 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -588,7 +588,7 @@ int free_memtype(u64 start, u64 end) if (!entry) { pr_info("x86/PAT: %s:%d freeing invalid memtype [mem %#010Lx-%#010Lx]\n", - current->comm, current->pid, start, end - 1); + current->comm, task_pid_nr(current), start, end - 1); return -EINVAL; } @@ -711,8 +711,8 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size) while (cursor < to) { if (!devmem_is_allowed(pfn)) { - pr_info("x86/PAT: Program %s tried to access /dev/mem between [mem %#010Lx-%#010Lx], PAT prevents it\n", - current->comm, from, to - 1); + pr_info("x86/PAT: Program %s tried to access /dev/mem between [mem %#010Lx-%#010Lx] (%#010Lx), PAT prevents it\n", + current->comm, from, to - 1, cursor); return 0; } cursor += PAGE_SIZE; @@ -782,7 +782,7 @@ int kernel_map_sync_memtype(u64 base, unsigned long size, if (ioremap_change_attr((unsigned long)__va(base), id_sz, pcm) < 0) { pr_info("x86/PAT: %s:%d ioremap_change_attr failed %s for [mem %#010Lx-%#010Lx]\n", - current->comm, current->pid, + current->comm, task_pid_nr(current), cattr_name(pcm), base, (unsigned long long)(base + size-1)); return -EINVAL; @@ -817,7 +817,7 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot, pcm = lookup_memtype(paddr); if (want_pcm != pcm) { pr_warn("x86/PAT: %s:%d map pfn RAM range req %s for [mem %#010Lx-%#010Lx], got %s\n", - current->comm, current->pid, + current->comm, task_pid_nr(current), cattr_name(want_pcm), (unsigned long long)paddr, (unsigned long long)(paddr + size - 1), @@ -838,7 +838,7 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot, !is_new_memtype_allowed(paddr, size, want_pcm, pcm)) { free_memtype(paddr, paddr + size); pr_err("x86/PAT: %s:%d map pfn expected mapping type %s for [mem %#010Lx-%#010Lx], got %s\n", - current->comm, current->pid, + current->comm, task_pid_nr(current), cattr_name(want_pcm), (unsigned long long)paddr, (unsigned long long)(paddr + size - 1), diff --git a/arch/x86/mm/pat_rbtree.c b/arch/x86/mm/pat_rbtree.c index 6393108..890adda 100644 --- a/arch/x86/mm/pat_rbtree.c +++ b/arch/x86/mm/pat_rbtree.c @@ -161,7 +161,7 @@ success: failure: pr_info("x86/PAT: %s:%d conflicting memory types %Lx-%Lx %s<->%s\n", - current->comm, current->pid, start, end, + current->comm, task_pid_nr(current), start, end, cattr_name(found_type), cattr_name(match->type)); return -EBUSY; } diff --git a/arch/x86/mm/pf_in.c b/arch/x86/mm/pf_in.c index 9f0614d..92ae64a 100644 --- a/arch/x86/mm/pf_in.c +++ b/arch/x86/mm/pf_in.c @@ -148,7 +148,7 @@ enum reason_type get_ins_type(unsigned long ins_addr) int i; enum reason_type rv = OTHERS; - p = (unsigned char *)ins_addr; + p = (unsigned char *)ktla_ktva(ins_addr); p += skip_prefix(p, &prf); p += get_opcode(p, &opcode); @@ -168,7 +168,7 @@ static unsigned int get_ins_reg_width(unsigned long ins_addr) struct prefix_bits prf; int i; - p = (unsigned char *)ins_addr; + p = (unsigned char *)ktla_ktva(ins_addr); p += skip_prefix(p, &prf); p += get_opcode(p, &opcode); @@ -191,7 +191,7 @@ unsigned int get_ins_mem_width(unsigned long ins_addr) struct prefix_bits prf; int i; - p = (unsigned char *)ins_addr; + p = (unsigned char *)ktla_ktva(ins_addr); p += skip_prefix(p, &prf); p += get_opcode(p, &opcode); @@ -415,7 +415,7 @@ unsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs) struct prefix_bits prf; int i; - p = (unsigned char *)ins_addr; + p = (unsigned char *)ktla_ktva(ins_addr); p += skip_prefix(p, &prf); p += get_opcode(p, &opcode); for (i = 0; i < ARRAY_SIZE(reg_rop); i++) @@ -470,7 +470,7 @@ unsigned long get_ins_imm_val(unsigned long ins_addr) struct prefix_bits prf; int i; - p = (unsigned char *)ins_addr; + p = (unsigned char *)ktla_ktva(ins_addr); p += skip_prefix(p, &prf); p += get_opcode(p, &opcode); for (i = 0; i < ARRAY_SIZE(imm_wop); i++) diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index fb0a9dd..5ab49c4 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c @@ -98,10 +98,75 @@ static inline void pgd_list_del(pgd_t *pgd) list_del(&page->lru); } -#define UNSHARED_PTRS_PER_PGD \ - (SHARED_KERNEL_PMD ? KERNEL_PGD_BOUNDARY : PTRS_PER_PGD) +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) +pgdval_t clone_pgd_mask __read_only = ~_PAGE_PRESENT; +void __shadow_user_pgds(pgd_t *dst, const pgd_t *src) +{ + unsigned int count = USER_PGD_PTRS; + if (!pax_user_shadow_base) + return; + + while (count--) + *dst++ = __pgd((pgd_val(*src++) | (_PAGE_NX & __supported_pte_mask)) & ~_PAGE_USER); +} +#endif + +#ifdef CONFIG_PAX_PER_CPU_PGD +void __clone_user_pgds(pgd_t *dst, const pgd_t *src) +{ + unsigned int count = USER_PGD_PTRS; + + while (count--) { + pgd_t pgd; + +#ifdef CONFIG_X86_64 + pgd = __pgd(pgd_val(*src++) | _PAGE_USER); +#else + pgd = *src++; +#endif + +#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF) + pgd = __pgd(pgd_val(pgd) & clone_pgd_mask); +#endif + + *dst++ = pgd; + } + +} +#endif + +#ifdef CONFIG_X86_64 +#define pxd_t pud_t +#define pyd_t pgd_t +#define paravirt_release_pxd(pfn) paravirt_release_pud(pfn) +#define pgtable_pxd_page_ctor(page) true +#define pgtable_pxd_page_dtor(page) do {} while (0) +#define pxd_free(mm, pud) pud_free((mm), (pud)) +#define pyd_populate(mm, pgd, pud) pgd_populate((mm), (pgd), (pud)) +#define pyd_offset(mm, address) pgd_offset((mm), (address)) +#define PYD_SIZE PGDIR_SIZE +#define mm_inc_nr_pxds(mm) do {} while (0) +#define mm_dec_nr_pxds(mm) do {} while (0) +#else +#define pxd_t pmd_t +#define pyd_t pud_t +#define paravirt_release_pxd(pfn) paravirt_release_pmd(pfn) +#define pgtable_pxd_page_ctor(page) pgtable_pmd_page_ctor(page) +#define pgtable_pxd_page_dtor(page) pgtable_pmd_page_dtor(page) +#define pxd_free(mm, pud) pmd_free((mm), (pud)) +#define pyd_populate(mm, pgd, pud) pud_populate((mm), (pgd), (pud)) +#define pyd_offset(mm, address) pud_offset((mm), (address)) +#define PYD_SIZE PUD_SIZE +#define mm_inc_nr_pxds(mm) mm_inc_nr_pmds(mm) +#define mm_dec_nr_pxds(mm) mm_dec_nr_pmds(mm) +#endif + +#ifdef CONFIG_PAX_PER_CPU_PGD +static inline void pgd_ctor(struct mm_struct *mm, pgd_t *pgd) {} +static inline void pgd_dtor(pgd_t *pgd) {} +#else static void pgd_set_mm(pgd_t *pgd, struct mm_struct *mm) { BUILD_BUG_ON(sizeof(virt_to_page(pgd)->index) < sizeof(mm)); @@ -142,6 +207,7 @@ static void pgd_dtor(pgd_t *pgd) pgd_list_del(pgd); spin_unlock(&pgd_lock); } +#endif /* * List of all pgd's needed for non-PAE so it can invalidate entries @@ -154,7 +220,7 @@ static void pgd_dtor(pgd_t *pgd) * -- nyc */ -#ifdef CONFIG_X86_PAE +#if defined(CONFIG_X86_32) && defined(CONFIG_X86_PAE) /* * In PAE mode, we need to do a cr3 reload (=tlb flush) when * updating the top-level pagetable entries to guarantee the @@ -166,7 +232,7 @@ static void pgd_dtor(pgd_t *pgd) * not shared between pagetables (!SHARED_KERNEL_PMDS), we allocate * and initialize the kernel pmds here. */ -#define PREALLOCATED_PMDS UNSHARED_PTRS_PER_PGD +#define PREALLOCATED_PXDS (SHARED_KERNEL_PMD ? KERNEL_PGD_BOUNDARY : PTRS_PER_PGD) void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd) { @@ -184,46 +250,48 @@ void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd) */ flush_tlb_mm(mm); } +#elif defined(CONFIG_X86_64) && defined(CONFIG_PAX_PER_CPU_PGD) +#define PREALLOCATED_PXDS USER_PGD_PTRS #else /* !CONFIG_X86_PAE */ /* No need to prepopulate any pagetable entries in non-PAE modes. */ -#define PREALLOCATED_PMDS 0 +#define PREALLOCATED_PXDS 0 #endif /* CONFIG_X86_PAE */ -static void free_pmds(struct mm_struct *mm, pmd_t *pmds[]) +static void free_pxds(struct mm_struct *mm, pxd_t *pxds[]) { int i; - for(i = 0; i < PREALLOCATED_PMDS; i++) - if (pmds[i]) { - pgtable_pmd_page_dtor(virt_to_page(pmds[i])); - free_page((unsigned long)pmds[i]); - mm_dec_nr_pmds(mm); + for(i = 0; i < PREALLOCATED_PXDS; i++) + if (pxds[i]) { + pgtable_pxd_page_dtor(virt_to_page(pxds[i])); + free_page((unsigned long)pxds[i]); + mm_dec_nr_pxds(mm); } } -static int preallocate_pmds(struct mm_struct *mm, pmd_t *pmds[]) +static int preallocate_pxds(struct mm_struct *mm, pxd_t *pxds[]) { int i; bool failed = false; - for(i = 0; i < PREALLOCATED_PMDS; i++) { - pmd_t *pmd = (pmd_t *)__get_free_page(PGALLOC_GFP); - if (!pmd) + for(i = 0; i < PREALLOCATED_PXDS; i++) { + pxd_t *pxd = (pxd_t *)__get_free_page(PGALLOC_GFP); + if (!pxd) failed = true; - if (pmd && !pgtable_pmd_page_ctor(virt_to_page(pmd))) { - free_page((unsigned long)pmd); - pmd = NULL; + if (pxd && !pgtable_pxd_page_ctor(virt_to_page(pxd))) { + free_page((unsigned long)pxd); + pxd = NULL; failed = true; } - if (pmd) - mm_inc_nr_pmds(mm); - pmds[i] = pmd; + if (pxd) + mm_inc_nr_pxds(mm); + pxds[i] = pxd; } if (failed) { - free_pmds(mm, pmds); + free_pxds(mm, pxds); return -ENOMEM; } @@ -236,43 +304,47 @@ static int preallocate_pmds(struct mm_struct *mm, pmd_t *pmds[]) * preallocate which never got a corresponding vma will need to be * freed manually. */ -static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp) +static void pgd_mop_up_pxds(struct mm_struct *mm, pgd_t *pgdp) { int i; - for(i = 0; i < PREALLOCATED_PMDS; i++) { + for(i = 0; i < PREALLOCATED_PXDS; i++) { pgd_t pgd = pgdp[i]; if (pgd_val(pgd) != 0) { - pmd_t *pmd = (pmd_t *)pgd_page_vaddr(pgd); + pxd_t *pxd = (pxd_t *)pgd_page_vaddr(pgd); - pgdp[i] = native_make_pgd(0); + set_pgd(pgdp + i, native_make_pgd(0)); - paravirt_release_pmd(pgd_val(pgd) >> PAGE_SHIFT); - pmd_free(mm, pmd); - mm_dec_nr_pmds(mm); + paravirt_release_pxd(pgd_val(pgd) >> PAGE_SHIFT); + pxd_free(mm, pxd); + mm_dec_nr_pxds(mm); } } } -static void pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmds[]) +static void pgd_prepopulate_pxd(struct mm_struct *mm, pgd_t *pgd, pxd_t *pxds[]) { - pud_t *pud; + pyd_t *pyd; int i; - if (PREALLOCATED_PMDS == 0) /* Work around gcc-3.4.x bug */ + if (PREALLOCATED_PXDS == 0) /* Work around gcc-3.4.x bug */ return; - pud = pud_offset(pgd, 0); +#ifdef CONFIG_X86_64 + pyd = pyd_offset(mm, 0L); +#else + pyd = pyd_offset(pgd, 0L); +#endif - for (i = 0; i < PREALLOCATED_PMDS; i++, pud++) { - pmd_t *pmd = pmds[i]; + for (i = 0; i < PREALLOCATED_PXDS; i++, pyd++) { + pxd_t *pxd = pxds[i]; if (i >= KERNEL_PGD_BOUNDARY) - memcpy(pmd, (pmd_t *)pgd_page_vaddr(swapper_pg_dir[i]), - sizeof(pmd_t) * PTRS_PER_PMD); + memcpy(pxd, (pxd_t *)pgd_page_vaddr(swapper_pg_dir[i]), + sizeof(pxd_t) * PTRS_PER_PMD); - pud_populate(mm, pud, pmd); + pyd_populate(mm, pyd, pxd); } } @@ -354,7 +426,7 @@ static inline void _pgd_free(pgd_t *pgd) pgd_t *pgd_alloc(struct mm_struct *mm) { pgd_t *pgd; - pmd_t *pmds[PREALLOCATED_PMDS]; + pxd_t *pxds[PREALLOCATED_PXDS]; pgd = _pgd_alloc(); @@ -363,11 +435,11 @@ pgd_t *pgd_alloc(struct mm_struct *mm) mm->pgd = pgd; - if (preallocate_pmds(mm, pmds) != 0) + if (preallocate_pxds(mm, pxds) != 0) goto out_free_pgd; if (paravirt_pgd_alloc(mm) != 0) - goto out_free_pmds; + goto out_free_pxds; /* * Make sure that pre-populating the pmds is atomic with @@ -377,14 +449,14 @@ pgd_t *pgd_alloc(struct mm_struct *mm) spin_lock(&pgd_lock); pgd_ctor(mm, pgd); - pgd_prepopulate_pmd(mm, pgd, pmds); + pgd_prepopulate_pxd(mm, pgd, pxds); spin_unlock(&pgd_lock); return pgd; -out_free_pmds: - free_pmds(mm, pmds); +out_free_pxds: + free_pxds(mm, pxds); out_free_pgd: _pgd_free(pgd); out: @@ -393,7 +465,7 @@ out: void pgd_free(struct mm_struct *mm, pgd_t *pgd) { - pgd_mop_up_pmds(mm, pgd); + pgd_mop_up_pxds(mm, pgd); pgd_dtor(pgd); paravirt_pgd_free(mm, pgd); _pgd_free(pgd); @@ -544,6 +616,55 @@ void __init reserve_top_address(unsigned long reserve) int fixmaps_set; +static void fix_user_fixmap(enum fixed_addresses idx, unsigned long address) +{ +#ifdef CONFIG_X86_64 + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + + switch (idx) { + default: + return; + +#ifdef CONFIG_X86_VSYSCALL_EMULATION + case VSYSCALL_PAGE: + break; +#endif + +#ifdef CONFIG_PARAVIRT_CLOCK + case PVCLOCK_FIXMAP_BEGIN ... PVCLOCK_FIXMAP_END: + break; +#endif + } + + pgd = pgd_offset_k(address); + if (!(pgd_val(*pgd) & _PAGE_USER)) { +#ifdef CONFIG_PAX_PER_CPU_PGD + unsigned int cpu; + pgd_t *pgd_cpu; + + for_each_possible_cpu(cpu) { + pgd_cpu = pgd_offset_cpu(cpu, kernel, address); + set_pgd(pgd_cpu, __pgd(pgd_val(*pgd_cpu) | _PAGE_USER)); + + pgd_cpu = pgd_offset_cpu(cpu, user, address); + set_pgd(pgd_cpu, __pgd(pgd_val(*pgd_cpu) | _PAGE_USER)); + } +#endif + set_pgd(pgd, __pgd(pgd_val(*pgd) | _PAGE_USER)); + } + + pud = pud_offset(pgd, address); + if (!(pud_val(*pud) & _PAGE_USER)) + set_pud(pud, __pud(pud_val(*pud) | _PAGE_USER)); + + pmd = pmd_offset(pud, address); + if (!(pmd_val(*pmd) & _PAGE_USER)) + set_pmd(pmd, __pmd(pmd_val(*pmd) | _PAGE_USER)); +#endif +} + void __native_set_fixmap(enum fixed_addresses idx, pte_t pte) { unsigned long address = __fix_to_virt(idx); @@ -554,6 +675,7 @@ void __native_set_fixmap(enum fixed_addresses idx, pte_t pte) } set_pte_vaddr(address, pte); fixmaps_set++; + fix_user_fixmap(idx, address); } void native_set_fixmap(enum fixed_addresses idx, phys_addr_t phys, @@ -620,9 +742,11 @@ int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot) prot = pgprot_4k_2_large(prot); + pax_open_kernel(); set_pte((pte_t *)pmd, pfn_pte( (u64)addr >> PAGE_SHIFT, __pgprot(pgprot_val(prot) | _PAGE_PSE))); + pax_close_kernel(); return 1; } diff --git a/arch/x86/mm/pgtable_32.c b/arch/x86/mm/pgtable_32.c index 75cc097..79a097f 100644 --- a/arch/x86/mm/pgtable_32.c +++ b/arch/x86/mm/pgtable_32.c @@ -47,10 +47,13 @@ void set_pte_vaddr(unsigned long vaddr, pte_t pteval) return; } pte = pte_offset_kernel(pmd, vaddr); + + pax_open_kernel(); if (pte_val(pteval)) set_pte_at(&init_mm, vaddr, pte, pteval); else pte_clear(&init_mm, vaddr, pte); + pax_close_kernel(); /* * It's enough to flush this one mapping. diff --git a/arch/x86/mm/setup_nx.c b/arch/x86/mm/setup_nx.c index 90555bf..f5f1828 100644 --- a/arch/x86/mm/setup_nx.c +++ b/arch/x86/mm/setup_nx.c @@ -5,8 +5,10 @@ #include #include +#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE) static int disable_nx; +#ifndef CONFIG_PAX_PAGEEXEC /* * noexec = on|off * @@ -28,12 +30,17 @@ static int __init noexec_setup(char *str) return 0; } early_param("noexec", noexec_setup); +#endif + +#endif void x86_configure_nx(void) { +#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE) if (cpu_has_nx && !disable_nx) __supported_pte_mask |= _PAGE_NX; else +#endif __supported_pte_mask &= ~_PAGE_NX; } diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 8ddb5d0..6f70318 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -45,7 +45,11 @@ void leave_mm(int cpu) BUG(); if (cpumask_test_cpu(cpu, mm_cpumask(active_mm))) { cpumask_clear_cpu(cpu, mm_cpumask(active_mm)); + +#ifndef CONFIG_PAX_PER_CPU_PGD load_cr3(swapper_pg_dir); +#endif + /* * This gets called in the idle path where RCU * functions differently. Tracing normally diff --git a/arch/x86/mm/uderef_64.c b/arch/x86/mm/uderef_64.c new file mode 100644 index 0000000..3fda3f3 --- /dev/null +++ b/arch/x86/mm/uderef_64.c @@ -0,0 +1,37 @@ +#include +#include +#include + +#ifdef CONFIG_PAX_MEMORY_UDEREF +/* PaX: due to the special call convention these functions must + * - remain leaf functions under all configurations, + * - never be called directly, only dereferenced from the wrappers. + */ +void __used __pax_open_userland(void) +{ + unsigned int cpu; + + if (unlikely(!segment_eq(get_fs(), USER_DS))) + return; + + cpu = raw_get_cpu(); + BUG_ON((read_cr3() & ~PAGE_MASK) != PCID_KERNEL); + write_cr3(__pa_nodebug(get_cpu_pgd(cpu, user)) | PCID_USER | PCID_NOFLUSH); + raw_put_cpu_no_resched(); +} +EXPORT_SYMBOL(__pax_open_userland); + +void __used __pax_close_userland(void) +{ + unsigned int cpu; + + if (unlikely(!segment_eq(get_fs(), USER_DS))) + return; + + cpu = raw_get_cpu(); + BUG_ON((read_cr3() & ~PAGE_MASK) != PCID_USER); + write_cr3(__pa_nodebug(get_cpu_pgd(cpu, kernel)) | PCID_KERNEL | PCID_NOFLUSH); + raw_put_cpu_no_resched(); +} +EXPORT_SYMBOL(__pax_close_userland); +#endif diff --git a/arch/x86/net/bpf_jit.S b/arch/x86/net/bpf_jit.S index 4093216..44b6b83 100644 --- a/arch/x86/net/bpf_jit.S +++ b/arch/x86/net/bpf_jit.S @@ -8,6 +8,7 @@ * of the License. */ #include +#include /* * Calling convention : @@ -37,6 +38,7 @@ sk_load_word_positive_offset: jle bpf_slow_path_word mov (SKBDATA,%rsi),%eax bswap %eax /* ntohl() */ + pax_force_retaddr ret sk_load_half: @@ -54,6 +56,7 @@ sk_load_half_positive_offset: jle bpf_slow_path_half movzwl (SKBDATA,%rsi),%eax rol $8,%ax # ntohs() + pax_force_retaddr ret sk_load_byte: @@ -68,6 +71,7 @@ sk_load_byte_positive_offset: cmp %esi,%r9d /* if (offset >= hlen) goto bpf_slow_path_byte */ jle bpf_slow_path_byte movzbl (SKBDATA,%rsi),%eax + pax_force_retaddr ret /* rsi contains offset and can be scratched */ @@ -89,6 +93,7 @@ bpf_slow_path_word: js bpf_error mov - MAX_BPF_STACK + 32(%rbp),%eax bswap %eax + pax_force_retaddr ret bpf_slow_path_half: @@ -97,12 +102,14 @@ bpf_slow_path_half: mov - MAX_BPF_STACK + 32(%rbp),%ax rol $8,%ax movzwl %ax,%eax + pax_force_retaddr ret bpf_slow_path_byte: bpf_slow_path_common(1) js bpf_error movzbl - MAX_BPF_STACK + 32(%rbp),%eax + pax_force_retaddr ret #define sk_negative_common(SIZE) \ @@ -125,6 +132,7 @@ sk_load_word_negative_offset: sk_negative_common(4) mov (%rax), %eax bswap %eax + pax_force_retaddr ret bpf_slow_path_half_neg: @@ -136,6 +144,7 @@ sk_load_half_negative_offset: mov (%rax),%ax rol $8,%ax movzwl %ax,%eax + pax_force_retaddr ret bpf_slow_path_byte_neg: @@ -145,6 +154,7 @@ sk_load_byte_negative_offset: .globl sk_load_byte_negative_offset sk_negative_common(1) movzbl (%rax), %eax + pax_force_retaddr ret bpf_error: @@ -155,4 +165,5 @@ bpf_error: mov - MAX_BPF_STACK + 16(%rbp),%r14 mov - MAX_BPF_STACK + 24(%rbp),%r15 leaveq + pax_force_retaddr ret diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 70efcd0..0a689c9 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -14,7 +14,11 @@ #include #include +#ifdef CONFIG_GRKERNSEC_BPF_HARDEN +int bpf_jit_enable __read_only; +#else int bpf_jit_enable __read_mostly; +#endif /* * assembly code in arch/x86/net/bpf_jit.S @@ -176,7 +180,9 @@ static u8 add_2reg(u8 byte, u32 dst_reg, u32 src_reg) static void jit_fill_hole(void *area, unsigned int size) { /* fill whole space with int3 instructions */ + pax_open_kernel(); memset(area, 0xcc, size); + pax_close_kernel(); } struct jit_context { @@ -1030,7 +1036,9 @@ common_load: pr_err("bpf_jit_compile fatal error\n"); return -EFAULT; } + pax_open_kernel(); memcpy(image + proglen, temp, ilen); + pax_close_kernel(); } proglen += ilen; addrs[i] = proglen; @@ -1107,7 +1115,6 @@ void bpf_int_jit_compile(struct bpf_prog *prog) if (image) { bpf_flush_icache(header, image + proglen); - set_memory_ro((unsigned long)header, header->pages); prog->bpf_func = (void *)image; prog->jited = true; } @@ -1120,12 +1127,8 @@ void bpf_jit_free(struct bpf_prog *fp) unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK; struct bpf_binary_header *header = (void *)addr; - if (!fp->jited) - goto free_filter; + if (fp->jited) + bpf_jit_binary_free(header); - set_memory_rw(addr, header->pages); - bpf_jit_binary_free(header); - -free_filter: bpf_prog_unlock_free(fp); } diff --git a/arch/x86/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c index 4e664bd..2beeaa2 100644 --- a/arch/x86/oprofile/backtrace.c +++ b/arch/x86/oprofile/backtrace.c @@ -46,11 +46,11 @@ dump_user_backtrace_32(struct stack_frame_ia32 *head) struct stack_frame_ia32 *fp; unsigned long bytes; - bytes = copy_from_user_nmi(bufhead, head, sizeof(bufhead)); + bytes = copy_from_user_nmi(bufhead, (const char __force_user *)head, sizeof(bufhead)); if (bytes != 0) return NULL; - fp = (struct stack_frame_ia32 *) compat_ptr(bufhead[0].next_frame); + fp = (struct stack_frame_ia32 __force_kernel *) compat_ptr(bufhead[0].next_frame); oprofile_add_trace(bufhead[0].return_address); @@ -92,7 +92,7 @@ static struct stack_frame *dump_user_backtrace(struct stack_frame *head) struct stack_frame bufhead[2]; unsigned long bytes; - bytes = copy_from_user_nmi(bufhead, head, sizeof(bufhead)); + bytes = copy_from_user_nmi(bufhead, (const char __force_user *)head, sizeof(bufhead)); if (bytes != 0) return NULL; diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 1d2e639..f6ef82a 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "op_counter.h" #include "op_x86_model.h" @@ -785,8 +786,11 @@ int __init op_nmi_init(struct oprofile_operations *ops) if (ret) return ret; - if (!model->num_virt_counters) - model->num_virt_counters = model->num_counters; + if (!model->num_virt_counters) { + pax_open_kernel(); + *(unsigned int *)&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 --- 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) num_counters = AMD64_NUM_COUNTERS; } - op_amd_spec.num_counters = num_counters; - 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); + 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 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "op_x86_model.h" #include "op_counter.h" @@ -221,8 +222,10 @@ static void arch_perfmon_setup_counters(void) num_counters = min((int)eax.split.num_counters, OP_MAX_COUNTER); - 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; + pax_close_kernel(); } static int arch_perfmon_init(struct oprofile_operations *ignore) diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 71e8a67..6a313bb 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -52,7 +52,7 @@ struct op_x86_model_spec { void (*switch_ctrl)(struct op_x86_model_spec const *model, struct op_msrs const * const msrs); #endif -}; +} __do_const; struct op_counter_config; diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c index 0d24e7c..d937be3 100644 --- a/arch/x86/pci/intel_mid_pci.c +++ b/arch/x86/pci/intel_mid_pci.c @@ -283,7 +283,7 @@ int __init intel_mid_pci_init(void) pci_mmcfg_late_init(); pcibios_enable_irq = intel_mid_pci_irq_enable; pcibios_disable_irq = intel_mid_pci_irq_disable; - pci_root_ops = intel_mid_pci_ops; + memcpy((void *)&pci_root_ops, &intel_mid_pci_ops, sizeof pci_root_ops); pci_soc_mode = 1; /* Continue with standard init */ return 1; diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index 32e7034..bf2dd06 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c @@ -51,7 +51,7 @@ struct irq_router { struct irq_router_handler { u16 vendor; int (*probe)(struct irq_router *r, struct pci_dev *router, u16 device); -}; +} __do_const; int (*pcibios_enable_irq)(struct pci_dev *dev) = pirq_enable_irq; void (*pcibios_disable_irq)(struct pci_dev *dev) = pirq_disable_irq; @@ -792,7 +792,7 @@ static __init int pico_router_probe(struct irq_router *r, struct pci_dev *router return 0; } -static __initdata struct irq_router_handler pirq_routers[] = { +static __initconst const struct irq_router_handler pirq_routers[] = { { PCI_VENDOR_ID_INTEL, intel_router_probe }, { PCI_VENDOR_ID_AL, ali_router_probe }, { PCI_VENDOR_ID_ITE, ite_router_probe }, @@ -819,7 +819,7 @@ static struct pci_dev *pirq_router_dev; static void __init pirq_find_router(struct irq_router *r) { struct irq_routing_table *rt = pirq_table; - struct irq_router_handler *h; + const struct irq_router_handler *h; #ifdef CONFIG_PCI_BIOS if (!rt->signature) { @@ -1092,7 +1092,7 @@ static int __init fix_acer_tm360_irqrouting(const struct dmi_system_id *d) return 0; } -static struct dmi_system_id __initdata pciirq_dmi_table[] = { +static const struct dmi_system_id __initconst pciirq_dmi_table[] = { { .callback = fix_broken_hp_bios_irq9, .ident = "HP Pavilion N5400 Series Laptop", diff --git a/arch/x86/pci/pcbios.c b/arch/x86/pci/pcbios.c index 9b83b90..2c256c5 100644 --- a/arch/x86/pci/pcbios.c +++ b/arch/x86/pci/pcbios.c @@ -79,7 +79,7 @@ union bios32 { static struct { unsigned long address; unsigned short segment; -} bios32_indirect __initdata = { 0, __KERNEL_CS }; +} bios32_indirect __initdata = { 0, __PCIBIOS_CS }; /* * Returns the entry point for the given service, NULL on error @@ -92,37 +92,80 @@ static unsigned long __init bios32_service(unsigned long service) unsigned long length; /* %ecx */ unsigned long entry; /* %edx */ unsigned long flags; + struct desc_struct d, *gdt; local_irq_save(flags); - __asm__("lcall *(%%edi); cld" + + gdt = get_cpu_gdt_table(smp_processor_id()); + + pack_descriptor(&d, 0UL, 0xFFFFFUL, 0x9B, 0xC); + write_gdt_entry(gdt, GDT_ENTRY_PCIBIOS_CS, &d, DESCTYPE_S); + pack_descriptor(&d, 0UL, 0xFFFFFUL, 0x93, 0xC); + write_gdt_entry(gdt, GDT_ENTRY_PCIBIOS_DS, &d, DESCTYPE_S); + + __asm__("movw %w7, %%ds; lcall *(%%edi); push %%ss; pop %%ds; cld" : "=a" (return_code), "=b" (address), "=c" (length), "=d" (entry) : "0" (service), "1" (0), - "D" (&bios32_indirect)); + "D" (&bios32_indirect), + "r"(__PCIBIOS_DS) + : "memory"); + + pax_open_kernel(); + gdt[GDT_ENTRY_PCIBIOS_CS].a = 0; + gdt[GDT_ENTRY_PCIBIOS_CS].b = 0; + gdt[GDT_ENTRY_PCIBIOS_DS].a = 0; + gdt[GDT_ENTRY_PCIBIOS_DS].b = 0; + pax_close_kernel(); + local_irq_restore(flags); switch (return_code) { - case 0: - return address + entry; - case 0x80: /* Not present */ - printk(KERN_WARNING "bios32_service(0x%lx): not present\n", service); - return 0; - default: /* Shouldn't happen */ - printk(KERN_WARNING "bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n", - service, return_code); + case 0: { + int cpu; + unsigned char flags; + + printk(KERN_INFO "bios32_service: base:%08lx length:%08lx entry:%08lx\n", address, length, entry); + if (address >= 0xFFFF0 || length > 0x100000 - address || length <= entry) { + printk(KERN_WARNING "bios32_service: not valid\n"); return 0; + } + address = address + PAGE_OFFSET; + length += 16UL; /* some BIOSs underreport this... */ + flags = 4; + if (length >= 64*1024*1024) { + length >>= PAGE_SHIFT; + flags |= 8; + } + + for (cpu = 0; cpu < nr_cpu_ids; cpu++) { + gdt = get_cpu_gdt_table(cpu); + pack_descriptor(&d, address, length, 0x9b, flags); + write_gdt_entry(gdt, GDT_ENTRY_PCIBIOS_CS, &d, DESCTYPE_S); + pack_descriptor(&d, address, length, 0x93, flags); + write_gdt_entry(gdt, GDT_ENTRY_PCIBIOS_DS, &d, DESCTYPE_S); + } + return entry; + } + case 0x80: /* Not present */ + printk(KERN_WARNING "bios32_service(0x%lx): not present\n", service); + return 0; + default: /* Shouldn't happen */ + printk(KERN_WARNING "bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n", + service, return_code); + return 0; } } static struct { unsigned long address; unsigned short segment; -} pci_indirect = { 0, __KERNEL_CS }; +} pci_indirect __read_only = { 0, __PCIBIOS_CS }; -static int pci_bios_present; +static int pci_bios_present __read_only; static int __init check_pcibios(void) { @@ -131,11 +174,13 @@ static int __init check_pcibios(void) unsigned long flags, pcibios_entry; if ((pcibios_entry = bios32_service(PCI_SERVICE))) { - pci_indirect.address = pcibios_entry + PAGE_OFFSET; + pci_indirect.address = pcibios_entry; local_irq_save(flags); - __asm__( - "lcall *(%%edi); cld\n\t" + __asm__("movw %w6, %%ds\n\t" + "lcall *%%ss:(%%edi); cld\n\t" + "push %%ss\n\t" + "pop %%ds\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -144,7 +189,8 @@ static int __init check_pcibios(void) "=b" (ebx), "=c" (ecx) : "1" (PCIBIOS_PCI_BIOS_PRESENT), - "D" (&pci_indirect) + "D" (&pci_indirect), + "r" (__PCIBIOS_DS) : "memory"); local_irq_restore(flags); @@ -189,7 +235,10 @@ static int pci_bios_read(unsigned int seg, unsigned int bus, switch (len) { case 1: - __asm__("lcall *(%%esi); cld\n\t" + __asm__("movw %w6, %%ds\n\t" + "lcall *%%ss:(%%esi); cld\n\t" + "push %%ss\n\t" + "pop %%ds\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -198,7 +247,8 @@ static int pci_bios_read(unsigned int seg, unsigned int bus, : "1" (PCIBIOS_READ_CONFIG_BYTE), "b" (bx), "D" ((long)reg), - "S" (&pci_indirect)); + "S" (&pci_indirect), + "r" (__PCIBIOS_DS)); /* * Zero-extend the result beyond 8 bits, do not trust the * BIOS having done it: @@ -206,7 +256,10 @@ static int pci_bios_read(unsigned int seg, unsigned int bus, *value &= 0xff; break; case 2: - __asm__("lcall *(%%esi); cld\n\t" + __asm__("movw %w6, %%ds\n\t" + "lcall *%%ss:(%%esi); cld\n\t" + "push %%ss\n\t" + "pop %%ds\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -215,7 +268,8 @@ static int pci_bios_read(unsigned int seg, unsigned int bus, : "1" (PCIBIOS_READ_CONFIG_WORD), "b" (bx), "D" ((long)reg), - "S" (&pci_indirect)); + "S" (&pci_indirect), + "r" (__PCIBIOS_DS)); /* * Zero-extend the result beyond 16 bits, do not trust the * BIOS having done it: @@ -223,7 +277,10 @@ static int pci_bios_read(unsigned int seg, unsigned int bus, *value &= 0xffff; break; case 4: - __asm__("lcall *(%%esi); cld\n\t" + __asm__("movw %w6, %%ds\n\t" + "lcall *%%ss:(%%esi); cld\n\t" + "push %%ss\n\t" + "pop %%ds\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -232,7 +289,8 @@ static int pci_bios_read(unsigned int seg, unsigned int bus, : "1" (PCIBIOS_READ_CONFIG_DWORD), "b" (bx), "D" ((long)reg), - "S" (&pci_indirect)); + "S" (&pci_indirect), + "r" (__PCIBIOS_DS)); break; } @@ -256,7 +314,10 @@ static int pci_bios_write(unsigned int seg, unsigned int bus, switch (len) { case 1: - __asm__("lcall *(%%esi); cld\n\t" + __asm__("movw %w6, %%ds\n\t" + "lcall *%%ss:(%%esi); cld\n\t" + "push %%ss\n\t" + "pop %%ds\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -265,10 +326,14 @@ static int pci_bios_write(unsigned int seg, unsigned int bus, "c" (value), "b" (bx), "D" ((long)reg), - "S" (&pci_indirect)); + "S" (&pci_indirect), + "r" (__PCIBIOS_DS)); break; case 2: - __asm__("lcall *(%%esi); cld\n\t" + __asm__("movw %w6, %%ds\n\t" + "lcall *%%ss:(%%esi); cld\n\t" + "push %%ss\n\t" + "pop %%ds\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -277,10 +342,14 @@ static int pci_bios_write(unsigned int seg, unsigned int bus, "c" (value), "b" (bx), "D" ((long)reg), - "S" (&pci_indirect)); + "S" (&pci_indirect), + "r" (__PCIBIOS_DS)); break; case 4: - __asm__("lcall *(%%esi); cld\n\t" + __asm__("movw %w6, %%ds\n\t" + "lcall *%%ss:(%%esi); cld\n\t" + "push %%ss\n\t" + "pop %%ds\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -289,7 +358,8 @@ static int pci_bios_write(unsigned int seg, unsigned int bus, "c" (value), "b" (bx), "D" ((long)reg), - "S" (&pci_indirect)); + "S" (&pci_indirect), + "r" (__PCIBIOS_DS)); break; } @@ -394,10 +464,13 @@ struct irq_routing_table * pcibios_get_irq_routing_table(void) DBG("PCI: Fetching IRQ routing table... "); __asm__("push %%es\n\t" + "movw %w8, %%ds\n\t" "push %%ds\n\t" "pop %%es\n\t" - "lcall *(%%esi); cld\n\t" + "lcall *%%ss:(%%esi); cld\n\t" "pop %%es\n\t" + "push %%ss\n\t" + "pop %%ds\n" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -408,7 +481,8 @@ struct irq_routing_table * pcibios_get_irq_routing_table(void) "1" (0), "D" ((long) &opt), "S" (&pci_indirect), - "m" (opt) + "m" (opt), + "r" (__PCIBIOS_DS) : "memory"); DBG("OK ret=%d, size=%d, map=%x\n", ret, opt.size, map); if (ret & 0xff00) @@ -432,7 +506,10 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq) { int ret; - __asm__("lcall *(%%esi); cld\n\t" + __asm__("movw %w5, %%ds\n\t" + "lcall *%%ss:(%%esi); cld\n\t" + "push %%ss\n\t" + "pop %%ds\n" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -440,7 +517,8 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq) : "0" (PCIBIOS_SET_PCI_HW_INT), "b" ((dev->bus->number << 8) | dev->devfn), "c" ((irq << 8) | (pin + 10)), - "S" (&pci_indirect)); + "S" (&pci_indirect), + "r" (__PCIBIOS_DS)); return !(ret & 0xff00); } EXPORT_SYMBOL(pcibios_set_irq_routing); diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c index ed5b673..24d2d53 100644 --- a/arch/x86/platform/efi/efi_32.c +++ b/arch/x86/platform/efi/efi_32.c @@ -61,11 +61,27 @@ pgd_t * __init efi_call_phys_prolog(void) struct desc_ptr gdt_descr; pgd_t *save_pgd; +#ifdef CONFIG_PAX_KERNEXEC + struct desc_struct d; +#endif + /* Current pgd is swapper_pg_dir, we'll restore it later: */ +#ifdef CONFIG_PAX_PER_CPU_PGD + save_pgd = get_cpu_pgd(smp_processor_id(), kernel); +#else save_pgd = swapper_pg_dir; +#endif + load_cr3(initial_page_table); __flush_tlb_all(); +#ifdef CONFIG_PAX_KERNEXEC + pack_descriptor(&d, 0, 0xFFFFF, 0x9B, 0xC); + write_gdt_entry(get_cpu_gdt_table(0), GDT_ENTRY_KERNEXEC_EFI_CS, &d, DESCTYPE_S); + pack_descriptor(&d, 0, 0xFFFFF, 0x93, 0xC); + write_gdt_entry(get_cpu_gdt_table(0), GDT_ENTRY_KERNEXEC_EFI_DS, &d, DESCTYPE_S); +#endif + gdt_descr.address = __pa(get_cpu_gdt_table(0)); gdt_descr.size = GDT_SIZE - 1; load_gdt(&gdt_descr); @@ -77,6 +93,14 @@ void __init efi_call_phys_epilog(pgd_t *save_pgd) { struct desc_ptr gdt_descr; +#ifdef CONFIG_PAX_KERNEXEC + struct desc_struct d; + + memset(&d, 0, sizeof d); + write_gdt_entry(get_cpu_gdt_table(0), GDT_ENTRY_KERNEXEC_EFI_CS, &d, DESCTYPE_S); + write_gdt_entry(get_cpu_gdt_table(0), GDT_ENTRY_KERNEXEC_EFI_DS, &d, DESCTYPE_S); +#endif + gdt_descr.address = (unsigned long)get_cpu_gdt_table(0); gdt_descr.size = GDT_SIZE - 1; load_gdt(&gdt_descr); diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index a0ac0f9..f41d324 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -96,6 +96,11 @@ pgd_t * __init efi_call_phys_prolog(void) vaddress = (unsigned long)__va(pgd * PGDIR_SIZE); set_pgd(pgd_offset_k(pgd * PGDIR_SIZE), *pgd_offset_k(vaddress)); } + +#ifdef CONFIG_PAX_PER_CPU_PGD + load_cr3(swapper_pg_dir); +#endif + __flush_tlb_all(); return save_pgd; @@ -119,6 +124,10 @@ void __init efi_call_phys_epilog(pgd_t *save_pgd) kfree(save_pgd); +#ifdef CONFIG_PAX_PER_CPU_PGD + load_cr3(get_cpu_pgd(smp_processor_id(), kernel)); +#endif + __flush_tlb_all(); early_code_mapping_set_exec(0); } @@ -148,8 +157,23 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) unsigned npages; pgd_t *pgd; - if (efi_enabled(EFI_OLD_MEMMAP)) + if (efi_enabled(EFI_OLD_MEMMAP)) { + /* PaX: We need to disable the NX bit in the PGD, otherwise we won't be + * able to execute the EFI services. + */ + if (__supported_pte_mask & _PAGE_NX) { + unsigned long addr = (unsigned long) __va(0); + pgd_t pe = __pgd(pgd_val(*pgd_offset_k(addr)) & ~_PAGE_NX); + + pr_alert("PAX: Disabling NX protection for low memory map. Try booting without \"efi=old_map\"\n"); +#ifdef CONFIG_PAX_PER_CPU_PGD + set_pgd(pgd_offset_cpu(0, kernel, addr), pe); +#endif + set_pgd(pgd_offset_k(addr), pe); + } + return 0; + } efi_scratch.efi_pgt = (pgd_t *)(unsigned long)real_mode_header->trampoline_pgd; pgd = __va(efi_scratch.efi_pgt); diff --git a/arch/x86/platform/efi/efi_stub_32.S b/arch/x86/platform/efi/efi_stub_32.S index 040192b..7d3300f 100644 --- a/arch/x86/platform/efi/efi_stub_32.S +++ b/arch/x86/platform/efi/efi_stub_32.S @@ -6,7 +6,9 @@ */ #include +#include #include +#include /* * efi_call_phys(void *, ...) is a function with variable parameters. @@ -20,7 +22,7 @@ * service functions will comply with gcc calling convention, too. */ -.text +__INIT ENTRY(efi_call_phys) /* * 0. The function can only be called in Linux kernel. So CS has been @@ -36,10 +38,24 @@ ENTRY(efi_call_phys) * The mapping of lower virtual memory has been created in prolog and * epilog. */ - movl $1f, %edx - subl $__PAGE_OFFSET, %edx - jmp *%edx +#ifdef CONFIG_PAX_KERNEXEC + movl $(__KERNEXEC_EFI_DS), %edx + mov %edx, %ds + mov %edx, %es + mov %edx, %ss + addl $2f,(1f) + ljmp *(1f) + +__INITDATA +1: .long __LOAD_PHYSICAL_ADDR, __KERNEXEC_EFI_CS +.previous + +2: + subl $2b,(1b) +#else + jmp 1f-__PAGE_OFFSET 1: +#endif /* * 2. Now on the top of stack is the return @@ -47,14 +63,8 @@ ENTRY(efi_call_phys) * parameter 2, ..., param n. To make things easy, we save the return * address of efi_call_phys in a global variable. */ - popl %edx - movl %edx, saved_return_addr - /* get the function pointer into ECX*/ - popl %ecx - movl %ecx, efi_rt_function_ptr - movl $2f, %edx - subl $__PAGE_OFFSET, %edx - pushl %edx + popl (saved_return_addr) + popl (efi_rt_function_ptr) /* * 3. Clear PG bit in %CR0. @@ -73,9 +83,8 @@ ENTRY(efi_call_phys) /* * 5. Call the physical function. */ - jmp *%ecx + call *(efi_rt_function_ptr-__PAGE_OFFSET) -2: /* * 6. After EFI runtime service returns, control will return to * following instruction. We'd better readjust stack pointer first. @@ -88,35 +97,36 @@ ENTRY(efi_call_phys) movl %cr0, %edx orl $0x80000000, %edx movl %edx, %cr0 - jmp 1f -1: + /* * 8. Now restore the virtual mode from flat mode by * adding EIP with PAGE_OFFSET. */ - movl $1f, %edx - jmp *%edx +#ifdef CONFIG_PAX_KERNEXEC + movl $(__KERNEL_DS), %edx + mov %edx, %ds + mov %edx, %es + mov %edx, %ss + ljmp $(__KERNEL_CS),$1f +#else + jmp 1f+__PAGE_OFFSET +#endif 1: /* * 9. Balance the stack. And because EAX contain the return value, * we'd better not clobber it. */ - leal efi_rt_function_ptr, %edx - movl (%edx), %ecx - pushl %ecx + pushl (efi_rt_function_ptr) /* - * 10. Push the saved return address onto the stack and return. + * 10. Return to the saved return address. */ - leal saved_return_addr, %edx - movl (%edx), %ecx - pushl %ecx - ret + jmpl *(saved_return_addr) ENDPROC(efi_call_phys) .previous -.data +__INITDATA saved_return_addr: .long 0 efi_rt_function_ptr: diff --git a/arch/x86/platform/efi/efi_stub_64.S b/arch/x86/platform/efi/efi_stub_64.S index 86d0f9e..6d499f4 100644 --- a/arch/x86/platform/efi/efi_stub_64.S +++ b/arch/x86/platform/efi/efi_stub_64.S @@ -11,6 +11,7 @@ #include #include #include +#include #define SAVE_XMM \ mov %rsp, %rax; \ @@ -88,6 +89,7 @@ ENTRY(efi_call) RESTORE_PGT addq $48, %rsp RESTORE_XMM + pax_force_retaddr 0, 1 ret ENDPROC(efi_call) diff --git a/arch/x86/platform/intel-mid/intel-mid.c b/arch/x86/platform/intel-mid/intel-mid.c index 01d54ea..ba1d71c 100644 --- a/arch/x86/platform/intel-mid/intel-mid.c +++ b/arch/x86/platform/intel-mid/intel-mid.c @@ -63,7 +63,7 @@ enum intel_mid_timer_options intel_mid_timer_options; /* intel_mid_ops to store sub arch ops */ struct intel_mid_ops *intel_mid_ops; /* getter function for sub arch ops*/ -static void *(*get_intel_mid_ops[])(void) = INTEL_MID_OPS_INIT; +static const void *(*get_intel_mid_ops[])(void) = INTEL_MID_OPS_INIT; enum intel_mid_cpu_type __intel_mid_cpu_chip; EXPORT_SYMBOL_GPL(__intel_mid_cpu_chip); @@ -71,9 +71,10 @@ static void intel_mid_power_off(void) { }; -static void intel_mid_reboot(void) +static void __noreturn intel_mid_reboot(void) { intel_scu_ipc_simple_command(IPCMSG_COLD_BOOT, 0); + BUG(); } static unsigned long __init intel_mid_calibrate_tsc(void) diff --git a/arch/x86/platform/intel-mid/intel_mid_weak_decls.h b/arch/x86/platform/intel-mid/intel_mid_weak_decls.h index 3c1c386..59a68ed 100644 --- a/arch/x86/platform/intel-mid/intel_mid_weak_decls.h +++ b/arch/x86/platform/intel-mid/intel_mid_weak_decls.h @@ -13,6 +13,6 @@ /* For every CPU addition a new get__ops interface needs * to be added. */ -extern void *get_penwell_ops(void); -extern void *get_cloverview_ops(void); -extern void *get_tangier_ops(void); +extern const void *get_penwell_ops(void); +extern const void *get_cloverview_ops(void); +extern const void *get_tangier_ops(void); diff --git a/arch/x86/platform/intel-mid/mfld.c b/arch/x86/platform/intel-mid/mfld.c index 23381d2..8ddc10e 100644 --- a/arch/x86/platform/intel-mid/mfld.c +++ b/arch/x86/platform/intel-mid/mfld.c @@ -64,12 +64,12 @@ static void __init penwell_arch_setup(void) pm_power_off = mfld_power_off; } -void *get_penwell_ops(void) +const void *get_penwell_ops(void) { return &penwell_ops; } -void *get_cloverview_ops(void) +const void *get_cloverview_ops(void) { return &penwell_ops; } diff --git a/arch/x86/platform/intel-mid/mrfl.c b/arch/x86/platform/intel-mid/mrfl.c index aaca917..66eadbc 100644 --- a/arch/x86/platform/intel-mid/mrfl.c +++ b/arch/x86/platform/intel-mid/mrfl.c @@ -97,7 +97,7 @@ static struct intel_mid_ops tangier_ops = { .arch_setup = tangier_arch_setup, }; -void *get_tangier_ops(void) +const void *get_tangier_ops(void) { return &tangier_ops; } diff --git a/arch/x86/platform/intel-quark/imr_selftest.c b/arch/x86/platform/intel-quark/imr_selftest.c index 278e4da..35db1a9 100644 --- a/arch/x86/platform/intel-quark/imr_selftest.c +++ b/arch/x86/platform/intel-quark/imr_selftest.c @@ -55,7 +55,7 @@ static void __init imr_self_test_result(int res, const char *fmt, ...) */ static void __init imr_self_test(void) { - phys_addr_t base = virt_to_phys(&_text); + phys_addr_t base = virt_to_phys((void *)ktla_ktva((unsigned long)_text)); size_t size = virt_to_phys(&__end_rodata) - base; const char *fmt_over = "overlapped IMR @ (0x%08lx - 0x%08lx)\n"; int ret; diff --git a/arch/x86/platform/olpc/olpc_dt.c b/arch/x86/platform/olpc/olpc_dt.c index d6ee929..3637cb5 100644 --- a/arch/x86/platform/olpc/olpc_dt.c +++ b/arch/x86/platform/olpc/olpc_dt.c @@ -156,7 +156,7 @@ void * __init prom_early_alloc(unsigned long size) return res; } -static struct of_pdt_ops prom_olpc_ops __initdata = { +static struct of_pdt_ops prom_olpc_ops __initconst = { .nextprop = olpc_dt_nextprop, .getproplen = olpc_dt_getproplen, .getproperty = olpc_dt_getproperty, diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c index 9ab5279..8ba4611 100644 --- a/arch/x86/power/cpu.c +++ b/arch/x86/power/cpu.c @@ -134,11 +134,8 @@ static void do_fpu_end(void) static void fix_processor_context(void) { int cpu = smp_processor_id(); - struct tss_struct *t = &per_cpu(cpu_tss, cpu); -#ifdef CONFIG_X86_64 - struct desc_struct *desc = get_cpu_gdt_table(cpu); - tss_desc tss; -#endif + struct tss_struct *t = cpu_tss + cpu; + set_tss_desc(cpu, t); /* * This just modifies memory; should not be * necessary. But... This is necessary, because @@ -147,10 +144,6 @@ static void fix_processor_context(void) */ #ifdef CONFIG_X86_64 - memcpy(&tss, &desc[GDT_ENTRY_TSS], sizeof(tss_desc)); - tss.type = 0x9; /* The available 64-bit TSS (see AMD vol 2, pg 91 */ - write_gdt_entry(desc, GDT_ENTRY_TSS, &tss, DESC_TSS); - syscall_init(); /* This sets MSR_*STAR and related */ #endif load_TR_desc(); /* This does ltr */ diff --git a/arch/x86/realmode/init.c b/arch/x86/realmode/init.c index 0b7a63d..dff2199 100644 --- a/arch/x86/realmode/init.c +++ b/arch/x86/realmode/init.c @@ -68,7 +68,13 @@ void __init setup_real_mode(void) __va(real_mode_header->trampoline_header); #ifdef CONFIG_X86_32 - trampoline_header->start = __pa_symbol(startup_32_smp); + trampoline_header->start = __pa_symbol(ktla_ktva((unsigned long)startup_32_smp)); + +#ifdef CONFIG_PAX_KERNEXEC + trampoline_header->start -= LOAD_PHYSICAL_ADDR; +#endif + + trampoline_header->boot_cs = __BOOT_CS; trampoline_header->gdt_limit = __BOOT_DS + 7; trampoline_header->gdt_base = __pa_symbol(boot_gdt); #else @@ -84,7 +90,7 @@ void __init setup_real_mode(void) *trampoline_cr4_features = __read_cr4(); trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd); - trampoline_pgd[0] = init_level4_pgt[pgd_index(__PAGE_OFFSET)].pgd; + trampoline_pgd[0] = init_level4_pgt[pgd_index(__PAGE_OFFSET)].pgd & ~_PAGE_NX; trampoline_pgd[511] = init_level4_pgt[511].pgd; #endif } diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile index 2730d77..2e4cd19 100644 --- a/arch/x86/realmode/rm/Makefile +++ b/arch/x86/realmode/rm/Makefile @@ -68,5 +68,8 @@ $(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 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 +++ b/arch/x86/realmode/rm/header.S @@ -30,7 +30,9 @@ GLOBAL(real_mode_header) #endif /* APM/BIOS reboot */ .long pa_machine_real_restart_asm -#ifdef CONFIG_X86_64 +#ifdef CONFIG_X86_32 + .long __KERNEL_CS +#else .long __KERNEL32_CS #endif END(real_mode_header) diff --git a/arch/x86/realmode/rm/reboot.S b/arch/x86/realmode/rm/reboot.S index d66c607..3def845 100644 --- a/arch/x86/realmode/rm/reboot.S +++ b/arch/x86/realmode/rm/reboot.S @@ -27,6 +27,10 @@ ENTRY(machine_real_restart_asm) lgdtl pa_tr_gdt /* Disable paging to drop us out of long mode */ + movl %cr4, %eax + andl $~X86_CR4_PCIDE, %eax + movl %eax, %cr4 + movl %cr0, %eax andl $~X86_CR0_PG, %eax movl %eax, %cr0 diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S index 48ddd76..c26749f 100644 --- a/arch/x86/realmode/rm/trampoline_32.S +++ b/arch/x86/realmode/rm/trampoline_32.S @@ -24,6 +24,12 @@ #include #include "realmode.h" +#ifdef CONFIG_PAX_KERNEXEC +#define ta(X) (X) +#else +#define ta(X) (pa_ ## X) +#endif + .text .code16 @@ -38,8 +44,6 @@ ENTRY(trampoline_start) cli # We should be safe anyway - movl tr_start, %eax # where we need to go - movl $0xA5A5A5A5, trampoline_status # write marker for master knows we're running @@ -55,7 +59,7 @@ ENTRY(trampoline_start) movw $1, %dx # protected mode (PE) bit lmsw %dx # into protected mode - ljmpl $__BOOT_CS, $pa_startup_32 + ljmpl *(trampoline_header) .section ".text32","ax" .code32 @@ -66,7 +70,7 @@ ENTRY(startup_32) # note: also used from wakeup_asm.S .balign 8 GLOBAL(trampoline_header) tr_start: .space 4 - tr_gdt_pad: .space 2 + tr_boot_cs: .space 2 tr_gdt: .space 6 END(trampoline_header) diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S index dac7b20..72dbaca 100644 --- a/arch/x86/realmode/rm/trampoline_64.S +++ b/arch/x86/realmode/rm/trampoline_64.S @@ -93,6 +93,7 @@ ENTRY(startup_32) movl %edx, %gs movl pa_tr_cr4, %eax + andl $~X86_CR4_PCIDE, %eax movl %eax, %cr4 # Enable PAE mode # Setup trampoline 4 level pagetables @@ -106,7 +107,7 @@ ENTRY(startup_32) wrmsr # Enable paging and in turn activate Long Mode - movl $(X86_CR0_PG | X86_CR0_WP | X86_CR0_PE), %eax + movl $(X86_CR0_PG | X86_CR0_PE), %eax movl %eax, %cr0 /* diff --git a/arch/x86/realmode/rm/wakeup_asm.S b/arch/x86/realmode/rm/wakeup_asm.S index 9e7e147..25a4158 100644 --- a/arch/x86/realmode/rm/wakeup_asm.S +++ b/arch/x86/realmode/rm/wakeup_asm.S @@ -126,11 +126,10 @@ ENTRY(wakeup_start) lgdtl pmode_gdt /* This really couldn't... */ - movl pmode_entry, %eax movl pmode_cr0, %ecx movl %ecx, %cr0 - ljmpl $__KERNEL_CS, $pa_startup_32 - /* -> jmp *%eax in trampoline_32.S */ + + ljmpl *pmode_entry #else jmp trampoline_start #endif diff --git a/arch/x86/tools/Makefile b/arch/x86/tools/Makefile index 604a37e..e49702a 100644 --- a/arch/x86/tools/Makefile +++ b/arch/x86/tools/Makefile @@ -37,7 +37,7 @@ $(obj)/test_get_len.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/in $(obj)/insn_sanity.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c -HOST_EXTRACFLAGS += -I$(srctree)/tools/include +HOST_EXTRACFLAGS += -I$(srctree)/tools/include -ggdb hostprogs-y += relocs relocs-objs := relocs_32.o relocs_64.o relocs_common.o PHONY += relocs diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c index 0c2fae8..88d7719 100644 --- a/arch/x86/tools/relocs.c +++ b/arch/x86/tools/relocs.c @@ -1,5 +1,7 @@ /* This is included from relocs_32/64.c */ +#include "../../../include/generated/autoconf.h" + #define ElfW(type) _ElfW(ELF_BITS, type) #define _ElfW(bits, type) __ElfW(bits, type) #define __ElfW(bits, type) Elf##bits##_##type @@ -11,6 +13,7 @@ #define Elf_Sym ElfW(Sym) static Elf_Ehdr ehdr; +static Elf_Phdr *phdr; struct relocs { uint32_t *offset; @@ -386,9 +389,39 @@ static void read_ehdr(FILE *fp) } } +static void read_phdrs(FILE *fp) +{ + unsigned int i; + + phdr = calloc(ehdr.e_phnum, sizeof(Elf_Phdr)); + if (!phdr) { + die("Unable to allocate %d program headers\n", + ehdr.e_phnum); + } + if (fseek(fp, ehdr.e_phoff, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + ehdr.e_phoff, strerror(errno)); + } + if (fread(phdr, sizeof(*phdr), ehdr.e_phnum, fp) != ehdr.e_phnum) { + die("Cannot read ELF program headers: %s\n", + strerror(errno)); + } + for(i = 0; i < ehdr.e_phnum; i++) { + phdr[i].p_type = elf_word_to_cpu(phdr[i].p_type); + phdr[i].p_offset = elf_off_to_cpu(phdr[i].p_offset); + phdr[i].p_vaddr = elf_addr_to_cpu(phdr[i].p_vaddr); + phdr[i].p_paddr = elf_addr_to_cpu(phdr[i].p_paddr); + phdr[i].p_filesz = elf_word_to_cpu(phdr[i].p_filesz); + phdr[i].p_memsz = elf_word_to_cpu(phdr[i].p_memsz); + phdr[i].p_flags = elf_word_to_cpu(phdr[i].p_flags); + phdr[i].p_align = elf_word_to_cpu(phdr[i].p_align); + } + +} + static void read_shdrs(FILE *fp) { - int i; + unsigned int i; Elf_Shdr shdr; secs = calloc(ehdr.e_shnum, sizeof(struct section)); @@ -423,7 +456,7 @@ static void read_shdrs(FILE *fp) static void read_strtabs(FILE *fp) { - int i; + unsigned int i; for (i = 0; i < ehdr.e_shnum; i++) { struct section *sec = &secs[i]; if (sec->shdr.sh_type != SHT_STRTAB) { @@ -448,7 +481,7 @@ static void read_strtabs(FILE *fp) static void read_symtabs(FILE *fp) { - int i,j; + unsigned int i,j; for (i = 0; i < ehdr.e_shnum; i++) { struct section *sec = &secs[i]; if (sec->shdr.sh_type != SHT_SYMTAB) { @@ -479,9 +512,11 @@ static void read_symtabs(FILE *fp) } -static void read_relocs(FILE *fp) +static void read_relocs(FILE *fp, int use_real_mode) { - int i,j; + unsigned int i,j; + uint32_t base; + for (i = 0; i < ehdr.e_shnum; i++) { struct section *sec = &secs[i]; if (sec->shdr.sh_type != SHT_REL_TYPE) { @@ -501,9 +536,22 @@ static void read_relocs(FILE *fp) die("Cannot read symbol table: %s\n", strerror(errno)); } + base = 0; + +#ifdef CONFIG_X86_32 + for (j = 0; !use_real_mode && j < ehdr.e_phnum; j++) { + if (phdr[j].p_type != PT_LOAD ) + continue; + if (secs[sec->shdr.sh_info].shdr.sh_offset < phdr[j].p_offset || secs[sec->shdr.sh_info].shdr.sh_offset >= phdr[j].p_offset + phdr[j].p_filesz) + continue; + base = CONFIG_PAGE_OFFSET + phdr[j].p_paddr - phdr[j].p_vaddr; + break; + } +#endif + for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { Elf_Rel *rel = &sec->reltab[j]; - rel->r_offset = elf_addr_to_cpu(rel->r_offset); + rel->r_offset = elf_addr_to_cpu(rel->r_offset) + base; rel->r_info = elf_xword_to_cpu(rel->r_info); #if (SHT_REL_TYPE == SHT_RELA) rel->r_addend = elf_xword_to_cpu(rel->r_addend); @@ -515,7 +563,7 @@ static void read_relocs(FILE *fp) static void print_absolute_symbols(void) { - int i; + unsigned int i; const char *format; if (ELF_BITS == 64) @@ -528,7 +576,7 @@ static void print_absolute_symbols(void) for (i = 0; i < ehdr.e_shnum; i++) { struct section *sec = &secs[i]; char *sym_strtab; - int j; + unsigned int j; if (sec->shdr.sh_type != SHT_SYMTAB) { continue; @@ -555,7 +603,7 @@ static void print_absolute_symbols(void) static void print_absolute_relocs(void) { - int i, printed = 0; + unsigned int i, printed = 0; const char *format; if (ELF_BITS == 64) @@ -568,7 +616,7 @@ static void print_absolute_relocs(void) struct section *sec_applies, *sec_symtab; char *sym_strtab; Elf_Sym *sh_symtab; - int j; + unsigned int j; if (sec->shdr.sh_type != SHT_REL_TYPE) { continue; } @@ -645,13 +693,13 @@ static void add_reloc(struct relocs *r, uint32_t offset) static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel, Elf_Sym *sym, const char *symname)) { - int i; + unsigned int i; /* Walk through the relocations */ for (i = 0; i < ehdr.e_shnum; i++) { char *sym_strtab; Elf_Sym *sh_symtab; struct section *sec_applies, *sec_symtab; - int j; + unsigned int j; struct section *sec = &secs[i]; if (sec->shdr.sh_type != SHT_REL_TYPE) { @@ -697,7 +745,7 @@ static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel, * kernel data and does not require special treatment. * */ -static int per_cpu_shndx = -1; +static unsigned int per_cpu_shndx = ~0; static Elf_Addr per_cpu_load_addr; static void percpu_init(void) @@ -830,6 +878,23 @@ static int do_reloc32(struct section *sec, Elf_Rel *rel, Elf_Sym *sym, { unsigned r_type = ELF32_R_TYPE(rel->r_info); int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname); + char *sym_strtab = sec->link->link->strtab; + + /* Don't relocate actual per-cpu variables, they are absolute indices, not addresses */ + if (!strcmp(sec_name(sym->st_shndx), ".data..percpu") && strcmp(sym_name(sym_strtab, sym), "__per_cpu_load")) + return 0; + +#ifdef CONFIG_PAX_KERNEXEC + /* Don't relocate actual code, they are relocated implicitly by the base address of KERNEL_CS */ + if (!strcmp(sec_name(sym->st_shndx), ".text.end") && !strcmp(sym_name(sym_strtab, sym), "_etext")) + return 0; + if (!strcmp(sec_name(sym->st_shndx), ".init.text")) + return 0; + if (!strcmp(sec_name(sym->st_shndx), ".exit.text")) + return 0; + if (!strcmp(sec_name(sym->st_shndx), ".text") && strcmp(sym_name(sym_strtab, sym), "__LOAD_PHYSICAL_ADDR")) + return 0; +#endif switch (r_type) { case R_386_NONE: @@ -968,7 +1033,7 @@ static int write32_as_text(uint32_t v, FILE *f) static void emit_relocs(int as_text, int use_real_mode) { - int i; + unsigned int i; int (*write_reloc)(uint32_t, FILE *) = write32; int (*do_reloc)(struct section *sec, Elf_Rel *rel, Elf_Sym *sym, const char *symname); @@ -1078,10 +1143,11 @@ void process(FILE *fp, int use_real_mode, int as_text, { regex_init(use_real_mode); read_ehdr(fp); + read_phdrs(fp); read_shdrs(fp); read_strtabs(fp); read_symtabs(fp); - read_relocs(fp); + read_relocs(fp, use_real_mode); if (ELF_BITS == 64) percpu_init(); if (show_absolute_syms) { diff --git a/arch/x86/um/mem_32.c b/arch/x86/um/mem_32.c index 744afdc..a0b8a0d 100644 --- a/arch/x86/um/mem_32.c +++ b/arch/x86/um/mem_32.c @@ -20,7 +20,7 @@ static int __init gate_vma_init(void) gate_vma.vm_start = FIXADDR_USER_START; gate_vma.vm_end = FIXADDR_USER_END; gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC; - gate_vma.vm_page_prot = __P101; + gate_vma.vm_page_prot = vm_get_page_prot(gate_vma.vm_flags); return 0; } diff --git a/arch/x86/um/tls_32.c b/arch/x86/um/tls_32.c index 48e3858..ab4458c 100644 --- a/arch/x86/um/tls_32.c +++ b/arch/x86/um/tls_32.c @@ -261,7 +261,7 @@ out: if (unlikely(task == current && !t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed)) { printk(KERN_ERR "get_tls_entry: task with pid %d got here " - "without flushed TLS.", current->pid); + "without flushed TLS.", task_pid_nr(current)); } return 0; diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig index c7b15f3..cc09a65 100644 --- a/arch/x86/xen/Kconfig +++ b/arch/x86/xen/Kconfig @@ -10,6 +10,7 @@ config XEN select XEN_HAVE_VPMU depends on X86_64 || (X86_32 && X86_PAE) depends on X86_LOCAL_APIC && X86_TSC + depends on !GRKERNSEC_CONFIG_AUTO || GRKERNSEC_CONFIG_VIRT_XEN help This is the Linux Xen port. Enabling this will allow the kernel to boot in a paravirtualized environment under the diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 993b7a7..59dec9a 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -130,8 +130,6 @@ EXPORT_SYMBOL_GPL(xen_start_info); struct shared_info xen_dummy_shared_info; -void *xen_initial_gdt; - RESERVE_BRK(shared_info_page_brk, PAGE_SIZE); __read_mostly int xen_have_vector_callback; EXPORT_SYMBOL_GPL(xen_have_vector_callback); @@ -589,8 +587,7 @@ static void xen_load_gdt(const struct desc_ptr *dtr) { unsigned long va = dtr->address; unsigned int size = dtr->size + 1; - unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE; - unsigned long frames[pages]; + unsigned long frames[65536 / PAGE_SIZE]; int f; /* @@ -638,8 +635,7 @@ static void __init xen_load_gdt_boot(const struct desc_ptr *dtr) { unsigned long va = dtr->address; unsigned int size = dtr->size + 1; - unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE; - unsigned long frames[pages]; + unsigned long frames[(GDT_SIZE + PAGE_SIZE - 1) / PAGE_SIZE]; int f; /* @@ -647,7 +643,7 @@ static void __init xen_load_gdt_boot(const struct desc_ptr *dtr) * 8-byte entries, or 16 4k pages.. */ - BUG_ON(size > 65536); + BUG_ON(size > GDT_SIZE); BUG_ON(va & ~PAGE_MASK); for (f = 0; va < dtr->address + size; va += PAGE_SIZE, f++) { @@ -1270,7 +1266,7 @@ static const struct pv_apic_ops xen_apic_ops __initconst = { #endif }; -static void xen_reboot(int reason) +static __noreturn void xen_reboot(int reason) { struct sched_shutdown r = { .reason = reason }; int cpu; @@ -1278,26 +1274,26 @@ static void xen_reboot(int reason) for_each_online_cpu(cpu) xen_pmu_finish(cpu); - if (HYPERVISOR_sched_op(SCHEDOP_shutdown, &r)) - BUG(); + HYPERVISOR_sched_op(SCHEDOP_shutdown, &r); + BUG(); } -static void xen_restart(char *msg) +static __noreturn void xen_restart(char *msg) { xen_reboot(SHUTDOWN_reboot); } -static void xen_emergency_restart(void) +static __noreturn void xen_emergency_restart(void) { xen_reboot(SHUTDOWN_reboot); } -static void xen_machine_halt(void) +static __noreturn void xen_machine_halt(void) { xen_reboot(SHUTDOWN_poweroff); } -static void xen_machine_power_off(void) +static __noreturn void xen_machine_power_off(void) { if (pm_power_off) pm_power_off(); @@ -1450,8 +1446,11 @@ static void __ref xen_setup_gdt(int cpu) pv_cpu_ops.write_gdt_entry = xen_write_gdt_entry_boot; pv_cpu_ops.load_gdt = xen_load_gdt_boot; - setup_stack_canary_segment(0); - switch_to_new_gdt(0); + setup_stack_canary_segment(cpu); +#ifdef CONFIG_X86_64 + load_percpu_segment(cpu); +#endif + switch_to_new_gdt(cpu); pv_cpu_ops.write_gdt_entry = xen_write_gdt_entry; pv_cpu_ops.load_gdt = xen_load_gdt; @@ -1567,7 +1566,17 @@ asmlinkage __visible void __init xen_start_kernel(void) __userpte_alloc_gfp &= ~__GFP_HIGHMEM; /* Work out if we support NX */ - x86_configure_nx(); +#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE) + if ((cpuid_eax(0x80000000) & 0xffff0000) == 0x80000000 && + (cpuid_edx(0x80000001) & (1U << (X86_FEATURE_NX & 31)))) { + unsigned l, h; + + __supported_pte_mask |= _PAGE_NX; + rdmsr(MSR_EFER, l, h); + l |= EFER_NX; + wrmsr(MSR_EFER, l, h); + } +#endif /* Get mfn list */ xen_build_dynamic_phys_to_machine(); @@ -1595,13 +1604,6 @@ asmlinkage __visible void __init xen_start_kernel(void) machine_ops = xen_machine_ops; - /* - * The only reliable way to retain the initial address of the - * percpu gdt_page is to remember it here, so we can go and - * mark it RW later, when the initial percpu area is freed. - */ - xen_initial_gdt = &per_cpu(gdt_page, 0); - xen_smp_init(); #ifdef CONFIG_ACPI_NUMA diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 9c479fe..7ec4091 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -1950,7 +1950,11 @@ void __init xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn) * L3_k[511] -> level2_fixmap_pgt */ convert_pfn_mfn(level3_kernel_pgt); + convert_pfn_mfn(level3_vmalloc_start_pgt); + convert_pfn_mfn(level3_vmalloc_end_pgt); + convert_pfn_mfn(level3_vmemmap_pgt); /* L3_k[511][506] -> level1_fixmap_pgt */ + /* L3_k[511][507] -> level1_vsyscall_pgt */ convert_pfn_mfn(level2_fixmap_pgt); } /* We get [511][511] and have Xen's version of level2_kernel_pgt */ @@ -1980,11 +1984,22 @@ void __init xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn) set_page_prot(init_level4_pgt, PAGE_KERNEL_RO); set_page_prot(level3_ident_pgt, PAGE_KERNEL_RO); set_page_prot(level3_kernel_pgt, PAGE_KERNEL_RO); + set_page_prot(level3_vmalloc_start_pgt, PAGE_KERNEL_RO); + set_page_prot(level3_vmalloc_end_pgt, PAGE_KERNEL_RO); + set_page_prot(level3_vmemmap_pgt, PAGE_KERNEL_RO); set_page_prot(level3_user_vsyscall, PAGE_KERNEL_RO); set_page_prot(level2_ident_pgt, PAGE_KERNEL_RO); + set_page_prot(level2_vmemmap_pgt, PAGE_KERNEL_RO); set_page_prot(level2_kernel_pgt, PAGE_KERNEL_RO); set_page_prot(level2_fixmap_pgt, PAGE_KERNEL_RO); - set_page_prot(level1_fixmap_pgt, PAGE_KERNEL_RO); + set_page_prot(level1_modules_pgt[0], PAGE_KERNEL_RO); + set_page_prot(level1_modules_pgt[1], PAGE_KERNEL_RO); + set_page_prot(level1_modules_pgt[2], PAGE_KERNEL_RO); + set_page_prot(level1_modules_pgt[3], PAGE_KERNEL_RO); + set_page_prot(level1_fixmap_pgt[0], PAGE_KERNEL_RO); + set_page_prot(level1_fixmap_pgt[1], PAGE_KERNEL_RO); + set_page_prot(level1_fixmap_pgt[2], PAGE_KERNEL_RO); + set_page_prot(level1_vsyscall_pgt, PAGE_KERNEL_RO); /* Pin down new L4 */ pin_pagetable_pfn(MMUEXT_PIN_L4_TABLE, @@ -2395,6 +2410,7 @@ static void __init xen_post_allocator_init(void) pv_mmu_ops.set_pud = xen_set_pud; #if CONFIG_PGTABLE_LEVELS == 4 pv_mmu_ops.set_pgd = xen_set_pgd; + pv_mmu_ops.set_pgd_batched = xen_set_pgd; #endif /* This will work as long as patching hasn't happened yet @@ -2473,6 +2489,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = { .pud_val = PV_CALLEE_SAVE(xen_pud_val), .make_pud = PV_CALLEE_SAVE(xen_make_pud), .set_pgd = xen_set_pgd_hyper, + .set_pgd_batched = xen_set_pgd_hyper, .alloc_pud = xen_alloc_pmd_init, .release_pud = xen_release_pmd_init, diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index 3f4ebf0..f074dc1 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -306,17 +306,13 @@ static void __init xen_smp_prepare_boot_cpu(void) if (xen_pv_domain()) { if (!xen_feature(XENFEAT_writable_page_tables)) - /* We've switched to the "real" per-cpu gdt, so make - * sure the old memory can be recycled. */ - make_lowmem_page_readwrite(xen_initial_gdt); - #ifdef CONFIG_X86_32 /* * Xen starts us with XEN_FLAT_RING1_DS, but linux code * expects __USER_DS */ - loadsegment(ds, __USER_DS); - loadsegment(es, __USER_DS); + loadsegment(ds, __KERNEL_DS); + loadsegment(es, __KERNEL_DS); #endif xen_filter_cpu_maps(); @@ -399,7 +395,7 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle) #ifdef CONFIG_X86_32 /* Note: PVH is not yet supported on x86_32. */ ctxt->user_regs.fs = __KERNEL_PERCPU; - ctxt->user_regs.gs = __KERNEL_STACK_CANARY; + savesegment(gs, ctxt->user_regs.gs); #endif memset(&ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt)); @@ -407,8 +403,8 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle) ctxt->user_regs.eip = (unsigned long)cpu_bringup_and_idle; ctxt->flags = VGCF_IN_KERNEL; ctxt->user_regs.eflags = 0x1000; /* IOPL_RING1 */ - ctxt->user_regs.ds = __USER_DS; - ctxt->user_regs.es = __USER_DS; + ctxt->user_regs.ds = __KERNEL_DS; + ctxt->user_regs.es = __KERNEL_DS; ctxt->user_regs.ss = __KERNEL_DS; xen_copy_trap_info(ctxt->trap_ctxt); @@ -747,7 +743,7 @@ static const struct smp_ops xen_smp_ops __initconst = { void __init xen_smp_init(void) { - smp_ops = xen_smp_ops; + memcpy((void *)&smp_ops, &xen_smp_ops, sizeof smp_ops); xen_fill_possible_map(); } diff --git a/arch/x86/xen/xen-asm_32.S b/arch/x86/xen/xen-asm_32.S index fd92a64..1f72641 100644 --- a/arch/x86/xen/xen-asm_32.S +++ b/arch/x86/xen/xen-asm_32.S @@ -99,7 +99,7 @@ ENTRY(xen_iret) pushw %fs movl $(__KERNEL_PERCPU), %eax movl %eax, %fs - movl %fs:xen_vcpu, %eax + mov PER_CPU_VAR(xen_vcpu), %eax POP_FS #else movl %ss:xen_vcpu, %eax diff --git a/arch/x86/xen/xen-head.S b/arch/x86/xen/xen-head.S index b65f59a..c43f9c6 100644 --- a/arch/x86/xen/xen-head.S +++ b/arch/x86/xen/xen-head.S @@ -41,6 +41,17 @@ ENTRY(startup_xen) #ifdef CONFIG_X86_32 mov %esi,xen_start_info mov $init_thread_union+THREAD_SIZE,%esp +#ifdef CONFIG_SMP + movl $cpu_gdt_table,%edi + movl $__per_cpu_load,%eax + movw %ax,__KERNEL_PERCPU + 2(%edi) + rorl $16,%eax + movb %al,__KERNEL_PERCPU + 4(%edi) + movb %ah,__KERNEL_PERCPU + 7(%edi) + movl $__per_cpu_end - 1,%eax + subl $__per_cpu_start,%eax + movw %ax,__KERNEL_PERCPU + 0(%edi) +#endif #else mov %rsi,xen_start_info mov $init_thread_union+THREAD_SIZE,%rsp diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index 1399423..b1ae0fa 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h @@ -16,8 +16,6 @@ void xen_syscall_target(void); void xen_syscall32_target(void); #endif -extern void *xen_initial_gdt; - struct trap_info; void xen_copy_trap_info(struct trap_info *traps); diff --git a/arch/xtensa/variants/dc232b/include/variant/core.h b/arch/xtensa/variants/dc232b/include/variant/core.h index 525bd3d..ef888b1 100644 --- a/arch/xtensa/variants/dc232b/include/variant/core.h +++ b/arch/xtensa/variants/dc232b/include/variant/core.h @@ -119,9 +119,9 @@ ----------------------------------------------------------------------*/ #define XCHAL_ICACHE_LINESIZE 32 /* I-cache line size in bytes */ -#define XCHAL_DCACHE_LINESIZE 32 /* D-cache line size in bytes */ #define XCHAL_ICACHE_LINEWIDTH 5 /* log2(I line size in bytes) */ #define XCHAL_DCACHE_LINEWIDTH 5 /* log2(D line size in bytes) */ +#define XCHAL_DCACHE_LINESIZE (_AC(1,UL) << XCHAL_DCACHE_LINEWIDTH) /* D-cache line size in bytes */ #define XCHAL_ICACHE_SIZE 16384 /* I-cache size in bytes or 0 */ #define XCHAL_DCACHE_SIZE 16384 /* D-cache size in bytes or 0 */ diff --git a/arch/xtensa/variants/fsf/include/variant/core.h b/arch/xtensa/variants/fsf/include/variant/core.h index 2f33760..835e50a 100644 --- a/arch/xtensa/variants/fsf/include/variant/core.h +++ b/arch/xtensa/variants/fsf/include/variant/core.h @@ -11,6 +11,7 @@ #ifndef _XTENSA_CORE_H #define _XTENSA_CORE_H +#include /**************************************************************************** Parameters Useful for Any Code, USER or PRIVILEGED @@ -112,9 +113,9 @@ ----------------------------------------------------------------------*/ #define XCHAL_ICACHE_LINESIZE 16 /* I-cache line size in bytes */ -#define XCHAL_DCACHE_LINESIZE 16 /* D-cache line size in bytes */ #define XCHAL_ICACHE_LINEWIDTH 4 /* log2(I line size in bytes) */ #define XCHAL_DCACHE_LINEWIDTH 4 /* log2(D line size in bytes) */ +#define XCHAL_DCACHE_LINESIZE (_AC(1,UL) << XCHAL_DCACHE_LINEWIDTH) /* D-cache line size in bytes */ #define XCHAL_ICACHE_SIZE 8192 /* I-cache size in bytes or 0 */ #define XCHAL_DCACHE_SIZE 8192 /* D-cache size in bytes or 0 */ diff --git a/block/bio.c b/block/bio.c index ad3f276..bef6d50 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1140,7 +1140,7 @@ struct bio *bio_copy_user_iov(struct request_queue *q, /* * Overflow, abort */ - if (end < start) + if (end < start || end - start > INT_MAX - nr_pages) return ERR_PTR(-EINVAL); nr_pages += end - start; @@ -1265,7 +1265,7 @@ struct bio *bio_map_user_iov(struct request_queue *q, /* * Overflow, abort */ - if (end < start) + if (end < start || end - start > INT_MAX - nr_pages) return ERR_PTR(-EINVAL); nr_pages += end - start; diff --git a/block/blk-core.c b/block/blk-core.c index 18e92a6..1834d7c 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1616,8 +1616,6 @@ static void blk_queue_bio(struct request_queue *q, struct bio *bio) struct request *req; unsigned int request_count = 0; - blk_queue_split(q, &bio, q->bio_split); - /* * low level driver can indicate that it wants pages above a * certain limit bounced to low memory (ie for highmem, or even @@ -1625,6 +1623,8 @@ static void blk_queue_bio(struct request_queue *q, struct bio *bio) */ blk_queue_bounce(q, &bio); + blk_queue_split(q, &bio, q->bio_split); + if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) { bio->bi_error = -EIO; bio_endio(bio); diff --git a/block/blk-iopoll.c b/block/blk-iopoll.c index 0736729..2ec3b48 100644 --- a/block/blk-iopoll.c +++ b/block/blk-iopoll.c @@ -74,7 +74,7 @@ void blk_iopoll_complete(struct blk_iopoll *iop) } EXPORT_SYMBOL(blk_iopoll_complete); -static void blk_iopoll_softirq(struct softirq_action *h) +static __latent_entropy void blk_iopoll_softirq(void) { struct list_head *list = this_cpu_ptr(&blk_cpu_iopoll); int rearm = 0, budget = blk_iopoll_budget; diff --git a/block/blk-map.c b/block/blk-map.c index f565e11..f05b424 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -214,7 +214,7 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, if (!len || !kbuf) return -EINVAL; - do_copy = !blk_rq_aligned(q, addr, len) || object_is_on_stack(kbuf); + do_copy = !blk_rq_aligned(q, addr, len) || object_starts_on_stack(kbuf); if (do_copy) bio = bio_copy_kern(q, kbuf, len, gfp_mask, reading); else diff --git a/block/blk-softirq.c b/block/blk-softirq.c index 53b1737..08177d2e 100644 --- a/block/blk-softirq.c +++ b/block/blk-softirq.c @@ -18,7 +18,7 @@ static DEFINE_PER_CPU(struct list_head, blk_cpu_done); * Softirq action handler - move entries to local list and loop over them * while passing them to the queue registered handler. */ -static void blk_done_softirq(struct softirq_action *h) +static __latent_entropy void blk_done_softirq(void) { struct list_head *cpu_list, local_list; diff --git a/block/bsg.c b/block/bsg.c index d214e92..9649863 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -140,16 +140,24 @@ static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq, struct sg_io_v4 *hdr, struct bsg_device *bd, fmode_t has_write_perm) { + unsigned char tmpcmd[sizeof(rq->__cmd)]; + unsigned char *cmdptr; + if (hdr->request_len > BLK_MAX_CDB) { rq->cmd = kzalloc(hdr->request_len, GFP_KERNEL); if (!rq->cmd) return -ENOMEM; - } + cmdptr = rq->cmd; + } else + cmdptr = tmpcmd; - if (copy_from_user(rq->cmd, (void __user *)(unsigned long)hdr->request, + if (copy_from_user(cmdptr, (void __user *)(unsigned long)hdr->request, hdr->request_len)) return -EFAULT; + if (cmdptr != rq->cmd) + memcpy(rq->cmd, cmdptr, hdr->request_len); + if (hdr->subprotocol == BSG_SUB_PROTOCOL_SCSI_CMD) { if (blk_verify_command(rq->cmd, has_write_perm)) return -EPERM; diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c index f678c73..f35aa18 100644 --- a/block/compat_ioctl.c +++ b/block/compat_ioctl.c @@ -156,7 +156,7 @@ static int compat_cdrom_generic_command(struct block_device *bdev, fmode_t mode, cgc = compat_alloc_user_space(sizeof(*cgc)); cgc32 = compat_ptr(arg); - if (copy_in_user(&cgc->cmd, &cgc32->cmd, sizeof(cgc->cmd)) || + if (copy_in_user(cgc->cmd, cgc32->cmd, sizeof(cgc->cmd)) || get_user(data, &cgc32->buffer) || put_user(compat_ptr(data), &cgc->buffer) || copy_in_user(&cgc->buflen, &cgc32->buflen, @@ -341,7 +341,7 @@ static int compat_fd_ioctl(struct block_device *bdev, fmode_t mode, err |= __get_user(f->spec1, &uf->spec1); err |= __get_user(f->fmt_gap, &uf->fmt_gap); err |= __get_user(name, &uf->name); - f->name = compat_ptr(name); + f->name = (void __force_kernel *)compat_ptr(name); if (err) { err = -EFAULT; goto out; diff --git a/block/genhd.c b/block/genhd.c index 0c706f3..7e54d22 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -470,21 +470,24 @@ static char *bdevt_str(dev_t devt, char *buf) /* * Register device numbers dev..(dev+range-1) - * range must be nonzero + * Noop if @range is zero. * The hash chain is sorted on range, so that subranges can override. */ void blk_register_region(dev_t devt, unsigned long range, struct module *module, struct kobject *(*probe)(dev_t, int *, void *), int (*lock)(dev_t, void *), void *data) { - kobj_map(bdev_map, devt, range, module, probe, lock, data); + if (range) + kobj_map(bdev_map, devt, range, module, probe, lock, data); } EXPORT_SYMBOL(blk_register_region); +/* undo blk_register_region(), noop if @range is zero */ void blk_unregister_region(dev_t devt, unsigned long range) { - kobj_unmap(bdev_map, devt, range); + if (range) + kobj_unmap(bdev_map, devt, range); } EXPORT_SYMBOL(blk_unregister_region); diff --git a/block/partitions/efi.c b/block/partitions/efi.c index 26cb624..a49c3a5 100644 --- a/block/partitions/efi.c +++ b/block/partitions/efi.c @@ -293,14 +293,14 @@ static gpt_entry *alloc_read_gpt_entries(struct parsed_partitions *state, if (!gpt) return NULL; + if (!le32_to_cpu(gpt->num_partition_entries)) + return NULL; + pte = kcalloc(le32_to_cpu(gpt->num_partition_entries), le32_to_cpu(gpt->sizeof_partition_entry), GFP_KERNEL); + if (!pte) + return NULL; + count = le32_to_cpu(gpt->num_partition_entries) * le32_to_cpu(gpt->sizeof_partition_entry); - if (!count) - return NULL; - pte = kmalloc(count, GFP_KERNEL); - if (!pte) - return NULL; - if (read_lba(state, le64_to_cpu(gpt->partition_entry_lba), (u8 *) pte, count) < count) { kfree(pte); diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index dda653c..028a13ee 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -67,7 +67,7 @@ static int scsi_get_bus(struct request_queue *q, int __user *p) return put_user(0, p); } -static int sg_get_timeout(struct request_queue *q) +static int __intentional_overflow(-1) sg_get_timeout(struct request_queue *q) { return jiffies_to_clock_t(q->sg_timeout); } @@ -227,8 +227,20 @@ EXPORT_SYMBOL(blk_verify_command); static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq, struct sg_io_hdr *hdr, fmode_t mode) { - if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len)) + unsigned char tmpcmd[sizeof(rq->__cmd)]; + unsigned char *cmdptr; + + if (rq->cmd != rq->__cmd) + cmdptr = rq->cmd; + else + cmdptr = tmpcmd; + + if (copy_from_user(cmdptr, hdr->cmdp, hdr->cmd_len)) return -EFAULT; + + if (cmdptr != rq->cmd) + memcpy(rq->cmd, cmdptr, hdr->cmd_len); + if (blk_verify_command(rq->cmd, mode & FMODE_WRITE)) return -EPERM; @@ -420,6 +432,8 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode, int err; unsigned int in_len, out_len, bytes, opcode, cmdlen; char *buffer = NULL, sense[SCSI_SENSE_BUFFERSIZE]; + unsigned char tmpcmd[sizeof(rq->__cmd)]; + unsigned char *cmdptr; if (!sic) return -EINVAL; @@ -458,9 +472,18 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode, */ err = -EFAULT; rq->cmd_len = cmdlen; - if (copy_from_user(rq->cmd, sic->data, cmdlen)) + + if (rq->cmd != rq->__cmd) + cmdptr = rq->cmd; + else + cmdptr = tmpcmd; + + if (copy_from_user(cmdptr, sic->data, cmdlen)) goto error; + if (rq->cmd != cmdptr) + memcpy(rq->cmd, cmdptr, cmdlen); + if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len)) goto error; diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c index b4ffc5b..e5b5721 100644 --- a/crypto/ablkcipher.c +++ b/crypto/ablkcipher.c @@ -277,12 +277,12 @@ static int ablkcipher_walk_first(struct ablkcipher_request *req, if (WARN_ON_ONCE(in_irq())) return -EDEADLK; + walk->iv = req->info; walk->nbytes = walk->total; if (unlikely(!walk->total)) return 0; walk->iv_buffer = NULL; - walk->iv = req->info; if (unlikely(((unsigned long)walk->iv & alignmask))) { int err = ablkcipher_copy_iv(walk, tfm, alignmask); diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index 11b9814..8cc1622 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c @@ -326,12 +326,12 @@ static int blkcipher_walk_first(struct blkcipher_desc *desc, if (WARN_ON_ONCE(in_irq())) return -EDEADLK; + walk->iv = desc->info; walk->nbytes = walk->total; if (unlikely(!walk->total)) return 0; walk->buffer = NULL; - walk->iv = desc->info; if (unlikely(((unsigned long)walk->iv & walk->alignmask))) { int err = blkcipher_copy_iv(walk); if (err) diff --git a/crypto/cryptd.c b/crypto/cryptd.c index c81861b..dbf894f 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -63,7 +63,7 @@ struct cryptd_blkcipher_ctx { struct cryptd_blkcipher_request_ctx { crypto_completion_t complete; -}; +} __no_const; struct cryptd_hash_ctx { struct crypto_shash *child; @@ -80,7 +80,7 @@ struct cryptd_aead_ctx { struct cryptd_aead_request_ctx { crypto_completion_t complete; -}; +} __no_const; static void cryptd_queue_worker(struct work_struct *work); diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c index ee9cfb9..30b36ed 100644 --- a/crypto/pcrypt.c +++ b/crypto/pcrypt.c @@ -392,7 +392,7 @@ static int pcrypt_sysfs_add(struct padata_instance *pinst, const char *name) int ret; pinst->kobj.kset = pcrypt_kset; - ret = kobject_add(&pinst->kobj, NULL, name); + ret = kobject_add(&pinst->kobj, NULL, "%s", name); if (!ret) kobject_uevent(&pinst->kobj, KOBJ_ADD); diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c index ea5815c..5880da6 100644 --- a/crypto/scatterwalk.c +++ b/crypto/scatterwalk.c @@ -109,14 +109,20 @@ void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg, { struct scatter_walk walk; struct scatterlist tmp[2]; + void *realbuf = buf; if (!nbytes) return; sg = scatterwalk_ffwd(tmp, sg, start); - if (sg_page(sg) == virt_to_page(buf) && - sg->offset == offset_in_page(buf)) +#ifdef CONFIG_GRKERNSEC_KSTACKOVERFLOW + if (object_starts_on_stack(buf)) + realbuf = buf - current->stack + current->lowmem_stack; +#endif + + if (sg_page(sg) == virt_to_page(realbuf) && + sg->offset == offset_in_page(realbuf)) return; scatterwalk_start(&walk, sg); diff --git a/crypto/zlib.c b/crypto/zlib.c index d51a30a..b6891a3 100644 --- a/crypto/zlib.c +++ b/crypto/zlib.c @@ -95,10 +95,10 @@ static int zlib_compress_setup(struct crypto_pcomp *tfm, const void *params, zlib_comp_exit(ctx); window_bits = tb[ZLIB_COMP_WINDOWBITS] - ? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS]) + ? nla_get_s32(tb[ZLIB_COMP_WINDOWBITS]) : MAX_WBITS; mem_level = tb[ZLIB_COMP_MEMLEVEL] - ? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL]) + ? nla_get_s32(tb[ZLIB_COMP_MEMLEVEL]) : DEF_MEM_LEVEL; workspacesize = zlib_deflate_workspacesize(window_bits, mem_level); @@ -108,15 +108,15 @@ static int zlib_compress_setup(struct crypto_pcomp *tfm, const void *params, ret = zlib_deflateInit2(stream, tb[ZLIB_COMP_LEVEL] - ? nla_get_u32(tb[ZLIB_COMP_LEVEL]) + ? nla_get_s32(tb[ZLIB_COMP_LEVEL]) : Z_DEFAULT_COMPRESSION, tb[ZLIB_COMP_METHOD] - ? nla_get_u32(tb[ZLIB_COMP_METHOD]) + ? nla_get_s32(tb[ZLIB_COMP_METHOD]) : Z_DEFLATED, window_bits, mem_level, tb[ZLIB_COMP_STRATEGY] - ? nla_get_u32(tb[ZLIB_COMP_STRATEGY]) + ? nla_get_s32(tb[ZLIB_COMP_STRATEGY]) : Z_DEFAULT_STRATEGY); if (ret != Z_OK) { vfree(stream->workspace); @@ -224,7 +224,7 @@ static int zlib_decompress_setup(struct crypto_pcomp *tfm, const void *params, zlib_decomp_exit(ctx); ctx->decomp_windowBits = tb[ZLIB_DECOMP_WINDOWBITS] - ? nla_get_u32(tb[ZLIB_DECOMP_WINDOWBITS]) + ? nla_get_s32(tb[ZLIB_DECOMP_WINDOWBITS]) : DEF_WBITS; stream->workspace = vzalloc(zlib_inflate_workspacesize()); diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 5778e8e..03a478b 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -394,7 +394,7 @@ static int video_disable_backlight_sysfs_if( return 0; } -static struct dmi_system_id video_dmi_table[] = { +static const struct dmi_system_id video_dmi_table[] = { /* * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121 */ diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index d62a616..387dbd0 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -70,11 +70,12 @@ static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id); /* Legacy functions are optional, based upon ACPI_REDUCED_HARDWARE */ static struct acpi_sleep_functions acpi_sleep_dispatch[] = { - {ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_sleep), - acpi_hw_extended_sleep}, - {ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake_prep), - acpi_hw_extended_wake_prep}, - {ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake), acpi_hw_extended_wake} + {.legacy_function = ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_sleep), + .extended_function = acpi_hw_extended_sleep}, + {.legacy_function = ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake_prep), + .extended_function = acpi_hw_extended_wake_prep}, + {.legacy_function = ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake), + .extended_function = acpi_hw_extended_wake} }; /* diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index 16129c7..8b675cd 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h @@ -19,7 +19,7 @@ typedef int (*apei_exec_ins_func_t)(struct apei_exec_context *ctx, struct apei_exec_ins_type { u32 flags; apei_exec_ins_func_t run; -}; +} __do_const; struct apei_exec_context { u32 ip; diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 23981ac..35eb27e 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -474,7 +474,7 @@ static void __ghes_print_estatus(const char *pfx, const struct acpi_hest_generic *generic, const struct acpi_hest_generic_status *estatus) { - static atomic_t seqno; + static atomic_unchecked_t seqno; unsigned int curr_seqno; char pfx_seq[64]; @@ -485,7 +485,7 @@ static void __ghes_print_estatus(const char *pfx, else pfx = KERN_ERR; } - curr_seqno = atomic_inc_return(&seqno); + curr_seqno = atomic_inc_return_unchecked(&seqno); snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}" HW_ERR, pfx, curr_seqno); printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n", pfx_seq, generic->header.source_id); diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c index a83e3c6..c3d617f 100644 --- a/drivers/acpi/bgrt.c +++ b/drivers/acpi/bgrt.c @@ -86,8 +86,10 @@ static int __init bgrt_init(void) if (!bgrt_image) return -ENODEV; - 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; + pax_close_kernel(); bgrt_kobj = kobject_create_and_add("bgrt", acpi_kobj); if (!bgrt_kobj) diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 96809cd..6a49f97 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -47,7 +47,7 @@ struct acpi_blacklist_item { u32 is_critical_error; }; -static struct dmi_system_id acpi_osi_dmi_table[] __initdata; +static const struct dmi_system_id acpi_osi_dmi_table[] __initconst; /* * POLICY: If *anything* doesn't work, put it on the blacklist. @@ -168,7 +168,7 @@ static int __init dmi_enable_rev_override(const struct dmi_system_id *d) } #endif -static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { +static const struct dmi_system_id acpi_osi_dmi_table[] __initconst = { { .callback = dmi_disable_osi_vista, .ident = "Fujitsu Siemens", diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a212cef..443c9c4 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -63,7 +63,7 @@ static int set_copy_dsdt(const struct dmi_system_id *id) } #endif -static struct dmi_system_id dsdt_dmi_table[] __initdata = { +static const struct dmi_system_id dsdt_dmi_table[] __initconst = { /* * Invoke DSDT corruption work-around on all Toshiba Satellite. * https://bugzilla.kernel.org/show_bug.cgi?id=14679 @@ -79,7 +79,7 @@ static struct dmi_system_id dsdt_dmi_table[] __initdata = { {} }; #else -static struct dmi_system_id dsdt_dmi_table[] __initdata = { +static const struct dmi_system_id dsdt_dmi_table[] __initconst = { {} }; #endif diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c index c68e724..e863008 100644 --- a/drivers/acpi/custom_method.c +++ b/drivers/acpi/custom_method.c @@ -29,6 +29,10 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf, struct acpi_table_header table; acpi_status status; +#ifdef CONFIG_GRKERNSEC_KMEM + return -EPERM; +#endif + if (!(*ppos)) { /* parse the table header to get the table length */ if (count <= sizeof(struct acpi_table_header)) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 4806b7f..78f0746 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -1041,6 +1041,8 @@ EXPORT_SYMBOL_GPL(acpi_subsys_freeze); #endif /* CONFIG_PM_SLEEP */ +static void acpi_dev_pm_detach(struct device *dev, bool power_off); + static struct dev_pm_domain acpi_general_pm_domain = { .ops = { .runtime_suspend = acpi_subsys_runtime_suspend, @@ -1057,6 +1059,7 @@ static struct dev_pm_domain acpi_general_pm_domain = { .restore_early = acpi_subsys_resume_early, #endif }, + .detach = acpi_dev_pm_detach }; /** @@ -1134,7 +1137,6 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on) acpi_device_wakeup(adev, ACPI_STATE_S0, false); } - dev->pm_domain->detach = acpi_dev_pm_detach; return 0; } EXPORT_SYMBOL_GPL(acpi_dev_pm_attach); diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 42c66b6..52256bc 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1470,7 +1470,7 @@ static int ec_clear_on_resume(const struct dmi_system_id *id) return 0; } -static struct dmi_system_id ec_dmi_table[] __initdata = { +static const struct dmi_system_id ec_dmi_table[] __initconst = { { ec_skip_dsdt_scan, "Compal JFL92", { DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"), diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index 7188e53..6012bc4 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -191,7 +191,7 @@ static int do_sta_before_sun(const struct dmi_system_id *d) return 0; } -static struct dmi_system_id acpi_pci_slot_dmi_table[] __initdata = { +static const struct dmi_system_id acpi_pci_slot_dmi_table[] __initconst = { /* * Fujitsu Primequest machines will return 1023 to indicate an * error if the _SUN method is evaluated on SxFy objects that diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 175c86b..f8226f0 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -906,7 +906,7 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) { int i, count = CPUIDLE_DRIVER_STATE_START; struct acpi_processor_cx *cx; - struct cpuidle_state *state; + cpuidle_state_no_const *state; struct cpuidle_driver *drv = &acpi_idle_driver; if (!pr->flags.power_setup_done) diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c index 7cfbda4..74f738c 100644 --- a/drivers/acpi/processor_pdc.c +++ b/drivers/acpi/processor_pdc.c @@ -173,7 +173,7 @@ static int __init set_no_mwait(const struct dmi_system_id *id) return 0; } -static struct dmi_system_id processor_idle_dmi_table[] __initdata = { +static const struct dmi_system_id processor_idle_dmi_table[] __initconst = { { set_no_mwait, "Extensa 5220", { DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 2f0d4db..b9e9b15 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -148,7 +148,7 @@ static int __init init_nvs_nosave(const struct dmi_system_id *d) return 0; } -static struct dmi_system_id acpisleep_dmi_table[] __initdata = { +static const struct dmi_system_id acpisleep_dmi_table[] __initconst = { { .callback = init_old_suspend_ordering, .ident = "Abit KN9 (nForce4 variant)", diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 40a4265..bb254e2 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -486,11 +486,11 @@ static u32 num_counters; static struct attribute **all_attrs; static u32 acpi_gpe_count; -static struct attribute_group interrupt_stats_attr_group = { +static attribute_group_no_const interrupt_stats_attr_group = { .name = "interrupts", }; -static struct kobj_attribute *counter_attrs; +static kobj_attribute_no_const *counter_attrs; static void delete_gpe_attr_array(void) { diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 30d8518..06efb1e 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -1208,7 +1208,7 @@ static int thermal_psv(const struct dmi_system_id *d) { return 0; } -static struct dmi_system_id thermal_dmi_table[] __initdata = { +static const struct dmi_system_id thermal_dmi_table[] __initconst = { /* * Award BIOS on this AOpen makes thermal control almost worthless. * http://bugzilla.kernel.org/show_bug.cgi?id=8842 diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 2922f1f..6c2fdaf 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -41,7 +41,6 @@ ACPI_MODULE_NAME("video"); void acpi_video_unregister_backlight(void); static bool backlight_notifier_registered; -static struct notifier_block backlight_nb; static struct work_struct backlight_notify_work; static enum acpi_backlight_type acpi_backlight_cmdline = acpi_backlight_undef; @@ -284,6 +283,10 @@ static int acpi_video_backlight_notify(struct notifier_block *nb, return NOTIFY_OK; } +static struct notifier_block backlight_nb = { + .notifier_call = acpi_video_backlight_notify, +}; + /* * Determine which type of backlight interface to use on this system, * First check cmdline, then dmi quirks, then do autodetect. @@ -314,8 +317,6 @@ enum acpi_backlight_type acpi_video_get_backlight_type(void) &video_caps, NULL); INIT_WORK(&backlight_notify_work, acpi_video_backlight_notify_work); - backlight_nb.notifier_call = acpi_video_backlight_notify; - backlight_nb.priority = 0; if (backlight_register_notifier(&backlight_nb) == 0) backlight_notifier_registered = true; init_done = true; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b79cb10..7daa9f7 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -102,7 +102,7 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev); static void ata_dev_xfermask(struct ata_device *dev); static unsigned long ata_dev_blacklisted(const struct ata_device *dev); -atomic_t ata_print_id = ATOMIC_INIT(0); +atomic_unchecked_t ata_print_id = ATOMIC_INIT(0); struct ata_force_param { const char *name; @@ -4801,7 +4801,7 @@ void ata_qc_free(struct ata_queued_cmd *qc) struct ata_port *ap; unsigned int tag; - WARN_ON_ONCE(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ + BUG_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ ap = qc->ap; qc->flags = 0; @@ -4818,7 +4818,7 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) struct ata_port *ap; struct ata_link *link; - WARN_ON_ONCE(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ + BUG_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ WARN_ON_ONCE(!(qc->flags & ATA_QCFLAG_ACTIVE)); ap = qc->ap; link = qc->dev->link; @@ -5925,6 +5925,7 @@ static void ata_finalize_port_ops(struct ata_port_operations *ops) return; spin_lock(&lock); + pax_open_kernel(); for (cur = ops->inherits; cur; cur = cur->inherits) { void **inherit = (void **)cur; @@ -5938,8 +5939,9 @@ static void ata_finalize_port_ops(struct ata_port_operations *ops) if (IS_ERR(*pp)) *pp = NULL; - ops->inherits = NULL; + *(struct ata_port_operations **)&ops->inherits = NULL; + pax_close_kernel(); spin_unlock(&lock); } @@ -6135,7 +6137,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) /* give ports names and add SCSI hosts */ for (i = 0; i < host->n_ports; i++) { - host->ports[i]->print_id = atomic_inc_return(&ata_print_id); + host->ports[i]->print_id = atomic_inc_return_unchecked(&ata_print_id); host->ports[i]->local_port_no = i + 1; } diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 0d7f0da..bc20aa6 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -4193,7 +4193,7 @@ int ata_sas_port_init(struct ata_port *ap) if (rc) return rc; - ap->print_id = atomic_inc_return(&ata_print_id); + ap->print_id = atomic_inc_return_unchecked(&ata_print_id); return 0; } EXPORT_SYMBOL_GPL(ata_sas_port_init); diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index f840ca1..edd6ef3 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -53,7 +53,7 @@ enum { ATA_DNXFER_QUIET = (1 << 31), }; -extern atomic_t ata_print_id; +extern atomic_unchecked_t ata_print_id; extern int atapi_passthru16; 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 --- 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) /* Handle platform specific quirks */ if (quirk) { if (quirk & CF_BROKEN_PIO) { - ap->ops->set_piomode = NULL; + pax_open_kernel(); + *(void **)&ap->ops->set_piomode = NULL; + pax_close_kernel(); ap->pio_mask = 0; } if (quirk & CF_BROKEN_MWDMA) diff --git a/drivers/atm/adummy.c b/drivers/atm/adummy.c index f9b983a..887b9d8 100644 --- a/drivers/atm/adummy.c +++ b/drivers/atm/adummy.c @@ -114,7 +114,7 @@ adummy_send(struct atm_vcc *vcc, struct sk_buff *skb) vcc->pop(vcc, skb); else dev_kfree_skb_any(skb); - atomic_inc(&vcc->stats->tx); + atomic_inc_unchecked(&vcc->stats->tx); return 0; } diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index f1a9198..f466a4a 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -454,7 +454,7 @@ static void tx_complete (amb_dev * dev, tx_out * tx) { PRINTD (DBG_FLOW|DBG_TX, "tx_complete %p %p", dev, tx); // VC layer stats - atomic_inc(&ATM_SKB(skb)->vcc->stats->tx); + atomic_inc_unchecked(&ATM_SKB(skb)->vcc->stats->tx); // free the descriptor kfree (tx_descr); @@ -495,7 +495,7 @@ static void rx_complete (amb_dev * dev, rx_out * rx) { dump_skb ("<<<", vc, skb); // VC layer stats - atomic_inc(&atm_vcc->stats->rx); + atomic_inc_unchecked(&atm_vcc->stats->rx); __net_timestamp(skb); // end of our responsibility atm_vcc->push (atm_vcc, skb); @@ -510,7 +510,7 @@ static void rx_complete (amb_dev * dev, rx_out * rx) { } else { PRINTK (KERN_INFO, "dropped over-size frame"); // should we count this? - atomic_inc(&atm_vcc->stats->rx_drop); + atomic_inc_unchecked(&atm_vcc->stats->rx_drop); } } else { @@ -1338,7 +1338,7 @@ static int amb_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) { } if (check_area (skb->data, skb->len)) { - atomic_inc(&atm_vcc->stats->tx_err); + atomic_inc_unchecked(&atm_vcc->stats->tx_err); return -ENOMEM; // ? } diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c index 480fa6f..947067c 100644 --- a/drivers/atm/atmtcp.c +++ b/drivers/atm/atmtcp.c @@ -206,7 +206,7 @@ static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb) if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); if (dev_data) return 0; - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); return -ENOLINK; } size = skb->len+sizeof(struct atmtcp_hdr); @@ -214,7 +214,7 @@ static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb) if (!new_skb) { if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); return -ENOBUFS; } hdr = (void *) skb_put(new_skb,sizeof(struct atmtcp_hdr)); @@ -225,8 +225,8 @@ static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb) if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); out_vcc->push(out_vcc,new_skb); - atomic_inc(&vcc->stats->tx); - atomic_inc(&out_vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->tx); + atomic_inc_unchecked(&out_vcc->stats->rx); return 0; } @@ -300,7 +300,7 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb) read_unlock(&vcc_sklist_lock); if (!out_vcc) { result = -EUNATCH; - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); goto done; } skb_pull(skb,sizeof(struct atmtcp_hdr)); @@ -312,8 +312,8 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb) __net_timestamp(new_skb); skb_copy_from_linear_data(skb, skb_put(new_skb, skb->len), skb->len); out_vcc->push(out_vcc,new_skb); - atomic_inc(&vcc->stats->tx); - atomic_inc(&out_vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->tx); + atomic_inc_unchecked(&out_vcc->stats->rx); done: if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 6339efd..2b441d5 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -525,7 +525,7 @@ static int rx_aal0(struct atm_vcc *vcc) DPRINTK(DEV_LABEL "(itf %d): trashing empty cell\n", vcc->dev->number); length = 0; - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); } else { length = ATM_CELL_SIZE-1; /* no HEC */ @@ -580,7 +580,7 @@ static int rx_aal5(struct atm_vcc *vcc) size); } eff = length = 0; - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); } else { size = (descr & MID_RED_COUNT)*(ATM_CELL_PAYLOAD >> 2); @@ -597,7 +597,7 @@ static int rx_aal5(struct atm_vcc *vcc) "(VCI=%d,length=%ld,size=%ld (descr 0x%lx))\n", vcc->dev->number,vcc->vci,length,size << 2,descr); length = eff = 0; - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); } } skb = eff ? atm_alloc_charge(vcc,eff << 2,GFP_ATOMIC) : NULL; @@ -770,7 +770,7 @@ rx_dequeued++; vcc->push(vcc,skb); pushed++; } - atomic_inc(&vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->rx); } wake_up(&eni_dev->rx_wait); } @@ -1230,7 +1230,7 @@ static void dequeue_tx(struct atm_dev *dev) DMA_TO_DEVICE); if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb_irq(skb); - atomic_inc(&vcc->stats->tx); + atomic_inc_unchecked(&vcc->stats->tx); wake_up(&eni_dev->tx_wait); dma_complete++; } diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index 82f2ae0..f205c02 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -749,7 +749,7 @@ static void process_txdone_queue (struct fs_dev *dev, struct queue *q) } } - atomic_inc(&ATM_SKB(skb)->vcc->stats->tx); + atomic_inc_unchecked(&ATM_SKB(skb)->vcc->stats->tx); fs_dprintk (FS_DEBUG_TXMEM, "i"); fs_dprintk (FS_DEBUG_ALLOC, "Free t-skb: %p\n", skb); @@ -816,7 +816,7 @@ static void process_incoming (struct fs_dev *dev, struct queue *q) #endif skb_put (skb, qe->p1 & 0xffff); ATM_SKB(skb)->vcc = atm_vcc; - atomic_inc(&atm_vcc->stats->rx); + atomic_inc_unchecked(&atm_vcc->stats->rx); __net_timestamp(skb); fs_dprintk (FS_DEBUG_ALLOC, "Free rec-skb: %p (pushed)\n", skb); atm_vcc->push (atm_vcc, skb); @@ -837,12 +837,12 @@ static void process_incoming (struct fs_dev *dev, struct queue *q) kfree (pe); } if (atm_vcc) - atomic_inc(&atm_vcc->stats->rx_drop); + atomic_inc_unchecked(&atm_vcc->stats->rx_drop); break; case 0x1f: /* Reassembly abort: no buffers. */ /* Silently increment error counter. */ if (atm_vcc) - atomic_inc(&atm_vcc->stats->rx_drop); + atomic_inc_unchecked(&atm_vcc->stats->rx_drop); break; default: /* Hmm. Haven't written the code to handle the others yet... -- REW */ printk (KERN_WARNING "Don't know what to do with RX status %x: %s.\n", diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 75dde90..4309ead 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -932,9 +932,9 @@ fore200e_tx_irq(struct fore200e* fore200e) #endif /* check error condition */ if (*entry->status & STATUS_ERROR) - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); else - atomic_inc(&vcc->stats->tx); + atomic_inc_unchecked(&vcc->stats->tx); } } @@ -1083,7 +1083,7 @@ fore200e_push_rpd(struct fore200e* fore200e, struct atm_vcc* vcc, struct rpd* rp if (skb == NULL) { DPRINTK(2, "unable to alloc new skb, rx PDU length = %d\n", pdu_len); - atomic_inc(&vcc->stats->rx_drop); + atomic_inc_unchecked(&vcc->stats->rx_drop); return -ENOMEM; } @@ -1126,14 +1126,14 @@ fore200e_push_rpd(struct fore200e* fore200e, struct atm_vcc* vcc, struct rpd* rp dev_kfree_skb_any(skb); - atomic_inc(&vcc->stats->rx_drop); + atomic_inc_unchecked(&vcc->stats->rx_drop); return -ENOMEM; } ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0); vcc->push(vcc, skb); - atomic_inc(&vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->rx); ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0); @@ -1211,7 +1211,7 @@ fore200e_rx_irq(struct fore200e* fore200e) DPRINTK(2, "damaged PDU on %d.%d.%d\n", fore200e->atm_dev->number, entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci); - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); } } @@ -1656,7 +1656,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) goto retry_here; } - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); fore200e->tx_sat++; DPRINTK(2, "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n", diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 0f5cb37..c8bcdef 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -1689,7 +1689,7 @@ he_service_rbrq(struct he_dev *he_dev, int group) if (RBRQ_HBUF_ERR(he_dev->rbrq_head)) { hprintk("HBUF_ERR! (cid 0x%x)\n", cid); - atomic_inc(&vcc->stats->rx_drop); + atomic_inc_unchecked(&vcc->stats->rx_drop); goto return_host_buffers; } @@ -1716,7 +1716,7 @@ he_service_rbrq(struct he_dev *he_dev, int group) RBRQ_LEN_ERR(he_dev->rbrq_head) ? "LEN_ERR" : "", vcc->vpi, vcc->vci); - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); goto return_host_buffers; } @@ -1768,7 +1768,7 @@ he_service_rbrq(struct he_dev *he_dev, int group) vcc->push(vcc, skb); spin_lock(&he_dev->global_lock); - atomic_inc(&vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->rx); return_host_buffers: ++pdus_assembled; @@ -2094,7 +2094,7 @@ __enqueue_tpd(struct he_dev *he_dev, struct he_tpd *tpd, unsigned cid) tpd->vcc->pop(tpd->vcc, tpd->skb); else dev_kfree_skb_any(tpd->skb); - atomic_inc(&tpd->vcc->stats->tx_err); + atomic_inc_unchecked(&tpd->vcc->stats->tx_err); } dma_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status)); return; @@ -2506,7 +2506,7 @@ he_send(struct atm_vcc *vcc, struct sk_buff *skb) vcc->pop(vcc, skb); else dev_kfree_skb_any(skb); - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); return -EINVAL; } @@ -2517,7 +2517,7 @@ he_send(struct atm_vcc *vcc, struct sk_buff *skb) vcc->pop(vcc, skb); else dev_kfree_skb_any(skb); - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); return -EINVAL; } #endif @@ -2529,7 +2529,7 @@ he_send(struct atm_vcc *vcc, struct sk_buff *skb) vcc->pop(vcc, skb); else dev_kfree_skb_any(skb); - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); spin_unlock_irqrestore(&he_dev->global_lock, flags); return -ENOMEM; } @@ -2571,7 +2571,7 @@ he_send(struct atm_vcc *vcc, struct sk_buff *skb) vcc->pop(vcc, skb); else dev_kfree_skb_any(skb); - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); spin_unlock_irqrestore(&he_dev->global_lock, flags); return -ENOMEM; } @@ -2602,7 +2602,7 @@ he_send(struct atm_vcc *vcc, struct sk_buff *skb) __enqueue_tpd(he_dev, tpd, cid); spin_unlock_irqrestore(&he_dev->global_lock, flags); - atomic_inc(&vcc->stats->tx); + atomic_inc_unchecked(&vcc->stats->tx); return 0; } diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index 527bbd5..96570c8 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -1018,7 +1018,7 @@ static void rx_schedule (hrz_dev * dev, int irq) { { struct atm_vcc * vcc = ATM_SKB(skb)->vcc; // VC layer stats - atomic_inc(&vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->rx); __net_timestamp(skb); // end of our responsibility vcc->push (vcc, skb); @@ -1170,7 +1170,7 @@ static void tx_schedule (hrz_dev * const dev, int irq) { dev->tx_iovec = NULL; // VC layer stats - atomic_inc(&ATM_SKB(skb)->vcc->stats->tx); + atomic_inc_unchecked(&ATM_SKB(skb)->vcc->stats->tx); // free the skb hrz_kfree_skb (skb); diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index 074616b..d6b3d5f 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -811,7 +811,7 @@ drain_scq(struct idt77252_dev *card, struct vc_map *vc) else dev_kfree_skb(skb); - atomic_inc(&vcc->stats->tx); + atomic_inc_unchecked(&vcc->stats->tx); } atomic_dec(&scq->used); @@ -1073,13 +1073,13 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe) if ((sb = dev_alloc_skb(64)) == NULL) { printk("%s: Can't allocate buffers for aal0.\n", card->name); - atomic_add(i, &vcc->stats->rx_drop); + atomic_add_unchecked(i, &vcc->stats->rx_drop); break; } if (!atm_charge(vcc, sb->truesize)) { RXPRINTK("%s: atm_charge() dropped aal0 packets.\n", card->name); - atomic_add(i - 1, &vcc->stats->rx_drop); + atomic_add_unchecked(i - 1, &vcc->stats->rx_drop); dev_kfree_skb(sb); break; } @@ -1096,7 +1096,7 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe) ATM_SKB(sb)->vcc = vcc; __net_timestamp(sb); vcc->push(vcc, sb); - atomic_inc(&vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->rx); cell += ATM_CELL_PAYLOAD; } @@ -1133,13 +1133,13 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe) "(CDC: %08x)\n", card->name, len, rpp->len, readl(SAR_REG_CDC)); recycle_rx_pool_skb(card, rpp); - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); return; } if (stat & SAR_RSQE_CRC) { RXPRINTK("%s: AAL5 CRC error.\n", card->name); recycle_rx_pool_skb(card, rpp); - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); return; } if (skb_queue_len(&rpp->queue) > 1) { @@ -1150,7 +1150,7 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe) RXPRINTK("%s: Can't alloc RX skb.\n", card->name); recycle_rx_pool_skb(card, rpp); - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); return; } if (!atm_charge(vcc, skb->truesize)) { @@ -1169,7 +1169,7 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe) __net_timestamp(skb); vcc->push(vcc, skb); - atomic_inc(&vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->rx); return; } @@ -1191,7 +1191,7 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe) __net_timestamp(skb); vcc->push(vcc, skb); - atomic_inc(&vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->rx); if (skb->truesize > SAR_FB_SIZE_3) add_rx_skb(card, 3, SAR_FB_SIZE_3, 1); @@ -1302,14 +1302,14 @@ idt77252_rx_raw(struct idt77252_dev *card) if (vcc->qos.aal != ATM_AAL0) { RPRINTK("%s: raw cell for non AAL0 vc %u.%u\n", card->name, vpi, vci); - atomic_inc(&vcc->stats->rx_drop); + atomic_inc_unchecked(&vcc->stats->rx_drop); goto drop; } if ((sb = dev_alloc_skb(64)) == NULL) { printk("%s: Can't allocate buffers for AAL0.\n", card->name); - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); goto drop; } @@ -1328,7 +1328,7 @@ idt77252_rx_raw(struct idt77252_dev *card) ATM_SKB(sb)->vcc = vcc; __net_timestamp(sb); vcc->push(vcc, sb); - atomic_inc(&vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->rx); drop: skb_pull(queue, 64); @@ -1953,13 +1953,13 @@ idt77252_send_skb(struct atm_vcc *vcc, struct sk_buff *skb, int oam) if (vc == NULL) { printk("%s: NULL connection in send().\n", card->name); - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); dev_kfree_skb(skb); return -EINVAL; } if (!test_bit(VCF_TX, &vc->flags)) { printk("%s: Trying to transmit on a non-tx VC.\n", card->name); - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); dev_kfree_skb(skb); return -EINVAL; } @@ -1971,14 +1971,14 @@ idt77252_send_skb(struct atm_vcc *vcc, struct sk_buff *skb, int oam) break; default: printk("%s: Unsupported AAL: %d\n", card->name, vcc->qos.aal); - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); dev_kfree_skb(skb); return -EINVAL; } if (skb_shinfo(skb)->nr_frags != 0) { printk("%s: No scatter-gather yet.\n", card->name); - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); dev_kfree_skb(skb); return -EINVAL; } @@ -1986,7 +1986,7 @@ idt77252_send_skb(struct atm_vcc *vcc, struct sk_buff *skb, int oam) err = queue_skb(card, vc, skb, oam); if (err) { - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); dev_kfree_skb(skb); return err; } @@ -2009,7 +2009,7 @@ idt77252_send_oam(struct atm_vcc *vcc, void *cell, int flags) skb = dev_alloc_skb(64); if (!skb) { printk("%s: Out of memory in send_oam().\n", card->name); - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); return -ENOMEM; } atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 65e6590..df77d04 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -1145,7 +1145,7 @@ static int rx_pkt(struct atm_dev *dev) status = (u_short) (buf_desc_ptr->desc_mode); if (status & (RX_CER | RX_PTE | RX_OFL)) { - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); IF_ERR(printk("IA: bad packet, dropping it");) if (status & RX_CER) { IF_ERR(printk(" cause: packet CRC error\n");) @@ -1168,7 +1168,7 @@ static int rx_pkt(struct atm_dev *dev) len = dma_addr - buf_addr; if (len > iadev->rx_buf_sz) { printk("Over %d bytes sdu received, dropped!!!\n", iadev->rx_buf_sz); - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); goto out_free_desc; } @@ -1318,7 +1318,7 @@ static void rx_dle_intr(struct atm_dev *dev) ia_vcc = INPH_IA_VCC(vcc); if (ia_vcc == NULL) { - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); atm_return(vcc, skb->truesize); dev_kfree_skb_any(skb); goto INCR_DLE; @@ -1330,7 +1330,7 @@ static void rx_dle_intr(struct atm_dev *dev) if ((length > iadev->rx_buf_sz) || (length > (skb->len - sizeof(struct cpcs_trailer)))) { - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); IF_ERR(printk("rx_dle_intr: Bad AAL5 trailer %d (skb len %d)", length, skb->len);) atm_return(vcc, skb->truesize); @@ -1346,7 +1346,7 @@ static void rx_dle_intr(struct atm_dev *dev) IF_RX(printk("rx_dle_intr: skb push");) vcc->push(vcc,skb); - atomic_inc(&vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->rx); iadev->rx_pkt_cnt++; } INCR_DLE: @@ -2828,15 +2828,15 @@ static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg) { struct k_sonet_stats *stats; stats = &PRIV(_ia_dev[board])->sonet_stats; - printk("section_bip: %d\n", atomic_read(&stats->section_bip)); - printk("line_bip : %d\n", atomic_read(&stats->line_bip)); - printk("path_bip : %d\n", atomic_read(&stats->path_bip)); - printk("line_febe : %d\n", atomic_read(&stats->line_febe)); - printk("path_febe : %d\n", atomic_read(&stats->path_febe)); - printk("corr_hcs : %d\n", atomic_read(&stats->corr_hcs)); - printk("uncorr_hcs : %d\n", atomic_read(&stats->uncorr_hcs)); - printk("tx_cells : %d\n", atomic_read(&stats->tx_cells)); - printk("rx_cells : %d\n", atomic_read(&stats->rx_cells)); + printk("section_bip: %d\n", atomic_read_unchecked(&stats->section_bip)); + printk("line_bip : %d\n", atomic_read_unchecked(&stats->line_bip)); + printk("path_bip : %d\n", atomic_read_unchecked(&stats->path_bip)); + printk("line_febe : %d\n", atomic_read_unchecked(&stats->line_febe)); + printk("path_febe : %d\n", atomic_read_unchecked(&stats->path_febe)); + printk("corr_hcs : %d\n", atomic_read_unchecked(&stats->corr_hcs)); + printk("uncorr_hcs : %d\n", atomic_read_unchecked(&stats->uncorr_hcs)); + printk("tx_cells : %d\n", atomic_read_unchecked(&stats->tx_cells)); + printk("rx_cells : %d\n", atomic_read_unchecked(&stats->rx_cells)); } ia_cmds.status = 0; break; @@ -2941,7 +2941,7 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) { if ((desc == 0) || (desc > iadev->num_tx_desc)) { IF_ERR(printk(DEV_LABEL "invalid desc for send: %d\n", desc);) - atomic_inc(&vcc->stats->tx); + atomic_inc_unchecked(&vcc->stats->tx); if (vcc->pop) vcc->pop(vcc, skb); else @@ -3046,14 +3046,14 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) { ATM_DESC(skb) = vcc->vci; skb_queue_tail(&iadev->tx_dma_q, skb); - atomic_inc(&vcc->stats->tx); + atomic_inc_unchecked(&vcc->stats->tx); iadev->tx_pkt_cnt++; /* Increment transaction counter */ writel(2, iadev->dma+IPHASE5575_TX_COUNTER); #if 0 /* add flow control logic */ - if (atomic_read(&vcc->stats->tx) % 20 == 0) { + if (atomic_read_unchecked(&vcc->stats->tx) % 20 == 0) { if (iavcc->vc_desc_cnt > 10) { vcc->tx_quota = vcc->tx_quota * 3 / 4; printk("Tx1: vcc->tx_quota = %d \n", (u32)vcc->tx_quota ); diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c index ce43ae3..969de38 100644 --- a/drivers/atm/lanai.c +++ b/drivers/atm/lanai.c @@ -1295,7 +1295,7 @@ static void lanai_send_one_aal5(struct lanai_dev *lanai, vcc_tx_add_aal5_trailer(lvcc, skb->len, 0, 0); lanai_endtx(lanai, lvcc); lanai_free_skb(lvcc->tx.atmvcc, skb); - atomic_inc(&lvcc->tx.atmvcc->stats->tx); + atomic_inc_unchecked(&lvcc->tx.atmvcc->stats->tx); } /* Try to fill the buffer - don't call unless there is backlog */ @@ -1418,7 +1418,7 @@ static void vcc_rx_aal5(struct lanai_vcc *lvcc, int endptr) ATM_SKB(skb)->vcc = lvcc->rx.atmvcc; __net_timestamp(skb); lvcc->rx.atmvcc->push(lvcc->rx.atmvcc, skb); - atomic_inc(&lvcc->rx.atmvcc->stats->rx); + atomic_inc_unchecked(&lvcc->rx.atmvcc->stats->rx); out: lvcc->rx.buf.ptr = end; cardvcc_write(lvcc, endptr, vcc_rxreadptr); @@ -1659,7 +1659,7 @@ static int handle_service(struct lanai_dev *lanai, u32 s) DPRINTK("(itf %d) got RX service entry 0x%X for non-AAL5 " "vcc %d\n", lanai->number, (unsigned int) s, vci); lanai->stats.service_rxnotaal5++; - atomic_inc(&lvcc->rx.atmvcc->stats->rx_err); + atomic_inc_unchecked(&lvcc->rx.atmvcc->stats->rx_err); return 0; } if (likely(!(s & (SERVICE_TRASH | SERVICE_STREAM | SERVICE_CRCERR)))) { @@ -1671,7 +1671,7 @@ static int handle_service(struct lanai_dev *lanai, u32 s) int bytes; read_unlock(&vcc_sklist_lock); DPRINTK("got trashed rx pdu on vci %d\n", vci); - atomic_inc(&lvcc->rx.atmvcc->stats->rx_err); + atomic_inc_unchecked(&lvcc->rx.atmvcc->stats->rx_err); lvcc->stats.x.aal5.service_trash++; bytes = (SERVICE_GET_END(s) * 16) - (((unsigned long) lvcc->rx.buf.ptr) - @@ -1683,7 +1683,7 @@ static int handle_service(struct lanai_dev *lanai, u32 s) } if (s & SERVICE_STREAM) { read_unlock(&vcc_sklist_lock); - atomic_inc(&lvcc->rx.atmvcc->stats->rx_err); + atomic_inc_unchecked(&lvcc->rx.atmvcc->stats->rx_err); lvcc->stats.x.aal5.service_stream++; printk(KERN_ERR DEV_LABEL "(itf %d): Got AAL5 stream " "PDU on VCI %d!\n", lanai->number, vci); @@ -1691,7 +1691,7 @@ static int handle_service(struct lanai_dev *lanai, u32 s) return 0; } DPRINTK("got rx crc error on vci %d\n", vci); - atomic_inc(&lvcc->rx.atmvcc->stats->rx_err); + atomic_inc_unchecked(&lvcc->rx.atmvcc->stats->rx_err); lvcc->stats.x.aal5.service_rxcrc++; lvcc->rx.buf.ptr = &lvcc->rx.buf.start[SERVICE_GET_END(s) * 4]; cardvcc_write(lvcc, SERVICE_GET_END(s), vcc_rxreadptr); diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c index ddc4ceb..36e29aa 100644 --- a/drivers/atm/nicstar.c +++ b/drivers/atm/nicstar.c @@ -1632,7 +1632,7 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) if ((vc = (vc_map *) vcc->dev_data) == NULL) { printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n", card->index); - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); dev_kfree_skb_any(skb); return -EINVAL; } @@ -1640,7 +1640,7 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) if (!vc->tx) { printk("nicstar%d: Trying to transmit on a non-tx VC.\n", card->index); - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); dev_kfree_skb_any(skb); return -EINVAL; } @@ -1648,14 +1648,14 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) { printk("nicstar%d: Only AAL0 and AAL5 are supported.\n", card->index); - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); dev_kfree_skb_any(skb); return -EINVAL; } if (skb_shinfo(skb)->nr_frags != 0) { printk("nicstar%d: No scatter-gather yet.\n", card->index); - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); dev_kfree_skb_any(skb); return -EINVAL; } @@ -1703,11 +1703,11 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) } if (push_scqe(card, vc, scq, &scqe, skb) != 0) { - atomic_inc(&vcc->stats->tx_err); + atomic_inc_unchecked(&vcc->stats->tx_err); dev_kfree_skb_any(skb); return -EIO; } - atomic_inc(&vcc->stats->tx); + atomic_inc_unchecked(&vcc->stats->tx); return 0; } @@ -2024,14 +2024,14 @@ static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe) printk ("nicstar%d: Can't allocate buffers for aal0.\n", card->index); - atomic_add(i, &vcc->stats->rx_drop); + atomic_add_unchecked(i, &vcc->stats->rx_drop); break; } if (!atm_charge(vcc, sb->truesize)) { RXPRINTK ("nicstar%d: atm_charge() dropped aal0 packets.\n", card->index); - atomic_add(i - 1, &vcc->stats->rx_drop); /* already increased by 1 */ + atomic_add_unchecked(i - 1, &vcc->stats->rx_drop); /* already increased by 1 */ dev_kfree_skb_any(sb); break; } @@ -2046,7 +2046,7 @@ static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe) ATM_SKB(sb)->vcc = vcc; __net_timestamp(sb); vcc->push(vcc, sb); - atomic_inc(&vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->rx); cell += ATM_CELL_PAYLOAD; } @@ -2063,7 +2063,7 @@ static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe) if (iovb == NULL) { printk("nicstar%d: Out of iovec buffers.\n", card->index); - atomic_inc(&vcc->stats->rx_drop); + atomic_inc_unchecked(&vcc->stats->rx_drop); recycle_rx_buf(card, skb); return; } @@ -2087,7 +2087,7 @@ static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe) small or large buffer itself. */ } else if (NS_PRV_IOVCNT(iovb) >= NS_MAX_IOVECS) { printk("nicstar%d: received too big AAL5 SDU.\n", card->index); - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data, NS_MAX_IOVECS); NS_PRV_IOVCNT(iovb) = 0; @@ -2107,7 +2107,7 @@ static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe) ("nicstar%d: Expected a small buffer, and this is not one.\n", card->index); which_list(card, skb); - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); recycle_rx_buf(card, skb); vc->rx_iov = NULL; recycle_iov_buf(card, iovb); @@ -2120,7 +2120,7 @@ static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe) ("nicstar%d: Expected a large buffer, and this is not one.\n", card->index); which_list(card, skb); - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data, NS_PRV_IOVCNT(iovb)); vc->rx_iov = NULL; @@ -2143,7 +2143,7 @@ static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe) printk(" - PDU size mismatch.\n"); else printk(".\n"); - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data, NS_PRV_IOVCNT(iovb)); vc->rx_iov = NULL; @@ -2157,14 +2157,14 @@ static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe) /* skb points to a small buffer */ if (!atm_charge(vcc, skb->truesize)) { push_rxbufs(card, skb); - atomic_inc(&vcc->stats->rx_drop); + atomic_inc_unchecked(&vcc->stats->rx_drop); } else { skb_put(skb, len); dequeue_sm_buf(card, skb); ATM_SKB(skb)->vcc = vcc; __net_timestamp(skb); vcc->push(vcc, skb); - atomic_inc(&vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->rx); } } else if (NS_PRV_IOVCNT(iovb) == 2) { /* One small plus one large buffer */ struct sk_buff *sb; @@ -2175,14 +2175,14 @@ static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe) if (len <= NS_SMBUFSIZE) { if (!atm_charge(vcc, sb->truesize)) { push_rxbufs(card, sb); - atomic_inc(&vcc->stats->rx_drop); + atomic_inc_unchecked(&vcc->stats->rx_drop); } else { skb_put(sb, len); dequeue_sm_buf(card, sb); ATM_SKB(sb)->vcc = vcc; __net_timestamp(sb); vcc->push(vcc, sb); - atomic_inc(&vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->rx); } push_rxbufs(card, skb); @@ -2191,7 +2191,7 @@ static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe) if (!atm_charge(vcc, skb->truesize)) { push_rxbufs(card, skb); - atomic_inc(&vcc->stats->rx_drop); + atomic_inc_unchecked(&vcc->stats->rx_drop); } else { dequeue_lg_buf(card, skb); skb_push(skb, NS_SMBUFSIZE); @@ -2201,7 +2201,7 @@ static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe) ATM_SKB(skb)->vcc = vcc; __net_timestamp(skb); vcc->push(vcc, skb); - atomic_inc(&vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->rx); } push_rxbufs(card, sb); @@ -2222,7 +2222,7 @@ static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe) printk ("nicstar%d: Out of huge buffers.\n", card->index); - atomic_inc(&vcc->stats->rx_drop); + atomic_inc_unchecked(&vcc->stats->rx_drop); recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, @@ -2273,7 +2273,7 @@ static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe) card->hbpool.count++; } else dev_kfree_skb_any(hb); - atomic_inc(&vcc->stats->rx_drop); + atomic_inc_unchecked(&vcc->stats->rx_drop); } else { /* Copy the small buffer to the huge buffer */ sb = (struct sk_buff *)iov->iov_base; @@ -2307,7 +2307,7 @@ static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe) ATM_SKB(hb)->vcc = vcc; __net_timestamp(hb); vcc->push(vcc, hb); - atomic_inc(&vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->rx); } } diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 3d7fb65..0f26393 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -843,7 +843,7 @@ static void solos_bh(unsigned long card_arg) } atm_charge(vcc, skb->truesize); vcc->push(vcc, skb); - atomic_inc(&vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->rx); break; case PKT_STATUS: @@ -1124,7 +1124,7 @@ static uint32_t fpga_tx(struct solos_card *card) vcc = SKB_CB(oldskb)->vcc; if (vcc) { - atomic_inc(&vcc->stats->tx); + atomic_inc_unchecked(&vcc->stats->tx); solos_pop(vcc, oldskb); } else { dev_kfree_skb_irq(oldskb); diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c index 0215934..ce9f5b1 100644 --- a/drivers/atm/suni.c +++ b/drivers/atm/suni.c @@ -49,8 +49,8 @@ static DEFINE_SPINLOCK(sunis_lock); #define ADD_LIMITED(s,v) \ - atomic_add((v),&stats->s); \ - if (atomic_read(&stats->s) < 0) atomic_set(&stats->s,INT_MAX); + atomic_add_unchecked((v),&stats->s); \ + if (atomic_read_unchecked(&stats->s) < 0) atomic_set_unchecked(&stats->s,INT_MAX); static void suni_hz(unsigned long from_timer) diff --git a/drivers/atm/uPD98402.c b/drivers/atm/uPD98402.c index 5120a96..e2572bd 100644 --- a/drivers/atm/uPD98402.c +++ b/drivers/atm/uPD98402.c @@ -42,7 +42,7 @@ static int fetch_stats(struct atm_dev *dev,struct sonet_stats __user *arg,int ze struct sonet_stats tmp; int error = 0; - atomic_add(GET(HECCT),&PRIV(dev)->sonet_stats.uncorr_hcs); + atomic_add_unchecked(GET(HECCT),&PRIV(dev)->sonet_stats.uncorr_hcs); sonet_copy_stats(&PRIV(dev)->sonet_stats,&tmp); if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp)); if (zero && !error) { @@ -161,9 +161,9 @@ static int uPD98402_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) #define ADD_LIMITED(s,v) \ - { atomic_add(GET(v),&PRIV(dev)->sonet_stats.s); \ - if (atomic_read(&PRIV(dev)->sonet_stats.s) < 0) \ - atomic_set(&PRIV(dev)->sonet_stats.s,INT_MAX); } + { atomic_add_unchecked(GET(v),&PRIV(dev)->sonet_stats.s); \ + if (atomic_read_unchecked(&PRIV(dev)->sonet_stats.s) < 0) \ + atomic_set_unchecked(&PRIV(dev)->sonet_stats.s,INT_MAX); } static void stat_event(struct atm_dev *dev) @@ -194,7 +194,7 @@ static void uPD98402_int(struct atm_dev *dev) if (reason & uPD98402_INT_PFM) stat_event(dev); if (reason & uPD98402_INT_PCO) { (void) GET(PCOCR); /* clear interrupt cause */ - atomic_add(GET(HECCT), + atomic_add_unchecked(GET(HECCT), &PRIV(dev)->sonet_stats.uncorr_hcs); } if ((reason & uPD98402_INT_RFO) && @@ -222,9 +222,9 @@ static int uPD98402_start(struct atm_dev *dev) PUT(~(uPD98402_INT_PFM | uPD98402_INT_ALM | uPD98402_INT_RFO | uPD98402_INT_LOS),PIMR); /* enable them */ (void) fetch_stats(dev,NULL,1); /* clear kernel counters */ - atomic_set(&PRIV(dev)->sonet_stats.corr_hcs,-1); - atomic_set(&PRIV(dev)->sonet_stats.tx_cells,-1); - atomic_set(&PRIV(dev)->sonet_stats.rx_cells,-1); + atomic_set_unchecked(&PRIV(dev)->sonet_stats.corr_hcs,-1); + atomic_set_unchecked(&PRIV(dev)->sonet_stats.tx_cells,-1); + atomic_set_unchecked(&PRIV(dev)->sonet_stats.rx_cells,-1); return 0; } diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index cecfb94..87009ec 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -459,7 +459,7 @@ printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]); } if (!size) { dev_kfree_skb_irq(skb); - if (vcc) atomic_inc(&vcc->stats->rx_err); + if (vcc) atomic_inc_unchecked(&vcc->stats->rx_err); continue; } if (!atm_charge(vcc,skb->truesize)) { @@ -469,7 +469,7 @@ printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]); skb->len = size; ATM_SKB(skb)->vcc = vcc; vcc->push(vcc,skb); - atomic_inc(&vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->rx); } zout(pos & 0xffff,MTA(mbx)); #if 0 /* probably a stupid idea */ @@ -733,7 +733,7 @@ if (*ZATM_PRV_DSC(skb) != (uPD98401_TXPD_V | uPD98401_TXPD_DP | skb_queue_head(&zatm_vcc->backlog,skb); break; } - atomic_inc(&vcc->stats->tx); + atomic_inc_unchecked(&vcc->stats->tx); wake_up(&zatm_vcc->tx_wait); } diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 5005924..9fc06c4 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -1141,7 +1141,7 @@ int subsys_interface_register(struct subsys_interface *sif) return -EINVAL; mutex_lock(&subsys->p->mutex); - list_add_tail(&sif->node, &subsys->p->interfaces); + pax_list_add_tail((struct list_head *)&sif->node, &subsys->p->interfaces); if (sif->add_dev) { subsys_dev_iter_init(&iter, subsys, NULL, NULL); while ((dev = subsys_dev_iter_next(&iter))) @@ -1166,7 +1166,7 @@ void subsys_interface_unregister(struct subsys_interface *sif) subsys = sif->subsys; mutex_lock(&subsys->p->mutex); - list_del_init(&sif->node); + pax_list_del_init((struct list_head *)&sif->node); if (sif->remove_dev) { subsys_dev_iter_init(&iter, subsys, NULL, NULL); while ((dev = subsys_dev_iter_next(&iter))) diff --git a/drivers/base/devres.c b/drivers/base/devres.c index 8754646..6828fbe 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -475,7 +475,9 @@ static int remove_nodes(struct device *dev, static int release_nodes(struct device *dev, struct list_head *first, struct list_head *end, unsigned long flags) - __releases(&dev->devres_lock) + __releases(&dev->devres_lock); +static int release_nodes(struct device *dev, struct list_head *first, + struct list_head *end, unsigned long flags) { LIST_HEAD(todo); int cnt; diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index 68f0314..ca2a609 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c @@ -354,7 +354,7 @@ int devtmpfs_mount(const char *mntdir) if (!thread) return 0; - err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT, NULL); + err = sys_mount((char __force_user *)"devtmpfs", (char __force_user *)mntdir, (char __force_user *)"devtmpfs", MS_SILENT, NULL); if (err) printk(KERN_INFO "devtmpfs: error mounting %i\n", err); else @@ -380,11 +380,11 @@ static int devtmpfsd(void *p) *err = sys_unshare(CLONE_NEWNS); if (*err) goto out; - *err = sys_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, options); + *err = sys_mount((char __force_user *)"devtmpfs", (char __force_user *)"/", (char __force_user *)"devtmpfs", MS_SILENT, (char __force_user *)options); if (*err) goto out; - sys_chdir("/.."); /* will traverse into overmounted root */ - sys_chroot("."); + sys_chdir((char __force_user *)"/.."); /* will traverse into overmounted root */ + sys_chroot((char __force_user *)"."); complete(&setup_done); while (1) { spin_lock(&req_lock); diff --git a/drivers/base/node.c b/drivers/base/node.c index 560751b..3a4847a 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -627,7 +627,7 @@ static ssize_t print_nodes_state(enum node_states state, char *buf) struct node_attr { struct device_attribute attr; enum node_states state; -}; +} __do_const; 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 134483d..5588d1c 100644 --- a/drivers/base/platform-msi.c +++ b/drivers/base/platform-msi.c @@ -24,6 +24,8 @@ #include #include +#include + #define DEV_ID_SHIFT 24 /* @@ -77,10 +79,12 @@ static void platform_msi_update_dom_ops(struct msi_domain_info *info) BUG_ON(!ops); + pax_open_kernel(); if (ops->msi_init == NULL) - ops->msi_init = platform_msi_init; + *(void **)&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; + pax_close_kernel(); } static void platform_msi_write_msg(struct irq_data *data, struct msi_msg *msg) @@ -98,16 +102,18 @@ static void platform_msi_update_chip_ops(struct msi_domain_info *info) struct irq_chip *chip = info->chip; BUG_ON(!chip); + pax_open_kernel(); if (!chip->irq_mask) - chip->irq_mask = irq_chip_mask_parent; + *(void **)&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; if (!chip->irq_eoi) - chip->irq_eoi = irq_chip_eoi_parent; + *(void **)&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; 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; + pax_close_kernel(); } static void platform_msi_free_descs(struct device *dev) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 16550c6..322c4c7 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1517,7 +1517,7 @@ int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state) { struct cpuidle_driver *cpuidle_drv; struct gpd_cpuidle_data *cpuidle_data; - struct cpuidle_state *idle_state; + cpuidle_state_no_const *idle_state; int ret = 0; if (IS_ERR_OR_NULL(genpd) || state < 0) @@ -1585,7 +1585,7 @@ int pm_genpd_name_attach_cpuidle(const char *name, int state) int pm_genpd_detach_cpuidle(struct generic_pm_domain *genpd) { struct gpd_cpuidle_data *cpuidle_data; - struct cpuidle_state *idle_state; + cpuidle_state_no_const *idle_state; int ret = 0; if (IS_ERR_OR_NULL(genpd)) @@ -2021,8 +2021,11 @@ int genpd_dev_pm_attach(struct device *dev) goto out; } - 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; + pax_close_kernel(); + ret = pm_genpd_poweron(pd); out: diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index e1a10a0..a6bc363 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -263,8 +263,8 @@ static int rpm_check_suspend_allowed(struct device *dev) * @cb: Runtime PM callback to run. * @dev: Device to run the callback for. */ +static int __rpm_callback(int (*cb)(struct device *), struct device *dev) __must_hold(&dev->power.lock); static int __rpm_callback(int (*cb)(struct device *), struct device *dev) - __releases(&dev->power.lock) __acquires(&dev->power.lock) { int retval; @@ -412,8 +412,8 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev) * * This function must be called under dev->power.lock with interrupts disabled. */ +static int rpm_suspend(struct device *dev, int rpmflags) __must_hold(&dev->power.lock); static int rpm_suspend(struct device *dev, int rpmflags) - __releases(&dev->power.lock) __acquires(&dev->power.lock) { int (*callback)(struct device *); struct device *parent = NULL; @@ -594,8 +594,8 @@ static int rpm_suspend(struct device *dev, int rpmflags) * * This function must be called under dev->power.lock with interrupts disabled. */ +static int rpm_resume(struct device *dev, int rpmflags) __must_hold(&dev->power.lock); static int rpm_resume(struct device *dev, int rpmflags) - __releases(&dev->power.lock) __acquires(&dev->power.lock) { int (*callback)(struct device *); struct device *parent = NULL; diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index a7b4679..d302490 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -181,7 +181,7 @@ static ssize_t rtpm_status_show(struct device *dev, return -EIO; } } - return sprintf(buf, p); + return sprintf(buf, "%s", p); } static DEVICE_ATTR(runtime_status, 0444, rtpm_status_show, NULL); diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 51f15bc..892a668 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -33,14 +33,14 @@ static bool pm_abort_suspend __read_mostly; * They need to be modified together atomically, so it's better to use one * atomic variable to hold them both. */ -static atomic_t combined_event_count = ATOMIC_INIT(0); +static atomic_unchecked_t combined_event_count = ATOMIC_INIT(0); #define IN_PROGRESS_BITS (sizeof(int) * 4) #define MAX_IN_PROGRESS ((1 << IN_PROGRESS_BITS) - 1) static void split_counters(unsigned int *cnt, unsigned int *inpr) { - unsigned int comb = atomic_read(&combined_event_count); + unsigned int comb = atomic_read_unchecked(&combined_event_count); *cnt = (comb >> IN_PROGRESS_BITS); *inpr = comb & MAX_IN_PROGRESS; @@ -537,7 +537,7 @@ static void wakeup_source_activate(struct wakeup_source *ws) ws->start_prevent_time = ws->last_time; /* Increment the counter of events in progress. */ - cec = atomic_inc_return(&combined_event_count); + cec = atomic_inc_return_unchecked(&combined_event_count); trace_wakeup_source_activate(ws->name, cec); } @@ -663,7 +663,7 @@ static void wakeup_source_deactivate(struct wakeup_source *ws) * Increment the counter of registered wakeup events and decrement the * couter of wakeup events in progress simultaneously. */ - cec = atomic_add_return(MAX_IN_PROGRESS, &combined_event_count); + cec = atomic_add_return_unchecked(MAX_IN_PROGRESS, &combined_event_count); trace_wakeup_source_deactivate(ws->name, cec); split_counters(&cnt, &inpr); diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 4c55cfb..b4c21fb 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -30,7 +30,7 @@ static LIST_HEAD(regmap_debugfs_early_list); static DEFINE_MUTEX(regmap_debugfs_early_lock); /* Calculate the length of a fixed format */ -static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size) +static size_t regmap_calc_reg_len(int max_val) { return snprintf(NULL, 0, "%x", max_val); } @@ -173,8 +173,7 @@ static inline void regmap_calc_tot_len(struct regmap *map, { /* Calculate the length of a fixed format */ if (!map->debugfs_tot_len) { - map->debugfs_reg_len = regmap_calc_reg_len(map->max_register, - buf, count); + map->debugfs_reg_len = regmap_calc_reg_len(map->max_register); map->debugfs_val_len = 2 * map->format.val_bytes; map->debugfs_tot_len = map->debugfs_reg_len + map->debugfs_val_len + 3; /* : \n */ @@ -404,7 +403,7 @@ static ssize_t regmap_access_read_file(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - int reg_len, tot_len; + size_t reg_len, tot_len; size_t buf_pos = 0; loff_t p = 0; ssize_t ret; @@ -420,7 +419,7 @@ static ssize_t regmap_access_read_file(struct file *file, return -ENOMEM; /* Calculate the length of a fixed format */ - reg_len = regmap_calc_reg_len(map->max_register, buf, count); + reg_len = regmap_calc_reg_len(map->max_register); tot_len = reg_len + 10; /* ': R W V P\n' */ for (i = 0; i <= map->max_register; i += map->reg_stride) { @@ -437,7 +436,7 @@ static ssize_t regmap_access_read_file(struct file *file, /* Format the register */ snprintf(buf + buf_pos, count - buf_pos, "%.*x: %c %c %c %c\n", - reg_len, i, + (int)reg_len, i, regmap_readable(map, i) ? 'y' : 'n', regmap_writeable(map, i) ? 'y' : 'n', regmap_volatile(map, i) ? 'y' : 'n', diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index afaf562..722e2a9 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -344,8 +344,8 @@ static void regmap_unlock_mutex(void *__map) mutex_unlock(&map->mutex); } +static void regmap_lock_spinlock(void *__map) __acquires(&map->spinlock); static void regmap_lock_spinlock(void *__map) -__acquires(&map->spinlock) { struct regmap *map = __map; unsigned long flags; @@ -354,8 +354,8 @@ __acquires(&map->spinlock) map->spinlock_flags = flags; } +static void regmap_unlock_spinlock(void *__map) __releases(&map->spinlock); static void regmap_unlock_spinlock(void *__map) -__releases(&map->spinlock) { struct regmap *map = __map; spin_unlock_irqrestore(&map->spinlock, map->spinlock_flags); diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c index 8d98a32..61d3165 100644 --- a/drivers/base/syscore.c +++ b/drivers/base/syscore.c @@ -22,7 +22,7 @@ static DEFINE_MUTEX(syscore_ops_lock); void register_syscore_ops(struct syscore_ops *ops) { mutex_lock(&syscore_ops_lock); - list_add_tail(&ops->node, &syscore_ops_list); + pax_list_add_tail((struct list_head *)&ops->node, &syscore_ops_list); mutex_unlock(&syscore_ops_lock); } EXPORT_SYMBOL_GPL(register_syscore_ops); @@ -34,7 +34,7 @@ EXPORT_SYMBOL_GPL(register_syscore_ops); void unregister_syscore_ops(struct syscore_ops *ops) { mutex_lock(&syscore_ops_lock); - list_del(&ops->node); + pax_list_del((struct list_head *)&ops->node); mutex_unlock(&syscore_ops_lock); } EXPORT_SYMBOL_GPL(unregister_syscore_ops); diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 0422c47..b222c7a 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -3024,7 +3024,7 @@ static void start_io(ctlr_info_t *h) while (!list_empty(&h->reqQ)) { c = list_entry(h->reqQ.next, CommandList_struct, list); /* can't do anything if fifo is full */ - if ((h->access.fifo_full(h))) { + if ((h->access->fifo_full(h))) { dev_warn(&h->pdev->dev, "fifo full\n"); break; } @@ -3034,7 +3034,7 @@ static void start_io(ctlr_info_t *h) h->Qdepth--; /* Tell the controller execute command */ - h->access.submit_command(h, c); + h->access->submit_command(h, c); /* Put job onto the completed Q */ addQ(&h->cmpQ, c); @@ -3460,17 +3460,17 @@ startio: static inline unsigned long get_next_completion(ctlr_info_t *h) { - return h->access.command_completed(h); + return h->access->command_completed(h); } static inline int interrupt_pending(ctlr_info_t *h) { - return h->access.intr_pending(h); + return h->access->intr_pending(h); } static inline long interrupt_not_for_us(ctlr_info_t *h) { - return ((h->access.intr_pending(h) == 0) || + return ((h->access->intr_pending(h) == 0) || (h->interrupts_enabled == 0)); } @@ -3503,7 +3503,7 @@ static inline u32 next_command(ctlr_info_t *h) u32 a; if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant))) - return h->access.command_completed(h); + return h->access->command_completed(h); if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) { a = *(h->reply_pool_head); /* Next cmd in ring buffer */ @@ -4060,7 +4060,7 @@ static void cciss_put_controller_into_performant_mode(ctlr_info_t *h) trans_support & CFGTBL_Trans_use_short_tags); /* Change the access methods to the performant access methods */ - h->access = SA5_performant_access; + h->access = &SA5_performant_access; h->transMethod = CFGTBL_Trans_Performant; return; @@ -4334,7 +4334,7 @@ static int cciss_pci_init(ctlr_info_t *h) if (prod_index < 0) return -ENODEV; h->product_name = products[prod_index].product_name; - h->access = *(products[prod_index].access); + h->access = products[prod_index].access; if (cciss_board_disabled(h)) { dev_warn(&h->pdev->dev, "controller appears to be disabled\n"); @@ -5065,7 +5065,7 @@ reinit_after_soft_reset: } /* make sure the board interrupts are off */ - h->access.set_intr_mask(h, CCISS_INTR_OFF); + h->access->set_intr_mask(h, CCISS_INTR_OFF); rc = cciss_request_irq(h, do_cciss_msix_intr, do_cciss_intx); if (rc) goto clean2; @@ -5115,7 +5115,7 @@ reinit_after_soft_reset: * fake ones to scoop up any residual completions. */ spin_lock_irqsave(&h->lock, flags); - h->access.set_intr_mask(h, CCISS_INTR_OFF); + h->access->set_intr_mask(h, CCISS_INTR_OFF); spin_unlock_irqrestore(&h->lock, flags); free_irq(h->intr[h->intr_mode], h); rc = cciss_request_irq(h, cciss_msix_discard_completions, @@ -5135,9 +5135,9 @@ reinit_after_soft_reset: dev_info(&h->pdev->dev, "Board READY.\n"); dev_info(&h->pdev->dev, "Waiting for stale completions to drain.\n"); - h->access.set_intr_mask(h, CCISS_INTR_ON); + h->access->set_intr_mask(h, CCISS_INTR_ON); msleep(10000); - h->access.set_intr_mask(h, CCISS_INTR_OFF); + h->access->set_intr_mask(h, CCISS_INTR_OFF); rc = controller_reset_failed(h->cfgtable); if (rc) @@ -5160,7 +5160,7 @@ reinit_after_soft_reset: cciss_scsi_setup(h); /* Turn the interrupts on so we can service requests */ - h->access.set_intr_mask(h, CCISS_INTR_ON); + h->access->set_intr_mask(h, CCISS_INTR_ON); /* Get the firmware version */ inq_buff = kzalloc(sizeof(InquiryData_struct), GFP_KERNEL); @@ -5232,7 +5232,7 @@ static void cciss_shutdown(struct pci_dev *pdev) kfree(flush_buf); if (return_code != IO_OK) dev_warn(&h->pdev->dev, "Error flushing cache\n"); - h->access.set_intr_mask(h, CCISS_INTR_OFF); + h->access->set_intr_mask(h, CCISS_INTR_OFF); free_irq(h->intr[h->intr_mode], h); } diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 7fda30e..2f27946 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -101,7 +101,7 @@ struct ctlr_info /* information about each logical volume */ drive_info_struct *drv[CISS_MAX_LUN]; - struct access_method access; + struct access_method *access; /* queue and queue Info */ struct list_head reqQ; @@ -402,27 +402,27 @@ static bool SA5_performant_intr_pending(ctlr_info_t *h) } static struct access_method SA5_access = { - SA5_submit_command, - SA5_intr_mask, - SA5_fifo_full, - SA5_intr_pending, - SA5_completed, + .submit_command = SA5_submit_command, + .set_intr_mask = SA5_intr_mask, + .fifo_full = SA5_fifo_full, + .intr_pending = SA5_intr_pending, + .command_completed = SA5_completed, }; static struct access_method SA5B_access = { - SA5_submit_command, - SA5B_intr_mask, - SA5_fifo_full, - SA5B_intr_pending, - SA5_completed, + .submit_command = SA5_submit_command, + .set_intr_mask = SA5B_intr_mask, + .fifo_full = SA5_fifo_full, + .intr_pending = SA5B_intr_pending, + .command_completed = SA5_completed, }; static struct access_method SA5_performant_access = { - SA5_submit_command, - SA5_performant_intr_mask, - SA5_fifo_full, - SA5_performant_intr_pending, - SA5_performant_completed, + .submit_command = SA5_submit_command, + .set_intr_mask = SA5_performant_intr_mask, + .fifo_full = SA5_fifo_full, + .intr_pending = SA5_performant_intr_pending, + .command_completed = SA5_performant_completed, }; struct board_type { diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index f749df9..5f8b9c4 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -404,7 +404,7 @@ static int cpqarray_register_ctlr(int i, struct pci_dev *pdev) if (register_blkdev(COMPAQ_SMART2_MAJOR+i, hba[i]->devname)) { goto Enomem4; } - hba[i]->access.set_intr_mask(hba[i], 0); + hba[i]->access->set_intr_mask(hba[i], 0); if (request_irq(hba[i]->intr, do_ida_intr, IRQF_SHARED, hba[i]->devname, hba[i])) { @@ -459,7 +459,7 @@ static int cpqarray_register_ctlr(int i, struct pci_dev *pdev) add_timer(&hba[i]->timer); /* Enable IRQ now that spinlock and rate limit timer are set up */ - hba[i]->access.set_intr_mask(hba[i], FIFO_NOT_EMPTY); + hba[i]->access->set_intr_mask(hba[i], FIFO_NOT_EMPTY); for(j=0; jproduct_name = products[i].product_name; - c->access = *(products[i].access); + c->access = products[i].access; break; } } @@ -792,7 +792,7 @@ static int cpqarray_eisa_detect(void) hba[ctlr]->intr = intr; sprintf(hba[ctlr]->devname, "ida%d", nr_ctlr); hba[ctlr]->product_name = products[j].product_name; - hba[ctlr]->access = *(products[j].access); + hba[ctlr]->access = products[j].access; hba[ctlr]->ctlr = ctlr; hba[ctlr]->board_id = board_id; hba[ctlr]->pci_dev = NULL; /* not PCI */ @@ -978,7 +978,7 @@ static void start_io(ctlr_info_t *h) while((c = h->reqQ) != NULL) { /* Can't do anything if we're busy */ - if (h->access.fifo_full(h) == 0) + if (h->access->fifo_full(h) == 0) return; /* Get the first entry from the request Q */ @@ -986,7 +986,7 @@ static void start_io(ctlr_info_t *h) h->Qdepth--; /* Tell the controller to do our bidding */ - h->access.submit_command(h, c); + h->access->submit_command(h, c); /* Get onto the completion Q */ addQ(&h->cmpQ, c); @@ -1048,7 +1048,7 @@ static irqreturn_t do_ida_intr(int irq, void *dev_id) unsigned long flags; __u32 a,a1; - istat = h->access.intr_pending(h); + istat = h->access->intr_pending(h); /* Is this interrupt for us? */ if (istat == 0) return IRQ_NONE; @@ -1059,7 +1059,7 @@ static irqreturn_t do_ida_intr(int irq, void *dev_id) */ spin_lock_irqsave(IDA_LOCK(h->ctlr), flags); if (istat & FIFO_NOT_EMPTY) { - while((a = h->access.command_completed(h))) { + while((a = h->access->command_completed(h))) { a1 = a; a &= ~3; if ((c = h->cmpQ) == NULL) { @@ -1448,11 +1448,11 @@ static int sendcmd( /* * Disable interrupt */ - info_p->access.set_intr_mask(info_p, 0); + info_p->access->set_intr_mask(info_p, 0); /* Make sure there is room in the command FIFO */ /* Actually it should be completely empty at this time. */ for (i = 200000; i > 0; i--) { - temp = info_p->access.fifo_full(info_p); + temp = info_p->access->fifo_full(info_p); if (temp != 0) { break; } @@ -1465,7 +1465,7 @@ DBG( /* * Send the cmd */ - info_p->access.submit_command(info_p, c); + info_p->access->submit_command(info_p, c); complete = pollcomplete(ctlr); pci_unmap_single(info_p->pci_dev, (dma_addr_t) c->req.sg[0].addr, @@ -1548,9 +1548,9 @@ static int revalidate_allvol(ctlr_info_t *host) * we check the new geometry. Then turn interrupts back on when * we're done. */ - host->access.set_intr_mask(host, 0); + host->access->set_intr_mask(host, 0); getgeometry(ctlr); - host->access.set_intr_mask(host, FIFO_NOT_EMPTY); + host->access->set_intr_mask(host, FIFO_NOT_EMPTY); for(i=0; i 0; i--) { - done = hba[ctlr]->access.command_completed(hba[ctlr]); + done = hba[ctlr]->access->command_completed(hba[ctlr]); if (done == 0) { udelay(10); /* a short fixed delay */ } else diff --git a/drivers/block/cpqarray.h b/drivers/block/cpqarray.h index be73e9d..7fbf140 100644 --- a/drivers/block/cpqarray.h +++ b/drivers/block/cpqarray.h @@ -99,7 +99,7 @@ struct ctlr_info { drv_info_t drv[NWD]; struct proc_dir_entry *proc; - struct access_method access; + struct access_method *access; cmdlist_t *reqQ; cmdlist_t *cmpQ; diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index e5e0f19..a5dfbd4 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -1027,7 +1027,7 @@ static void bm_page_io_async(struct drbd_bm_aio_ctx *ctx, int page_nr) __must_ho submit_bio(rw, bio); /* this should not count as user activity and cause the * resync to throttle -- see drbd_rs_should_slow_down(). */ - atomic_add(len >> 9, &device->rs_sect_ev); + atomic_add_unchecked(len >> 9, &device->rs_sect_ev); } } diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 015c6e9..8226d6c 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -386,7 +386,7 @@ struct drbd_epoch { struct drbd_connection *connection; struct list_head list; unsigned int barrier_nr; - atomic_t epoch_size; /* increased on every request added. */ + atomic_unchecked_t epoch_size; /* increased on every request added. */ atomic_t active; /* increased on every req. added, and dec on every finished. */ unsigned long flags; }; @@ -947,7 +947,7 @@ struct drbd_device { unsigned int al_tr_number; int al_tr_cycle; wait_queue_head_t seq_wait; - atomic_t packet_seq; + atomic_unchecked_t packet_seq; unsigned int peer_seq; spinlock_t peer_seq_lock; unsigned long comm_bm_set; /* communicated number of set bits. */ @@ -956,8 +956,8 @@ struct drbd_device { struct mutex own_state_mutex; struct mutex *state_mutex; /* either own_state_mutex or first_peer_device(device)->connection->cstate_mutex */ char congestion_reason; /* Why we where congested... */ - atomic_t rs_sect_in; /* for incoming resync data rate, SyncTarget */ - atomic_t rs_sect_ev; /* for submitted resync data rate, both */ + atomic_unchecked_t rs_sect_in; /* for incoming resync data rate, SyncTarget */ + atomic_unchecked_t rs_sect_ev; /* for submitted resync data rate, both */ int rs_last_sect_ev; /* counter to compare with */ int rs_last_events; /* counter of read or write "events" (unit sectors) * on the lower level device when we last looked. */ diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 74d97f4..bb5a486 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1328,7 +1328,7 @@ static int _drbd_send_ack(struct drbd_peer_device *peer_device, enum drbd_packet p->sector = sector; p->block_id = block_id; p->blksize = blksize; - p->seq_num = cpu_to_be32(atomic_inc_return(&peer_device->device->packet_seq)); + p->seq_num = cpu_to_be32(atomic_inc_return_unchecked(&peer_device->device->packet_seq)); return drbd_send_command(peer_device, sock, cmd, sizeof(*p), NULL, 0); } @@ -1634,7 +1634,7 @@ int drbd_send_dblock(struct drbd_peer_device *peer_device, struct drbd_request * return -EIO; p->sector = cpu_to_be64(req->i.sector); p->block_id = (unsigned long)req; - p->seq_num = cpu_to_be32(atomic_inc_return(&device->packet_seq)); + p->seq_num = cpu_to_be32(atomic_inc_return_unchecked(&device->packet_seq)); dp_flags = bio_flags_to_wire(peer_device->connection, req->master_bio->bi_rw); if (device->state.conn >= C_SYNC_SOURCE && device->state.conn <= C_PAUSED_SYNC_T) @@ -1915,8 +1915,8 @@ void drbd_init_set_defaults(struct drbd_device *device) atomic_set(&device->unacked_cnt, 0); atomic_set(&device->local_cnt, 0); atomic_set(&device->pp_in_use_by_net, 0); - atomic_set(&device->rs_sect_in, 0); - atomic_set(&device->rs_sect_ev, 0); + atomic_set_unchecked(&device->rs_sect_in, 0); + atomic_set_unchecked(&device->rs_sect_ev, 0); atomic_set(&device->ap_in_flight, 0); atomic_set(&device->md_io.in_use, 0); @@ -2683,8 +2683,8 @@ void drbd_destroy_connection(struct kref *kref) struct drbd_connection *connection = container_of(kref, struct drbd_connection, kref); struct drbd_resource *resource = connection->resource; - if (atomic_read(&connection->current_epoch->epoch_size) != 0) - drbd_err(connection, "epoch_size:%d\n", atomic_read(&connection->current_epoch->epoch_size)); + if (atomic_read_unchecked(&connection->current_epoch->epoch_size) != 0) + drbd_err(connection, "epoch_size:%d\n", atomic_read_unchecked(&connection->current_epoch->epoch_size)); kfree(connection->current_epoch); idr_destroy(&connection->peer_devices); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index e80cbef..42533f1 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -3637,13 +3637,13 @@ finish: void drbd_bcast_event(struct drbd_device *device, const struct sib_info *sib) { - static atomic_t drbd_genl_seq = ATOMIC_INIT(2); /* two. */ + static atomic_unchecked_t drbd_genl_seq = ATOMIC_INIT(2); /* two. */ struct sk_buff *msg; struct drbd_genlmsghdr *d_out; unsigned seq; int err = -ENOMEM; - seq = atomic_inc_return(&drbd_genl_seq); + seq = atomic_inc_return_unchecked(&drbd_genl_seq); msg = genlmsg_new(NLMSG_GOODSIZE, GFP_NOIO); if (!msg) goto failed; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index c097909..b0dd588 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -870,7 +870,7 @@ int drbd_connected(struct drbd_peer_device *peer_device) struct drbd_device *device = peer_device->device; int err; - atomic_set(&device->packet_seq, 0); + atomic_set_unchecked(&device->packet_seq, 0); device->peer_seq = 0; device->state_mutex = peer_device->connection->agreed_pro_version < 100 ? @@ -1233,7 +1233,7 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_connection *connectio do { next_epoch = NULL; - epoch_size = atomic_read(&epoch->epoch_size); + epoch_size = atomic_read_unchecked(&epoch->epoch_size); switch (ev & ~EV_CLEANUP) { case EV_PUT: @@ -1273,7 +1273,7 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_connection *connectio rv = FE_DESTROYED; } else { epoch->flags = 0; - atomic_set(&epoch->epoch_size, 0); + atomic_set_unchecked(&epoch->epoch_size, 0); /* atomic_set(&epoch->active, 0); is already zero */ if (rv == FE_STILL_LIVE) rv = FE_RECYCLED; @@ -1550,7 +1550,7 @@ static int receive_Barrier(struct drbd_connection *connection, struct packet_inf conn_wait_active_ee_empty(connection); drbd_flush(connection); - if (atomic_read(&connection->current_epoch->epoch_size)) { + if (atomic_read_unchecked(&connection->current_epoch->epoch_size)) { epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO); if (epoch) break; @@ -1564,11 +1564,11 @@ static int receive_Barrier(struct drbd_connection *connection, struct packet_inf } epoch->flags = 0; - atomic_set(&epoch->epoch_size, 0); + atomic_set_unchecked(&epoch->epoch_size, 0); atomic_set(&epoch->active, 0); spin_lock(&connection->epoch_lock); - if (atomic_read(&connection->current_epoch->epoch_size)) { + if (atomic_read_unchecked(&connection->current_epoch->epoch_size)) { list_add(&epoch->list, &connection->current_epoch->list); connection->current_epoch = epoch; connection->epochs++; @@ -1780,7 +1780,9 @@ static int e_end_resync_block(struct drbd_work *w, int unused) } static int recv_resync_read(struct drbd_peer_device *peer_device, sector_t sector, - struct packet_info *pi) __releases(local) + struct packet_info *pi) __releases(local); +static int recv_resync_read(struct drbd_peer_device *peer_device, sector_t sector, + struct packet_info *pi) { struct drbd_device *device = peer_device->device; struct drbd_peer_request *peer_req; @@ -1802,7 +1804,7 @@ static int recv_resync_read(struct drbd_peer_device *peer_device, sector_t secto list_add_tail(&peer_req->w.list, &device->sync_ee); spin_unlock_irq(&device->resource->req_lock); - atomic_add(pi->size >> 9, &device->rs_sect_ev); + atomic_add_unchecked(pi->size >> 9, &device->rs_sect_ev); if (drbd_submit_peer_request(device, peer_req, WRITE, DRBD_FAULT_RS_WR) == 0) return 0; @@ -1900,7 +1902,7 @@ static int receive_RSDataReply(struct drbd_connection *connection, struct packet drbd_send_ack_dp(peer_device, P_NEG_ACK, p, pi->size); } - atomic_add(pi->size >> 9, &device->rs_sect_in); + atomic_add_unchecked(pi->size >> 9, &device->rs_sect_in); return err; } @@ -2290,7 +2292,7 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info * err = wait_for_and_update_peer_seq(peer_device, peer_seq); drbd_send_ack_dp(peer_device, P_NEG_ACK, p, pi->size); - atomic_inc(&connection->current_epoch->epoch_size); + atomic_inc_unchecked(&connection->current_epoch->epoch_size); err2 = drbd_drain_block(peer_device, pi->size); if (!err) err = err2; @@ -2334,7 +2336,7 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info * spin_lock(&connection->epoch_lock); peer_req->epoch = connection->current_epoch; - atomic_inc(&peer_req->epoch->epoch_size); + atomic_inc_unchecked(&peer_req->epoch->epoch_size); atomic_inc(&peer_req->epoch->active); spin_unlock(&connection->epoch_lock); @@ -2479,7 +2481,7 @@ bool drbd_rs_c_min_rate_throttle(struct drbd_device *device) curr_events = (int)part_stat_read(&disk->part0, sectors[0]) + (int)part_stat_read(&disk->part0, sectors[1]) - - atomic_read(&device->rs_sect_ev); + atomic_read_unchecked(&device->rs_sect_ev); if (atomic_read(&device->ap_actlog_cnt) || curr_events - device->rs_last_events > 64) { @@ -2618,7 +2620,7 @@ static int receive_DataRequest(struct drbd_connection *connection, struct packet device->use_csums = true; } else if (pi->cmd == P_OV_REPLY) { /* track progress, we may need to throttle */ - atomic_add(size >> 9, &device->rs_sect_in); + atomic_add_unchecked(size >> 9, &device->rs_sect_in); peer_req->w.cb = w_e_end_ov_reply; dec_rs_pending(device); /* drbd_rs_begin_io done when we sent this request, @@ -2691,7 +2693,7 @@ static int receive_DataRequest(struct drbd_connection *connection, struct packet goto out_free_e; submit_for_resync: - atomic_add(size >> 9, &device->rs_sect_ev); + atomic_add_unchecked(size >> 9, &device->rs_sect_ev); submit: update_receiver_timing_details(connection, drbd_submit_peer_request); @@ -4564,7 +4566,7 @@ struct data_cmd { int expect_payload; size_t pkt_size; int (*fn)(struct drbd_connection *, struct packet_info *); -}; +} __do_const; static struct data_cmd drbd_cmd_handler[] = { [P_DATA] = { 1, sizeof(struct p_data), receive_Data }, @@ -4678,7 +4680,7 @@ static void conn_disconnect(struct drbd_connection *connection) if (!list_empty(&connection->current_epoch->list)) drbd_err(connection, "ASSERTION FAILED: connection->current_epoch->list not empty\n"); /* ok, no more ee's on the fly, it is safe to reset the epoch_size */ - atomic_set(&connection->current_epoch->epoch_size, 0); + atomic_set_unchecked(&connection->current_epoch->epoch_size, 0); connection->send.seen_any_write_yet = false; drbd_info(connection, "Connection closed\n"); @@ -5182,7 +5184,7 @@ static int got_IsInSync(struct drbd_connection *connection, struct packet_info * put_ldev(device); } dec_rs_pending(device); - atomic_add(blksize >> 9, &device->rs_sect_in); + atomic_add_unchecked(blksize >> 9, &device->rs_sect_in); return 0; } @@ -5470,7 +5472,7 @@ static int connection_finish_peer_reqs(struct drbd_connection *connection) struct asender_cmd { size_t pkt_size; int (*fn)(struct drbd_connection *connection, struct packet_info *); -}; +} __do_const; static struct asender_cmd asender_tbl[] = { [P_PING] = { 0, got_Ping }, diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 5578c14..a05f791 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -94,7 +94,8 @@ void drbd_md_endio(struct bio *bio) /* reads on behalf of the partner, * "submitted" by the receiver */ -static void drbd_endio_read_sec_final(struct drbd_peer_request *peer_req) __releases(local) +static void drbd_endio_read_sec_final(struct drbd_peer_request *peer_req) __releases(local); +static void drbd_endio_read_sec_final(struct drbd_peer_request *peer_req) { unsigned long flags = 0; struct drbd_peer_device *peer_device = peer_req->peer_device; @@ -115,7 +116,8 @@ static void drbd_endio_read_sec_final(struct drbd_peer_request *peer_req) __rele /* writes on behalf of the partner, or resync writes, * "submitted" by the receiver, final stage. */ -void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __releases(local) +void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __releases(local); +void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) { unsigned long flags = 0; struct drbd_peer_device *peer_device = peer_req->peer_device; @@ -386,7 +388,7 @@ static int read_for_csum(struct drbd_peer_device *peer_device, sector_t sector, list_add_tail(&peer_req->w.list, &device->read_ee); spin_unlock_irq(&device->resource->req_lock); - atomic_add(size >> 9, &device->rs_sect_ev); + atomic_add_unchecked(size >> 9, &device->rs_sect_ev); if (drbd_submit_peer_request(device, peer_req, READ, DRBD_FAULT_RS_RD) == 0) return 0; @@ -531,7 +533,7 @@ static int drbd_rs_number_requests(struct drbd_device *device) unsigned int sect_in; /* Number of sectors that came in since the last turn */ int number, mxb; - sect_in = atomic_xchg(&device->rs_sect_in, 0); + sect_in = atomic_xchg_unchecked(&device->rs_sect_in, 0); device->rs_in_flight -= sect_in; rcu_read_lock(); @@ -1573,8 +1575,8 @@ void drbd_rs_controller_reset(struct drbd_device *device) struct gendisk *disk = device->ldev->backing_bdev->bd_contains->bd_disk; struct fifo_buffer *plan; - atomic_set(&device->rs_sect_in, 0); - atomic_set(&device->rs_sect_ev, 0); + atomic_set_unchecked(&device->rs_sect_in, 0); + atomic_set_unchecked(&device->rs_sect_ev, 0); device->rs_in_flight = 0; device->rs_last_events = (int)part_stat_read(&disk->part0, sectors[0]) + diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 7be2375..8747286 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -109,7 +109,7 @@ static int pkt_seq_show(struct seq_file *m, void *p); static sector_t get_zone(sector_t sector, struct pktcdvd_device *pd) { - return (sector + pd->offset) & ~(sector_t)(pd->settings.size - 1); + return (sector + pd->offset) & ~(sector_t)(pd->settings.size - 1UL); } /* @@ -1890,7 +1890,7 @@ static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd) return -EROFS; } pd->settings.fp = ti.fp; - pd->offset = (be32_to_cpu(ti.track_start) << 2) & (pd->settings.size - 1); + pd->offset = (be32_to_cpu(ti.track_start) << 2) & (pd->settings.size - 1UL); if (ti.nwa_v) { pd->nwa = be32_to_cpu(ti.next_writable); diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 8630a77..aad8d5aa 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -64,7 +64,7 @@ * If the counter is already at its maximum value returns * -EINVAL without updating it. */ -static int atomic_inc_return_safe(atomic_t *v) +static int __intentional_overflow(-1) atomic_inc_return_safe(atomic_t *v) { unsigned int counter; diff --git a/drivers/block/smart1,2.h b/drivers/block/smart1,2.h index e5565fb..71be10b4 100644 --- a/drivers/block/smart1,2.h +++ b/drivers/block/smart1,2.h @@ -108,11 +108,11 @@ static unsigned long smart4_intr_pending(ctlr_info_t *h) } static struct access_method smart4_access = { - smart4_submit_command, - smart4_intr_mask, - smart4_fifo_full, - smart4_intr_pending, - smart4_completed, + .submit_command = smart4_submit_command, + .set_intr_mask = smart4_intr_mask, + .fifo_full = smart4_fifo_full, + .intr_pending = smart4_intr_pending, + .command_completed = smart4_completed, }; /* @@ -144,11 +144,11 @@ static unsigned long smart2_intr_pending(ctlr_info_t *h) } static struct access_method smart2_access = { - smart2_submit_command, - smart2_intr_mask, - smart2_fifo_full, - smart2_intr_pending, - smart2_completed, + .submit_command = smart2_submit_command, + .set_intr_mask = smart2_intr_mask, + .fifo_full = smart2_fifo_full, + .intr_pending = smart2_intr_pending, + .command_completed = smart2_completed, }; /* @@ -180,11 +180,11 @@ static unsigned long smart2e_intr_pending(ctlr_info_t *h) } static struct access_method smart2e_access = { - smart2e_submit_command, - smart2e_intr_mask, - smart2e_fifo_full, - smart2e_intr_pending, - smart2e_completed, + .submit_command = smart2e_submit_command, + .set_intr_mask = smart2e_intr_mask, + .fifo_full = smart2e_fifo_full, + .intr_pending = smart2e_intr_pending, + .command_completed = smart2e_completed, }; /* @@ -270,9 +270,9 @@ static unsigned long smart1_intr_pending(ctlr_info_t *h) } static struct access_method smart1_access = { - smart1_submit_command, - smart1_intr_mask, - smart1_fifo_full, - smart1_intr_pending, - smart1_completed, + .submit_command = smart1_submit_command, + .set_intr_mask = smart1_intr_mask, + .fifo_full = smart1_fifo_full, + .intr_pending = smart1_intr_pending, + .command_completed = smart1_completed, }; diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c index 7a722df..54b76ab 100644 --- a/drivers/bluetooth/btwilink.c +++ b/drivers/bluetooth/btwilink.c @@ -288,7 +288,7 @@ static int ti_st_send_frame(struct hci_dev *hdev, struct sk_buff *skb) static int bt_ti_probe(struct platform_device *pdev) { - static struct ti_st *hst; + struct ti_st *hst; struct hci_dev *hdev; int err; diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c index 577cc4b..bfe0c2d 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 model->event_attrs); if (!attrs) return -ENOMEM; - pmu_event_attr_group.attrs = attrs; + pax_open_kernel(); + *(struct attribute ***)&pmu_event_attr_group.attrs = attrs; + pax_close_kernel(); } if (model->nformat_attrs) { attrs = alloc_attrs(pdev, model->nformat_attrs, model->format_attrs); if (!attrs) return -ENOMEM; - pmu_format_attr_group.attrs = attrs; + pax_open_kernel(); + *(struct attribute ***)&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; + pax_close_kernel(); return 0; } diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 5d28a45..a538f90 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -610,7 +610,6 @@ int register_cdrom(struct cdrom_device_info *cdi) ENSURE(reset, CDC_RESET); ENSURE(generic_packet, CDC_GENERIC_PACKET); cdi->mc_flags = 0; - cdo->n_minors = 0; cdi->options = CDO_USE_FFLAGS; if (autoclose == 1 && CDROM_CAN(CDC_CLOSE_TRAY)) @@ -630,8 +629,11 @@ int register_cdrom(struct cdrom_device_info *cdi) else cdi->cdda_method = CDDA_OLD; - if (!cdo->generic_packet) - cdo->generic_packet = cdrom_dummy_generic_packet; + if (!cdo->generic_packet) { + pax_open_kernel(); + *(void **)&cdo->generic_packet = cdrom_dummy_generic_packet; + pax_close_kernel(); + } cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); mutex_lock(&cdrom_mutex); @@ -652,7 +654,6 @@ void unregister_cdrom(struct cdrom_device_info *cdi) if (cdi->exit) cdi->exit(cdi); - cdi->ops->n_minors--; cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name); } @@ -2126,7 +2127,7 @@ static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf, */ nr = nframes; do { - cgc.buffer = kmalloc(CD_FRAMESIZE_RAW * nr, GFP_KERNEL); + cgc.buffer = kzalloc(CD_FRAMESIZE_RAW * nr, GFP_KERNEL); if (cgc.buffer) break; @@ -3434,7 +3435,7 @@ static int cdrom_print_info(const char *header, int val, char *info, struct cdrom_device_info *cdi; int ret; - ret = scnprintf(info + *pos, max_size - *pos, header); + ret = scnprintf(info + *pos, max_size - *pos, "%s", header); if (!ret) return 1; diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index 584bc31..e64a12c 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -491,7 +491,6 @@ static struct cdrom_device_ops gdrom_ops = { .audio_ioctl = gdrom_audio_ioctl, .capability = CDC_MULTI_SESSION | CDC_MEDIA_CHANGED | CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R, - .n_minors = 1, }; static int gdrom_bdops_open(struct block_device *bdev, fmode_t mode) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index a043107..1263e4a 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -17,7 +17,8 @@ config DEVMEM config DEVKMEM bool "/dev/kmem virtual device support" - default y + default n + depends on !GRKERNSEC_KMEM help Say Y here if you want to support the /dev/kmem device. The /dev/kmem device is rarely used, but can be used for certain @@ -586,6 +587,7 @@ config DEVPORT bool depends on !M68K depends on ISA || PCI + depends on !GRKERNSEC_KMEM default y source "drivers/s390/char/Kconfig" diff --git a/drivers/char/agp/compat_ioctl.c b/drivers/char/agp/compat_ioctl.c index a48e05b..6bac831 100644 --- a/drivers/char/agp/compat_ioctl.c +++ b/drivers/char/agp/compat_ioctl.c @@ -108,7 +108,7 @@ static int compat_agpioc_reserve_wrap(struct agp_file_private *priv, void __user return -ENOMEM; } - if (copy_from_user(usegment, (void __user *) ureserve.seg_list, + if (copy_from_user(usegment, (void __force_user *) ureserve.seg_list, sizeof(*usegment) * ureserve.seg_count)) { kfree(usegment); kfree(ksegment); diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c index 09f17eb..8531d2f 100644 --- a/drivers/char/agp/frontend.c +++ b/drivers/char/agp/frontend.c @@ -806,7 +806,7 @@ static int agpioc_reserve_wrap(struct agp_file_private *priv, void __user *arg) if (copy_from_user(&reserve, arg, sizeof(struct agp_region))) return -EFAULT; - if ((unsigned) reserve.seg_count >= ~0U/sizeof(struct agp_segment)) + if ((unsigned) reserve.seg_count >= ~0U/sizeof(struct agp_segment_priv)) return -EFAULT; client = agp_find_client_by_pid(reserve.pid); @@ -836,7 +836,7 @@ static int agpioc_reserve_wrap(struct agp_file_private *priv, void __user *arg) if (segment == NULL) return -ENOMEM; - if (copy_from_user(segment, (void __user *) reserve.seg_list, + if (copy_from_user(segment, (void __force_user *) reserve.seg_list, sizeof(struct agp_segment) * reserve.seg_count)) { kfree(segment); return -EFAULT; diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 1341a94..8a45bc2 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1408,8 +1408,8 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, } EXPORT_SYMBOL(intel_gmch_probe); -void intel_gtt_get(u64 *gtt_total, size_t *stolen_size, - phys_addr_t *mappable_base, u64 *mappable_end) +void intel_gtt_get(u64 *gtt_total, u64 *stolen_size, + u64 *mappable_base, u64 *mappable_end) { *gtt_total = intel_private.gtt_total_entries << PAGE_SHIFT; *stolen_size = intel_private.stolen_size; diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c index 4f94375..413694e 100644 --- a/drivers/char/genrtc.c +++ b/drivers/char/genrtc.c @@ -273,6 +273,7 @@ static int gen_rtc_ioctl(struct file *file, switch (cmd) { case RTC_PLL_GET: + memset(&pll, 0, sizeof(pll)); if (get_rtc_pll(&pll)) return -EINVAL; else diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 5c0baa9..44011b1 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -575,7 +575,7 @@ static inline unsigned long hpet_time_div(struct hpets *hpets, } static int -hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, +hpet_ioctl_common(struct hpet_dev *devp, unsigned int cmd, unsigned long arg, struct hpet_info *info) { struct hpet_timer __iomem *timer; diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index e3536da..b1617f0 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -436,7 +436,7 @@ struct ipmi_smi { struct proc_dir_entry *proc_dir; char proc_dir_name[10]; - atomic_t stats[IPMI_NUM_STATS]; + atomic_unchecked_t stats[IPMI_NUM_STATS]; /* * run_to_completion duplicate of smb_info, smi_info @@ -468,9 +468,9 @@ static LIST_HEAD(smi_watchers); static DEFINE_MUTEX(smi_watchers_mutex); #define ipmi_inc_stat(intf, stat) \ - atomic_inc(&(intf)->stats[IPMI_STAT_ ## stat]) + atomic_inc_unchecked(&(intf)->stats[IPMI_STAT_ ## stat]) #define ipmi_get_stat(intf, stat) \ - ((unsigned int) atomic_read(&(intf)->stats[IPMI_STAT_ ## stat])) + ((unsigned int) atomic_read_unchecked(&(intf)->stats[IPMI_STAT_ ## stat])) static char *addr_src_to_str[] = { "invalid", "hotmod", "hardcoded", "SPMI", "ACPI", "SMBIOS", "PCI", @@ -2834,7 +2834,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, INIT_LIST_HEAD(&intf->cmd_rcvrs); init_waitqueue_head(&intf->waitq); for (i = 0; i < IPMI_NUM_STATS; i++) - atomic_set(&intf->stats[i], 0); + atomic_set_unchecked(&intf->stats[i], 0); intf->proc_dir = NULL; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 654f6f3..b36fbf4 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -300,7 +300,7 @@ struct smi_info { unsigned char slave_addr; /* Counters and things for the proc filesystem. */ - atomic_t stats[SI_NUM_STATS]; + atomic_unchecked_t stats[SI_NUM_STATS]; struct task_struct *thread; @@ -309,9 +309,9 @@ struct smi_info { }; #define smi_inc_stat(smi, stat) \ - atomic_inc(&(smi)->stats[SI_STAT_ ## stat]) + atomic_inc_unchecked(&(smi)->stats[SI_STAT_ ## stat]) #define smi_get_stat(smi, stat) \ - ((unsigned int) atomic_read(&(smi)->stats[SI_STAT_ ## stat])) + ((unsigned int) atomic_read_unchecked(&(smi)->stats[SI_STAT_ ## stat])) #define SI_MAX_PARMS 4 @@ -1208,14 +1208,14 @@ static int smi_start_processing(void *send_info, new_smi->intf = intf; - /* Try to claim any interrupts. */ - if (new_smi->irq_setup) - new_smi->irq_setup(new_smi); - /* Set up the timer that drives the interface. */ setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi); smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES); + /* Try to claim any interrupts. */ + if (new_smi->irq_setup) + new_smi->irq_setup(new_smi); + /* * Check if the user forcefully enabled the daemon. */ @@ -3598,7 +3598,7 @@ static int try_smi_init(struct smi_info *new_smi) atomic_set(&new_smi->req_events, 0); new_smi->run_to_completion = false; for (i = 0; i < SI_NUM_STATS; i++) - atomic_set(&new_smi->stats[i], 0); + atomic_set_unchecked(&new_smi->stats[i], 0); new_smi->interrupt_disabled = true; atomic_set(&new_smi->need_watch, 0); diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 6b1721f..fda9398 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,10 @@ #define DEVPORT_MINOR 4 +#if defined(CONFIG_GRKERNSEC) && !defined(CONFIG_GRKERNSEC_NO_RBAC) +extern const struct file_operations grsec_fops; +#endif + static inline unsigned long size_inside_page(unsigned long start, unsigned long size) { @@ -67,9 +72,13 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size) while (cursor < to) { if (!devmem_is_allowed(pfn)) { +#ifdef CONFIG_GRKERNSEC_KMEM + gr_handle_mem_readwrite(from, to); +#else printk(KERN_INFO "Program %s tried to access /dev/mem between %Lx->%Lx.\n", current->comm, from, to); +#endif return 0; } cursor += PAGE_SIZE; @@ -77,6 +86,11 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size) } return 1; } +#elif defined(CONFIG_GRKERNSEC_KMEM) +static inline int range_is_allowed(unsigned long pfn, unsigned long size) +{ + return 0; +} #else static inline int range_is_allowed(unsigned long pfn, unsigned long size) { @@ -124,7 +138,8 @@ static ssize_t read_mem(struct file *file, char __user *buf, #endif while (count > 0) { - unsigned long remaining; + unsigned long remaining = 0; + char *temp; sz = size_inside_page(p, count); @@ -140,7 +155,24 @@ static ssize_t read_mem(struct file *file, char __user *buf, if (!ptr) return -EFAULT; - remaining = copy_to_user(buf, ptr, sz); +#ifdef CONFIG_PAX_USERCOPY + temp = kmalloc(sz, GFP_KERNEL|GFP_USERCOPY); + if (!temp) { + unxlate_dev_mem_ptr(p, ptr); + return -ENOMEM; + } + remaining = probe_kernel_read(temp, ptr, sz); +#else + temp = ptr; +#endif + + if (!remaining) + remaining = copy_to_user(buf, temp, sz); + +#ifdef CONFIG_PAX_USERCOPY + kfree(temp); +#endif + unxlate_dev_mem_ptr(p, ptr); if (remaining) return -EFAULT; @@ -380,9 +412,8 @@ static ssize_t read_kmem(struct file *file, char __user *buf, size_t count, loff_t *ppos) { unsigned long p = *ppos; - ssize_t low_count, read, sz; + ssize_t low_count, read, sz, err = 0; char *kbuf; /* k-addr because vread() takes vmlist_lock rwlock */ - int err = 0; read = 0; if (p < (unsigned long) high_memory) { @@ -404,6 +435,8 @@ static ssize_t read_kmem(struct file *file, char __user *buf, } #endif while (low_count > 0) { + char *temp; + sz = size_inside_page(p, low_count); /* @@ -413,7 +446,23 @@ static ssize_t read_kmem(struct file *file, char __user *buf, */ kbuf = xlate_dev_kmem_ptr((void *)p); - if (copy_to_user(buf, kbuf, sz)) +#ifdef CONFIG_PAX_USERCOPY + temp = kmalloc(sz, GFP_KERNEL|GFP_USERCOPY); + if (!temp) + return -ENOMEM; + err = probe_kernel_read(temp, kbuf, sz); +#else + temp = kbuf; +#endif + + if (!err) + err = copy_to_user(buf, temp, sz); + +#ifdef CONFIG_PAX_USERCOPY + kfree(temp); +#endif + + if (err) return -EFAULT; buf += sz; p += sz; @@ -802,6 +851,9 @@ static const struct memdev { #ifdef CONFIG_PRINTK [11] = { "kmsg", 0644, &kmsg_fops, 0 }, #endif +#if defined(CONFIG_GRKERNSEC) && !defined(CONFIG_GRKERNSEC_NO_RBAC) + [13] = { "grsec",S_IRUSR | S_IWUGO, &grsec_fops, 0 }, +#endif }; static int memory_open(struct inode *inode, struct file *filp) @@ -863,7 +915,7 @@ static int __init chr_dev_init(void) continue; device_create(mem_class, NULL, MKDEV(MEM_MAJOR, minor), - NULL, devlist[minor].name); + NULL, "%s", devlist[minor].name); } return tty_init(); diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index 97c2d8d..aa03a89 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -247,7 +247,7 @@ static ssize_t nvram_read(struct file *file, char __user *buf, spin_unlock_irq(&rtc_lock); - if (copy_to_user(buf, contents, tmp - contents)) + if (tmp - contents > sizeof(contents) || copy_to_user(buf, contents, tmp - contents)) return -EFAULT; *ppos = i; diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 7680d52..073f799e 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2345,7 +2345,7 @@ static void mgslpc_close(struct tty_struct *tty, struct file * filp) if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgslpc_close(%s) entry, count=%d\n", - __FILE__, __LINE__, info->device_name, port->count); + __FILE__, __LINE__, info->device_name, atomic_read(&port->count)); if (tty_port_close_start(port, tty, filp) == 0) goto cleanup; @@ -2363,7 +2363,7 @@ static void mgslpc_close(struct tty_struct *tty, struct file * filp) cleanup: if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgslpc_close(%s) exit, count=%d\n", __FILE__, __LINE__, - tty->driver->name, port->count); + tty->driver->name, atomic_read(&port->count)); } /* Wait until the transmitter is empty. @@ -2505,7 +2505,7 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp) if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgslpc_open(%s), old ref count = %d\n", - __FILE__, __LINE__, tty->driver->name, port->count); + __FILE__, __LINE__, tty->driver->name, atomic_read(&port->count)); /* If port is closing, signal caller to try again */ if (port->flags & ASYNC_CLOSING){ @@ -2525,11 +2525,11 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp) goto cleanup; } spin_lock(&port->lock); - port->count++; + atomic_inc(&port->count); spin_unlock(&port->lock); spin_unlock_irqrestore(&info->netlock, flags); - if (port->count == 1) { + if (atomic_read(&port->count) == 1) { /* 1st open on this device, init hardware */ retval = startup(info, tty); if (retval < 0) @@ -3918,7 +3918,7 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, unsigned short new_crctype; /* return error if TTY interface open */ - if (info->port.count) + if (atomic_read(&info->port.count)) return -EBUSY; switch (encoding) @@ -4022,7 +4022,7 @@ static int hdlcdev_open(struct net_device *dev) /* arbitrate between network and tty opens */ spin_lock_irqsave(&info->netlock, flags); - if (info->port.count != 0 || info->netcount != 0) { + if (atomic_read(&info->port.count) != 0 || info->netcount != 0) { printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name); spin_unlock_irqrestore(&info->netlock, flags); return -EBUSY; @@ -4112,7 +4112,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) printk("%s:hdlcdev_ioctl(%s)\n", __FILE__, dev->name); /* return error if TTY interface open */ - if (info->port.count) + if (atomic_read(&info->port.count)) return -EBUSY; if (cmd != SIOCWANDEV) diff --git a/drivers/char/random.c b/drivers/char/random.c index d0da5d8..739fd3a 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -289,9 +289,6 @@ /* * To allow fractional bits to be tracked, the entropy_count field is * denominated in units of 1/8th bits. - * - * 2*(ENTROPY_SHIFT + log2(poolbits)) must <= 31, or the multiply in - * credit_entropy_bits() needs to be 64 bits wide. */ #define ENTROPY_SHIFT 3 #define ENTROPY_BITS(r) ((r)->entropy_count >> ENTROPY_SHIFT) @@ -442,9 +439,9 @@ struct entropy_store { }; static void push_to_pool(struct work_struct *work); -static __u32 input_pool_data[INPUT_POOL_WORDS]; -static __u32 blocking_pool_data[OUTPUT_POOL_WORDS]; -static __u32 nonblocking_pool_data[OUTPUT_POOL_WORDS]; +static __u32 input_pool_data[INPUT_POOL_WORDS] __latent_entropy; +static __u32 blocking_pool_data[OUTPUT_POOL_WORDS] __latent_entropy; +static __u32 nonblocking_pool_data[OUTPUT_POOL_WORDS] __latent_entropy; static struct entropy_store input_pool = { .poolinfo = &poolinfo_table[0], @@ -654,7 +651,7 @@ retry: /* The +2 corresponds to the /4 in the denominator */ do { - unsigned int anfrac = min(pnfrac, pool_size/2); + u64 anfrac = min(pnfrac, pool_size/2); unsigned int add = ((pool_size - entropy_count)*anfrac*3) >> s; @@ -1227,7 +1224,7 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, extract_buf(r, tmp); i = min_t(int, nbytes, EXTRACT_SIZE); - if (copy_to_user(buf, tmp, i)) { + if (i > sizeof(tmp) || copy_to_user(buf, tmp, i)) { ret = -EFAULT; break; } @@ -1668,7 +1665,7 @@ static char sysctl_bootid[16]; static int proc_do_uuid(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - struct ctl_table fake_table; + ctl_table_no_const fake_table; unsigned char buf[64], tmp_uuid[16], *uuid; uuid = table->data; @@ -1698,7 +1695,7 @@ static int proc_do_uuid(struct ctl_table *table, int write, static int proc_do_entropy(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - struct ctl_table fake_table; + ctl_table_no_const fake_table; int entropy_count; entropy_count = *(int *)table->data >> ENTROPY_SHIFT; diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index e496dae..3db53b6 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -54,6 +54,7 @@ #include #include +#include #include @@ -490,7 +491,7 @@ static struct sonypi_device { spinlock_t fifo_lock; wait_queue_head_t fifo_proc_list; struct fasync_struct *fifo_async; - int open_count; + local_t open_count; int model; struct input_dev *input_jog_dev; struct input_dev *input_key_dev; @@ -892,7 +893,7 @@ static int sonypi_misc_fasync(int fd, struct file *filp, int on) static int sonypi_misc_release(struct inode *inode, struct file *file) { mutex_lock(&sonypi_device.lock); - sonypi_device.open_count--; + local_dec(&sonypi_device.open_count); mutex_unlock(&sonypi_device.lock); return 0; } @@ -901,9 +902,9 @@ static int sonypi_misc_open(struct inode *inode, struct file *file) { mutex_lock(&sonypi_device.lock); /* Flush input queue on first open */ - if (!sonypi_device.open_count) + if (!local_read(&sonypi_device.open_count)) kfifo_reset(&sonypi_device.fifo); - sonypi_device.open_count++; + local_inc(&sonypi_device.open_count); mutex_unlock(&sonypi_device.lock); return 0; @@ -1491,7 +1492,7 @@ static struct platform_driver sonypi_driver = { static struct platform_device *sonypi_platform_device; -static struct dmi_system_id __initdata sonypi_dmi_table[] = { +static const struct dmi_system_id __initconst sonypi_dmi_table[] = { { .ident = "Sony Vaio", .matches = { diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c index 565a947..dcdc06e 100644 --- a/drivers/char/tpm/tpm_acpi.c +++ b/drivers/char/tpm/tpm_acpi.c @@ -98,11 +98,12 @@ int read_log(struct tpm_bios_log *log) virt = acpi_os_map_iomem(start, len); if (!virt) { kfree(log->bios_event_log); + log->bios_event_log = NULL; printk("%s: ERROR - Unable to map memory\n", __func__); return -EIO; } - memcpy_fromio(log->bios_event_log, virt, len); + memcpy_fromio(log->bios_event_log, (const char __force_kernel *)virt, len); acpi_os_unmap_iomem(virt, len); return 0; diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c index 3a56a13..f6570e6 100644 --- a/drivers/char/tpm/tpm_eventlog.c +++ b/drivers/char/tpm/tpm_eventlog.c @@ -95,7 +95,7 @@ static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos) event = addr; if ((event->event_type == 0 && event->event_size == 0) || - ((addr + sizeof(struct tcpa_event) + event->event_size) >= limit)) + (event->event_size >= limit - addr - sizeof(struct tcpa_event))) return NULL; return addr; @@ -120,7 +120,7 @@ static void *tpm_bios_measurements_next(struct seq_file *m, void *v, return NULL; if ((event->event_type == 0 && event->event_size == 0) || - ((v + sizeof(struct tcpa_event) + event->event_size) >= limit)) + (event->event_size >= limit - v - sizeof(struct tcpa_event))) return NULL; (*pos)++; diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index d2406fe..473a5c0 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -685,11 +685,11 @@ static ssize_t fill_readbuf(struct port *port, char __user *out_buf, if (to_user) { ssize_t ret; - ret = copy_to_user(out_buf, buf->buf + buf->offset, out_count); + ret = copy_to_user((char __force_user *)out_buf, buf->buf + buf->offset, out_count); if (ret) return -EFAULT; } else { - memcpy((__force char *)out_buf, buf->buf + buf->offset, + memcpy((__force_kernel char *)out_buf, buf->buf + buf->offset, out_count); } @@ -1164,7 +1164,7 @@ static int get_chars(u32 vtermno, char *buf, int count) /* If we don't have an input queue yet, we can't get input. */ BUG_ON(!port->in_vq); - return fill_readbuf(port, (__force char __user *)buf, count, false); + return fill_readbuf(port, (char __force_user *)buf, count, false); } static void resize_console(struct port *port) diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 4735de0..de4ffc9 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -196,7 +196,7 @@ struct clk *clk_register_composite(struct device *dev, const char *name, struct clk *clk; struct clk_init_data init; struct clk_composite *composite; - struct clk_ops *clk_composite_ops; + clk_ops_no_const *clk_composite_ops; composite = kzalloc(sizeof(*composite), GFP_KERNEL); if (!composite) diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index aa872d2..afeae37 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -261,7 +261,7 @@ struct samsung_gate_clock { #define GATE_DA(_id, dname, cname, pname, o, b, f, gf, a) \ __GATE(_id, dname, cname, pname, o, b, f, gf, a) -#define PNAME(x) static const char *x[] __initdata +#define PNAME(x) static const char * const x[] __initconst /** * 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 --- a/drivers/clk/socfpga/clk-gate.c +++ b/drivers/clk/socfpga/clk-gate.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "clk.h" @@ -169,7 +170,7 @@ static int socfpga_clk_prepare(struct clk_hw *hwclk) return 0; } -static struct clk_ops gateclk_ops = { +static clk_ops_no_const gateclk_ops __read_only = { .prepare = socfpga_clk_prepare, .recalc_rate = socfpga_clk_recalc_rate, .get_parent = socfpga_clk_get_parent, @@ -202,8 +203,10 @@ static void __init __socfpga_gate_init(struct device_node *node, socfpga_clk->hw.reg = clk_mgr_base_addr + clk_gate[0]; socfpga_clk->hw.bit_idx = clk_gate[1]; - 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; + 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 --- a/drivers/clk/socfpga/clk-pll.c +++ b/drivers/clk/socfpga/clk-pll.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "clk.h" @@ -75,7 +76,7 @@ static u8 clk_pll_get_parent(struct clk_hw *hwclk) CLK_MGR_PLL_CLK_SRC_MASK; } -static struct clk_ops clk_pll_ops = { +static clk_ops_no_const clk_pll_ops __read_only = { .recalc_rate = clk_pll_recalc_rate, .get_parent = clk_pll_get_parent, }; @@ -114,8 +115,10 @@ static __init struct clk *__socfpga_pll_init(struct device_node *node, pll_clk->hw.hw.init = &init; pll_clk->hw.bit_idx = SOCFPGA_PLL_EXT_ENA; - 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; + 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 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -25,6 +25,8 @@ #include #include +#include + #include "clock.h" #undef pr_fmt @@ -84,8 +86,10 @@ int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops) } ti_clk_ll_ops = ops; - 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; + pax_close_kernel(); return 0; } diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index 30f5228..c19e7fc 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -178,26 +178,21 @@ static int cn_call_callback(struct sk_buff *skb) * * It checks skb, netlink header and msg sizes, and calls callback helper. */ -static void cn_rx_skb(struct sk_buff *__skb) +static void cn_rx_skb(struct sk_buff *skb) { struct nlmsghdr *nlh; - struct sk_buff *skb; int len, err; - skb = skb_get(__skb); - if (skb->len >= NLMSG_HDRLEN) { nlh = nlmsg_hdr(skb); len = nlmsg_len(nlh); if (len < (int)sizeof(struct cn_msg) || skb->len < nlh->nlmsg_len || - len > CONNECTOR_MAX_MSG_SIZE) { - kfree_skb(skb); + len > CONNECTOR_MAX_MSG_SIZE) return; - } - err = cn_call_callback(skb); + err = cn_call_callback(skb_get(skb)); if (err < 0) kfree_skb(skb); } diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index cec1ee2..d8e33a0 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -687,8 +687,11 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) data->acpi_perf_cpu = cpu; policy->driver_data = data; - if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) - 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; + pax_close_kernel(); + } result = acpi_processor_register_performance(perf, cpu); if (result) @@ -821,7 +824,9 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu); break; 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; + pax_close_kernel(); break; default: break; @@ -916,8 +921,10 @@ static void __init acpi_cpufreq_boost_init(void) if (!msrs) return; - acpi_cpufreq_driver.boost_supported = true; - acpi_cpufreq_driver.boost_enabled = boost_state(0); + pax_open_kernel(); + *(bool *)&acpi_cpufreq_driver.boost_supported = true; + *(bool *)&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 7c0d70e..a09ca84 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -456,7 +456,9 @@ static int dt_cpufreq_probe(struct platform_device *pdev) if (!IS_ERR(cpu_reg)) regulator_put(cpu_reg); - dt_cpufreq_driver.driver_data = dev_get_platdata(&pdev->dev); + pax_open_kernel(); + *(void **)&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 25c4c15..6052159 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2120,7 +2120,7 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor) read_unlock_irqrestore(&cpufreq_driver_lock, flags); mutex_lock(&cpufreq_governor_mutex); - list_del(&governor->governor_list); + pax_list_del(&governor->governor_list); mutex_unlock(&cpufreq_governor_mutex); return; } @@ -2346,7 +2346,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -static struct notifier_block __refdata cpufreq_cpu_notifier = { +static struct notifier_block cpufreq_cpu_notifier = { .notifier_call = cpufreq_cpu_callback, }; @@ -2386,13 +2386,17 @@ int cpufreq_boost_trigger_state(int state) return 0; write_lock_irqsave(&cpufreq_driver_lock, flags); - cpufreq_driver->boost_enabled = state; + pax_open_kernel(); + *(bool *)&cpufreq_driver->boost_enabled = state; + pax_close_kernel(); write_unlock_irqrestore(&cpufreq_driver_lock, flags); ret = cpufreq_driver->set_boost(state); if (ret) { write_lock_irqsave(&cpufreq_driver_lock, flags); - cpufreq_driver->boost_enabled = !state; + pax_open_kernel(); + *(bool *)&cpufreq_driver->boost_enabled = !state; + pax_close_kernel(); write_unlock_irqrestore(&cpufreq_driver_lock, flags); pr_err("%s: Cannot %s BOOST\n", @@ -2422,8 +2426,11 @@ static int create_boost_sysfs_file(void) * Check if driver provides function to enable boost - * if not, use cpufreq_boost_set_sw as default */ - if (!cpufreq_driver->set_boost) - cpufreq_driver->set_boost = cpufreq_boost_set_sw; + if (!cpufreq_driver->set_boost) { + pax_open_kernel(); + *(void **)&cpufreq_driver->set_boost = cpufreq_boost_set_sw; + pax_close_kernel(); + } ret = cpufreq_sysfs_create_file(&boost.attr); if (ret) @@ -2447,7 +2454,9 @@ int cpufreq_enable_boost_support(void) if (cpufreq_boost_supported()) return 0; - cpufreq_driver->boost_supported = true; + pax_open_kernel(); + *(bool *)&cpufreq_driver->boost_supported = true; + pax_close_kernel(); /* This will get removed on driver unregister */ return create_boost_sysfs_file(); @@ -2504,8 +2513,11 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) cpufreq_driver = driver_data; write_unlock_irqrestore(&cpufreq_driver_lock, flags); - if (driver_data->setpolicy) - driver_data->flags |= CPUFREQ_CONST_LOOPS; + if (driver_data->setpolicy) { + pax_open_kernel(); + *(u8 *)&driver_data->flags |= CPUFREQ_CONST_LOOPS; + pax_close_kernel(); + } ret = create_boost_sysfs_file(); if (ret) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 939197f..02cf2e1 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -466,7 +466,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, cs_dbs_info->enable = 1; cs_dbs_info->requested_freq = policy->cur; } else { - struct od_ops *od_ops = cdata->gov_ops; + const struct od_ops *od_ops = cdata->gov_ops; struct od_cpu_dbs_info_s *od_dbs_info = cdata->get_cpu_dbs_info_s(cpu); od_dbs_info->rate_mult = 1; diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 50f1717..7e99891 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -218,7 +218,7 @@ struct common_dbs_data { void (*exit)(struct dbs_data *dbs_data, bool notify); /* Governor specific ops, see below */ - void *gov_ops; + const void *gov_ops; /* * Protects governor's data (struct dbs_data and struct common_dbs_data) @@ -240,7 +240,7 @@ struct od_ops { unsigned int (*powersave_bias_target)(struct cpufreq_policy *policy, unsigned int freq_next, unsigned int relation); void (*freq_increase)(struct cpufreq_policy *policy, unsigned int freq); -}; +} __no_const; static inline int delay_for_sampling_rate(unsigned int sampling_rate) { diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 1fa9088..d05d551 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -517,7 +517,7 @@ static void od_exit(struct dbs_data *dbs_data, bool notify) define_get_cpu_dbs_routines(od_cpu_dbs_info); -static struct od_ops od_ops = { +static struct od_ops od_ops __read_only = { .powersave_bias_init_cpu = ondemand_powersave_bias_init_cpu, .powersave_bias_target = generic_powersave_bias_target, .freq_increase = dbs_freq_increase, @@ -576,14 +576,18 @@ void od_register_powersave_bias_handler(unsigned int (*f) (struct cpufreq_policy *, unsigned int, unsigned int), unsigned int powersave_bias) { - od_ops.powersave_bias_target = f; + pax_open_kernel(); + *(void **)&od_ops.powersave_bias_target = f; + pax_close_kernel(); od_set_powersave_bias(powersave_bias); } EXPORT_SYMBOL_GPL(od_register_powersave_bias_handler); void od_unregister_powersave_bias_handler(void) { - od_ops.powersave_bias_target = generic_powersave_bias_target; + pax_open_kernel(); + *(void **)&od_ops.powersave_bias_target = generic_powersave_bias_target; + pax_close_kernel(); od_set_powersave_bias(0); } EXPORT_SYMBOL_GPL(od_unregister_powersave_bias_handler); diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index aa33b92..42d64c8 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -137,10 +137,10 @@ struct pstate_funcs { struct cpu_defaults { struct pstate_adjust_policy pid_policy; struct pstate_funcs funcs; -}; +} __do_const; static struct pstate_adjust_policy pid_params; -static struct pstate_funcs pstate_funcs; +static struct pstate_funcs *pstate_funcs; static int hwp_active; struct perf_limits { @@ -736,18 +736,18 @@ static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate, bool force) cpu->pstate.current_pstate = pstate; - pstate_funcs.set(cpu, pstate); + pstate_funcs->set(cpu, pstate); } static void intel_pstate_get_cpu_pstates(struct cpudata *cpu) { - cpu->pstate.min_pstate = pstate_funcs.get_min(); - cpu->pstate.max_pstate = pstate_funcs.get_max(); - cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(); - cpu->pstate.scaling = pstate_funcs.get_scaling(); + cpu->pstate.min_pstate = pstate_funcs->get_min(); + cpu->pstate.max_pstate = pstate_funcs->get_max(); + cpu->pstate.turbo_pstate = pstate_funcs->get_turbo(); + cpu->pstate.scaling = pstate_funcs->get_scaling(); - if (pstate_funcs.get_vid) - pstate_funcs.get_vid(cpu); + if (pstate_funcs->get_vid) + pstate_funcs->get_vid(cpu); intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate, false); } @@ -1097,15 +1097,15 @@ static unsigned int force_load; static int intel_pstate_msrs_not_valid(void) { - if (!pstate_funcs.get_max() || - !pstate_funcs.get_min() || - !pstate_funcs.get_turbo()) + if (!pstate_funcs->get_max() || + !pstate_funcs->get_min() || + !pstate_funcs->get_turbo()) return -ENODEV; return 0; } -static void copy_pid_params(struct pstate_adjust_policy *policy) +static void copy_pid_params(const struct pstate_adjust_policy *policy) { pid_params.sample_rate_ms = policy->sample_rate_ms; pid_params.p_gain_pct = policy->p_gain_pct; @@ -1117,12 +1117,7 @@ static void copy_pid_params(struct pstate_adjust_policy *policy) static void copy_cpu_funcs(struct pstate_funcs *funcs) { - pstate_funcs.get_max = funcs->get_max; - pstate_funcs.get_min = funcs->get_min; - pstate_funcs.get_turbo = funcs->get_turbo; - pstate_funcs.get_scaling = funcs->get_scaling; - pstate_funcs.set = funcs->set; - pstate_funcs.get_vid = funcs->get_vid; + pstate_funcs = funcs; } #if IS_ENABLED(CONFIG_ACPI) diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c index 5dd95da..abc3837 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) case 0x0F: /* Core Duo */ case 0x16: /* Celeron Core */ case 0x1C: /* Atom */ - p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; + pax_open_kernel(); + *(u8 *)&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; + pax_close_kernel(); /* fall through */ case 0x09: /* Pentium M (Banias) */ return speedstep_get_frequency(SPEEDSTEP_CPU_PM); @@ -149,7 +153,9 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) /* on P-4s, the TSC runs with constant frequency independent whether * throttling is active or not. */ - p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; + pax_open_kernel(); + *(u8 *)&p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; + pax_close_kernel(); if (speedstep_detect_processor() == SPEEDSTEP_CPU_P4M) { printk(KERN_WARNING PFX "Warning: Pentium 4-M detected. " diff --git a/drivers/cpufreq/sparc-us3-cpufreq.c b/drivers/cpufreq/sparc-us3-cpufreq.c index 9bb42ba..b01b4a2 100644 --- a/drivers/cpufreq/sparc-us3-cpufreq.c +++ b/drivers/cpufreq/sparc-us3-cpufreq.c @@ -18,14 +18,12 @@ #include #include -static struct cpufreq_driver *cpufreq_us3_driver; - struct us3_freq_percpu_info { struct cpufreq_frequency_table table[4]; }; /* Indexed by cpu number. */ -static struct us3_freq_percpu_info *us3_freq_table; +static struct us3_freq_percpu_info us3_freq_table[NR_CPUS]; /* UltraSPARC-III has three dividers: 1, 2, and 32. These are controlled * in the Safari config register. @@ -156,16 +154,27 @@ static int __init us3_freq_cpu_init(struct cpufreq_policy *policy) static int us3_freq_cpu_exit(struct cpufreq_policy *policy) { - if (cpufreq_us3_driver) - us3_freq_target(policy, 0); + us3_freq_target(policy, 0); return 0; } +static int __init us3_freq_init(void); +static void __exit us3_freq_exit(void); + +static struct cpufreq_driver cpufreq_us3_driver = { + .init = us3_freq_cpu_init, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = us3_freq_target, + .get = us3_freq_get, + .exit = us3_freq_cpu_exit, + .name = "UltraSPARC-III", + +}; + static int __init us3_freq_init(void) { unsigned long manuf, impl, ver; - int ret; if (tlb_type != cheetah && tlb_type != cheetah_plus) return -ENODEV; @@ -178,55 +187,15 @@ static int __init us3_freq_init(void) (impl == CHEETAH_IMPL || impl == CHEETAH_PLUS_IMPL || impl == JAGUAR_IMPL || - impl == PANTHER_IMPL)) { - struct cpufreq_driver *driver; - - ret = -ENOMEM; - driver = kzalloc(sizeof(*driver), GFP_KERNEL); - if (!driver) - goto err_out; - - us3_freq_table = kzalloc((NR_CPUS * sizeof(*us3_freq_table)), - GFP_KERNEL); - if (!us3_freq_table) - goto err_out; - - driver->init = us3_freq_cpu_init; - driver->verify = cpufreq_generic_frequency_table_verify; - driver->target_index = us3_freq_target; - driver->get = us3_freq_get; - driver->exit = us3_freq_cpu_exit; - strcpy(driver->name, "UltraSPARC-III"); - - cpufreq_us3_driver = driver; - ret = cpufreq_register_driver(driver); - if (ret) - goto err_out; - - return 0; - -err_out: - if (driver) { - kfree(driver); - cpufreq_us3_driver = NULL; - } - kfree(us3_freq_table); - us3_freq_table = NULL; - return ret; - } + impl == PANTHER_IMPL)) + return cpufreq_register_driver(&cpufreq_us3_driver); return -ENODEV; } static void __exit us3_freq_exit(void) { - if (cpufreq_us3_driver) { - cpufreq_unregister_driver(cpufreq_us3_driver); - kfree(cpufreq_us3_driver); - cpufreq_us3_driver = NULL; - kfree(us3_freq_table); - us3_freq_table = NULL; - } + cpufreq_unregister_driver(&cpufreq_us3_driver); } MODULE_AUTHOR("David S. Miller "); diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c index 7d4a315..21bb886 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) !cpu_has(cpu, X86_FEATURE_EST)) return -ENODEV; - if (cpu_has(cpu, X86_FEATURE_CONSTANT_TSC)) - centrino_driver.flags |= CPUFREQ_CONST_LOOPS; + if (cpu_has(cpu, X86_FEATURE_CONSTANT_TSC)) { + pax_open_kernel(); + *(u8 *)¢rino_driver.flags |= CPUFREQ_CONST_LOOPS; + pax_close_kernel(); + } if (policy->cpu != 0) return -ENODEV; diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index 389ade4..e328b5ce 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -193,7 +193,7 @@ static int poll_idle(struct cpuidle_device *dev, static void poll_idle_init(struct cpuidle_driver *drv) { - struct cpuidle_state *state = &drv->states[0]; + cpuidle_state_no_const *state = &drv->states[0]; snprintf(state->name, CPUIDLE_NAME_LEN, "POLL"); snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE"); diff --git a/drivers/cpuidle/dt_idle_states.c b/drivers/cpuidle/dt_idle_states.c index a5c111b..1113002 100644 --- a/drivers/cpuidle/dt_idle_states.c +++ b/drivers/cpuidle/dt_idle_states.c @@ -21,7 +21,7 @@ #include "dt_idle_states.h" -static int init_state_node(struct cpuidle_state *idle_state, +static int init_state_node(cpuidle_state_no_const *idle_state, const struct of_device_id *matches, struct device_node *state_node) { diff --git a/drivers/cpuidle/governor.c b/drivers/cpuidle/governor.c index fb9f511..213e6cc 100644 --- a/drivers/cpuidle/governor.c +++ b/drivers/cpuidle/governor.c @@ -87,7 +87,7 @@ int cpuidle_register_governor(struct cpuidle_governor *gov) mutex_lock(&cpuidle_lock); if (__cpuidle_find_governor(gov->name) == NULL) { ret = 0; - list_add_tail(&gov->governor_list, &cpuidle_governors); + pax_list_add_tail((struct list_head *)&gov->governor_list, &cpuidle_governors); if (!cpuidle_curr_governor || cpuidle_curr_governor->rating < gov->rating) cpuidle_switch_governor(gov); diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 832a2c3..1794080 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -135,7 +135,7 @@ static struct attribute *cpuidle_switch_attrs[] = { NULL }; -static struct attribute_group cpuidle_attr_group = { +static attribute_group_no_const cpuidle_attr_group = { .attrs = cpuidle_default_attrs, .name = "cpuidle", }; diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c index 8d2a772..33826c9 100644 --- a/drivers/crypto/hifn_795x.c +++ b/drivers/crypto/hifn_795x.c @@ -51,7 +51,7 @@ module_param_string(hifn_pll_ref, hifn_pll_ref, sizeof(hifn_pll_ref), 0444); MODULE_PARM_DESC(hifn_pll_ref, "PLL reference clock (pci[freq] or ext[freq], default ext)"); -static atomic_t hifn_dev_number; +static atomic_unchecked_t hifn_dev_number; #define ACRYPTO_OP_DECRYPT 0 #define ACRYPTO_OP_ENCRYPT 1 @@ -2577,7 +2577,7 @@ static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_out_disable_pci_device; snprintf(name, sizeof(name), "hifn%d", - atomic_inc_return(&hifn_dev_number)-1); + atomic_inc_return_unchecked(&hifn_dev_number)-1); err = pci_request_regions(pdev, name); if (err) diff --git a/drivers/crypto/nx/nx-aes-ccm.c b/drivers/crypto/nx/nx-aes-ccm.c index 73ef499..7038f36 100644 --- a/drivers/crypto/nx/nx-aes-ccm.c +++ b/drivers/crypto/nx/nx-aes-ccm.c @@ -409,7 +409,7 @@ static int ccm_nx_decrypt(struct aead_request *req, processed += to_process; } while (processed < nbytes); - rc = memcmp(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag, + rc = crypto_memneq(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag, authsize) ? -EBADMSG : 0; out: spin_unlock_irqrestore(&nx_ctx->lock, irq_flags); diff --git a/drivers/crypto/nx/nx-aes-gcm.c b/drivers/crypto/nx/nx-aes-gcm.c index eee624f..bf61bed 100644 --- a/drivers/crypto/nx/nx-aes-gcm.c +++ b/drivers/crypto/nx/nx-aes-gcm.c @@ -418,7 +418,7 @@ mac: itag, req->src, req->assoclen + nbytes, crypto_aead_authsize(crypto_aead_reqtfm(req)), SCATTERWALK_FROM_SG); - rc = memcmp(itag, otag, + rc = crypto_memneq(itag, otag, crypto_aead_authsize(crypto_aead_reqtfm(req))) ? -EBADMSG : 0; } diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 3b20a1b..8b327d8 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -1015,7 +1015,7 @@ static void ipsec_esp_decrypt_swauth_done(struct device *dev, } else oicv = (char *)&edesc->link_tbl[0]; - err = memcmp(oicv, icv, authsize) ? -EBADMSG : 0; + err = crypto_memneq(oicv, icv, authsize) ? -EBADMSG : 0; } kfree(edesc); diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index ca848cc..9049c89 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -671,7 +671,7 @@ int devfreq_add_governor(struct devfreq_governor *governor) goto err_out; } - list_add(&governor->node, &devfreq_governor_list); + pax_list_add((struct list_head *)&governor->node, &devfreq_governor_list); list_for_each_entry(devfreq, &devfreq_list, node) { int ret = 0; @@ -759,7 +759,7 @@ int devfreq_remove_governor(struct devfreq_governor *governor) } } - list_del(&governor->node); + pax_list_del((struct list_head *)&governor->node); err_out: mutex_unlock(&devfreq_list_lock); diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c index 10fcaba..326f709 100644 --- a/drivers/dma/sh/shdma-base.c +++ b/drivers/dma/sh/shdma-base.c @@ -227,8 +227,8 @@ static int shdma_alloc_chan_resources(struct dma_chan *chan) schan->slave_id = -EINVAL; } - schan->desc = kcalloc(NR_DESCS_PER_CHANNEL, - sdev->desc_size, GFP_KERNEL); + schan->desc = kcalloc(sdev->desc_size, + NR_DESCS_PER_CHANNEL, GFP_KERNEL); if (!schan->desc) { ret = -ENOMEM; goto edescalloc; diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c index 11707df..2ea96f7 100644 --- a/drivers/dma/sh/shdmac.c +++ b/drivers/dma/sh/shdmac.c @@ -513,7 +513,7 @@ static int sh_dmae_nmi_handler(struct notifier_block *self, return ret; } -static struct notifier_block sh_dmae_nmi_notifier __read_mostly = { +static struct notifier_block sh_dmae_nmi_notifier = { .notifier_call = sh_dmae_nmi_handler, /* Run before NMI debug handler and KGDB */ diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index 592af5f..bb1d583 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -477,9 +477,9 @@ void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev, */ int edac_device_alloc_index(void) { - static atomic_t device_indexes = ATOMIC_INIT(0); + static atomic_unchecked_t device_indexes = ATOMIC_INIT(0); - return atomic_inc_return(&device_indexes) - 1; + return atomic_inc_return_unchecked(&device_indexes) - 1; } EXPORT_SYMBOL_GPL(edac_device_alloc_index); diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 33df7d9..0794989 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -154,7 +154,7 @@ static const char * const edac_caps[] = { struct dev_ch_attribute { struct device_attribute attr; int channel; -}; +} __do_const; #define DEVICE_CHANNEL(_name, _mode, _show, _store, _var) \ static struct dev_ch_attribute dev_attr_legacy_##_name = \ diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c index 2cf44b4d..6dd2dc7 100644 --- a/drivers/edac/edac_pci.c +++ b/drivers/edac/edac_pci.c @@ -29,7 +29,7 @@ static DEFINE_MUTEX(edac_pci_ctls_mutex); static LIST_HEAD(edac_pci_list); -static atomic_t pci_indexes = ATOMIC_INIT(0); +static atomic_unchecked_t pci_indexes = ATOMIC_INIT(0); /* * edac_pci_alloc_ctl_info @@ -315,7 +315,7 @@ EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period); */ int edac_pci_alloc_index(void) { - return atomic_inc_return(&pci_indexes) - 1; + return atomic_inc_return_unchecked(&pci_indexes) - 1; } EXPORT_SYMBOL_GPL(edac_pci_alloc_index); diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index 24d877f..4e30133 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c @@ -23,8 +23,8 @@ static int edac_pci_log_pe = 1; /* log PCI parity errors */ static int edac_pci_log_npe = 1; /* log PCI non-parity error errors */ static int edac_pci_poll_msec = 1000; /* one second workq period */ -static atomic_t pci_parity_count = ATOMIC_INIT(0); -static atomic_t pci_nonparity_count = ATOMIC_INIT(0); +static atomic_unchecked_t pci_parity_count = ATOMIC_INIT(0); +static atomic_unchecked_t pci_nonparity_count = ATOMIC_INIT(0); static struct kobject *edac_pci_top_main_kobj; static atomic_t edac_pci_sysfs_refcount = ATOMIC_INIT(0); @@ -232,7 +232,7 @@ struct edac_pci_dev_attribute { void *value; ssize_t(*show) (void *, char *); ssize_t(*store) (void *, const char *, size_t); -}; +} __do_const; /* Set of show/store abstract level functions for PCI Parity object */ static ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr, @@ -576,7 +576,7 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev) edac_printk(KERN_CRIT, EDAC_PCI, "Signaled System Error on %s\n", pci_name(dev)); - atomic_inc(&pci_nonparity_count); + atomic_inc_unchecked(&pci_nonparity_count); } if (status & (PCI_STATUS_PARITY)) { @@ -584,7 +584,7 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev) "Master Data Parity Error on %s\n", pci_name(dev)); - atomic_inc(&pci_parity_count); + atomic_inc_unchecked(&pci_parity_count); } if (status & (PCI_STATUS_DETECTED_PARITY)) { @@ -592,7 +592,7 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev) "Detected Parity Error on %s\n", pci_name(dev)); - atomic_inc(&pci_parity_count); + atomic_inc_unchecked(&pci_parity_count); } } @@ -615,7 +615,7 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev) edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " "Signaled System Error on %s\n", pci_name(dev)); - atomic_inc(&pci_nonparity_count); + atomic_inc_unchecked(&pci_nonparity_count); } if (status & (PCI_STATUS_PARITY)) { @@ -623,7 +623,7 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev) "Master Data Parity Error on " "%s\n", pci_name(dev)); - atomic_inc(&pci_parity_count); + atomic_inc_unchecked(&pci_parity_count); } if (status & (PCI_STATUS_DETECTED_PARITY)) { @@ -631,7 +631,7 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev) "Detected Parity Error on %s\n", pci_name(dev)); - atomic_inc(&pci_parity_count); + atomic_inc_unchecked(&pci_parity_count); } } } @@ -669,7 +669,7 @@ void edac_pci_do_parity_check(void) if (!check_pci_errors) return; - before_count = atomic_read(&pci_parity_count); + before_count = atomic_read_unchecked(&pci_parity_count); /* scan all PCI devices looking for a Parity Error on devices and * bridges. @@ -681,7 +681,7 @@ void edac_pci_do_parity_check(void) /* Only if operator has selected panic on PCI Error */ if (edac_pci_get_panic_on_pe()) { /* If the count is different 'after' from 'before' */ - if (before_count != atomic_read(&pci_parity_count)) + if (before_count != atomic_read_unchecked(&pci_parity_count)) panic("EDAC: PCI Parity Error"); } } diff --git a/drivers/edac/mce_amd.h b/drivers/edac/mce_amd.h index c2359a1..8bd119d 100644 --- a/drivers/edac/mce_amd.h +++ b/drivers/edac/mce_amd.h @@ -74,7 +74,7 @@ struct amd_decoder_ops { bool (*mc0_mce)(u16, u8); bool (*mc1_mce)(u16, u8); bool (*mc2_mce)(u16, u8); -}; +} __no_const; void amd_report_gart_errors(bool); void amd_register_ecc_decoder(void (*f)(int, struct mce *)); diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 57ea7f4..af06b76 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -528,9 +528,9 @@ void fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver, struct device *device) { - static atomic_t index = ATOMIC_INIT(-1); + static atomic_unchecked_t index = ATOMIC_INIT(-1); - card->index = atomic_inc_return(&index); + card->index = atomic_inc_return_unchecked(&index); card->driver = driver; card->device = device; card->current_tlabel = 0; @@ -680,7 +680,7 @@ EXPORT_SYMBOL_GPL(fw_card_release); void fw_core_remove_card(struct fw_card *card) { - struct fw_card_driver dummy_driver = dummy_driver_template; + fw_card_driver_no_const dummy_driver = dummy_driver_template; card->driver->update_phy_reg(card, 4, PHY_LINK_ACTIVE | PHY_CONTENDER, 0); diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index f9e3aee..269dbdb 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -256,7 +256,7 @@ EXPORT_SYMBOL(fw_device_enable_phys_dma); struct config_rom_attribute { struct device_attribute attr; u32 key; -}; +} __do_const; static ssize_t show_immediate(struct device *dev, struct device_attribute *dattr, char *buf) diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index d6a09b9..18e90dd 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -38,6 +38,7 @@ #include #include #include +#include #include diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index e1480ff6..1a429bd 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -111,6 +111,7 @@ struct fw_card_driver { int (*stop_iso)(struct fw_iso_context *ctx); }; +typedef struct fw_card_driver __no_const fw_card_driver_no_const; void fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver, struct device *device); diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index c2f5117..e36414d 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -2049,10 +2049,12 @@ static void bus_reset_work(struct work_struct *work) be32_to_cpu(ohci->next_header)); } +#ifndef CONFIG_GRKERNSEC if (param_remote_dma) { reg_write(ohci, OHCI1394_PhyReqFilterHiSet, ~0); reg_write(ohci, OHCI1394_PhyReqFilterLoSet, ~0); } +#endif spin_unlock_irq(&ohci->lock); @@ -2584,8 +2586,10 @@ static int ohci_enable_phys_dma(struct fw_card *card, unsigned long flags; int n, ret = 0; +#ifndef CONFIG_GRKERNSEC if (param_remote_dma) return 0; +#endif /* * FIXME: Make sure this bitmask is cleared when we clear the busReset diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c index 94a58a0..f5eba42 100644 --- a/drivers/firmware/dmi-id.c +++ b/drivers/firmware/dmi-id.c @@ -16,7 +16,7 @@ struct dmi_device_attribute{ struct device_attribute dev_attr; int field; -}; +} __do_const; #define to_dmi_dev_attr(_dev_attr) \ container_of(_dev_attr, struct dmi_device_attribute, dev_attr) diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index ac1ce4a..321745e 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -690,14 +690,18 @@ static int __init dmi_init(void) if (!dmi_table) goto err_tables; - 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; + pax_close_kernel(); ret = sysfs_create_bin_file(tables_kobj, &bin_attr_smbios_entry_point); if (ret) goto err_unmap; - 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; + pax_close_kernel(); ret = sysfs_create_bin_file(tables_kobj, &bin_attr_DMI); if (!ret) return 0; diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index d425374..1da1716 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c @@ -44,12 +44,12 @@ static char rcd_decode_str[CPER_REC_LEN]; */ u64 cper_next_record_id(void) { - static atomic64_t seq; + static atomic64_unchecked_t seq; - if (!atomic64_read(&seq)) - atomic64_set(&seq, ((u64)get_seconds()) << 32); + if (!atomic64_read_unchecked(&seq)) + atomic64_set_unchecked(&seq, ((u64)get_seconds()) << 32); - return atomic64_inc_return(&seq); + return atomic64_inc_return_unchecked(&seq); } EXPORT_SYMBOL_GPL(cper_next_record_id); diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index d6144e3..23f9686 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -170,14 +170,16 @@ static struct attribute_group efi_subsys_attr_group = { }; static struct efivars generic_efivars; -static struct efivar_operations generic_ops; +static efivar_operations_no_const generic_ops __read_only; static int generic_ops_register(void) { - generic_ops.get_variable = efi.get_variable; - generic_ops.set_variable = efi.set_variable; - 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.get_next_variable = efi.get_next_variable; + *(void **)&generic_ops.query_variable_store = efi_query_variable_store; + pax_close_kernel(); return efivars_register(&generic_efivars, &generic_ops, efi_kobj); } diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c index 756eca8..2336d08 100644 --- a/drivers/firmware/efi/efivars.c +++ b/drivers/firmware/efi/efivars.c @@ -590,7 +590,7 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var) static int create_efivars_bin_attributes(void) { - struct bin_attribute *attr; + bin_attribute_no_const *attr; int error; /* new_var */ diff --git a/drivers/firmware/efi/runtime-map.c b/drivers/firmware/efi/runtime-map.c index 5c55227..97f4978 100644 --- a/drivers/firmware/efi/runtime-map.c +++ b/drivers/firmware/efi/runtime-map.c @@ -97,7 +97,7 @@ static void map_release(struct kobject *kobj) kfree(entry); } -static struct kobj_type __refdata map_ktype = { +static const struct kobj_type __refconst map_ktype = { .sysfs_ops = &map_attr_ops, .default_attrs = def_attrs, .release = map_release, diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index f1ab05e..ab51228 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -709,7 +709,7 @@ static u32 __init hash_oem_table_id(char s[8]) return local_hash_64(input, 32); } -static struct dmi_system_id gsmi_dmi_table[] __initdata = { +static const struct dmi_system_id gsmi_dmi_table[] __initconst = { { .ident = "Google Board", .matches = { diff --git a/drivers/firmware/google/memconsole.c b/drivers/firmware/google/memconsole.c index 2f569aa..26e4f39 100644 --- a/drivers/firmware/google/memconsole.c +++ b/drivers/firmware/google/memconsole.c @@ -136,7 +136,7 @@ static bool __init found_memconsole(void) return false; } -static struct dmi_system_id memconsole_dmi_table[] __initdata = { +static const struct dmi_system_id memconsole_dmi_table[] __initconst = { { .ident = "Google Board", .matches = { @@ -155,7 +155,10 @@ static int __init memconsole_init(void) if (!found_memconsole()) return -ENODEV; - memconsole_bin_attr.size = memconsole_length; + pax_open_kernel(); + *(size_t *)&memconsole_bin_attr.size = memconsole_length; + pax_close_kernel(); + return sysfs_create_bin_file(firmware_kobj, &memconsole_bin_attr); } diff --git a/drivers/firmware/memmap.c b/drivers/firmware/memmap.c index 5de3ed2..d839c56 100644 --- a/drivers/firmware/memmap.c +++ b/drivers/firmware/memmap.c @@ -124,7 +124,7 @@ static void __meminit release_firmware_map_entry(struct kobject *kobj) kfree(entry); } -static struct kobj_type __refdata memmap_ktype = { +static const struct kobj_type __refconst memmap_ktype = { .release = release_firmware_map_entry, .sysfs_ops = &memmap_attr_ops, .default_attrs = def_attrs, diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 42700f0..3745ec6 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -52,7 +52,7 @@ bool psci_tos_resident_on(int cpu) return cpu == resident_cpu; } -struct psci_operations psci_ops; +struct psci_operations psci_ops __read_only; typedef unsigned long (psci_fn)(unsigned long, unsigned long, unsigned long, unsigned long); diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 5e71538..00b7406 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -441,9 +441,9 @@ static struct irq_chip *davinci_gpio_get_irq_chip(unsigned int irq) return &gpio_unbanked.chip; }; -static struct irq_chip *keystone_gpio_get_irq_chip(unsigned int irq) +static irq_chip_no_const *keystone_gpio_get_irq_chip(unsigned int irq) { - static struct irq_chip gpio_unbanked; + static irq_chip_no_const gpio_unbanked; gpio_unbanked = *irq_get_chip(irq); return &gpio_unbanked; @@ -473,7 +473,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) struct davinci_gpio_regs __iomem *g; struct irq_domain *irq_domain = NULL; const struct of_device_id *match; - struct irq_chip *irq_chip; + irq_chip_no_const *irq_chip; gpio_get_irq_chip_cb_t gpio_get_irq_chip; /* diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index 6bca1e1..ed8b22e 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -274,7 +274,7 @@ static int em_gio_probe(struct platform_device *pdev) struct em_gio_priv *p; struct resource *io[2], *irq[2]; struct gpio_chip *gpio_chip; - struct irq_chip *irq_chip; + irq_chip_no_const *irq_chip; const char *name = dev_name(&pdev->dev); unsigned int ngpios; int ret; diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index 4ba7ed5..1536b5d 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -94,7 +94,7 @@ struct ichx_desc { * this option allows driver caching written output values */ bool use_outlvl_cache; -}; +} __do_const; static struct { spinlock_t lock; diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 5236db1..74e292a 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1072,7 +1072,7 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) writel_relaxed(0, base + bank->regs->ctrl); } -static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) +static int omap_gpio_chip_init(struct gpio_bank *bank, irq_chip_no_const *irqc) { static int gpio; int irq_base = 0; @@ -1157,7 +1157,7 @@ static int omap_gpio_probe(struct platform_device *pdev) const struct omap_gpio_platform_data *pdata; struct resource *res; struct gpio_bank *bank; - struct irq_chip *irqc; + irq_chip_no_const *irqc; int ret; match = of_match_device(of_match_ptr(omap_gpio_match), dev); diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 2a81224..ec01fb3 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -398,7 +398,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) struct gpio_rcar_priv *p; struct resource *io, *irq; struct gpio_chip *gpio_chip; - struct irq_chip *irq_chip; + irq_chip_no_const *irq_chip; struct device *dev = &pdev->dev; const char *name = dev_name(dev); int ret; diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c index c1caa45..f0f97d2 100644 --- a/drivers/gpio/gpio-vr41xx.c +++ b/drivers/gpio/gpio-vr41xx.c @@ -224,7 +224,7 @@ static int giu_get_irq(unsigned int irq) printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n", maskl, pendl, maskh, pendh); - atomic_inc(&irq_err_count); + atomic_inc_unchecked(&irq_err_count); return -EINVAL; } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 5db3445..21414d5 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -572,8 +572,10 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) } if (gpiochip->irqchip) { - 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; + pax_close_kernel(); gpiochip->irqchip = NULL; } } @@ -649,8 +651,10 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, */ if (!irqchip->irq_request_resources && !irqchip->irq_release_resources) { - 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; + pax_close_kernel(); } /* diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c index 8e99514..3d68786 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c @@ -737,44 +737,44 @@ static int amdgpu_cgs_get_firmware_info(void *cgs_device, } static const struct cgs_ops amdgpu_cgs_ops = { - amdgpu_cgs_gpu_mem_info, - amdgpu_cgs_gmap_kmem, - amdgpu_cgs_gunmap_kmem, - amdgpu_cgs_alloc_gpu_mem, - amdgpu_cgs_free_gpu_mem, - amdgpu_cgs_gmap_gpu_mem, - amdgpu_cgs_gunmap_gpu_mem, - amdgpu_cgs_kmap_gpu_mem, - amdgpu_cgs_kunmap_gpu_mem, - amdgpu_cgs_read_register, - amdgpu_cgs_write_register, - amdgpu_cgs_read_ind_register, - amdgpu_cgs_write_ind_register, - amdgpu_cgs_read_pci_config_byte, - amdgpu_cgs_read_pci_config_word, - amdgpu_cgs_read_pci_config_dword, - amdgpu_cgs_write_pci_config_byte, - amdgpu_cgs_write_pci_config_word, - amdgpu_cgs_write_pci_config_dword, - amdgpu_cgs_atom_get_data_table, - amdgpu_cgs_atom_get_cmd_table_revs, - amdgpu_cgs_atom_exec_cmd_table, - amdgpu_cgs_create_pm_request, - amdgpu_cgs_destroy_pm_request, - amdgpu_cgs_set_pm_request, - amdgpu_cgs_pm_request_clock, - amdgpu_cgs_pm_request_engine, - amdgpu_cgs_pm_query_clock_limits, - amdgpu_cgs_set_camera_voltages, - amdgpu_cgs_get_firmware_info, - amdgpu_cgs_set_powergating_state, - amdgpu_cgs_set_clockgating_state + .gpu_mem_info = amdgpu_cgs_gpu_mem_info, + .gmap_kmem = amdgpu_cgs_gmap_kmem, + .gunmap_kmem = amdgpu_cgs_gunmap_kmem, + .alloc_gpu_mem = amdgpu_cgs_alloc_gpu_mem, + .free_gpu_mem = amdgpu_cgs_free_gpu_mem, + .gmap_gpu_mem = amdgpu_cgs_gmap_gpu_mem, + .gunmap_gpu_mem = amdgpu_cgs_gunmap_gpu_mem, + .kmap_gpu_mem = amdgpu_cgs_kmap_gpu_mem, + .kunmap_gpu_mem = amdgpu_cgs_kunmap_gpu_mem, + .read_register = amdgpu_cgs_read_register, + .write_register = amdgpu_cgs_write_register, + .read_ind_register = amdgpu_cgs_read_ind_register, + .write_ind_register = amdgpu_cgs_write_ind_register, + .read_pci_config_byte = amdgpu_cgs_read_pci_config_byte, + .read_pci_config_word = amdgpu_cgs_read_pci_config_word, + .read_pci_config_dword = amdgpu_cgs_read_pci_config_dword, + .write_pci_config_byte = amdgpu_cgs_write_pci_config_byte, + .write_pci_config_word = amdgpu_cgs_write_pci_config_word, + .write_pci_config_dword = amdgpu_cgs_write_pci_config_dword, + .atom_get_data_table = amdgpu_cgs_atom_get_data_table, + .atom_get_cmd_table_revs = amdgpu_cgs_atom_get_cmd_table_revs, + .atom_exec_cmd_table = amdgpu_cgs_atom_exec_cmd_table, + .create_pm_request = amdgpu_cgs_create_pm_request, + .destroy_pm_request = amdgpu_cgs_destroy_pm_request, + .set_pm_request = amdgpu_cgs_set_pm_request, + .pm_request_clock = amdgpu_cgs_pm_request_clock, + .pm_request_engine = amdgpu_cgs_pm_request_engine, + .pm_query_clock_limits = amdgpu_cgs_pm_query_clock_limits, + .set_camera_voltages = amdgpu_cgs_set_camera_voltages, + .get_firmware_info = amdgpu_cgs_get_firmware_info, + .set_powergating_state = amdgpu_cgs_set_powergating_state, + .set_clockgating_state = amdgpu_cgs_set_clockgating_state }; static const struct cgs_os_ops amdgpu_cgs_os_ops = { - amdgpu_cgs_add_irq_source, - amdgpu_cgs_irq_get, - amdgpu_cgs_irq_put + .add_irq_source = amdgpu_cgs_add_irq_source, + .irq_get = amdgpu_cgs_irq_get, + .irq_put = amdgpu_cgs_irq_put }; void *amdgpu_cgs_create_device(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 6068d82..7ecd87c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1074,7 +1074,7 @@ static bool amdgpu_switcheroo_can_switch(struct pci_dev *pdev) * locking inversion with the driver load path. And the access here is * completely racy anyway. So don't bother with locking for now. */ - return dev->open_count == 0; + return local_read(&dev->open_count) == 0; } static const struct vga_switcheroo_client_ops amdgpu_switcheroo_ops = { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index c6a1b4c..32873f8 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -419,7 +419,7 @@ static int kfd_ioctl_set_memory_policy(struct file *filep, (args->alternate_policy == KFD_IOC_CACHE_POLICY_COHERENT) ? cache_policy_coherent : cache_policy_noncoherent; - if (!dev->dqm->ops.set_cache_memory_policy(dev->dqm, + if (!dev->dqm->ops->set_cache_memory_policy(dev->dqm, &pdd->qpd, default_policy, alternate_policy, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 3f95f7c..0a62dad 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -298,7 +298,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, goto device_queue_manager_error; } - if (kfd->dqm->ops.start(kfd->dqm) != 0) { + if (kfd->dqm->ops->start(kfd->dqm) != 0) { dev_err(kfd_device, "Error starting queuen manager for device (%x:%x)\n", kfd->pdev->vendor, kfd->pdev->device); @@ -354,7 +354,7 @@ void kgd2kfd_suspend(struct kfd_dev *kfd) BUG_ON(kfd == NULL); if (kfd->init_complete) { - kfd->dqm->ops.stop(kfd->dqm); + kfd->dqm->ops->stop(kfd->dqm); amd_iommu_set_invalidate_ctx_cb(kfd->pdev, NULL); amd_iommu_set_invalid_ppr_cb(kfd->pdev, NULL); amd_iommu_free_device(kfd->pdev); @@ -377,7 +377,7 @@ int kgd2kfd_resume(struct kfd_dev *kfd) amd_iommu_set_invalidate_ctx_cb(kfd->pdev, iommu_pasid_shutdown_callback); amd_iommu_set_invalid_ppr_cb(kfd->pdev, iommu_invalid_ppr_cb); - kfd->dqm->ops.start(kfd->dqm); + kfd->dqm->ops->start(kfd->dqm); } return 0; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 4bb7f42..320fcac 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -242,7 +242,7 @@ static int create_compute_queue_nocpsch(struct device_queue_manager *dqm, BUG_ON(!dqm || !q || !qpd); - mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); + mqd = dqm->ops->get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); if (mqd == NULL) return -ENOMEM; @@ -288,14 +288,14 @@ static int destroy_queue_nocpsch(struct device_queue_manager *dqm, mutex_lock(&dqm->lock); if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE) { - mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); + mqd = dqm->ops->get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); if (mqd == NULL) { retval = -ENOMEM; goto out; } deallocate_hqd(dqm, q); } else if (q->properties.type == KFD_QUEUE_TYPE_SDMA) { - mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA); + mqd = dqm->ops->get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA); if (mqd == NULL) { retval = -ENOMEM; goto out; @@ -347,7 +347,7 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q) BUG_ON(!dqm || !q || !q->mqd); mutex_lock(&dqm->lock); - mqd = dqm->ops.get_mqd_manager(dqm, + mqd = dqm->ops->get_mqd_manager(dqm, get_mqd_type_from_queue_type(q->properties.type)); if (mqd == NULL) { mutex_unlock(&dqm->lock); @@ -414,7 +414,7 @@ static int register_process_nocpsch(struct device_queue_manager *dqm, mutex_lock(&dqm->lock); list_add(&n->list, &dqm->queues); - retval = dqm->ops_asic_specific.register_process(dqm, qpd); + retval = dqm->ops_asic_specific->register_process(dqm, qpd); dqm->processes_count++; @@ -502,7 +502,7 @@ int init_pipelines(struct device_queue_manager *dqm, memset(hpdptr, 0, CIK_HPD_EOP_BYTES * pipes_num); - mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); + mqd = dqm->ops->get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); if (mqd == NULL) { kfd_gtt_sa_free(dqm->dev, dqm->pipeline_mem); return -ENOMEM; @@ -635,7 +635,7 @@ static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm, struct mqd_manager *mqd; int retval; - mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA); + mqd = dqm->ops->get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA); if (!mqd) return -ENOMEM; @@ -650,7 +650,7 @@ static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm, pr_debug(" sdma queue id: %d\n", q->properties.sdma_queue_id); pr_debug(" sdma engine id: %d\n", q->properties.sdma_engine_id); - dqm->ops_asic_specific.init_sdma_vm(dqm, q, qpd); + dqm->ops_asic_specific->init_sdma_vm(dqm, q, qpd); retval = mqd->init_mqd(mqd, &q->mqd, &q->mqd_mem_obj, &q->gart_mqd_addr, &q->properties); if (retval != 0) { @@ -712,7 +712,7 @@ static int initialize_cpsch(struct device_queue_manager *dqm) dqm->queue_count = dqm->processes_count = 0; dqm->sdma_queue_count = 0; dqm->active_runlist = false; - retval = dqm->ops_asic_specific.initialize(dqm); + retval = dqm->ops_asic_specific->initialize(dqm); if (retval != 0) goto fail_init_pipelines; @@ -879,7 +879,7 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q, if (q->properties.type == KFD_QUEUE_TYPE_SDMA) select_sdma_engine_id(q); - mqd = dqm->ops.get_mqd_manager(dqm, + mqd = dqm->ops->get_mqd_manager(dqm, get_mqd_type_from_queue_type(q->properties.type)); if (mqd == NULL) { @@ -887,7 +887,7 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q, return -ENOMEM; } - dqm->ops_asic_specific.init_sdma_vm(dqm, q, qpd); + dqm->ops_asic_specific->init_sdma_vm(dqm, q, qpd); retval = mqd->init_mqd(mqd, &q->mqd, &q->mqd_mem_obj, &q->gart_mqd_addr, &q->properties); if (retval != 0) @@ -1060,7 +1060,7 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm, } - mqd = dqm->ops.get_mqd_manager(dqm, + mqd = dqm->ops->get_mqd_manager(dqm, get_mqd_type_from_queue_type(q->properties.type)); if (!mqd) { retval = -ENOMEM; @@ -1149,7 +1149,7 @@ static bool set_cache_memory_policy(struct device_queue_manager *dqm, qpd->sh_mem_ape1_limit = limit >> 16; } - retval = dqm->ops_asic_specific.set_cache_memory_policy( + retval = dqm->ops_asic_specific->set_cache_memory_policy( dqm, qpd, default_policy, @@ -1172,6 +1172,36 @@ out: return false; } +static const struct device_queue_manager_ops cp_dqm_ops = { + .create_queue = create_queue_cpsch, + .initialize = initialize_cpsch, + .start = start_cpsch, + .stop = stop_cpsch, + .destroy_queue = destroy_queue_cpsch, + .update_queue = update_queue, + .get_mqd_manager = get_mqd_manager_nocpsch, + .register_process = register_process_nocpsch, + .unregister_process = unregister_process_nocpsch, + .uninitialize = uninitialize_nocpsch, + .create_kernel_queue = create_kernel_queue_cpsch, + .destroy_kernel_queue = destroy_kernel_queue_cpsch, + .set_cache_memory_policy = set_cache_memory_policy, +}; + +static const struct device_queue_manager_ops no_cp_dqm_ops = { + .start = start_nocpsch, + .stop = stop_nocpsch, + .create_queue = create_queue_nocpsch, + .destroy_queue = destroy_queue_nocpsch, + .update_queue = update_queue, + .get_mqd_manager = get_mqd_manager_nocpsch, + .register_process = register_process_nocpsch, + .unregister_process = unregister_process_nocpsch, + .initialize = initialize_nocpsch, + .uninitialize = uninitialize_nocpsch, + .set_cache_memory_policy = set_cache_memory_policy, +}; + struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev) { struct device_queue_manager *dqm; @@ -1189,33 +1219,11 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev) case KFD_SCHED_POLICY_HWS: case KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION: /* initialize dqm for cp scheduling */ - dqm->ops.create_queue = create_queue_cpsch; - dqm->ops.initialize = initialize_cpsch; - dqm->ops.start = start_cpsch; - dqm->ops.stop = stop_cpsch; - dqm->ops.destroy_queue = destroy_queue_cpsch; - dqm->ops.update_queue = update_queue; - dqm->ops.get_mqd_manager = get_mqd_manager_nocpsch; - dqm->ops.register_process = register_process_nocpsch; - dqm->ops.unregister_process = unregister_process_nocpsch; - dqm->ops.uninitialize = uninitialize_nocpsch; - dqm->ops.create_kernel_queue = create_kernel_queue_cpsch; - dqm->ops.destroy_kernel_queue = destroy_kernel_queue_cpsch; - dqm->ops.set_cache_memory_policy = set_cache_memory_policy; + dqm->ops = &cp_dqm_ops; break; case KFD_SCHED_POLICY_NO_HWS: /* initialize dqm for no cp scheduling */ - dqm->ops.start = start_nocpsch; - dqm->ops.stop = stop_nocpsch; - dqm->ops.create_queue = create_queue_nocpsch; - dqm->ops.destroy_queue = destroy_queue_nocpsch; - dqm->ops.update_queue = update_queue; - dqm->ops.get_mqd_manager = get_mqd_manager_nocpsch; - dqm->ops.register_process = register_process_nocpsch; - dqm->ops.unregister_process = unregister_process_nocpsch; - dqm->ops.initialize = initialize_nocpsch; - dqm->ops.uninitialize = uninitialize_nocpsch; - dqm->ops.set_cache_memory_policy = set_cache_memory_policy; + dqm->ops = &no_cp_dqm_ops; break; default: BUG(); @@ -1224,15 +1232,15 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev) switch (dev->device_info->asic_family) { case CHIP_CARRIZO: - device_queue_manager_init_vi(&dqm->ops_asic_specific); + device_queue_manager_init_vi(dqm); break; case CHIP_KAVERI: - device_queue_manager_init_cik(&dqm->ops_asic_specific); + device_queue_manager_init_cik(dqm); break; } - if (dqm->ops.initialize(dqm) != 0) { + if (dqm->ops->initialize(dqm) != 0) { kfree(dqm); return NULL; } @@ -1244,6 +1252,6 @@ void device_queue_manager_uninit(struct device_queue_manager *dqm) { BUG_ON(!dqm); - dqm->ops.uninitialize(dqm); + dqm->ops->uninitialize(dqm); kfree(dqm); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index ec4036a..a7800c0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h @@ -154,8 +154,8 @@ struct device_queue_manager_asic_ops { */ struct device_queue_manager { - struct device_queue_manager_ops ops; - struct device_queue_manager_asic_ops ops_asic_specific; + const struct device_queue_manager_ops *ops; + const struct device_queue_manager_asic_ops *ops_asic_specific; struct mqd_manager *mqds[KFD_MQD_TYPE_MAX]; struct packet_manager packets; @@ -178,8 +178,8 @@ struct device_queue_manager { bool active_runlist; }; -void device_queue_manager_init_cik(struct device_queue_manager_asic_ops *ops); -void device_queue_manager_init_vi(struct device_queue_manager_asic_ops *ops); +void device_queue_manager_init_cik(struct device_queue_manager *dqm); +void device_queue_manager_init_vi(struct device_queue_manager *dqm); void program_sh_mem_settings(struct device_queue_manager *dqm, struct qcm_process_device *qpd); int init_pipelines(struct device_queue_manager *dqm, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c index c6f435a..34fb247 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c @@ -37,12 +37,16 @@ static int initialize_cpsch_cik(struct device_queue_manager *dqm); static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q, struct qcm_process_device *qpd); -void device_queue_manager_init_cik(struct device_queue_manager_asic_ops *ops) +static const struct device_queue_manager_asic_ops cik_dqm_asic_ops = { + .set_cache_memory_policy = set_cache_memory_policy_cik, + .register_process = register_process_cik, + .initialize = initialize_cpsch_cik, + .init_sdma_vm = init_sdma_vm, +}; + +void device_queue_manager_init_cik(struct device_queue_manager *dqm) { - ops->set_cache_memory_policy = set_cache_memory_policy_cik; - ops->register_process = register_process_cik; - ops->initialize = initialize_cpsch_cik; - ops->init_sdma_vm = init_sdma_vm; + dqm->ops_asic_specific = &cik_dqm_asic_ops; } static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c index 7e9cae9..fbe7ba5 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c @@ -39,12 +39,16 @@ static int initialize_cpsch_vi(struct device_queue_manager *dqm); static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q, struct qcm_process_device *qpd); -void device_queue_manager_init_vi(struct device_queue_manager_asic_ops *ops) +static const struct device_queue_manager_asic_ops vi_dqm_asic_ops = { + .set_cache_memory_policy = set_cache_memory_policy_vi, + .register_process = register_process_vi, + .initialize = initialize_cpsch_vi, + .init_sdma_vm = init_sdma_vm, +}; + +void device_queue_manager_init_vi(struct device_queue_manager *dqm) { - ops->set_cache_memory_policy = set_cache_memory_policy_vi; - ops->register_process = register_process_vi; - ops->initialize = initialize_cpsch_vi; - ops->init_sdma_vm = init_sdma_vm; + dqm->ops_asic_specific = &vi_dqm_asic_ops; } static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c b/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c index 7f134aa..cd34d4a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c @@ -50,8 +50,8 @@ static void interrupt_wq(struct work_struct *); int kfd_interrupt_init(struct kfd_dev *kfd) { - void *interrupt_ring = kmalloc_array(KFD_INTERRUPT_RING_SIZE, - kfd->device_info->ih_ring_entry_size, + void *interrupt_ring = kmalloc_array(kfd->device_info->ih_ring_entry_size, + KFD_INTERRUPT_RING_SIZE, GFP_KERNEL); if (!interrupt_ring) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c index 8fa8941..5ae07df 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c @@ -56,7 +56,7 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, switch (type) { case KFD_QUEUE_TYPE_DIQ: case KFD_QUEUE_TYPE_HIQ: - kq->mqd = dev->dqm->ops.get_mqd_manager(dev->dqm, + kq->mqd = dev->dqm->ops->get_mqd_manager(dev->dqm, KFD_MQD_TYPE_HIQ); break; default: diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h index 5940531..a75b0e5 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h @@ -62,7 +62,7 @@ struct kernel_queue_ops { void (*submit_packet)(struct kernel_queue *kq); void (*rollback_packet)(struct kernel_queue *kq); -}; +} __no_const; struct kernel_queue { struct kernel_queue_ops ops; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index 7b69070..d7bd78b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -194,7 +194,7 @@ int pqm_create_queue(struct process_queue_manager *pqm, if (list_empty(&pqm->queues)) { pdd->qpd.pqm = pqm; - dev->dqm->ops.register_process(dev->dqm, &pdd->qpd); + dev->dqm->ops->register_process(dev->dqm, &pdd->qpd); } pqn = kzalloc(sizeof(struct process_queue_node), GFP_KERNEL); @@ -220,7 +220,7 @@ int pqm_create_queue(struct process_queue_manager *pqm, goto err_create_queue; pqn->q = q; pqn->kq = NULL; - retval = dev->dqm->ops.create_queue(dev->dqm, q, &pdd->qpd, + retval = dev->dqm->ops->create_queue(dev->dqm, q, &pdd->qpd, &q->properties.vmid); pr_debug("DQM returned %d for create_queue\n", retval); print_queue(q); @@ -234,7 +234,7 @@ int pqm_create_queue(struct process_queue_manager *pqm, kq->queue->properties.queue_id = *qid; pqn->kq = kq; pqn->q = NULL; - retval = dev->dqm->ops.create_kernel_queue(dev->dqm, + retval = dev->dqm->ops->create_kernel_queue(dev->dqm, kq, &pdd->qpd); break; default: @@ -265,7 +265,7 @@ err_allocate_pqn: /* check if queues list is empty unregister process from device */ clear_bit(*qid, pqm->queue_slot_bitmap); if (list_empty(&pqm->queues)) - dev->dqm->ops.unregister_process(dev->dqm, &pdd->qpd); + dev->dqm->ops->unregister_process(dev->dqm, &pdd->qpd); return retval; } @@ -306,13 +306,13 @@ int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid) if (pqn->kq) { /* destroy kernel queue (DIQ) */ dqm = pqn->kq->dev->dqm; - dqm->ops.destroy_kernel_queue(dqm, pqn->kq, &pdd->qpd); + dqm->ops->destroy_kernel_queue(dqm, pqn->kq, &pdd->qpd); kernel_queue_uninit(pqn->kq); } if (pqn->q) { dqm = pqn->q->device->dqm; - retval = dqm->ops.destroy_queue(dqm, &pdd->qpd, pqn->q); + retval = dqm->ops->destroy_queue(dqm, &pdd->qpd, pqn->q); if (retval != 0) return retval; @@ -324,7 +324,7 @@ int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid) clear_bit(qid, pqm->queue_slot_bitmap); if (list_empty(&pqm->queues)) - dqm->ops.unregister_process(dqm, &pdd->qpd); + dqm->ops->unregister_process(dqm, &pdd->qpd); return retval; } @@ -349,7 +349,7 @@ int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid, pqn->q->properties.queue_percent = p->queue_percent; pqn->q->properties.priority = p->priority; - retval = pqn->q->device->dqm->ops.update_queue(pqn->q->device->dqm, + retval = pqn->q->device->dqm->ops->update_queue(pqn->q->device->dqm, pqn->q); if (retval != 0) return retval; diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 8328e70..fbd9db2 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4058,7 +4058,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, goto done; } - if (copy_to_user(&enum_ptr[copied].name, + if (copy_to_user(enum_ptr[copied].name, &prop_enum->name, DRM_PROP_NAME_LEN)) { ret = -EFAULT; goto done; diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 53d09a1..b55a078 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -433,7 +433,7 @@ void drm_unplug_dev(struct drm_device *dev) drm_device_set_unplugged(dev); - if (dev->open_count == 0) { + if (local_read(&dev->open_count) == 0) { drm_put_dev(dev); } mutex_unlock(&drm_global_mutex); diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index c59ce4d..056d413 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -89,7 +89,7 @@ int drm_open(struct inode *inode, struct file *filp) return PTR_ERR(minor); dev = minor->dev; - if (!dev->open_count++) + if (local_inc_return(&dev->open_count) == 1) need_setup = 1; /* share address_space across all char-devs of a single device */ @@ -106,7 +106,7 @@ int drm_open(struct inode *inode, struct file *filp) return 0; err_undo: - dev->open_count--; + local_dec(&dev->open_count); drm_minor_release(minor); return retcode; } @@ -377,7 +377,7 @@ int drm_release(struct inode *inode, struct file *filp) mutex_lock(&drm_global_mutex); - DRM_DEBUG("open_count = %d\n", dev->open_count); + DRM_DEBUG("open_count = %ld\n", local_read(&dev->open_count)); mutex_lock(&dev->struct_mutex); list_del(&file_priv->lhead); @@ -392,10 +392,10 @@ int drm_release(struct inode *inode, struct file *filp) * Begin inline drm_release */ - DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", + DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %ld\n", task_pid_nr(current), (long)old_encode_dev(file_priv->minor->kdev->devt), - dev->open_count); + local_read(&dev->open_count)); /* if the master has gone away we can't do anything with the lock */ if (file_priv->minor->master) @@ -465,7 +465,7 @@ int drm_release(struct inode *inode, struct file *filp) * End inline drm_release */ - if (!--dev->open_count) { + if (local_dec_and_test(&dev->open_count)) { retcode = drm_lastclose(dev); if (drm_device_is_unplugged(dev)) drm_put_dev(dev); diff --git a/drivers/gpu/drm/drm_global.c b/drivers/gpu/drm/drm_global.c index 3d2e91c..d31c4c9 100644 --- a/drivers/gpu/drm/drm_global.c +++ b/drivers/gpu/drm/drm_global.c @@ -36,7 +36,7 @@ struct drm_global_item { struct mutex mutex; void *object; - int refcount; + atomic_t refcount; }; static struct drm_global_item glob[DRM_GLOBAL_NUM]; @@ -49,7 +49,7 @@ void drm_global_init(void) struct drm_global_item *item = &glob[i]; mutex_init(&item->mutex); item->object = NULL; - item->refcount = 0; + atomic_set(&item->refcount, 0); } } @@ -59,7 +59,7 @@ void drm_global_release(void) for (i = 0; i < DRM_GLOBAL_NUM; ++i) { struct drm_global_item *item = &glob[i]; BUG_ON(item->object != NULL); - BUG_ON(item->refcount != 0); + BUG_ON(atomic_read(&item->refcount) != 0); } } @@ -69,7 +69,7 @@ int drm_global_item_ref(struct drm_global_reference *ref) struct drm_global_item *item = &glob[ref->global_type]; mutex_lock(&item->mutex); - if (item->refcount == 0) { + if (atomic_read(&item->refcount) == 0) { item->object = kzalloc(ref->size, GFP_KERNEL); if (unlikely(item->object == NULL)) { ret = -ENOMEM; @@ -82,7 +82,7 @@ int drm_global_item_ref(struct drm_global_reference *ref) goto out_err; } - ++item->refcount; + atomic_inc(&item->refcount); ref->object = item->object; mutex_unlock(&item->mutex); return 0; @@ -98,9 +98,9 @@ void drm_global_item_unref(struct drm_global_reference *ref) struct drm_global_item *item = &glob[ref->global_type]; mutex_lock(&item->mutex); - BUG_ON(item->refcount == 0); + BUG_ON(atomic_read(&item->refcount) == 0); BUG_ON(ref->object != item->object); - if (--item->refcount == 0) { + if (atomic_dec_and_test(&item->refcount)) { ref->release(ref); item->object = NULL; } diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c index cbb4fc0..5c756cb9 100644 --- a/drivers/gpu/drm/drm_info.c +++ b/drivers/gpu/drm/drm_info.c @@ -77,10 +77,13 @@ int drm_vm_info(struct seq_file *m, void *data) struct drm_local_map *map; struct drm_map_list *r_list; - /* Hardcoded from _DRM_FRAME_BUFFER, - _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and - _DRM_SCATTER_GATHER and _DRM_CONSISTENT */ - const char *types[] = { "FB", "REG", "SHM", "AGP", "SG", "PCI" }; + static const char * const types[] = { + [_DRM_FRAME_BUFFER] = "FB", + [_DRM_REGISTERS] = "REG", + [_DRM_SHM] = "SHM", + [_DRM_AGP] = "AGP", + [_DRM_SCATTER_GATHER] = "SG", + [_DRM_CONSISTENT] = "PCI"}; const char *type; int i; @@ -91,7 +94,7 @@ int drm_vm_info(struct seq_file *m, void *data) map = r_list->map; if (!map) continue; - if (map->type < 0 || map->type > 5) + if (map->type >= ARRAY_SIZE(types)) type = "??"; else type = types[map->type]; diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index ddfa601..be1def0 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -458,7 +458,7 @@ static int compat_drm_infobufs(struct file *file, unsigned int cmd, request = compat_alloc_user_space(nbytes); if (!request) return -EFAULT; - list = (struct drm_buf_desc *) (request + 1); + list = (struct drm_buf_desc __user *) (request + 1); if (__put_user(count, &request->count) || __put_user(list, &request->list)) @@ -519,7 +519,7 @@ static int compat_drm_mapbufs(struct file *file, unsigned int cmd, request = compat_alloc_user_space(nbytes); if (!request) return -EFAULT; - list = (struct drm_buf_pub *) (request + 1); + list = (struct drm_buf_pub __user *) (request + 1); if (__put_user(count, &request->count) || __put_user(list, &request->list)) @@ -1072,7 +1072,7 @@ static int compat_drm_mode_addfb2(struct file *file, unsigned int cmd, return 0; } -static drm_ioctl_compat_t *drm_compat_ioctls[] = { +static drm_ioctl_compat_t drm_compat_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_VERSION32)] = compat_drm_version, [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE32)] = compat_drm_getunique, [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP32)] = compat_drm_getmap, @@ -1119,7 +1119,6 @@ static drm_ioctl_compat_t *drm_compat_ioctls[] = { long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { unsigned int nr = DRM_IOCTL_NR(cmd); - drm_ioctl_compat_t *fn; int ret; /* Assume that ioctls without an explicit compat routine will just @@ -1129,10 +1128,8 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (nr >= ARRAY_SIZE(drm_compat_ioctls)) return drm_ioctl(filp, cmd, arg); - fn = drm_compat_ioctls[nr]; - - if (fn != NULL) - ret = (*fn) (filp, cmd, arg); + if (drm_compat_ioctls[nr] != NULL) + ret = (*drm_compat_ioctls[nr]) (filp, cmd, arg); else ret = drm_ioctl(filp, cmd, arg); diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index d93e737..edb8a4a 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -652,7 +652,7 @@ long drm_ioctl(struct file *filp, struct drm_file *file_priv = filp->private_data; struct drm_device *dev; const struct drm_ioctl_desc *ioctl = NULL; - drm_ioctl_t *func; + drm_ioctl_no_const_t func; unsigned int nr = DRM_IOCTL_NR(cmd); int retcode = -EINVAL; char stack_kdata[128]; diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c index d4813e0..6c1ab4d 100644 --- a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c +++ b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c @@ -825,10 +825,16 @@ void mdfld_dsi_dpi_mode_set(struct drm_encoder *encoder, u32 pipeconf_reg = PIPEACONF; u32 dspcntr_reg = DSPACNTR; - u32 pipeconf = dev_priv->pipeconf[pipe]; - u32 dspcntr = dev_priv->dspcntr[pipe]; + u32 pipeconf; + u32 dspcntr; u32 mipi = MIPI_PORT_EN | PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX; + if (pipe == -1) + return; + + pipeconf = dev_priv->pipeconf[pipe]; + dspcntr = dev_priv->dspcntr[pipe]; + if (pipe) { pipeconf_reg = PIPECCONF; dspcntr_reg = DSPCCNTR; diff --git a/drivers/gpu/drm/i810/i810_drv.h b/drivers/gpu/drm/i810/i810_drv.h index 93ec5dc..82acbaf 100644 --- a/drivers/gpu/drm/i810/i810_drv.h +++ b/drivers/gpu/drm/i810/i810_drv.h @@ -110,8 +110,8 @@ typedef struct drm_i810_private { int page_flipping; wait_queue_head_t irq_queue; - atomic_t irq_received; - atomic_t irq_emitted; + atomic_unchecked_t irq_received; + atomic_unchecked_t irq_emitted; int front_offset; } drm_i810_private_t; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index ab37d11..df030da 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -383,7 +383,7 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev) * locking inversion with the driver load path. And the access here is * completely racy anyway. So don't bother with locking for now. */ - return dev->open_count == 0; + return local_read(&dev->open_count) == 0; } static const struct vga_switcheroo_client_ops i915_switcheroo_ops = { diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index a953d49..bf179e7 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -940,12 +940,12 @@ i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec) static int validate_exec_list(struct drm_device *dev, struct drm_i915_gem_exec_object2 *exec, - int count) + unsigned int count) { unsigned relocs_total = 0; unsigned relocs_max = UINT_MAX / sizeof(struct drm_i915_gem_relocation_entry); unsigned invalid_flags; - int i; + unsigned int i; invalid_flags = __EXEC_OBJECT_UNKNOWN_FLAGS; if (USES_FULL_PPGTT(dev)) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 96054a5..bdd1955 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2408,8 +2408,8 @@ static void chv_setup_private_ppat(struct drm_i915_private *dev_priv) static int gen8_gmch_probe(struct drm_device *dev, u64 *gtt_total, - size_t *stolen, - phys_addr_t *mappable_base, + u64 *stolen, + u64 *mappable_base, u64 *mappable_end) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -2456,8 +2456,8 @@ static int gen8_gmch_probe(struct drm_device *dev, static int gen6_gmch_probe(struct drm_device *dev, u64 *gtt_total, - size_t *stolen, - phys_addr_t *mappable_base, + u64 *stolen, + u64 *mappable_base, u64 *mappable_end) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -2507,8 +2507,8 @@ static void gen6_gmch_remove(struct i915_address_space *vm) static int i915_gmch_probe(struct drm_device *dev, u64 *gtt_total, - size_t *stolen, - phys_addr_t *mappable_base, + u64 *stolen, + u64 *mappable_base, u64 *mappable_end) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -2576,8 +2576,8 @@ int i915_gem_gtt_init(struct drm_device *dev) /* GMADR is the PCI mmio aperture into the global GTT. */ DRM_INFO("Memory usable by graphics device = %lluM\n", gtt->base.total >> 20); - DRM_DEBUG_DRIVER("GMADR size = %lldM\n", gtt->mappable_end >> 20); - DRM_DEBUG_DRIVER("GTT stolen size = %zdM\n", gtt->stolen_size >> 20); + DRM_DEBUG_DRIVER("GMADR size = %lluM\n", gtt->mappable_end >> 20); + DRM_DEBUG_DRIVER("GTT stolen size = %lluM\n", gtt->stolen_size >> 20); #ifdef CONFIG_INTEL_IOMMU if (intel_iommu_gfx_mapped) DRM_INFO("VT-d active for gfx access\n"); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index e1cfa29..0092778 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -317,10 +317,10 @@ struct i915_address_space { struct i915_gtt { struct i915_address_space base; - size_t stolen_size; /* Total size of stolen memory */ + u64 stolen_size; /* Total size of stolen memory */ u64 mappable_end; /* End offset that we can CPU map */ struct io_mapping *mappable; /* Mapping to our CPU mappable region */ - phys_addr_t mappable_base; /* PA of our GMADR */ + u64 mappable_base; /* PA of our GMADR */ /** "Graphics Stolen Memory" holds the global PTEs */ void __iomem *gsm; @@ -331,7 +331,7 @@ struct i915_gtt { /* global gtt ops */ int (*gtt_probe)(struct drm_device *dev, u64 *gtt_total, - size_t *stolen, phys_addr_t *mappable_base, + u64 *stolen, u64 *mappable_base, u64 *mappable_end); }; diff --git a/drivers/gpu/drm/i915/i915_ioc32.c b/drivers/gpu/drm/i915/i915_ioc32.c index 97f3a56..32c712e 100644 --- a/drivers/gpu/drm/i915/i915_ioc32.c +++ b/drivers/gpu/drm/i915/i915_ioc32.c @@ -65,7 +65,7 @@ static int compat_i915_getparam(struct file *file, unsigned int cmd, (unsigned long)request); } -static drm_ioctl_compat_t *i915_compat_ioctls[] = { +static drm_ioctl_compat_t i915_compat_ioctls[] = { [DRM_I915_GETPARAM] = compat_i915_getparam, }; @@ -81,17 +81,13 @@ static drm_ioctl_compat_t *i915_compat_ioctls[] = { long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { unsigned int nr = DRM_IOCTL_NR(cmd); - drm_ioctl_compat_t *fn = NULL; int ret; if (nr < DRM_COMMAND_BASE || nr >= DRM_COMMAND_END) return drm_compat_ioctl(filp, cmd, arg); - if (nr < DRM_COMMAND_BASE + ARRAY_SIZE(i915_compat_ioctls)) - fn = i915_compat_ioctls[nr - DRM_COMMAND_BASE]; - - if (fn != NULL) - ret = (*fn) (filp, cmd, arg); + if (nr < DRM_COMMAND_BASE + ARRAY_SIZE(i915_compat_ioctls) && i915_compat_ioctls[nr - DRM_COMMAND_BASE]) + ret = (*i915_compat_ioctls[nr - DRM_COMMAND_BASE])(filp, cmd, arg); else ret = drm_ioctl(filp, cmd, arg); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b2270d5..e5c48fe 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14594,13 +14594,13 @@ struct intel_quirk { int subsystem_vendor; int subsystem_device; void (*hook)(struct drm_device *dev); -}; +} __do_const; /* 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)[]; -}; +} __do_const; static int intel_dmi_reverse_brightness(const struct dmi_system_id *id) { @@ -14608,18 +14608,20 @@ static int intel_dmi_reverse_brightness(const struct dmi_system_id *id) return 1; } -static const struct intel_dmi_quirk intel_dmi_quirks[] = { +static const struct dmi_system_id intel_dmi_quirks_table[] = { { - .dmi_id_list = &(const struct dmi_system_id[]) { - { - .callback = intel_dmi_reverse_brightness, - .ident = "NCR Corporation", - .matches = {DMI_MATCH(DMI_SYS_VENDOR, "NCR Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, ""), - }, - }, - { } /* terminating entry */ + .callback = intel_dmi_reverse_brightness, + .ident = "NCR Corporation", + .matches = {DMI_MATCH(DMI_SYS_VENDOR, "NCR Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, ""), }, + }, + { } /* terminating entry */ +}; + +static const struct intel_dmi_quirk intel_dmi_quirks[] = { + { + .dmi_id_list = &intel_dmi_quirks_table, .hook = quirk_invert_brightness, }, }; diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 74f505b..21f6914 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -355,7 +355,7 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, if (imxdrm->pipes >= MAX_CRTC) return -EINVAL; - if (imxdrm->drm->open_count) + if (local_read(&imxdrm->drm->open_count)) return -EBUSY; imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL); diff --git a/drivers/gpu/drm/mga/mga_drv.h b/drivers/gpu/drm/mga/mga_drv.h index b4a20149..219ab78 100644 --- a/drivers/gpu/drm/mga/mga_drv.h +++ b/drivers/gpu/drm/mga/mga_drv.h @@ -122,9 +122,9 @@ typedef struct drm_mga_private { u32 clear_cmd; u32 maccess; - atomic_t vbl_received; /**< Number of vblanks received. */ + atomic_unchecked_t vbl_received; /**< Number of vblanks received. */ wait_queue_head_t fence_queue; - atomic_t last_fence_retired; + atomic_unchecked_t last_fence_retired; u32 next_fence_to_post; unsigned int fb_cpp; diff --git a/drivers/gpu/drm/mga/mga_ioc32.c b/drivers/gpu/drm/mga/mga_ioc32.c index 729bfd5..14bae78 100644 --- a/drivers/gpu/drm/mga/mga_ioc32.c +++ b/drivers/gpu/drm/mga/mga_ioc32.c @@ -190,7 +190,7 @@ static int compat_mga_dma_bootstrap(struct file *file, unsigned int cmd, return 0; } -drm_ioctl_compat_t *mga_compat_ioctls[] = { +drm_ioctl_compat_t mga_compat_ioctls[] = { [DRM_MGA_INIT] = compat_mga_init, [DRM_MGA_GETPARAM] = compat_mga_getparam, [DRM_MGA_DMA_BOOTSTRAP] = compat_mga_dma_bootstrap, @@ -208,17 +208,13 @@ drm_ioctl_compat_t *mga_compat_ioctls[] = { long mga_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { unsigned int nr = DRM_IOCTL_NR(cmd); - drm_ioctl_compat_t *fn = NULL; int ret; if (nr < DRM_COMMAND_BASE) return drm_compat_ioctl(filp, cmd, arg); - if (nr < DRM_COMMAND_BASE + ARRAY_SIZE(mga_compat_ioctls)) - fn = mga_compat_ioctls[nr - DRM_COMMAND_BASE]; - - if (fn != NULL) - ret = (*fn) (filp, cmd, arg); + if (nr < DRM_COMMAND_BASE + ARRAY_SIZE(mga_compat_ioctls) && mga_compat_ioctls[nr - DRM_COMMAND_BASE]) + ret = (*mga_compat_ioctls[nr - DRM_COMMAND_BASE]) (filp, cmd, arg); else ret = drm_ioctl(filp, cmd, arg); diff --git a/drivers/gpu/drm/mga/mga_irq.c b/drivers/gpu/drm/mga/mga_irq.c index 1b071b8..de8601a 100644 --- a/drivers/gpu/drm/mga/mga_irq.c +++ b/drivers/gpu/drm/mga/mga_irq.c @@ -43,7 +43,7 @@ u32 mga_get_vblank_counter(struct drm_device *dev, int crtc) if (crtc != 0) return 0; - return atomic_read(&dev_priv->vbl_received); + return atomic_read_unchecked(&dev_priv->vbl_received); } @@ -59,7 +59,7 @@ irqreturn_t mga_driver_irq_handler(int irq, void *arg) /* VBLANK interrupt */ if (status & MGA_VLINEPEN) { MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR); - atomic_inc(&dev_priv->vbl_received); + atomic_inc_unchecked(&dev_priv->vbl_received); drm_handle_vblank(dev, 0); handled = 1; } @@ -78,7 +78,7 @@ irqreturn_t mga_driver_irq_handler(int irq, void *arg) if ((prim_start & ~0x03) != (prim_end & ~0x03)) MGA_WRITE(MGA_PRIMEND, prim_end); - atomic_inc(&dev_priv->last_fence_retired); + atomic_inc_unchecked(&dev_priv->last_fence_retired); wake_up(&dev_priv->fence_queue); handled = 1; } @@ -129,7 +129,7 @@ int mga_driver_fence_wait(struct drm_device *dev, unsigned int *sequence) * using fences. */ DRM_WAIT_ON(ret, dev_priv->fence_queue, 3 * HZ, - (((cur_fence = atomic_read(&dev_priv->last_fence_retired)) + (((cur_fence = atomic_read_unchecked(&dev_priv->last_fence_retired)) - *sequence) <= (1 << 23))); *sequence = cur_fence; diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 4dca65a..3486961 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -964,7 +964,7 @@ static int parse_bit_tmds_tbl_entry(struct drm_device *dev, struct nvbios *bios, struct bit_table { const char id; int (* const parse_fn)(struct drm_device *, struct nvbios *, struct bit_entry *); -}; +} __no_const; #define BIT_TABLE(id, funcid) ((struct bit_table){ id, parse_bit_##funcid##_tbl_entry }) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index 3c902c2..1b2d658 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h @@ -125,7 +125,6 @@ struct nouveau_drm { struct drm_global_reference mem_global_ref; struct ttm_bo_global_ref bo_global_ref; struct ttm_bo_device bdev; - atomic_t validate_sequence; int (*move)(struct nouveau_channel *, struct ttm_buffer_object *, struct ttm_mem_reg *, struct ttm_mem_reg *); diff --git a/drivers/gpu/drm/nouveau/nouveau_ioc32.c b/drivers/gpu/drm/nouveau/nouveau_ioc32.c index 462679a..88e32a7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ioc32.c +++ b/drivers/gpu/drm/nouveau/nouveau_ioc32.c @@ -50,7 +50,7 @@ long nouveau_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { unsigned int nr = DRM_IOCTL_NR(cmd); - drm_ioctl_compat_t *fn = NULL; + drm_ioctl_compat_t fn = NULL; int ret; if (nr < DRM_COMMAND_BASE) diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index 3f0fb55..ad5fa4a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -104,10 +104,10 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man, } const struct ttm_mem_type_manager_func nouveau_vram_manager = { - nouveau_vram_manager_init, - nouveau_vram_manager_fini, - nouveau_vram_manager_new, - nouveau_vram_manager_del, + .init = nouveau_vram_manager_init, + .takedown = nouveau_vram_manager_fini, + .get_node = nouveau_vram_manager_new, + .put_node = nouveau_vram_manager_del, }; static int @@ -180,11 +180,11 @@ nouveau_gart_manager_debug(struct ttm_mem_type_manager *man, const char *prefix) } const struct ttm_mem_type_manager_func nouveau_gart_manager = { - nouveau_gart_manager_init, - nouveau_gart_manager_fini, - nouveau_gart_manager_new, - nouveau_gart_manager_del, - nouveau_gart_manager_debug + .init = nouveau_gart_manager_init, + .takedown = nouveau_gart_manager_fini, + .get_node = nouveau_gart_manager_new, + .put_node = nouveau_gart_manager_del, + .debug = nouveau_gart_manager_debug }; /*XXX*/ @@ -253,11 +253,11 @@ nv04_gart_manager_debug(struct ttm_mem_type_manager *man, const char *prefix) } const struct ttm_mem_type_manager_func nv04_gart_manager = { - nv04_gart_manager_init, - nv04_gart_manager_fini, - nv04_gart_manager_new, - nv04_gart_manager_del, - nv04_gart_manager_debug + .init = nv04_gart_manager_init, + .takedown = nv04_gart_manager_fini, + .get_node = nv04_gart_manager_new, + .put_node = nv04_gart_manager_del, + .debug = nv04_gart_manager_debug }; int diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c index af89c36..83ef136 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vga.c +++ b/drivers/gpu/drm/nouveau/nouveau_vga.c @@ -73,7 +73,7 @@ nouveau_switcheroo_can_switch(struct pci_dev *pdev) * locking inversion with the driver load path. And the access here is * completely racy anyway. So don't bother with locking for now. */ - return dev->open_count == 0; + return local_read(&dev->open_count) == 0; } static const struct vga_switcheroo_client_ops diff --git a/drivers/gpu/drm/omapdrm/Makefile b/drivers/gpu/drm/omapdrm/Makefile index 778372b..4b81cb4 100644 --- a/drivers/gpu/drm/omapdrm/Makefile +++ b/drivers/gpu/drm/omapdrm/Makefile @@ -3,7 +3,7 @@ # Direct Rendering Infrastructure (DRI) # -ccflags-y := -Iinclude/drm -Werror +ccflags-y := -Iinclude/drm omapdrm-y := omap_drv.o \ omap_irq.o \ omap_debugfs.o \ diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c index fdc1833..f307630 100644 --- a/drivers/gpu/drm/qxl/qxl_cmd.c +++ b/drivers/gpu/drm/qxl/qxl_cmd.c @@ -285,27 +285,27 @@ static int wait_for_io_cmd_user(struct qxl_device *qdev, uint8_t val, long port, int ret; mutex_lock(&qdev->async_io_mutex); - irq_num = atomic_read(&qdev->irq_received_io_cmd); + irq_num = atomic_read_unchecked(&qdev->irq_received_io_cmd); if (qdev->last_sent_io_cmd > irq_num) { if (intr) ret = wait_event_interruptible_timeout(qdev->io_cmd_event, - atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); + atomic_read_unchecked(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); else ret = wait_event_timeout(qdev->io_cmd_event, - atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); + atomic_read_unchecked(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); /* 0 is timeout, just bail the "hw" has gone away */ if (ret <= 0) goto out; - irq_num = atomic_read(&qdev->irq_received_io_cmd); + irq_num = atomic_read_unchecked(&qdev->irq_received_io_cmd); } outb(val, addr); qdev->last_sent_io_cmd = irq_num + 1; if (intr) ret = wait_event_interruptible_timeout(qdev->io_cmd_event, - atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); + atomic_read_unchecked(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); else ret = wait_event_timeout(qdev->io_cmd_event, - atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); + atomic_read_unchecked(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); out: if (ret > 0) ret = 0; diff --git a/drivers/gpu/drm/qxl/qxl_debugfs.c b/drivers/gpu/drm/qxl/qxl_debugfs.c index 6911b8c..89d6867 100644 --- a/drivers/gpu/drm/qxl/qxl_debugfs.c +++ b/drivers/gpu/drm/qxl/qxl_debugfs.c @@ -42,10 +42,10 @@ qxl_debugfs_irq_received(struct seq_file *m, void *data) struct drm_info_node *node = (struct drm_info_node *) m->private; struct qxl_device *qdev = node->minor->dev->dev_private; - seq_printf(m, "%d\n", atomic_read(&qdev->irq_received)); - seq_printf(m, "%d\n", atomic_read(&qdev->irq_received_display)); - seq_printf(m, "%d\n", atomic_read(&qdev->irq_received_cursor)); - seq_printf(m, "%d\n", atomic_read(&qdev->irq_received_io_cmd)); + seq_printf(m, "%d\n", atomic_read_unchecked(&qdev->irq_received)); + seq_printf(m, "%d\n", atomic_read_unchecked(&qdev->irq_received_display)); + seq_printf(m, "%d\n", atomic_read_unchecked(&qdev->irq_received_cursor)); + seq_printf(m, "%d\n", atomic_read_unchecked(&qdev->irq_received_io_cmd)); seq_printf(m, "%d\n", qdev->irq_received_error); return 0; } diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 01a8694..584fb48 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -290,10 +290,10 @@ struct qxl_device { unsigned int last_sent_io_cmd; /* interrupt handling */ - atomic_t irq_received; - atomic_t irq_received_display; - atomic_t irq_received_cursor; - atomic_t irq_received_io_cmd; + atomic_unchecked_t irq_received; + atomic_unchecked_t irq_received_display; + atomic_unchecked_t irq_received_cursor; + atomic_unchecked_t irq_received_io_cmd; unsigned irq_received_error; wait_queue_head_t display_event; wait_queue_head_t cursor_event; diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c index bda5c5f..140ac46 100644 --- a/drivers/gpu/drm/qxl/qxl_ioctl.c +++ b/drivers/gpu/drm/qxl/qxl_ioctl.c @@ -183,7 +183,7 @@ static int qxl_process_single_command(struct qxl_device *qdev, /* TODO copy slow path code from i915 */ fb_cmd = qxl_bo_kmap_atomic_page(qdev, cmd_bo, (release->release_offset & PAGE_SIZE)); - unwritten = __copy_from_user_inatomic_nocache(fb_cmd + sizeof(union qxl_release_info) + (release->release_offset & ~PAGE_SIZE), (void *)(unsigned long)cmd->command, cmd->command_size); + unwritten = __copy_from_user_inatomic_nocache(fb_cmd + sizeof(union qxl_release_info) + (release->release_offset & ~PAGE_SIZE), (void __force_user *)(unsigned long)cmd->command, cmd->command_size); { struct qxl_drawable *draw = fb_cmd; @@ -203,7 +203,7 @@ static int qxl_process_single_command(struct qxl_device *qdev, struct drm_qxl_reloc reloc; if (copy_from_user(&reloc, - &((struct drm_qxl_reloc *)(uintptr_t)cmd->relocs)[i], + &((struct drm_qxl_reloc __force_user *)(uintptr_t)cmd->relocs)[i], sizeof(reloc))) { ret = -EFAULT; goto out_free_bos; @@ -282,10 +282,10 @@ static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data, for (cmd_num = 0; cmd_num < execbuffer->commands_num; ++cmd_num) { - struct drm_qxl_command *commands = - (struct drm_qxl_command *)(uintptr_t)execbuffer->commands; + struct drm_qxl_command __user *commands = + (struct drm_qxl_command __user *)(uintptr_t)execbuffer->commands; - if (copy_from_user(&user_cmd, &commands[cmd_num], + if (copy_from_user(&user_cmd, (struct drm_qxl_command __force_user *)&commands[cmd_num], sizeof(user_cmd))) return -EFAULT; diff --git a/drivers/gpu/drm/qxl/qxl_irq.c b/drivers/gpu/drm/qxl/qxl_irq.c index 0bf1e20..42a7310 100644 --- a/drivers/gpu/drm/qxl/qxl_irq.c +++ b/drivers/gpu/drm/qxl/qxl_irq.c @@ -36,19 +36,19 @@ irqreturn_t qxl_irq_handler(int irq, void *arg) if (!pending) return IRQ_NONE; - atomic_inc(&qdev->irq_received); + atomic_inc_unchecked(&qdev->irq_received); if (pending & QXL_INTERRUPT_DISPLAY) { - atomic_inc(&qdev->irq_received_display); + atomic_inc_unchecked(&qdev->irq_received_display); wake_up_all(&qdev->display_event); qxl_queue_garbage_collect(qdev, false); } if (pending & QXL_INTERRUPT_CURSOR) { - atomic_inc(&qdev->irq_received_cursor); + atomic_inc_unchecked(&qdev->irq_received_cursor); wake_up_all(&qdev->cursor_event); } if (pending & QXL_INTERRUPT_IO_CMD) { - atomic_inc(&qdev->irq_received_io_cmd); + atomic_inc_unchecked(&qdev->irq_received_io_cmd); wake_up_all(&qdev->io_cmd_event); } if (pending & QXL_INTERRUPT_ERROR) { @@ -85,10 +85,10 @@ int qxl_irq_init(struct qxl_device *qdev) init_waitqueue_head(&qdev->io_cmd_event); INIT_WORK(&qdev->client_monitors_config_work, qxl_client_monitors_config_work_func); - atomic_set(&qdev->irq_received, 0); - atomic_set(&qdev->irq_received_display, 0); - atomic_set(&qdev->irq_received_cursor, 0); - atomic_set(&qdev->irq_received_io_cmd, 0); + atomic_set_unchecked(&qdev->irq_received, 0); + atomic_set_unchecked(&qdev->irq_received_display, 0); + atomic_set_unchecked(&qdev->irq_received_cursor, 0); + atomic_set_unchecked(&qdev->irq_received_io_cmd, 0); qdev->irq_received_error = 0; 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 0cbc4c9..0e46686 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) } } -static struct vm_operations_struct qxl_ttm_vm_ops; +static vm_operations_struct_no_const qxl_ttm_vm_ops __read_only; static const struct vm_operations_struct *ttm_vm_ops; static int qxl_ttm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) @@ -145,8 +145,10 @@ int qxl_mmap(struct file *filp, struct vm_area_struct *vma) return r; if (unlikely(ttm_vm_ops == NULL)) { ttm_vm_ops = vma->vm_ops; + pax_open_kernel(); qxl_ttm_vm_ops = *ttm_vm_ops; qxl_ttm_vm_ops.fault = &qxl_ttm_fault; + pax_close_kernel(); } vma->vm_ops = &qxl_ttm_vm_ops; return 0; @@ -464,25 +466,23 @@ static int qxl_mm_dump_table(struct seq_file *m, void *data) static int qxl_ttm_debugfs_init(struct qxl_device *qdev) { #if defined(CONFIG_DEBUG_FS) - static struct drm_info_list qxl_mem_types_list[QXL_DEBUGFS_MEM_TYPES]; - static char qxl_mem_types_names[QXL_DEBUGFS_MEM_TYPES][32]; - unsigned i; + static struct drm_info_list qxl_mem_types_list[QXL_DEBUGFS_MEM_TYPES] = { + { + .name = "qxl_mem_mm", + .show = &qxl_mm_dump_table, + }, + { + .name = "qxl_surf_mm", + .show = &qxl_mm_dump_table, + } + }; - for (i = 0; i < QXL_DEBUGFS_MEM_TYPES; i++) { - if (i == 0) - sprintf(qxl_mem_types_names[i], "qxl_mem_mm"); - else - sprintf(qxl_mem_types_names[i], "qxl_surf_mm"); - qxl_mem_types_list[i].name = qxl_mem_types_names[i]; - qxl_mem_types_list[i].show = &qxl_mm_dump_table; - qxl_mem_types_list[i].driver_features = 0; - if (i == 0) - qxl_mem_types_list[i].data = qdev->mman.bdev.man[TTM_PL_VRAM].priv; - 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; + pax_close_kernel(); - } - return qxl_debugfs_add_files(qdev, qxl_mem_types_list, i); + return qxl_debugfs_add_files(qdev, qxl_mem_types_list, QXL_DEBUGFS_MEM_TYPES); #else return 0; #endif diff --git a/drivers/gpu/drm/r128/r128_cce.c b/drivers/gpu/drm/r128/r128_cce.c index 2c45ac9..5d740f8 100644 --- a/drivers/gpu/drm/r128/r128_cce.c +++ b/drivers/gpu/drm/r128/r128_cce.c @@ -377,7 +377,7 @@ static int r128_do_init_cce(struct drm_device *dev, drm_r128_init_t *init) /* GH: Simple idle check. */ - atomic_set(&dev_priv->idle_count, 0); + atomic_set_unchecked(&dev_priv->idle_count, 0); /* 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.h b/drivers/gpu/drm/r128/r128_drv.h index 723e5d6..102dbaf 100644 --- a/drivers/gpu/drm/r128/r128_drv.h +++ b/drivers/gpu/drm/r128/r128_drv.h @@ -93,14 +93,14 @@ typedef struct drm_r128_private { int is_pci; unsigned long cce_buffers_offset; - atomic_t idle_count; + atomic_unchecked_t idle_count; int page_flipping; int current_page; u32 crtc_offset; u32 crtc_offset_cntl; - atomic_t vbl_received; + atomic_unchecked_t vbl_received; u32 color_fmt; unsigned int front_offset; diff --git a/drivers/gpu/drm/r128/r128_ioc32.c b/drivers/gpu/drm/r128/r128_ioc32.c index 663f38c..ec159a1 100644 --- a/drivers/gpu/drm/r128/r128_ioc32.c +++ b/drivers/gpu/drm/r128/r128_ioc32.c @@ -178,7 +178,7 @@ static int compat_r128_getparam(struct file *file, unsigned int cmd, return drm_ioctl(file, DRM_IOCTL_R128_GETPARAM, (unsigned long)getparam); } -drm_ioctl_compat_t *r128_compat_ioctls[] = { +drm_ioctl_compat_t r128_compat_ioctls[] = { [DRM_R128_INIT] = compat_r128_init, [DRM_R128_DEPTH] = compat_r128_depth, [DRM_R128_STIPPLE] = compat_r128_stipple, @@ -197,17 +197,13 @@ drm_ioctl_compat_t *r128_compat_ioctls[] = { long r128_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { unsigned int nr = DRM_IOCTL_NR(cmd); - drm_ioctl_compat_t *fn = NULL; int ret; if (nr < DRM_COMMAND_BASE) return drm_compat_ioctl(filp, cmd, arg); - if (nr < DRM_COMMAND_BASE + ARRAY_SIZE(r128_compat_ioctls)) - fn = r128_compat_ioctls[nr - DRM_COMMAND_BASE]; - - if (fn != NULL) - ret = (*fn) (filp, cmd, arg); + if (nr < DRM_COMMAND_BASE + ARRAY_SIZE(r128_compat_ioctls) && r128_compat_ioctls[nr - DRM_COMMAND_BASE]) + ret = (*r128_compat_ioctls[nr - DRM_COMMAND_BASE]) (filp, cmd, arg); else ret = drm_ioctl(filp, cmd, arg); diff --git a/drivers/gpu/drm/r128/r128_irq.c b/drivers/gpu/drm/r128/r128_irq.c index c2ae496..30b5993 100644 --- a/drivers/gpu/drm/r128/r128_irq.c +++ b/drivers/gpu/drm/r128/r128_irq.c @@ -41,7 +41,7 @@ u32 r128_get_vblank_counter(struct drm_device *dev, int crtc) if (crtc != 0) return 0; - return atomic_read(&dev_priv->vbl_received); + return atomic_read_unchecked(&dev_priv->vbl_received); } irqreturn_t r128_driver_irq_handler(int irq, void *arg) @@ -55,7 +55,7 @@ irqreturn_t r128_driver_irq_handler(int irq, void *arg) /* VBLANK interrupt */ if (status & R128_CRTC_VBLANK_INT) { R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); - atomic_inc(&dev_priv->vbl_received); + atomic_inc_unchecked(&dev_priv->vbl_received); drm_handle_vblank(dev, 0); return IRQ_HANDLED; } diff --git a/drivers/gpu/drm/r128/r128_state.c b/drivers/gpu/drm/r128/r128_state.c index 8fd2d9f..18c9660 100644 --- a/drivers/gpu/drm/r128/r128_state.c +++ b/drivers/gpu/drm/r128/r128_state.c @@ -320,10 +320,10 @@ static void r128_clear_box(drm_r128_private_t *dev_priv, static void r128_cce_performance_boxes(drm_r128_private_t *dev_priv) { - if (atomic_read(&dev_priv->idle_count) == 0) + if (atomic_read_unchecked(&dev_priv->idle_count) == 0) r128_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0); else - atomic_set(&dev_priv->idle_count, 0); + atomic_set_unchecked(&dev_priv->idle_count, 0); } #endif diff --git a/drivers/gpu/drm/radeon/mkregtable.c b/drivers/gpu/drm/radeon/mkregtable.c index b928c17..e5d9400 100644 --- a/drivers/gpu/drm/radeon/mkregtable.c +++ b/drivers/gpu/drm/radeon/mkregtable.c @@ -624,14 +624,14 @@ static int parser_auth(struct table *t, const char *filename) regex_t mask_rex; regmatch_t match[4]; char buf[1024]; - size_t end; + long end; int len; int done = 0; int r; unsigned o; struct offset *offset; char last_reg_s[10]; - int last_reg; + unsigned long last_reg; if (regcomp (&mask_rex, "(0x[0-9a-fA-F]*) *([_a-zA-Z0-9]*)", REG_EXTENDED)) { diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index f3f562f..0c099bb 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1253,7 +1253,7 @@ static bool radeon_switcheroo_can_switch(struct pci_dev *pdev) * locking inversion with the driver load path. And the access here is * completely racy anyway. So don't bother with locking for now. */ - return dev->open_count == 0; + return local_read(&dev->open_count) == 0; } static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = { diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h index 46bd393..6ae4719 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.h +++ b/drivers/gpu/drm/radeon/radeon_drv.h @@ -264,7 +264,7 @@ typedef struct drm_radeon_private { /* SW interrupt */ wait_queue_head_t swi_queue; - atomic_t swi_emitted; + atomic_unchecked_t swi_emitted; int vblank_crtc; uint32_t irq_enable_reg; uint32_t r500_disp_irq_reg; diff --git a/drivers/gpu/drm/radeon/radeon_ioc32.c b/drivers/gpu/drm/radeon/radeon_ioc32.c index 0b98ea1..a3c770f 100644 --- a/drivers/gpu/drm/radeon/radeon_ioc32.c +++ b/drivers/gpu/drm/radeon/radeon_ioc32.c @@ -358,7 +358,7 @@ static int compat_radeon_cp_setparam(struct file *file, unsigned int cmd, request = compat_alloc_user_space(sizeof(*request)); if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) || __put_user(req32.param, &request->param) - || __put_user((void __user *)(unsigned long)req32.value, + || __put_user((unsigned long)req32.value, &request->value)) return -EFAULT; @@ -368,7 +368,7 @@ static int compat_radeon_cp_setparam(struct file *file, unsigned int cmd, #define compat_radeon_cp_setparam NULL #endif /* X86_64 || IA64 */ -static drm_ioctl_compat_t *radeon_compat_ioctls[] = { +static drm_ioctl_compat_t radeon_compat_ioctls[] = { [DRM_RADEON_CP_INIT] = compat_radeon_cp_init, [DRM_RADEON_CLEAR] = compat_radeon_cp_clear, [DRM_RADEON_STIPPLE] = compat_radeon_cp_stipple, @@ -393,17 +393,13 @@ static drm_ioctl_compat_t *radeon_compat_ioctls[] = { long radeon_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { unsigned int nr = DRM_IOCTL_NR(cmd); - drm_ioctl_compat_t *fn = NULL; int ret; if (nr < DRM_COMMAND_BASE) return drm_compat_ioctl(filp, cmd, arg); - if (nr < DRM_COMMAND_BASE + ARRAY_SIZE(radeon_compat_ioctls)) - fn = radeon_compat_ioctls[nr - DRM_COMMAND_BASE]; - - if (fn != NULL) - ret = (*fn) (filp, cmd, arg); + if (nr < DRM_COMMAND_BASE + ARRAY_SIZE(radeon_compat_ioctls) && radeon_compat_ioctls[nr - DRM_COMMAND_BASE]) + ret = (*radeon_compat_ioctls[nr - DRM_COMMAND_BASE]) (filp, cmd, arg); else ret = drm_ioctl(filp, cmd, arg); diff --git a/drivers/gpu/drm/radeon/radeon_irq.c b/drivers/gpu/drm/radeon/radeon_irq.c index 244b19b..c19226d 100644 --- a/drivers/gpu/drm/radeon/radeon_irq.c +++ b/drivers/gpu/drm/radeon/radeon_irq.c @@ -226,8 +226,8 @@ static int radeon_emit_irq(struct drm_device * dev) unsigned int ret; RING_LOCALS; - atomic_inc(&dev_priv->swi_emitted); - ret = atomic_read(&dev_priv->swi_emitted); + atomic_inc_unchecked(&dev_priv->swi_emitted); + ret = atomic_read_unchecked(&dev_priv->swi_emitted); BEGIN_RING(4); OUT_RING_REG(RADEON_LAST_SWI_REG, ret); @@ -353,7 +353,7 @@ int radeon_driver_irq_postinstall(struct drm_device *dev) drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; - atomic_set(&dev_priv->swi_emitted, 0); + atomic_set_unchecked(&dev_priv->swi_emitted, 0); init_waitqueue_head(&dev_priv->swi_queue); dev->max_vblank_count = 0x001fffff; diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c index 15aee72..cda326e 100644 --- a/drivers/gpu/drm/radeon/radeon_state.c +++ b/drivers/gpu/drm/radeon/radeon_state.c @@ -2168,7 +2168,7 @@ static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file * if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS) sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; - if (copy_from_user(&depth_boxes, clear->depth_boxes, + if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS || copy_from_user(&depth_boxes, clear->depth_boxes, sarea_priv->nbox * sizeof(depth_boxes[0]))) return -EFAULT; @@ -3031,7 +3031,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil { drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_getparam_t *param = data; - int value; + int value = 0; DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 06ac59fe..57e0681 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -961,7 +961,7 @@ void radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 size) man->size = size >> PAGE_SHIFT; } -static struct vm_operations_struct radeon_ttm_vm_ops; +static vm_operations_struct_no_const radeon_ttm_vm_ops __read_only; static const struct vm_operations_struct *ttm_vm_ops = NULL; static int radeon_ttm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) @@ -1002,8 +1002,10 @@ int radeon_mmap(struct file *filp, struct vm_area_struct *vma) } if (unlikely(ttm_vm_ops == NULL)) { ttm_vm_ops = vma->vm_ops; + pax_open_kernel(); radeon_ttm_vm_ops = *ttm_vm_ops; radeon_ttm_vm_ops.fault = &radeon_ttm_fault; + pax_close_kernel(); } vma->vm_ops = &radeon_ttm_vm_ops; return 0; diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index ddefb85..9011500 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -1656,7 +1656,7 @@ static int tegra_dc_debugfs_init(struct tegra_dc *dc, struct drm_minor *minor) } for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) - dc->debugfs_files[i].data = dc; + *(void **)&dc->debugfs_files[i].data = dc; err = drm_debugfs_create_files(dc->debugfs_files, ARRAY_SIZE(debugfs_files), diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index f0a138e..a390c07 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -62,7 +62,7 @@ struct tegra_dsi { struct clk *clk_lp; struct clk *clk; - struct drm_info_list *debugfs_files; + drm_info_list_no_const *debugfs_files; struct drm_minor *minor; struct dentry *debugfs; diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 52b32cb..a8b2d5b 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -64,7 +64,7 @@ struct tegra_hdmi { bool stereo; bool dvi; - struct drm_info_list *debugfs_files; + drm_info_list_no_const *debugfs_files; struct drm_minor *minor; struct dentry *debugfs; }; diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index da1715e..f6fee95 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, goto remove; } - for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) - 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; + pax_close_kernel(); + } err = drm_debugfs_create_files(sor->debugfs_files, ARRAY_SIZE(debugfs_files), diff --git a/drivers/gpu/drm/tilcdc/Makefile b/drivers/gpu/drm/tilcdc/Makefile index deeca48..54e1b6c 100644 --- a/drivers/gpu/drm/tilcdc/Makefile +++ b/drivers/gpu/drm/tilcdc/Makefile @@ -1,7 +1,7 @@ ccflags-y := -Iinclude/drm -ifeq (, $(findstring -W,$(EXTRA_CFLAGS))) - ccflags-y += -Werror -endif +#ifeq (, $(findstring -W,$(EXTRA_CFLAGS))) +# ccflags-y += -Werror +#endif obj-$(CONFIG_DRM_TILCDC_SLAVE_COMPAT) += tilcdc_slave_compat.o \ tilcdc_slave_compat.dtb.o diff --git a/drivers/gpu/drm/ttm/ttm_bo_manager.c b/drivers/gpu/drm/ttm/ttm_bo_manager.c index aa0bd054..aea6a01 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_manager.c +++ b/drivers/gpu/drm/ttm/ttm_bo_manager.c @@ -148,10 +148,10 @@ static void ttm_bo_man_debug(struct ttm_mem_type_manager *man, } const struct ttm_mem_type_manager_func ttm_bo_manager_func = { - ttm_bo_man_init, - ttm_bo_man_takedown, - ttm_bo_man_get_node, - ttm_bo_man_put_node, - ttm_bo_man_debug + .init = ttm_bo_man_init, + .takedown = ttm_bo_man_takedown, + .get_node = ttm_bo_man_get_node, + .put_node = ttm_bo_man_put_node, + .debug = ttm_bo_man_debug }; EXPORT_SYMBOL(ttm_bo_manager_func); diff --git a/drivers/gpu/drm/ttm/ttm_memory.c b/drivers/gpu/drm/ttm/ttm_memory.c index a1803fb..c53f6b0 100644 --- a/drivers/gpu/drm/ttm/ttm_memory.c +++ b/drivers/gpu/drm/ttm/ttm_memory.c @@ -264,7 +264,7 @@ static int ttm_mem_init_kernel_zone(struct ttm_mem_global *glob, zone->glob = glob; glob->zone_kernel = zone; ret = kobject_init_and_add( - &zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, zone->name); + &zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, "%s", zone->name); if (unlikely(ret != 0)) { kobject_put(&zone->kobj); return ret; @@ -348,7 +348,7 @@ static int ttm_mem_init_dma32_zone(struct ttm_mem_global *glob, zone->glob = glob; glob->zone_dma32 = zone; ret = kobject_init_and_add( - &zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, zone->name); + &zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, "%s", zone->name); if (unlikely(ret != 0)) { kobject_put(&zone->kobj); return ret; diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c index 025c429..314062f 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c @@ -54,7 +54,7 @@ #define NUM_PAGES_TO_ALLOC (PAGE_SIZE/sizeof(struct page *)) #define SMALL_ALLOCATION 16 -#define FREE_ALL_PAGES (~0U) +#define FREE_ALL_PAGES (~0UL) /* times are in msecs */ #define PAGE_FREE_INTERVAL 1000 @@ -299,15 +299,14 @@ static void ttm_pool_update_free_locked(struct ttm_page_pool *pool, * @free_all: If set to true will free all pages in pool * @use_static: Safe to use static buffer **/ -static int ttm_page_pool_free(struct ttm_page_pool *pool, unsigned nr_free, +static unsigned long ttm_page_pool_free(struct ttm_page_pool *pool, unsigned long nr_free, bool use_static) { static struct page *static_buf[NUM_PAGES_TO_ALLOC]; unsigned long irq_flags; struct page *p; struct page **pages_to_free; - unsigned freed_pages = 0, - npages_to_free = nr_free; + unsigned long freed_pages = 0, npages_to_free = nr_free; if (NUM_PAGES_TO_ALLOC < nr_free) npages_to_free = NUM_PAGES_TO_ALLOC; @@ -371,7 +370,8 @@ restart: __list_del(&p->lru, &pool->list); ttm_pool_update_free_locked(pool, freed_pages); - nr_free -= freed_pages; + if (likely(nr_free != FREE_ALL_PAGES)) + nr_free -= freed_pages; } spin_unlock_irqrestore(&pool->lock, irq_flags); @@ -399,7 +399,7 @@ ttm_pool_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) unsigned i; unsigned pool_offset; struct ttm_page_pool *pool; - int shrink_pages = sc->nr_to_scan; + unsigned long shrink_pages = sc->nr_to_scan; unsigned long freed = 0; if (!mutex_trylock(&lock)) @@ -407,7 +407,7 @@ ttm_pool_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) pool_offset = ++start_pool % NUM_POOLS; /* select start pool in round robin fashion */ for (i = 0; i < NUM_POOLS; ++i) { - unsigned nr_free = shrink_pages; + unsigned long nr_free = shrink_pages; if (shrink_pages == 0) break; pool = &_manager->pools[(i + pool_offset)%NUM_POOLS]; @@ -673,7 +673,7 @@ out: } /* Put all pages in pages list to correct pool to wait for reuse */ -static void ttm_put_pages(struct page **pages, unsigned npages, int flags, +static void ttm_put_pages(struct page **pages, unsigned long npages, int flags, enum ttm_caching_state cstate) { unsigned long irq_flags; @@ -728,7 +728,7 @@ static int ttm_get_pages(struct page **pages, unsigned npages, int flags, struct list_head plist; struct page *p = NULL; gfp_t gfp_flags = GFP_USER; - unsigned count; + unsigned long count; int r; /* set zero flag for page allocation if required */ diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c index 624d941..106fa1f 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c @@ -56,7 +56,7 @@ #define NUM_PAGES_TO_ALLOC (PAGE_SIZE/sizeof(struct page *)) #define SMALL_ALLOCATION 4 -#define FREE_ALL_PAGES (~0U) +#define FREE_ALL_PAGES (~0UL) /* times are in msecs */ #define IS_UNDEFINED (0) #define IS_WC (1<<1) @@ -416,7 +416,7 @@ static void ttm_dma_page_put(struct dma_pool *pool, struct dma_page *d_page) * @nr_free: If set to true will free all pages in pool * @use_static: Safe to use static buffer **/ -static unsigned ttm_dma_page_pool_free(struct dma_pool *pool, unsigned nr_free, +static unsigned long ttm_dma_page_pool_free(struct dma_pool *pool, unsigned long nr_free, bool use_static) { static struct page *static_buf[NUM_PAGES_TO_ALLOC]; @@ -424,8 +424,7 @@ static unsigned ttm_dma_page_pool_free(struct dma_pool *pool, unsigned nr_free, struct dma_page *dma_p, *tmp; struct page **pages_to_free; struct list_head d_pages; - unsigned freed_pages = 0, - npages_to_free = nr_free; + unsigned long freed_pages = 0, npages_to_free = nr_free; if (NUM_PAGES_TO_ALLOC < nr_free) npages_to_free = NUM_PAGES_TO_ALLOC; @@ -502,7 +501,8 @@ restart: /* remove range of pages from the pool */ if (freed_pages) { ttm_pool_update_free_locked(pool, freed_pages); - nr_free -= freed_pages; + if (likely(nr_free != FREE_ALL_PAGES)) + nr_free -= freed_pages; } spin_unlock_irqrestore(&pool->lock, irq_flags); @@ -939,7 +939,7 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev) struct dma_page *d_page, *next; enum pool_type type; bool is_cached = false; - unsigned count = 0, i, npages = 0; + unsigned long count = 0, i, npages = 0; unsigned long irq_flags; type = ttm_to_type(ttm->page_flags, ttm->caching_state); @@ -1014,7 +1014,7 @@ ttm_dma_pool_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) static unsigned start_pool; unsigned idx = 0; unsigned pool_offset; - unsigned shrink_pages = sc->nr_to_scan; + unsigned long shrink_pages = sc->nr_to_scan; struct device_pools *p; unsigned long freed = 0; @@ -1027,7 +1027,7 @@ ttm_dma_pool_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) goto out; pool_offset = ++start_pool % _manager->npools; list_for_each_entry(p, &_manager->pools, pools) { - unsigned nr_free; + unsigned long nr_free; if (!p->dev) continue; @@ -1041,7 +1041,7 @@ ttm_dma_pool_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) shrink_pages = ttm_dma_page_pool_free(p->pool, nr_free, true); freed += nr_free - shrink_pages; - pr_debug("%s: (%s:%d) Asked to shrink %d, have %d more to go\n", + pr_debug("%s: (%s:%d) Asked to shrink %lu, have %lu more to go\n", p->pool->dev_name, p->pool->name, current->pid, nr_free, shrink_pages); } diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index 62c7b1d..2018818 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -367,7 +367,6 @@ static int udl_fb_release(struct fb_info *info, int user) fb_deferred_io_cleanup(info); kfree(info->fbdefio); info->fbdefio = NULL; - info->fbops->fb_mmap = udl_fb_mmap; } pr_warn("released /dev/fb%d user=%d count=%d\n", diff --git a/drivers/gpu/drm/via/via_drv.h b/drivers/gpu/drm/via/via_drv.h index ef8c500..01030c8 100644 --- a/drivers/gpu/drm/via/via_drv.h +++ b/drivers/gpu/drm/via/via_drv.h @@ -53,7 +53,7 @@ typedef struct drm_via_ring_buffer { typedef uint32_t maskarray_t[5]; typedef struct drm_via_irq { - atomic_t irq_received; + atomic_unchecked_t irq_received; uint32_t pending_mask; uint32_t enable_mask; wait_queue_head_t irq_queue; @@ -77,7 +77,7 @@ typedef struct drm_via_private { struct timeval last_vblank; int last_vblank_valid; unsigned usec_per_vblank; - atomic_t vbl_received; + atomic_unchecked_t vbl_received; drm_via_state_t hc_state; char pci_buf[VIA_PCI_BUF_SIZE]; const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE]; diff --git a/drivers/gpu/drm/via/via_irq.c b/drivers/gpu/drm/via/via_irq.c index 1319433..a993b0c 100644 --- a/drivers/gpu/drm/via/via_irq.c +++ b/drivers/gpu/drm/via/via_irq.c @@ -101,7 +101,7 @@ u32 via_get_vblank_counter(struct drm_device *dev, int crtc) if (crtc != 0) return 0; - return atomic_read(&dev_priv->vbl_received); + return atomic_read_unchecked(&dev_priv->vbl_received); } irqreturn_t via_driver_irq_handler(int irq, void *arg) @@ -116,8 +116,8 @@ irqreturn_t via_driver_irq_handler(int irq, void *arg) status = VIA_READ(VIA_REG_INTERRUPT); if (status & VIA_IRQ_VBLANK_PENDING) { - atomic_inc(&dev_priv->vbl_received); - if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) { + atomic_inc_unchecked(&dev_priv->vbl_received); + if (!(atomic_read_unchecked(&dev_priv->vbl_received) & 0x0F)) { do_gettimeofday(&cur_vblank); if (dev_priv->last_vblank_valid) { dev_priv->usec_per_vblank = @@ -127,7 +127,7 @@ irqreturn_t via_driver_irq_handler(int irq, void *arg) dev_priv->last_vblank = cur_vblank; dev_priv->last_vblank_valid = 1; } - if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) { + if (!(atomic_read_unchecked(&dev_priv->vbl_received) & 0xFF)) { DRM_DEBUG("US per vblank is: %u\n", dev_priv->usec_per_vblank); } @@ -137,7 +137,7 @@ irqreturn_t via_driver_irq_handler(int irq, void *arg) for (i = 0; i < dev_priv->num_irqs; ++i) { if (status & cur_irq->pending_mask) { - atomic_inc(&cur_irq->irq_received); + atomic_inc_unchecked(&cur_irq->irq_received); wake_up(&cur_irq->irq_queue); handled = 1; if (dev_priv->irq_map[drm_via_irq_dma0_td] == i) @@ -242,11 +242,11 @@ via_driver_irq_wait(struct drm_device *dev, unsigned int irq, int force_sequence DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * HZ, ((VIA_READ(masks[irq][2]) & masks[irq][3]) == masks[irq][4])); - cur_irq_sequence = atomic_read(&cur_irq->irq_received); + cur_irq_sequence = atomic_read_unchecked(&cur_irq->irq_received); } else { DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * HZ, (((cur_irq_sequence = - atomic_read(&cur_irq->irq_received)) - + atomic_read_unchecked(&cur_irq->irq_received)) - *sequence) <= (1 << 23))); } *sequence = cur_irq_sequence; @@ -284,7 +284,7 @@ void via_driver_irq_preinstall(struct drm_device *dev) } for (i = 0; i < dev_priv->num_irqs; ++i) { - atomic_set(&cur_irq->irq_received, 0); + atomic_set_unchecked(&cur_irq->irq_received, 0); cur_irq->enable_mask = dev_priv->irq_masks[i][0]; cur_irq->pending_mask = dev_priv->irq_masks[i][1]; init_waitqueue_head(&cur_irq->irq_queue); @@ -366,7 +366,7 @@ int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv) switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) { case VIA_IRQ_RELATIVE: irqwait->request.sequence += - atomic_read(&cur_irq->irq_received); + atomic_read_unchecked(&cur_irq->irq_received); irqwait->request.type &= ~_DRM_VBLANK_RELATIVE; case VIA_IRQ_ABSOLUTE: break; diff --git a/drivers/gpu/drm/virtio/virtgpu_ttm.c b/drivers/gpu/drm/virtio/virtgpu_ttm.c index b092d7b..3bbecd9 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ttm.c +++ b/drivers/gpu/drm/virtio/virtgpu_ttm.c @@ -197,11 +197,11 @@ static void ttm_bo_man_debug(struct ttm_mem_type_manager *man, } static const struct ttm_mem_type_manager_func virtio_gpu_bo_manager_func = { - ttm_bo_man_init, - ttm_bo_man_takedown, - ttm_bo_man_get_node, - ttm_bo_man_put_node, - ttm_bo_man_debug + .init = &ttm_bo_man_init, + .takedown = &ttm_bo_man_takedown, + .get_node = &ttm_bo_man_get_node, + .put_node = &ttm_bo_man_put_node, + .debug = &ttm_bo_man_debug }; static int virtio_gpu_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index f19fd39..429e1ebe 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -434,7 +434,7 @@ struct vmw_private { * Fencing and IRQs. */ - atomic_t marker_seq; + atomic_unchecked_t marker_seq; wait_queue_head_t fence_queue; wait_queue_head_t fifo_queue; spinlock_t waiter_lock; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index 80c40c3..ed6de49 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -156,7 +156,7 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) (unsigned int) min, (unsigned int) fifo->capabilities); - atomic_set(&dev_priv->marker_seq, dev_priv->last_read_seqno); + atomic_set_unchecked(&dev_priv->marker_seq, dev_priv->last_read_seqno); iowrite32(dev_priv->last_read_seqno, fifo_mem + SVGA_FIFO_FENCE); vmw_marker_queue_init(&fifo->marker_queue); @@ -378,7 +378,7 @@ static void *vmw_local_fifo_reserve(struct vmw_private *dev_priv, if (reserveable) iowrite32(bytes, fifo_mem + SVGA_FIFO_RESERVED); - return (void __force *) (fifo_mem + + return (void __force_kernel *) (fifo_mem + (next_cmd >> 2)); } else { need_bounce = true; @@ -568,7 +568,7 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *seqno) fm = vmw_fifo_reserve(dev_priv, bytes); if (unlikely(fm == NULL)) { - *seqno = atomic_read(&dev_priv->marker_seq); + *seqno = atomic_read_unchecked(&dev_priv->marker_seq); ret = -ENOMEM; (void)vmw_fallback_wait(dev_priv, false, true, *seqno, false, 3*HZ); @@ -576,7 +576,7 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *seqno) } do { - *seqno = atomic_add_return(1, &dev_priv->marker_seq); + *seqno = atomic_add_return_unchecked(1, &dev_priv->marker_seq); } while (*seqno == 0); if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE)) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c index 170b61b..fec7348 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c @@ -164,9 +164,9 @@ static void vmw_gmrid_man_debug(struct ttm_mem_type_manager *man, } const struct ttm_mem_type_manager_func vmw_gmrid_manager_func = { - vmw_gmrid_man_init, - vmw_gmrid_man_takedown, - vmw_gmrid_man_get_node, - vmw_gmrid_man_put_node, - vmw_gmrid_man_debug + .init = vmw_gmrid_man_init, + .takedown = vmw_gmrid_man_takedown, + .get_node = vmw_gmrid_man_get_node, + .put_node = vmw_gmrid_man_put_node, + .debug = vmw_gmrid_man_debug }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c index 9498a5e..d532ac1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c @@ -105,7 +105,7 @@ bool vmw_seqno_passed(struct vmw_private *dev_priv, * emitted. Then the fence is stale and signaled. */ - ret = ((atomic_read(&dev_priv->marker_seq) - seqno) + ret = ((atomic_read_unchecked(&dev_priv->marker_seq) - seqno) > VMW_FENCE_WRAP); return ret; @@ -144,7 +144,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv, } } - signal_seq = atomic_read(&dev_priv->marker_seq); + signal_seq = atomic_read_unchecked(&dev_priv->marker_seq); ret = 0; for (;;) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_marker.c b/drivers/gpu/drm/vmwgfx/vmwgfx_marker.c index efd1ffd..0ae13ca 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_marker.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_marker.c @@ -135,7 +135,7 @@ int vmw_wait_lag(struct vmw_private *dev_priv, while (!vmw_lag_lt(queue, us)) { spin_lock(&queue->lock); if (list_empty(&queue->head)) - seqno = atomic_read(&dev_priv->marker_seq); + seqno = atomic_read_unchecked(&dev_priv->marker_seq); else { marker = list_first_entry(&queue->head, struct vmw_marker, head); diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index 2106066..e759b59 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c @@ -657,7 +657,7 @@ static int vga_switcheroo_runtime_resume(struct device *dev) /* this version is for the case where the power switch is separate to the device being powered down. */ int vga_switcheroo_init_domain_pm_ops(struct device *dev, - struct dev_pm_domain *domain) + dev_pm_domain_no_const *domain) { /* copy over all the bus versions */ if (dev->bus && dev->bus->pm) { @@ -711,7 +711,7 @@ static int vga_switcheroo_runtime_resume_hdmi_audio(struct device *dev) int vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, - struct dev_pm_domain *domain) + dev_pm_domain_no_const *domain) { /* copy over all the bus versions */ if (dev->bus && dev->bus->pm) { diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 70a11ac..9852312 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2575,7 +2575,7 @@ EXPORT_SYMBOL_GPL(hid_ignore); int hid_add_device(struct hid_device *hdev) { - static atomic_t id = ATOMIC_INIT(0); + static atomic_unchecked_t id = ATOMIC_INIT(0); int ret; if (WARN_ON(hdev->status & HID_STAT_ADDED)) @@ -2618,7 +2618,7 @@ int hid_add_device(struct hid_device *hdev) /* XXX hack, any other cleaner solution after the driver core * is converted to allow more than 20 bytes as the device name? */ dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus, - hdev->vendor, hdev->product, atomic_inc_return(&id)); + hdev->vendor, hdev->product, atomic_inc_return_unchecked(&id)); hid_debug_register(hdev, dev_name(&hdev->dev)); ret = device_add(&hdev->dev); diff --git a/drivers/hid/hid-sensor-custom.c b/drivers/hid/hid-sensor-custom.c index 5614fee..8a6f5f6 100644 --- a/drivers/hid/hid-sensor-custom.c +++ b/drivers/hid/hid-sensor-custom.c @@ -590,7 +590,7 @@ static int hid_sensor_custom_add_attributes(struct hid_sensor_custom j = 0; while (j < HID_CUSTOM_TOTAL_ATTRS && hid_custom_attrs[j].name) { - struct device_attribute *device_attr; + device_attribute_no_const *device_attr; device_attr = &sensor_inst->fields[i].sd_attrs[j]; diff --git a/drivers/hid/hid-wiimote-debug.c b/drivers/hid/hid-wiimote-debug.c index c13fb5b..55a3802 100644 --- a/drivers/hid/hid-wiimote-debug.c +++ b/drivers/hid/hid-wiimote-debug.c @@ -66,7 +66,7 @@ static ssize_t wiidebug_eeprom_read(struct file *f, char __user *u, size_t s, else if (size == 0) return -EIO; - if (copy_to_user(u, buf, size)) + if (size > sizeof(buf) || copy_to_user(u, buf, size)) return -EFAULT; *off += size; diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index c4dcab0..a505f18 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -382,7 +382,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, int ret = 0; next_gpadl_handle = - (atomic_inc_return(&vmbus_connection.next_gpadl_handle) - 1); + (atomic_inc_return_unchecked(&vmbus_connection.next_gpadl_handle) - 1); ret = create_gpadl_header(kbuffer, size, &msginfo, &msgcount); if (ret) @@ -696,9 +696,7 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel, * Adjust the size down since vmbus_channel_packet_page_buffer is the * largest size we support */ - descsize = sizeof(struct vmbus_channel_packet_page_buffer) - - ((MAX_PAGE_BUFFER_COUNT - pagecount) * - sizeof(struct hv_page_buffer)); + descsize = offsetof(struct vmbus_channel_packet_page_buffer, range[pagecount]); packetlen = descsize + bufferlen; packetlen_aligned = ALIGN(packetlen, sizeof(u64)); diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 6341be8..1a2fc8d 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -95,7 +95,7 @@ static u64 do_hypercall(u64 control, void *input, void *output) { u64 input_address = (input) ? virt_to_phys(input) : 0; u64 output_address = (output) ? virt_to_phys(output) : 0; - void *hypercall_page = hv_context.hypercall_page; + void *hypercall_page = (void *)ktva_ktla((unsigned long)hv_context.hypercall_page); #ifdef CONFIG_X86_64 u64 hv_status = 0; @@ -219,7 +219,7 @@ int hv_init(void) /* See if the hypercall page is already set */ rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); - virtaddr = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_EXEC); + virtaddr = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_RX); if (!virtaddr) goto cleanup; diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index b853b4b..3647b37 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -471,7 +471,7 @@ MODULE_PARM_DESC(hot_add, "If set attempt memory hot_add"); module_param(pressure_report_delay, uint, (S_IRUGO | S_IWUSR)); MODULE_PARM_DESC(pressure_report_delay, "Delay in secs in reporting pressure"); -static atomic_t trans_id = ATOMIC_INIT(0); +static atomic_unchecked_t trans_id = ATOMIC_INIT(0); static int dm_ring_size = (5 * PAGE_SIZE); @@ -945,7 +945,7 @@ static void hot_add_req(struct work_struct *dummy) pr_info("Memory hot add failed\n"); dm->state = DM_INITIALIZED; - resp.hdr.trans_id = atomic_inc_return(&trans_id); + resp.hdr.trans_id = atomic_inc_return_unchecked(&trans_id); vmbus_sendpacket(dm->dev->channel, &resp, sizeof(struct dm_hot_add_response), (unsigned long)NULL, @@ -1026,7 +1026,7 @@ static void post_status(struct hv_dynmem_device *dm) memset(&status, 0, sizeof(struct dm_status)); status.hdr.type = DM_STATUS_REPORT; status.hdr.size = sizeof(struct dm_status); - status.hdr.trans_id = atomic_inc_return(&trans_id); + status.hdr.trans_id = atomic_inc_return_unchecked(&trans_id); /* * The host expects the guest to report free and committed memory. @@ -1050,7 +1050,7 @@ static void post_status(struct hv_dynmem_device *dm) * send the status. This can happen if we were interrupted * after we picked our transaction ID. */ - if (status.hdr.trans_id != atomic_read(&trans_id)) + if (status.hdr.trans_id != atomic_read_unchecked(&trans_id)) return; /* @@ -1195,7 +1195,7 @@ static void balloon_up(struct work_struct *dummy) */ do { - bl_resp->hdr.trans_id = atomic_inc_return(&trans_id); + bl_resp->hdr.trans_id = atomic_inc_return_unchecked(&trans_id); ret = vmbus_sendpacket(dm_device.dev->channel, bl_resp, bl_resp->hdr.size, @@ -1241,7 +1241,7 @@ static void balloon_down(struct hv_dynmem_device *dm, memset(&resp, 0, sizeof(struct dm_unballoon_response)); resp.hdr.type = DM_UNBALLOON_RESPONSE; - resp.hdr.trans_id = atomic_inc_return(&trans_id); + resp.hdr.trans_id = atomic_inc_return_unchecked(&trans_id); resp.hdr.size = sizeof(struct dm_unballoon_response); vmbus_sendpacket(dm_device.dev->channel, &resp, @@ -1301,7 +1301,7 @@ static void version_resp(struct hv_dynmem_device *dm, memset(&version_req, 0, sizeof(struct dm_version_request)); version_req.hdr.type = DM_VERSION_REQUEST; version_req.hdr.size = sizeof(struct dm_version_request); - version_req.hdr.trans_id = atomic_inc_return(&trans_id); + version_req.hdr.trans_id = atomic_inc_return_unchecked(&trans_id); version_req.version.version = dm->next_version; /* @@ -1487,7 +1487,7 @@ static int balloon_probe(struct hv_device *dev, memset(&version_req, 0, sizeof(struct dm_version_request)); version_req.hdr.type = DM_VERSION_REQUEST; version_req.hdr.size = sizeof(struct dm_version_request); - version_req.hdr.trans_id = atomic_inc_return(&trans_id); + version_req.hdr.trans_id = atomic_inc_return_unchecked(&trans_id); version_req.version.version = DYNMEM_PROTOCOL_VERSION_WIN10; version_req.is_last_attempt = 0; @@ -1518,7 +1518,7 @@ static int balloon_probe(struct hv_device *dev, memset(&cap_msg, 0, sizeof(struct dm_capabilities)); cap_msg.hdr.type = DM_CAPABILITIES_REPORT; cap_msg.hdr.size = sizeof(struct dm_capabilities); - cap_msg.hdr.trans_id = atomic_inc_return(&trans_id); + cap_msg.hdr.trans_id = atomic_inc_return_unchecked(&trans_id); cap_msg.caps.cap_bits.balloon = 1; cap_msg.caps.cap_bits.hot_add = 1; diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 3d70e36..465d989 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -659,7 +659,7 @@ enum vmbus_connect_state { struct vmbus_connection { enum vmbus_connect_state conn_state; - atomic_t next_gpadl_handle; + atomic_unchecked_t next_gpadl_handle; struct completion unload_event; /* diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 579bdf9..0dac21d5 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -116,7 +116,7 @@ struct sensor_template { struct device_attribute *devattr, const char *buf, size_t count); int index; -}; +} __do_const; /* Averaging interval */ static int update_avg_interval(struct acpi_power_meter_resource *resource) @@ -631,7 +631,7 @@ static int register_attrs(struct acpi_power_meter_resource *resource, struct sensor_template *attrs) { struct device *dev = &resource->acpi_dev->dev; - struct sensor_device_attribute *sensors = + sensor_device_attribute_no_const *sensors = &resource->sensors[resource->num_sensors]; int res = 0; @@ -973,7 +973,7 @@ static int __init enable_cap_knobs(const struct dmi_system_id *d) return 0; } -static struct dmi_system_id __initdata pm_dmi_table[] = { +static const struct dmi_system_id __initconst pm_dmi_table[] = { { enable_cap_knobs, "IBM Active Energy Manager", { diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 0af63da..05a183a 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -1105,7 +1105,7 @@ static int applesmc_create_nodes(struct applesmc_node_group *groups, int num) { struct applesmc_node_group *grp; struct applesmc_dev_attr *node; - struct attribute *attr; + attribute_no_const *attr; int ret, i; for (grp = groups; grp->format; grp++) { diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index cccef87..06ce8ec 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -147,10 +147,10 @@ MODULE_DEVICE_TABLE(acpi, atk_ids); struct atk_sensor_data { struct list_head list; struct atk_data *data; - struct device_attribute label_attr; - struct device_attribute input_attr; - struct device_attribute limit1_attr; - struct device_attribute limit2_attr; + device_attribute_no_const label_attr; + device_attribute_no_const input_attr; + device_attribute_no_const limit1_attr; + device_attribute_no_const limit2_attr; char label_attr_name[ATTR_NAME_SIZE]; char input_attr_name[ATTR_NAME_SIZE]; char limit1_attr_name[ATTR_NAME_SIZE]; @@ -270,7 +270,7 @@ static ssize_t atk_name_show(struct device *dev, static struct device_attribute atk_name_attr = __ATTR(name, 0444, atk_name_show, NULL); -static void atk_init_attribute(struct device_attribute *attr, char *name, +static void atk_init_attribute(device_attribute_no_const *attr, char *name, sysfs_show_func show) { sysfs_attr_init(&attr->attr); diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 3e03379..ec521d3 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -783,7 +783,7 @@ static int coretemp_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -static struct notifier_block coretemp_cpu_notifier __refdata = { +static struct notifier_block coretemp_cpu_notifier = { .notifier_call = coretemp_cpu_callback, }; diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index c848789..e9e9217 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -819,7 +819,7 @@ static const struct i8k_config_data i8k_config_data[] = { }, }; -static struct dmi_system_id i8k_dmi_table[] __initdata = { +static const struct dmi_system_id i8k_dmi_table[] __initconst = { { .ident = "Dell Inspiron", .matches = { diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c index 7a8a6fb..015c1fd 100644 --- a/drivers/hwmon/ibmaem.c +++ b/drivers/hwmon/ibmaem.c @@ -924,7 +924,7 @@ static int aem_register_sensors(struct aem_data *data, struct aem_rw_sensor_template *rw) { struct device *dev = &data->pdev->dev; - struct sensor_device_attribute *sensors = data->sensors; + sensor_device_attribute_no_const *sensors = data->sensors; int err; /* Set up read-only sensors */ diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c index 17ae2eb..21b71dd 100644 --- a/drivers/hwmon/iio_hwmon.c +++ b/drivers/hwmon/iio_hwmon.c @@ -61,7 +61,7 @@ static int iio_hwmon_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct iio_hwmon_state *st; - struct sensor_device_attribute *a; + sensor_device_attribute_no_const *a; int ret, i; int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1; enum iio_chan_type type; diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c index 37f0170..414ec2c 100644 --- a/drivers/hwmon/nct6683.c +++ b/drivers/hwmon/nct6683.c @@ -397,11 +397,11 @@ static struct attribute_group * nct6683_create_attr_group(struct device *dev, struct sensor_template_group *tg, int repeat) { - struct sensor_device_attribute_2 *a2; - struct sensor_device_attribute *a; + sensor_device_attribute_2_no_const *a2; + sensor_device_attribute_no_const *a; struct sensor_device_template **t; struct sensor_device_attr_u *su; - struct attribute_group *group; + attribute_group_no_const *group; struct attribute **attrs; int i, j, count; diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index 8b4fa55..fb3c20b 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c @@ -970,10 +970,10 @@ static struct attribute_group * nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg, int repeat) { - struct attribute_group *group; + attribute_group_no_const *group; struct sensor_device_attr_u *su; - struct sensor_device_attribute *a; - struct sensor_device_attribute_2 *a2; + sensor_device_attribute_no_const *a; + sensor_device_attribute_2_no_const *a2; struct attribute **attrs; struct sensor_device_template **t; int i, count; diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index ba59eae..dbf694c 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -824,7 +824,7 @@ static int pmbus_add_attribute(struct pmbus_data *data, struct attribute *attr) return 0; } -static void pmbus_dev_attr_init(struct device_attribute *dev_attr, +static void pmbus_dev_attr_init(device_attribute_no_const *dev_attr, const char *name, umode_t mode, ssize_t (*show)(struct device *dev, @@ -841,7 +841,7 @@ static void pmbus_dev_attr_init(struct device_attribute *dev_attr, dev_attr->store = store; } -static void pmbus_attr_init(struct sensor_device_attribute *a, +static void pmbus_attr_init(sensor_device_attribute_no_const *a, const char *name, umode_t mode, ssize_t (*show)(struct device *dev, @@ -863,7 +863,7 @@ static int pmbus_add_boolean(struct pmbus_data *data, u16 reg, u8 mask) { struct pmbus_boolean *boolean; - struct sensor_device_attribute *a; + sensor_device_attribute_no_const *a; boolean = devm_kzalloc(data->dev, sizeof(*boolean), GFP_KERNEL); if (!boolean) @@ -888,7 +888,7 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, bool update, bool readonly) { struct pmbus_sensor *sensor; - struct device_attribute *a; + device_attribute_no_const *a; sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL); if (!sensor) @@ -919,7 +919,7 @@ static int pmbus_add_label(struct pmbus_data *data, const char *lstring, int index) { struct pmbus_label *label; - struct device_attribute *a; + device_attribute_no_const *a; label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL); if (!label) diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index a2fdbb7..e749a3c 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -170,7 +170,7 @@ struct sht15_data { int supply_uv; bool supply_uv_valid; struct work_struct update_supply_work; - atomic_t interrupt_handled; + atomic_unchecked_t interrupt_handled; }; /** @@ -530,13 +530,13 @@ static int sht15_measurement(struct sht15_data *data, ret = gpio_direction_input(data->pdata->gpio_data); if (ret) return ret; - atomic_set(&data->interrupt_handled, 0); + atomic_set_unchecked(&data->interrupt_handled, 0); enable_irq(gpio_to_irq(data->pdata->gpio_data)); if (gpio_get_value(data->pdata->gpio_data) == 0) { disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data)); /* Only relevant if the interrupt hasn't occurred. */ - if (!atomic_read(&data->interrupt_handled)) + if (!atomic_read_unchecked(&data->interrupt_handled)) schedule_work(&data->read_work); } ret = wait_event_timeout(data->wait_queue, @@ -808,7 +808,7 @@ static irqreturn_t sht15_interrupt_fired(int irq, void *d) /* First disable the interrupt */ disable_irq_nosync(irq); - atomic_inc(&data->interrupt_handled); + atomic_inc_unchecked(&data->interrupt_handled); /* Then schedule a reading work struct */ if (data->state != SHT15_READING_NOTHING) schedule_work(&data->read_work); @@ -830,11 +830,11 @@ static void sht15_bh_read_data(struct work_struct *work_s) * If not, then start the interrupt again - care here as could * have gone low in meantime so verify it hasn't! */ - atomic_set(&data->interrupt_handled, 0); + atomic_set_unchecked(&data->interrupt_handled, 0); enable_irq(gpio_to_irq(data->pdata->gpio_data)); /* If still not occurred or another handler was scheduled */ if (gpio_get_value(data->pdata->gpio_data) - || atomic_read(&data->interrupt_handled)) + || atomic_read_unchecked(&data->interrupt_handled)) return; } diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c index ac91c07..8e69663 100644 --- a/drivers/hwmon/via-cputemp.c +++ b/drivers/hwmon/via-cputemp.c @@ -295,7 +295,7 @@ static int via_cputemp_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -static struct notifier_block via_cputemp_cpu_notifier __refdata = { +static struct notifier_block via_cputemp_cpu_notifier = { .notifier_call = via_cputemp_cpu_callback, }; diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c index 65e3240..e6c511d 100644 --- a/drivers/i2c/busses/i2c-amd756-s4882.c +++ b/drivers/i2c/busses/i2c-amd756-s4882.c @@ -39,7 +39,7 @@ extern struct i2c_adapter amd756_smbus; static struct i2c_adapter *s4882_adapter; -static struct i2c_algorithm *s4882_algo; +static i2c_algorithm_no_const *s4882_algo; /* Wrapper access functions for multiplexed SMBus */ static DEFINE_MUTEX(amd756_lock); diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index df23e8c..1354d8e 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -60,7 +60,7 @@ struct dw_scl_sda_cfg { }; struct dw_pci_controller { - u32 bus_num; + int bus_num; u32 bus_cfg; u32 tx_fifo_depth; u32 rx_fifo_depth; diff --git a/drivers/i2c/busses/i2c-nforce2-s4985.c b/drivers/i2c/busses/i2c-nforce2-s4985.c index 88eda09..cf40434 100644 --- a/drivers/i2c/busses/i2c-nforce2-s4985.c +++ b/drivers/i2c/busses/i2c-nforce2-s4985.c @@ -37,7 +37,7 @@ extern struct i2c_adapter *nforce2_smbus; static struct i2c_adapter *s4985_adapter; -static struct i2c_algorithm *s4985_algo; +static i2c_algorithm_no_const *s4985_algo; /* Wrapper access functions for multiplexed SMBus */ static DEFINE_MUTEX(nforce2_lock); diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 71c7a39..71dd3e0 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -272,7 +272,7 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client, break; } - data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; + data_ptrs[i] = (u8 __force_user *)rdwr_pa[i].buf; rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len); if (IS_ERR(rdwr_pa[i].buf)) { res = PTR_ERR(rdwr_pa[i].buf); diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 64a6b82..a524354 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -768,7 +768,7 @@ static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq) alignment = queue_dma_alignment(q) | q->dma_pad_mask; if ((unsigned long)buf & alignment || blk_rq_bytes(rq) & q->dma_pad_mask - || object_is_on_stack(buf)) + || object_starts_on_stack(buf)) drive->dma = 0; } } diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 56b9708..980b63b 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -178,7 +178,7 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, * 1073741822 == 549756 MB or 48bit addressing fake drive */ -static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq, +static ide_startstop_t __intentional_overflow(-1) ide_do_rw_disk(ide_drive_t *drive, struct request *rq, sector_t block) { ide_hwif_t *hwif = drive->hwif; diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index b3fcc2c..6f90dc4 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -590,7 +590,7 @@ static ssize_t iio_write_channel_info(struct device *dev, } static -int __iio_device_attr_init(struct device_attribute *dev_attr, +int __iio_device_attr_init(device_attribute_no_const *dev_attr, const char *postfix, struct iio_chan_spec const *chan, ssize_t (*readfunc)(struct device *dev, diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index b13936d..65322b2 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -776,7 +776,7 @@ static int ak8975_probe(struct i2c_client *client, name = id->name; } else if (ACPI_HANDLE(&client->dev)) name = ak8975_match_acpi_device(&client->dev, &chipset); - else + if (!name) return -ENOSYS; if (chipset >= AK_MAX_TYPE) { diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 4f918b9..97b5a90 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -115,7 +115,7 @@ static char const counter_group_names[CM_COUNTER_GROUPS] struct cm_counter_group { struct kobject obj; - atomic_long_t counter[CM_ATTR_COUNT]; + atomic_long_unchecked_t counter[CM_ATTR_COUNT]; }; struct cm_counter_attribute { @@ -1476,7 +1476,7 @@ static void cm_dup_req_handler(struct cm_work *work, struct ib_mad_send_buf *msg = NULL; int ret; - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + atomic_long_inc_unchecked(&work->port->counter_group[CM_RECV_DUPLICATES]. counter[CM_REQ_COUNTER]); /* Quick state check to discard duplicate REQs. */ @@ -1862,7 +1862,7 @@ static void cm_dup_rep_handler(struct cm_work *work) if (!cm_id_priv) return; - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + atomic_long_inc_unchecked(&work->port->counter_group[CM_RECV_DUPLICATES]. counter[CM_REP_COUNTER]); ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg); if (ret) @@ -2029,7 +2029,7 @@ static int cm_rtu_handler(struct cm_work *work) if (cm_id_priv->id.state != IB_CM_REP_SENT && cm_id_priv->id.state != IB_CM_MRA_REP_RCVD) { spin_unlock_irq(&cm_id_priv->lock); - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + atomic_long_inc_unchecked(&work->port->counter_group[CM_RECV_DUPLICATES]. counter[CM_RTU_COUNTER]); goto out; } @@ -2212,7 +2212,7 @@ static int cm_dreq_handler(struct cm_work *work) cm_id_priv = cm_acquire_id(dreq_msg->remote_comm_id, dreq_msg->local_comm_id); if (!cm_id_priv) { - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + atomic_long_inc_unchecked(&work->port->counter_group[CM_RECV_DUPLICATES]. counter[CM_DREQ_COUNTER]); cm_issue_drep(work->port, work->mad_recv_wc); return -EINVAL; @@ -2237,7 +2237,7 @@ static int cm_dreq_handler(struct cm_work *work) case IB_CM_MRA_REP_RCVD: break; case IB_CM_TIMEWAIT: - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + atomic_long_inc_unchecked(&work->port->counter_group[CM_RECV_DUPLICATES]. counter[CM_DREQ_COUNTER]); if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg)) goto unlock; @@ -2251,7 +2251,7 @@ static int cm_dreq_handler(struct cm_work *work) cm_free_msg(msg); goto deref; case IB_CM_DREQ_RCVD: - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + atomic_long_inc_unchecked(&work->port->counter_group[CM_RECV_DUPLICATES]. counter[CM_DREQ_COUNTER]); goto unlock; default: @@ -2618,7 +2618,7 @@ static int cm_mra_handler(struct cm_work *work) ib_modify_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg, timeout)) { if (cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD) - atomic_long_inc(&work->port-> + atomic_long_inc_unchecked(&work->port-> counter_group[CM_RECV_DUPLICATES]. counter[CM_MRA_COUNTER]); goto out; @@ -2627,7 +2627,7 @@ static int cm_mra_handler(struct cm_work *work) break; case IB_CM_MRA_REQ_RCVD: case IB_CM_MRA_REP_RCVD: - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + atomic_long_inc_unchecked(&work->port->counter_group[CM_RECV_DUPLICATES]. counter[CM_MRA_COUNTER]); /* fall through */ default: @@ -2789,7 +2789,7 @@ static int cm_lap_handler(struct cm_work *work) case IB_CM_LAP_IDLE: break; case IB_CM_MRA_LAP_SENT: - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + atomic_long_inc_unchecked(&work->port->counter_group[CM_RECV_DUPLICATES]. counter[CM_LAP_COUNTER]); if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg)) goto unlock; @@ -2805,7 +2805,7 @@ static int cm_lap_handler(struct cm_work *work) cm_free_msg(msg); goto deref; case IB_CM_LAP_RCVD: - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + atomic_long_inc_unchecked(&work->port->counter_group[CM_RECV_DUPLICATES]. counter[CM_LAP_COUNTER]); goto unlock; default: @@ -3091,7 +3091,7 @@ static int cm_sidr_req_handler(struct cm_work *work) cur_cm_id_priv = cm_insert_remote_sidr(cm_id_priv); if (cur_cm_id_priv) { spin_unlock_irq(&cm.lock); - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + atomic_long_inc_unchecked(&work->port->counter_group[CM_RECV_DUPLICATES]. counter[CM_SIDR_REQ_COUNTER]); goto out; /* Duplicate message. */ } @@ -3305,10 +3305,10 @@ static void cm_send_handler(struct ib_mad_agent *mad_agent, if (!msg->context[0] && (attr_index != CM_REJ_COUNTER)) msg->retries = 1; - atomic_long_add(1 + msg->retries, + atomic_long_add_unchecked(1 + msg->retries, &port->counter_group[CM_XMIT].counter[attr_index]); if (msg->retries) - atomic_long_add(msg->retries, + atomic_long_add_unchecked(msg->retries, &port->counter_group[CM_XMIT_RETRIES]. counter[attr_index]); @@ -3534,7 +3534,7 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent, } attr_id = be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id); - atomic_long_inc(&port->counter_group[CM_RECV]. + atomic_long_inc_unchecked(&port->counter_group[CM_RECV]. counter[attr_id - CM_ATTR_ID_OFFSET]); work = kmalloc(sizeof *work + sizeof(struct ib_sa_path_rec) * paths, @@ -3777,7 +3777,7 @@ static ssize_t cm_show_counter(struct kobject *obj, struct attribute *attr, cm_attr = container_of(attr, struct cm_counter_attribute, attr); return sprintf(buf, "%ld\n", - atomic_long_read(&group->counter[cm_attr->index])); + atomic_long_read_unchecked(&group->counter[cm_attr->index])); } static const struct sysfs_ops cm_counter_ops = { diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c index 9f5ad7c..588cd84 100644 --- a/drivers/infiniband/core/fmr_pool.c +++ b/drivers/infiniband/core/fmr_pool.c @@ -98,8 +98,8 @@ struct ib_fmr_pool { struct task_struct *thread; - atomic_t req_ser; - atomic_t flush_ser; + atomic_unchecked_t req_ser; + atomic_unchecked_t flush_ser; wait_queue_head_t force_wait; }; @@ -179,10 +179,10 @@ static int ib_fmr_cleanup_thread(void *pool_ptr) struct ib_fmr_pool *pool = pool_ptr; do { - if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) { + if (atomic_read_unchecked(&pool->flush_ser) - atomic_read_unchecked(&pool->req_ser) < 0) { ib_fmr_batch_release(pool); - atomic_inc(&pool->flush_ser); + atomic_inc_unchecked(&pool->flush_ser); wake_up_interruptible(&pool->force_wait); if (pool->flush_function) @@ -190,7 +190,7 @@ static int ib_fmr_cleanup_thread(void *pool_ptr) } set_current_state(TASK_INTERRUPTIBLE); - if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 && + if (atomic_read_unchecked(&pool->flush_ser) - atomic_read_unchecked(&pool->req_ser) >= 0 && !kthread_should_stop()) schedule(); __set_current_state(TASK_RUNNING); @@ -282,8 +282,8 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, pool->dirty_watermark = params->dirty_watermark; pool->dirty_len = 0; spin_lock_init(&pool->pool_lock); - atomic_set(&pool->req_ser, 0); - atomic_set(&pool->flush_ser, 0); + atomic_set_unchecked(&pool->req_ser, 0); + atomic_set_unchecked(&pool->flush_ser, 0); init_waitqueue_head(&pool->force_wait); pool->thread = kthread_run(ib_fmr_cleanup_thread, @@ -411,11 +411,11 @@ int ib_flush_fmr_pool(struct ib_fmr_pool *pool) } spin_unlock_irq(&pool->pool_lock); - serial = atomic_inc_return(&pool->req_ser); + serial = atomic_inc_return_unchecked(&pool->req_ser); wake_up_process(pool->thread); if (wait_event_interruptible(pool->force_wait, - atomic_read(&pool->flush_ser) - serial >= 0)) + atomic_read_unchecked(&pool->flush_ser) - serial >= 0)) return -EINTR; return 0; @@ -525,7 +525,7 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr) } else { list_add_tail(&fmr->list, &pool->dirty_list); if (++pool->dirty_len >= pool->dirty_watermark) { - atomic_inc(&pool->req_ser); + atomic_inc_unchecked(&pool->req_ser); wake_up_process(pool->thread); } } diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index be4cb9f..a2bd947 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -959,6 +959,9 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; + if (!access_ok_noprefault(VERIFY_READ, cmd.start, cmd.length)) + return -EFAULT; + INIT_UDATA(&udata, buf + sizeof cmd, (unsigned long) cmd.response + sizeof resp, in_len - sizeof cmd, out_len - sizeof resp); diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c index 026b91e..47c3bdb 100644 --- a/drivers/infiniband/hw/cxgb4/mem.c +++ b/drivers/infiniband/hw/cxgb4/mem.c @@ -256,7 +256,7 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry, int err; struct fw_ri_tpte tpt; u32 stag_idx; - static atomic_t key; + static atomic_unchecked_t key; if (c4iw_fatal_error(rdev)) return -EIO; @@ -277,7 +277,7 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry, if (rdev->stats.stag.cur > rdev->stats.stag.max) rdev->stats.stag.max = rdev->stats.stag.cur; mutex_unlock(&rdev->stats.lock); - *stag = (stag_idx << 8) | (atomic_inc_return(&key) & 0xff); + *stag = (stag_idx << 8) | (atomic_inc_return_unchecked(&key) & 0xff); } PDBG("%s stag_state 0x%0x type 0x%0x pdid 0x%0x, stag_idx 0x%x\n", __func__, stag_state, type, pdid, stag_idx); diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index 1cd75ff..8fc6bc7 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -98,7 +98,7 @@ __be64 mlx4_ib_gen_node_guid(void) __be64 mlx4_ib_get_new_demux_tid(struct mlx4_ib_demux_ctx *ctx) { - return cpu_to_be64(atomic_inc_return(&ctx->tid)) | + return cpu_to_be64(atomic_inc_return_unchecked(&ctx->tid)) | cpu_to_be64(0xff00000000000000LL); } diff --git a/drivers/infiniband/hw/mlx4/mcg.c b/drivers/infiniband/hw/mlx4/mcg.c index 2d5bccd..a5d2030 100644 --- a/drivers/infiniband/hw/mlx4/mcg.c +++ b/drivers/infiniband/hw/mlx4/mcg.c @@ -1046,7 +1046,7 @@ int mlx4_ib_mcg_port_init(struct mlx4_ib_demux_ctx *ctx) { char name[20]; - atomic_set(&ctx->tid, 0); + atomic_set_unchecked(&ctx->tid, 0); sprintf(name, "mlx4_ib_mcg%d", ctx->port); ctx->mcg_wq = create_singlethread_workqueue(name); if (!ctx->mcg_wq) diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index 1e7b23b..527fb1d 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -448,7 +448,7 @@ struct mlx4_ib_demux_ctx { struct list_head mcg_mgid0_list; struct workqueue_struct *mcg_wq; struct mlx4_ib_demux_pv_ctx **tun; - atomic_t tid; + atomic_unchecked_t tid; int flushing; /* flushing the work queue */ }; diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index c7f49bb..6a021bb 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -772,7 +772,7 @@ static void mthca_setup_cmd_doorbells(struct mthca_dev *dev, u64 base) mthca_dbg(dev, "Mapped doorbell page for posting FW commands\n"); } -int mthca_QUERY_FW(struct mthca_dev *dev) +int __intentional_overflow(-1) mthca_QUERY_FW(struct mthca_dev *dev) { struct mthca_mailbox *mailbox; u32 *outbox; @@ -1612,7 +1612,7 @@ int mthca_HW2SW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox, CMD_TIME_CLASS_B); } -int mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox, +int __intentional_overflow(-1) mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox, int num_mtt) { return mthca_cmd(dev, mailbox->dma, num_mtt, 0, CMD_WRITE_MTT, @@ -1634,7 +1634,7 @@ int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap, 0, CMD_MAP_EQ, CMD_TIME_CLASS_B); } -int mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, +int __intentional_overflow(-1) mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, int eq_num) { return mthca_cmd(dev, mailbox->dma, eq_num, 0, CMD_SW2HW_EQ, @@ -1857,7 +1857,7 @@ int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn) CMD_TIME_CLASS_B); } -int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey, +int __intentional_overflow(-1) mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey, int port, const struct ib_wc *in_wc, const struct ib_grh *in_grh, const void *in_mad, void *response_mad) { diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index ded76c1..0cf0a08 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -692,7 +692,7 @@ err_close: return err; } -static int mthca_setup_hca(struct mthca_dev *dev) +static int __intentional_overflow(-1) mthca_setup_hca(struct mthca_dev *dev) { int err; diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c index ed9a989..6aa5dc2 100644 --- a/drivers/infiniband/hw/mthca/mthca_mr.c +++ b/drivers/infiniband/hw/mthca/mthca_mr.c @@ -81,7 +81,7 @@ struct mthca_mpt_entry { * through the bitmaps) */ -static u32 mthca_buddy_alloc(struct mthca_buddy *buddy, int order) +static u32 __intentional_overflow(-1) mthca_buddy_alloc(struct mthca_buddy *buddy, int order) { int o; int m; @@ -426,7 +426,7 @@ static inline u32 adjust_key(struct mthca_dev *dev, u32 key) return key; } -int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift, +int __intentional_overflow(-1) mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift, u64 iova, u64 total_size, u32 access, struct mthca_mr *mr) { struct mthca_mailbox *mailbox; @@ -516,7 +516,7 @@ int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd, return mthca_mr_alloc(dev, pd, 12, 0, ~0ULL, access, mr); } -int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd, +int __intentional_overflow(-1) mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd, u64 *buffer_list, int buffer_size_shift, int list_len, u64 iova, u64 total_size, u32 access, struct mthca_mr *mr) diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index dc2d48c..c1deb7b 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -772,7 +772,7 @@ unlock: return 0; } -static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) +static int __intentional_overflow(-1) mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) { struct mthca_dev *dev = to_mdev(ibcq->device); struct mthca_cq *cq = to_mcq(ibcq); diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index 9f9d5c5..3c19aac 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -97,7 +97,7 @@ MODULE_PARM_DESC(limit_maxrdreqsz, "Limit max read request size to 256 Bytes"); LIST_HEAD(nes_adapter_list); static LIST_HEAD(nes_dev_list); -atomic_t qps_destroyed; +atomic_unchecked_t qps_destroyed; static unsigned int ee_flsh_adapter; static unsigned int sysfs_nonidx_addr; @@ -279,7 +279,7 @@ static void nes_cqp_rem_ref_callback(struct nes_device *nesdev, struct nes_cqp_r struct nes_qp *nesqp = cqp_request->cqp_callback_pointer; struct nes_adapter *nesadapter = nesdev->nesadapter; - atomic_inc(&qps_destroyed); + atomic_inc_unchecked(&qps_destroyed); /* Free the control structures */ diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h index bd9d132..70d84f4 100644 --- a/drivers/infiniband/hw/nes/nes.h +++ b/drivers/infiniband/hw/nes/nes.h @@ -180,17 +180,17 @@ extern unsigned int nes_debug_level; extern unsigned int wqm_quanta; extern struct list_head nes_adapter_list; -extern atomic_t cm_connects; -extern atomic_t cm_accepts; -extern atomic_t cm_disconnects; -extern atomic_t cm_closes; -extern atomic_t cm_connecteds; -extern atomic_t cm_connect_reqs; -extern atomic_t cm_rejects; -extern atomic_t mod_qp_timouts; -extern atomic_t qps_created; -extern atomic_t qps_destroyed; -extern atomic_t sw_qps_destroyed; +extern atomic_unchecked_t cm_connects; +extern atomic_unchecked_t cm_accepts; +extern atomic_unchecked_t cm_disconnects; +extern atomic_unchecked_t cm_closes; +extern atomic_unchecked_t cm_connecteds; +extern atomic_unchecked_t cm_connect_reqs; +extern atomic_unchecked_t cm_rejects; +extern atomic_unchecked_t mod_qp_timouts; +extern atomic_unchecked_t qps_created; +extern atomic_unchecked_t qps_destroyed; +extern atomic_unchecked_t sw_qps_destroyed; extern u32 mh_detected; extern u32 mh_pauses_sent; extern u32 cm_packets_sent; @@ -199,16 +199,16 @@ extern u32 cm_packets_created; extern u32 cm_packets_received; extern u32 cm_packets_dropped; extern u32 cm_packets_retrans; -extern atomic_t cm_listens_created; -extern atomic_t cm_listens_destroyed; +extern atomic_unchecked_t cm_listens_created; +extern atomic_unchecked_t cm_listens_destroyed; extern u32 cm_backlog_drops; -extern atomic_t cm_loopbacks; -extern atomic_t cm_nodes_created; -extern atomic_t cm_nodes_destroyed; -extern atomic_t cm_accel_dropped_pkts; -extern atomic_t cm_resets_recvd; -extern atomic_t pau_qps_created; -extern atomic_t pau_qps_destroyed; +extern atomic_unchecked_t cm_loopbacks; +extern atomic_unchecked_t cm_nodes_created; +extern atomic_unchecked_t cm_nodes_destroyed; +extern atomic_unchecked_t cm_accel_dropped_pkts; +extern atomic_unchecked_t cm_resets_recvd; +extern atomic_unchecked_t pau_qps_created; +extern atomic_unchecked_t pau_qps_destroyed; extern u32 int_mod_timer_init; extern u32 int_mod_cq_depth_256; diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 8a3ad17..e1ed4bc 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -69,14 +69,14 @@ u32 cm_packets_dropped; u32 cm_packets_retrans; u32 cm_packets_created; u32 cm_packets_received; -atomic_t cm_listens_created; -atomic_t cm_listens_destroyed; +atomic_unchecked_t cm_listens_created; +atomic_unchecked_t cm_listens_destroyed; u32 cm_backlog_drops; -atomic_t cm_loopbacks; -atomic_t cm_nodes_created; -atomic_t cm_nodes_destroyed; -atomic_t cm_accel_dropped_pkts; -atomic_t cm_resets_recvd; +atomic_unchecked_t cm_loopbacks; +atomic_unchecked_t cm_nodes_created; +atomic_unchecked_t cm_nodes_destroyed; +atomic_unchecked_t cm_accel_dropped_pkts; +atomic_unchecked_t cm_resets_recvd; static inline int mini_cm_accelerated(struct nes_cm_core *, struct nes_cm_node *); static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *, struct nes_vnic *, struct nes_cm_info *); @@ -135,28 +135,28 @@ static void record_ird_ord(struct nes_cm_node *, u16, u16); /* instance of function pointers for client API */ /* set address of this instance to cm_core->cm_ops at cm_core alloc */ static struct nes_cm_ops nes_cm_api = { - mini_cm_accelerated, - mini_cm_listen, - mini_cm_del_listen, - mini_cm_connect, - mini_cm_close, - mini_cm_accept, - mini_cm_reject, - mini_cm_recv_pkt, - mini_cm_dealloc_core, - mini_cm_get, - mini_cm_set + .accelerated = mini_cm_accelerated, + .listen = mini_cm_listen, + .stop_listener = mini_cm_del_listen, + .connect = mini_cm_connect, + .close = mini_cm_close, + .accept = mini_cm_accept, + .reject = mini_cm_reject, + .recv_pkt = mini_cm_recv_pkt, + .destroy_cm_core = mini_cm_dealloc_core, + .get = mini_cm_get, + .set = mini_cm_set }; static struct nes_cm_core *g_cm_core; -atomic_t cm_connects; -atomic_t cm_accepts; -atomic_t cm_disconnects; -atomic_t cm_closes; -atomic_t cm_connecteds; -atomic_t cm_connect_reqs; -atomic_t cm_rejects; +atomic_unchecked_t cm_connects; +atomic_unchecked_t cm_accepts; +atomic_unchecked_t cm_disconnects; +atomic_unchecked_t cm_closes; +atomic_unchecked_t cm_connecteds; +atomic_unchecked_t cm_connect_reqs; +atomic_unchecked_t cm_rejects; int nes_add_ref_cm_node(struct nes_cm_node *cm_node) { @@ -1461,7 +1461,7 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core, kfree(listener); listener = NULL; ret = 0; - atomic_inc(&cm_listens_destroyed); + atomic_inc_unchecked(&cm_listens_destroyed); } else { spin_unlock_irqrestore(&cm_core->listen_list_lock, flags); } @@ -1670,7 +1670,7 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core, cm_node->rem_mac); add_hte_node(cm_core, cm_node); - atomic_inc(&cm_nodes_created); + atomic_inc_unchecked(&cm_nodes_created); return cm_node; } @@ -1731,7 +1731,7 @@ static int rem_ref_cm_node(struct nes_cm_core *cm_core, } atomic_dec(&cm_core->node_cnt); - atomic_inc(&cm_nodes_destroyed); + atomic_inc_unchecked(&cm_nodes_destroyed); nesqp = cm_node->nesqp; if (nesqp) { nesqp->cm_node = NULL; @@ -1795,7 +1795,7 @@ static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, static void drop_packet(struct sk_buff *skb) { - atomic_inc(&cm_accel_dropped_pkts); + atomic_inc_unchecked(&cm_accel_dropped_pkts); dev_kfree_skb_any(skb); } @@ -1858,7 +1858,7 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, { int reset = 0; /* whether to send reset in case of err.. */ - atomic_inc(&cm_resets_recvd); + atomic_inc_unchecked(&cm_resets_recvd); nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u." " refcnt=%d\n", cm_node, cm_node->state, atomic_read(&cm_node->ref_count)); @@ -2526,7 +2526,7 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core, rem_ref_cm_node(cm_node->cm_core, cm_node); return NULL; } - atomic_inc(&cm_loopbacks); + atomic_inc_unchecked(&cm_loopbacks); loopbackremotenode->loopbackpartner = cm_node; loopbackremotenode->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE; @@ -2807,7 +2807,7 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core, nes_queue_mgt_skbs(skb, nesvnic, cm_node->nesqp); else { rem_ref_cm_node(cm_core, cm_node); - atomic_inc(&cm_accel_dropped_pkts); + atomic_inc_unchecked(&cm_accel_dropped_pkts); dev_kfree_skb_any(skb); } break; @@ -3118,7 +3118,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) if ((cm_id) && (cm_id->event_handler)) { if (issue_disconn) { - atomic_inc(&cm_disconnects); + atomic_inc_unchecked(&cm_disconnects); cm_event.event = IW_CM_EVENT_DISCONNECT; cm_event.status = disconn_status; cm_event.local_addr = cm_id->local_addr; @@ -3140,7 +3140,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) } if (issue_close) { - atomic_inc(&cm_closes); + atomic_inc_unchecked(&cm_closes); nes_disconnect(nesqp, 1); cm_id->provider_data = nesqp; @@ -3278,7 +3278,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) nes_debug(NES_DBG_CM, "QP%u, cm_node=%p, jiffies = %lu listener = %p\n", nesqp->hwqp.qp_id, cm_node, jiffies, cm_node->listener); - atomic_inc(&cm_accepts); + atomic_inc_unchecked(&cm_accepts); nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n", netdev_refcnt_read(nesvnic->netdev)); @@ -3476,7 +3476,7 @@ int nes_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len) struct nes_cm_core *cm_core; u8 *start_buff; - atomic_inc(&cm_rejects); + atomic_inc_unchecked(&cm_rejects); cm_node = (struct nes_cm_node *)cm_id->provider_data; loopback = cm_node->loopbackpartner; cm_core = cm_node->cm_core; @@ -3541,7 +3541,7 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) ntohs(raddr->sin_port), ntohl(laddr->sin_addr.s_addr), ntohs(laddr->sin_port)); - atomic_inc(&cm_connects); + atomic_inc_unchecked(&cm_connects); nesqp->active_conn = 1; /* cache the cm_id in the qp */ @@ -3688,7 +3688,7 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog) g_cm_core->api->stop_listener(g_cm_core, (void *)cm_node); return err; } - atomic_inc(&cm_listens_created); + atomic_inc_unchecked(&cm_listens_created); } cm_id->add_ref(cm_id); @@ -3795,7 +3795,7 @@ static void cm_event_connected(struct nes_cm_event *event) if (nesqp->destroyed) return; - atomic_inc(&cm_connecteds); + atomic_inc_unchecked(&cm_connecteds); nes_debug(NES_DBG_CM, "QP%u attempting to connect to 0x%08X:0x%04X on" " local port 0x%04X. jiffies = %lu.\n", nesqp->hwqp.qp_id, ntohl(raddr->sin_addr.s_addr), @@ -3980,7 +3980,7 @@ static void cm_event_reset(struct nes_cm_event *event) cm_id->add_ref(cm_id); ret = cm_id->event_handler(cm_id, &cm_event); - atomic_inc(&cm_closes); + atomic_inc_unchecked(&cm_closes); cm_event.event = IW_CM_EVENT_CLOSE; cm_event.status = 0; cm_event.provider_data = cm_id->provider_data; @@ -4020,7 +4020,7 @@ static void cm_event_mpa_req(struct nes_cm_event *event) return; cm_id = cm_node->cm_id; - atomic_inc(&cm_connect_reqs); + atomic_inc_unchecked(&cm_connect_reqs); nes_debug(NES_DBG_CM, "cm_node = %p - cm_id = %p, jiffies = %lu\n", cm_node, cm_id, jiffies); @@ -4069,7 +4069,7 @@ static void cm_event_mpa_reject(struct nes_cm_event *event) return; cm_id = cm_node->cm_id; - atomic_inc(&cm_connect_reqs); + atomic_inc_unchecked(&cm_connect_reqs); nes_debug(NES_DBG_CM, "cm_node = %p - cm_id = %p, jiffies = %lu\n", cm_node, cm_id, jiffies); diff --git a/drivers/infiniband/hw/nes/nes_mgt.c b/drivers/infiniband/hw/nes/nes_mgt.c index 4166452..fc952c3 100644 --- a/drivers/infiniband/hw/nes/nes_mgt.c +++ b/drivers/infiniband/hw/nes/nes_mgt.c @@ -40,8 +40,8 @@ #include "nes.h" #include "nes_mgt.h" -atomic_t pau_qps_created; -atomic_t pau_qps_destroyed; +atomic_unchecked_t pau_qps_created; +atomic_unchecked_t pau_qps_destroyed; static void nes_replenish_mgt_rq(struct nes_vnic_mgt *mgtvnic) { @@ -621,7 +621,7 @@ void nes_destroy_pau_qp(struct nes_device *nesdev, struct nes_qp *nesqp) { struct sk_buff *skb; unsigned long flags; - atomic_inc(&pau_qps_destroyed); + atomic_inc_unchecked(&pau_qps_destroyed); /* Free packets that have not yet been forwarded */ /* Lock is acquired by skb_dequeue when removing the skb */ @@ -810,7 +810,7 @@ static void nes_mgt_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq * cq->cq_vbase[head].cqe_words[NES_NIC_CQE_HASH_RCVNXT]); skb_queue_head_init(&nesqp->pau_list); spin_lock_init(&nesqp->pau_lock); - atomic_inc(&pau_qps_created); + atomic_inc_unchecked(&pau_qps_created); nes_change_quad_hash(nesdev, mgtvnic->nesvnic, nesqp); } diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index 70acda9..a96de9d 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -1274,39 +1274,39 @@ static void nes_netdev_get_ethtool_stats(struct net_device *netdev, target_stat_values[++index] = mh_detected; target_stat_values[++index] = mh_pauses_sent; target_stat_values[++index] = nesvnic->endnode_ipv4_tcp_retransmits; - target_stat_values[++index] = atomic_read(&cm_connects); - target_stat_values[++index] = atomic_read(&cm_accepts); - target_stat_values[++index] = atomic_read(&cm_disconnects); - target_stat_values[++index] = atomic_read(&cm_connecteds); - target_stat_values[++index] = atomic_read(&cm_connect_reqs); - target_stat_values[++index] = atomic_read(&cm_rejects); - target_stat_values[++index] = atomic_read(&mod_qp_timouts); - target_stat_values[++index] = atomic_read(&qps_created); - target_stat_values[++index] = atomic_read(&sw_qps_destroyed); - target_stat_values[++index] = atomic_read(&qps_destroyed); - target_stat_values[++index] = atomic_read(&cm_closes); + target_stat_values[++index] = atomic_read_unchecked(&cm_connects); + target_stat_values[++index] = atomic_read_unchecked(&cm_accepts); + target_stat_values[++index] = atomic_read_unchecked(&cm_disconnects); + target_stat_values[++index] = atomic_read_unchecked(&cm_connecteds); + target_stat_values[++index] = atomic_read_unchecked(&cm_connect_reqs); + target_stat_values[++index] = atomic_read_unchecked(&cm_rejects); + target_stat_values[++index] = atomic_read_unchecked(&mod_qp_timouts); + target_stat_values[++index] = atomic_read_unchecked(&qps_created); + target_stat_values[++index] = atomic_read_unchecked(&sw_qps_destroyed); + target_stat_values[++index] = atomic_read_unchecked(&qps_destroyed); + target_stat_values[++index] = atomic_read_unchecked(&cm_closes); target_stat_values[++index] = cm_packets_sent; target_stat_values[++index] = cm_packets_bounced; target_stat_values[++index] = cm_packets_created; target_stat_values[++index] = cm_packets_received; target_stat_values[++index] = cm_packets_dropped; target_stat_values[++index] = cm_packets_retrans; - target_stat_values[++index] = atomic_read(&cm_listens_created); - target_stat_values[++index] = atomic_read(&cm_listens_destroyed); + target_stat_values[++index] = atomic_read_unchecked(&cm_listens_created); + target_stat_values[++index] = atomic_read_unchecked(&cm_listens_destroyed); target_stat_values[++index] = cm_backlog_drops; - target_stat_values[++index] = atomic_read(&cm_loopbacks); - target_stat_values[++index] = atomic_read(&cm_nodes_created); - target_stat_values[++index] = atomic_read(&cm_nodes_destroyed); - target_stat_values[++index] = atomic_read(&cm_accel_dropped_pkts); - target_stat_values[++index] = atomic_read(&cm_resets_recvd); + target_stat_values[++index] = atomic_read_unchecked(&cm_loopbacks); + target_stat_values[++index] = atomic_read_unchecked(&cm_nodes_created); + target_stat_values[++index] = atomic_read_unchecked(&cm_nodes_destroyed); + target_stat_values[++index] = atomic_read_unchecked(&cm_accel_dropped_pkts); + target_stat_values[++index] = atomic_read_unchecked(&cm_resets_recvd); target_stat_values[++index] = nesadapter->free_4kpbl; target_stat_values[++index] = nesadapter->free_256pbl; target_stat_values[++index] = int_mod_timer_init; target_stat_values[++index] = nesvnic->lro_mgr.stats.aggregated; target_stat_values[++index] = nesvnic->lro_mgr.stats.flushed; target_stat_values[++index] = nesvnic->lro_mgr.stats.no_desc; - target_stat_values[++index] = atomic_read(&pau_qps_created); - target_stat_values[++index] = atomic_read(&pau_qps_destroyed); + target_stat_values[++index] = atomic_read_unchecked(&pau_qps_created); + target_stat_values[++index] = atomic_read_unchecked(&pau_qps_destroyed); } /** diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 44cb513..6702198 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -46,9 +46,9 @@ #include -atomic_t mod_qp_timouts; -atomic_t qps_created; -atomic_t sw_qps_destroyed; +atomic_unchecked_t mod_qp_timouts; +atomic_unchecked_t qps_created; +atomic_unchecked_t sw_qps_destroyed; static void nes_unregister_ofa_device(struct nes_ib_device *nesibdev); @@ -1146,7 +1146,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd, if (init_attr->create_flags) return ERR_PTR(-EINVAL); - atomic_inc(&qps_created); + atomic_inc_unchecked(&qps_created); switch (init_attr->qp_type) { case IB_QPT_RC: if (nes_drv_opt & NES_DRV_OPT_NO_INLINE_DATA) { @@ -1480,7 +1480,7 @@ static int nes_destroy_qp(struct ib_qp *ibqp) struct iw_cm_event cm_event; int ret = 0; - atomic_inc(&sw_qps_destroyed); + atomic_inc_unchecked(&sw_qps_destroyed); 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/ulp/ipoib/ipoib_netlink.c b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c index cdc7df4..a2fdfdb 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c @@ -156,7 +156,7 @@ static size_t ipoib_get_size(const struct net_device *dev) nla_total_size(2); /* IFLA_IPOIB_UMCAST */ } -static struct rtnl_link_ops ipoib_link_ops __read_mostly = { +static struct rtnl_link_ops ipoib_link_ops = { .kind = "ipoib", .maxtype = IFLA_IPOIB_MAX, .policy = ipoib_policy, diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 4a2a9e3..b9261a7 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -527,14 +527,14 @@ EXPORT_SYMBOL(gameport_set_phys); */ static void gameport_init_port(struct gameport *gameport) { - static atomic_t gameport_no = ATOMIC_INIT(-1); + static atomic_unchecked_t gameport_no = ATOMIC_INIT(-1); __module_get(THIS_MODULE); mutex_init(&gameport->drv_mutex); device_initialize(&gameport->dev); dev_set_name(&gameport->dev, "gameport%lu", - (unsigned long)atomic_inc_return(&gameport_no)); + (unsigned long)atomic_inc_return_unchecked(&gameport_no)); gameport->dev.bus = &gameport_bus; gameport->dev.release = gameport_release_port; if (gameport->parent) diff --git a/drivers/input/input.c b/drivers/input/input.c index 5391abd..d454638 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1781,7 +1781,7 @@ EXPORT_SYMBOL_GPL(input_class); */ struct input_dev *input_allocate_device(void) { - static atomic_t input_no = ATOMIC_INIT(-1); + static atomic_unchecked_t input_no = ATOMIC_INIT(-1); struct input_dev *dev; dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); @@ -1796,7 +1796,7 @@ struct input_dev *input_allocate_device(void) INIT_LIST_HEAD(&dev->node); dev_set_name(&dev->dev, "input%lu", - (unsigned long)atomic_inc_return(&input_no)); + (unsigned long)atomic_inc_return_unchecked(&input_no)); __module_get(THIS_MODULE); } diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c index 4a95b22..874c182 100644 --- a/drivers/input/joystick/sidewinder.c +++ b/drivers/input/joystick/sidewinder.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index f8850f9..9708a2d 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -959,7 +959,7 @@ static void xpad_led_set(struct led_classdev *led_cdev, static int xpad_led_probe(struct usb_xpad *xpad) { - static atomic_t led_seq = ATOMIC_INIT(-1); + static atomic_unchecked_t led_seq = ATOMIC_INIT(-1); struct xpad_led *led; struct led_classdev *led_cdev; int error; @@ -971,7 +971,7 @@ static int xpad_led_probe(struct usb_xpad *xpad) if (!led) return -ENOMEM; - xpad->led_no = atomic_inc_return(&led_seq); + xpad->led_no = atomic_inc_return_unchecked(&led_seq); snprintf(led->name, sizeof(led->name), "xpad%lu", xpad->led_no); led->xpad = xpad; diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c index ac1fa5f..5f7502c 100644 --- a/drivers/input/misc/ims-pcu.c +++ b/drivers/input/misc/ims-pcu.c @@ -1851,7 +1851,7 @@ static int ims_pcu_identify_type(struct ims_pcu *pcu, u8 *device_id) static int ims_pcu_init_application_mode(struct ims_pcu *pcu) { - static atomic_t device_no = ATOMIC_INIT(-1); + static atomic_unchecked_t device_no = ATOMIC_INIT(-1); const struct ims_pcu_device_info *info; int error; @@ -1882,7 +1882,7 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu) } /* Device appears to be operable, complete initialization */ - pcu->device_no = atomic_inc_return(&device_no); + pcu->device_no = atomic_inc_return_unchecked(&device_no); /* * PCU-B devices, both GEN_1 and GEN_2 do not have OFN sensor diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index ad5a5a1..5eac214 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -125,7 +125,7 @@ struct psmouse_attribute { ssize_t (*set)(struct psmouse *psmouse, void *data, const char *buf, size_t count); bool protect; -}; +} __do_const; #define to_psmouse_attr(a) container_of((a), struct psmouse_attribute, dattr) ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *attr, diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index b604564..3f14ae4 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -744,7 +744,7 @@ static ssize_t mousedev_read(struct file *file, char __user *buffer, spin_unlock_irq(&client->packet_lock); - if (copy_to_user(buffer, data, count)) + if (count > sizeof(data) || copy_to_user(buffer, data, count)) return -EFAULT; return count; diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 8f82897..f5efcd9 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -512,7 +512,7 @@ static void serio_release_port(struct device *dev) */ static void serio_init_port(struct serio *serio) { - static atomic_t serio_no = ATOMIC_INIT(-1); + static atomic_unchecked_t serio_no = ATOMIC_INIT(-1); __module_get(THIS_MODULE); @@ -523,7 +523,7 @@ static void serio_init_port(struct serio *serio) mutex_init(&serio->drv_mutex); device_initialize(&serio->dev); dev_set_name(&serio->dev, "serio%lu", - (unsigned long)atomic_inc_return(&serio_no)); + (unsigned long)atomic_inc_return_unchecked(&serio_no)); serio->dev.bus = &serio_bus; serio->dev.release = serio_release_port; serio->dev.groups = serio_device_attr_groups; diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 71ef5d6..93380a9 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -292,7 +292,7 @@ static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data, static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) { - static atomic_t serio_raw_no = ATOMIC_INIT(-1); + static atomic_unchecked_t serio_raw_no = ATOMIC_INIT(-1); struct serio_raw *serio_raw; int err; @@ -303,7 +303,7 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) } snprintf(serio_raw->name, sizeof(serio_raw->name), - "serio_raw%ld", (long)atomic_inc_return(&serio_raw_no)); + "serio_raw%ld", (long)atomic_inc_return_unchecked(&serio_raw_no)); kref_init(&serio_raw->kref); INIT_LIST_HEAD(&serio_raw->client_list); init_waitqueue_head(&serio_raw->wait); diff --git a/drivers/input/touchscreen/htcpen.c b/drivers/input/touchscreen/htcpen.c index 92e2243..8fd9092 100644 --- a/drivers/input/touchscreen/htcpen.c +++ b/drivers/input/touchscreen/htcpen.c @@ -219,7 +219,7 @@ static struct isa_driver htcpen_isa_driver = { } }; -static struct dmi_system_id htcshift_dmi_table[] __initdata = { +static const struct dmi_system_id htcshift_dmi_table[] __initconst = { { .ident = "Shift", .matches = { diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index cbe6a89..da64411 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -102,6 +102,7 @@ config AMD_IOMMU_STATS bool "Export AMD IOMMU statistics to debugfs" depends on AMD_IOMMU select DEBUG_FS + depends on !GRKERNSEC_KMEM ---help--- This option enables code in the AMD IOMMU driver to collect various statistics about whats happening in the driver and exports that diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 532e2a2..a60aa73 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -794,11 +794,21 @@ static void copy_cmd_to_buffer(struct amd_iommu *iommu, static void build_completion_wait(struct iommu_cmd *cmd, u64 address) { + phys_addr_t physaddr; WARN_ON(address & 0x7ULL); memset(cmd, 0, sizeof(*cmd)); - cmd->data[0] = lower_32_bits(__pa(address)) | CMD_COMPL_WAIT_STORE_MASK; - cmd->data[1] = upper_32_bits(__pa(address)); + +#ifdef CONFIG_GRKERNSEC_KSTACKOVERFLOW + if (object_starts_on_stack((void *)address)) { + void *adjbuf = (void *)address - current->stack + current->lowmem_stack; + physaddr = __pa((u64)adjbuf); + } else +#endif + physaddr = __pa(address); + + cmd->data[0] = lower_32_bits(physaddr) | CMD_COMPL_WAIT_STORE_MASK; + cmd->data[1] = upper_32_bits(physaddr); cmd->data[2] = 1; CMD_SET_TYPE(cmd, CMD_COMPL_WAIT); } diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 286e890..c2220cc 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -1516,7 +1516,7 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain) .iommu_dev = smmu->dev, }; - pgtbl_ops = alloc_io_pgtable_ops(fmt, &pgtbl_cfg, smmu_domain); + pgtbl_ops = alloc_io_pgtable(fmt, &pgtbl_cfg, smmu_domain); if (!pgtbl_ops) return -ENOMEM; diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 48a39df..d7db978 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -331,7 +331,7 @@ enum arm_smmu_domain_stage { struct arm_smmu_domain { struct arm_smmu_device *smmu; - struct io_pgtable_ops *pgtbl_ops; + struct io_pgtable *pgtbl; spinlock_t pgtbl_lock; struct arm_smmu_cfg cfg; enum arm_smmu_domain_stage stage; @@ -793,7 +793,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, { int irq, start, ret = 0; unsigned long ias, oas; - struct io_pgtable_ops *pgtbl_ops; + struct io_pgtable *pgtbl; struct io_pgtable_cfg pgtbl_cfg; enum io_pgtable_fmt fmt; struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); @@ -879,14 +879,16 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, }; smmu_domain->smmu = smmu; - pgtbl_ops = alloc_io_pgtable_ops(fmt, &pgtbl_cfg, smmu_domain); - if (!pgtbl_ops) { + pgtbl = alloc_io_pgtable(fmt, &pgtbl_cfg, smmu_domain); + if (!pgtbl) { ret = -ENOMEM; goto out_clear_smmu; } /* 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; + pax_close_kernel(); /* Initialise the context bank with our page table cfg */ arm_smmu_init_context_bank(smmu_domain, &pgtbl_cfg); @@ -907,7 +909,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, mutex_unlock(&smmu_domain->init_mutex); /* Publish page table ops for map/unmap */ - smmu_domain->pgtbl_ops = pgtbl_ops; + smmu_domain->pgtbl = pgtbl; return 0; out_clear_smmu: @@ -940,8 +942,7 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain) free_irq(irq, domain); } - if (smmu_domain->pgtbl_ops) - free_io_pgtable_ops(smmu_domain->pgtbl_ops); + free_io_pgtable(smmu_domain->pgtbl); __arm_smmu_free_bitmap(smmu->context_map, cfg->cbndx); } @@ -1167,13 +1168,13 @@ static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova, int ret; unsigned long flags; struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); - struct io_pgtable_ops *ops= smmu_domain->pgtbl_ops; + struct io_pgtable *iop = smmu_domain->pgtbl; - if (!ops) + if (!iop) return -ENODEV; spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags); - ret = ops->map(ops, iova, paddr, size, prot); + ret = iop->ops->map(iop, iova, paddr, size, prot); spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags); return ret; } @@ -1184,13 +1185,13 @@ static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova, size_t ret; unsigned long flags; struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); - struct io_pgtable_ops *ops= smmu_domain->pgtbl_ops; + struct io_pgtable *iop = smmu_domain->pgtbl; - if (!ops) + if (!iop) return 0; spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags); - ret = ops->unmap(ops, iova, size); + ret = iop->ops->unmap(iop, iova, size); spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags); return ret; } @@ -1201,7 +1202,7 @@ static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain, struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); struct arm_smmu_device *smmu = smmu_domain->smmu; struct arm_smmu_cfg *cfg = &smmu_domain->cfg; - struct io_pgtable_ops *ops= smmu_domain->pgtbl_ops; + struct io_pgtable *iop = smmu_domain->pgtbl; struct device *dev = smmu->dev; void __iomem *cb_base; u32 tmp; @@ -1224,7 +1225,7 @@ static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain, dev_err(dev, "iova to phys timed out on 0x%pad. Falling back to software table walk.\n", &iova); - return ops->iova_to_phys(ops, iova); + return iop->ops->iova_to_phys(iop, iova); } phys = readl_relaxed(cb_base + ARM_SMMU_CB_PAR_LO); @@ -1245,9 +1246,9 @@ static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain, phys_addr_t ret; unsigned long flags; struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); - struct io_pgtable_ops *ops= smmu_domain->pgtbl_ops; + struct io_pgtable *iop = smmu_domain->pgtbl; - if (!ops) + if (!iop) return 0; spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags); @@ -1255,7 +1256,7 @@ static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain, smmu_domain->stage == ARM_SMMU_DOMAIN_S1) { ret = arm_smmu_iova_to_phys_hard(domain, iova); } else { - ret = ops->iova_to_phys(ops, iova); + ret = iop->ops->iova_to_phys(iop, iova); } spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags); @@ -1658,7 +1659,9 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) size |= SZ_64K | SZ_512M; } - arm_smmu_ops.pgsize_bitmap &= size; + pax_open_kernel(); + *(unsigned long *)&arm_smmu_ops.pgsize_bitmap &= size; + pax_close_kernel(); dev_notice(smmu->dev, "\tSupported page sizes: 0x%08lx\n", size); if (smmu->features & ARM_SMMU_FEAT_TRANS_S1) diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 7df9777..6fc3d9a 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -38,12 +38,6 @@ #define io_pgtable_to_data(x) \ container_of((x), struct arm_lpae_io_pgtable, iop) -#define io_pgtable_ops_to_pgtable(x) \ - container_of((x), struct io_pgtable, ops) - -#define io_pgtable_ops_to_data(x) \ - io_pgtable_to_data(io_pgtable_ops_to_pgtable(x)) - /* * For consistency with the architecture, we always consider * ARM_LPAE_MAX_LEVELS levels, with the walk starting at level n >=0 @@ -376,10 +370,10 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data, return pte; } -static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova, +static int arm_lpae_map(struct io_pgtable *iop, unsigned long iova, phys_addr_t paddr, size_t size, int iommu_prot) { - struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); + struct arm_lpae_io_pgtable *data = io_pgtable_to_data(iop); arm_lpae_iopte *ptep = data->pgd; int ret, lvl = ARM_LPAE_START_LVL(data); arm_lpae_iopte prot; @@ -523,12 +517,11 @@ static int __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, return __arm_lpae_unmap(data, iova, size, lvl + 1, ptep); } -static int arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova, +static int arm_lpae_unmap(struct io_pgtable *iop, unsigned long iova, size_t size) { size_t unmapped; - struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); - struct io_pgtable *iop = &data->iop; + struct arm_lpae_io_pgtable *data = io_pgtable_to_data(iop); arm_lpae_iopte *ptep = data->pgd; int lvl = ARM_LPAE_START_LVL(data); @@ -539,10 +532,10 @@ static int arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova, return unmapped; } -static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops, +static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable *iop, unsigned long iova) { - struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); + struct arm_lpae_io_pgtable *data = io_pgtable_to_data(iop); arm_lpae_iopte pte, *ptep = data->pgd; int lvl = ARM_LPAE_START_LVL(data); @@ -609,6 +602,12 @@ static void arm_lpae_restrict_pgsizes(struct io_pgtable_cfg *cfg) } } +static struct io_pgtable_ops arm_lpae_io_pgtable_ops = { + .map = arm_lpae_map, + .unmap = arm_lpae_unmap, + .iova_to_phys = arm_lpae_iova_to_phys, +}; + static struct arm_lpae_io_pgtable * arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg) { @@ -645,11 +644,7 @@ arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg) pgd_bits = va_bits - (data->bits_per_level * (data->levels - 1)); data->pgd_size = 1UL << (pgd_bits + ilog2(sizeof(arm_lpae_iopte))); - data->iop.ops = (struct io_pgtable_ops) { - .map = arm_lpae_map, - .unmap = arm_lpae_unmap, - .iova_to_phys = arm_lpae_iova_to_phys, - }; + data->iop.ops = &arm_lpae_io_pgtable_ops; return data; } @@ -907,9 +902,9 @@ static struct iommu_gather_ops dummy_tlb_ops __initdata = { .tlb_sync = dummy_tlb_sync, }; -static void __init arm_lpae_dump_ops(struct io_pgtable_ops *ops) +static void __init arm_lpae_dump_ops(struct io_pgtable *iop) { - struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); + struct arm_lpae_io_pgtable *data = io_pgtable_to_data(iop); struct io_pgtable_cfg *cfg = &data->iop.cfg; pr_err("cfg: pgsize_bitmap 0x%lx, ias %u-bit\n", @@ -919,9 +914,9 @@ static void __init arm_lpae_dump_ops(struct io_pgtable_ops *ops) data->bits_per_level, data->pgd); } -#define __FAIL(ops, i) ({ \ +#define __FAIL(iop, i) ({ \ WARN(1, "selftest: test failed for fmt idx %d\n", (i)); \ - arm_lpae_dump_ops(ops); \ + arm_lpae_dump_ops(iop); \ selftest_running = false; \ -EFAULT; \ }) @@ -936,30 +931,32 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg) int i, j; unsigned long iova; size_t size; - struct io_pgtable_ops *ops; + struct io_pgtable *iop; + const struct io_pgtable_ops *ops; selftest_running = true; for (i = 0; i < ARRAY_SIZE(fmts); ++i) { cfg_cookie = cfg; - ops = alloc_io_pgtable_ops(fmts[i], cfg, cfg); - if (!ops) { + iop = alloc_io_pgtable(fmts[i], cfg, cfg); + if (!iop) { pr_err("selftest: failed to allocate io pgtable ops\n"); return -ENOMEM; } + ops = iop->ops; /* * Initial sanity checks. * Empty page tables shouldn't provide any translations. */ - if (ops->iova_to_phys(ops, 42)) - return __FAIL(ops, i); + if (ops->iova_to_phys(iop, 42)) + return __FAIL(iop, i); - if (ops->iova_to_phys(ops, SZ_1G + 42)) - return __FAIL(ops, i); + if (ops->iova_to_phys(iop, SZ_1G + 42)) + return __FAIL(iop, i); - if (ops->iova_to_phys(ops, SZ_2G + 42)) - return __FAIL(ops, i); + if (ops->iova_to_phys(iop, SZ_2G + 42)) + return __FAIL(iop, i); /* * Distinct mappings of different granule sizes. @@ -969,19 +966,19 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg) while (j != BITS_PER_LONG) { size = 1UL << j; - if (ops->map(ops, iova, iova, size, IOMMU_READ | + if (ops->map(iop, iova, iova, size, IOMMU_READ | IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_CACHE)) - return __FAIL(ops, i); + return __FAIL(iop, i); /* Overlapping mappings */ - if (!ops->map(ops, iova, iova + size, size, + if (!ops->map(iop, iova, iova + size, size, IOMMU_READ | IOMMU_NOEXEC)) - return __FAIL(ops, i); + return __FAIL(iop, i); - if (ops->iova_to_phys(ops, iova + 42) != (iova + 42)) - return __FAIL(ops, i); + if (ops->iova_to_phys(iop, iova + 42) != (iova + 42)) + return __FAIL(iop, i); iova += SZ_1G; j++; @@ -990,15 +987,15 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg) /* Partial unmap */ size = 1UL << __ffs(cfg->pgsize_bitmap); - if (ops->unmap(ops, SZ_1G + size, size) != size) - return __FAIL(ops, i); + if (ops->unmap(iop, SZ_1G + size, size) != size) + return __FAIL(iop, i); /* Remap of partial unmap */ - if (ops->map(ops, SZ_1G + size, size, size, IOMMU_READ)) - return __FAIL(ops, i); + if (ops->map(iop, SZ_1G + size, size, size, IOMMU_READ)) + return __FAIL(iop, i); - if (ops->iova_to_phys(ops, SZ_1G + size + 42) != (size + 42)) - return __FAIL(ops, i); + if (ops->iova_to_phys(iop, SZ_1G + size + 42) != (size + 42)) + return __FAIL(iop, i); /* Full unmap */ iova = 0; @@ -1006,25 +1003,25 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg) while (j != BITS_PER_LONG) { size = 1UL << j; - if (ops->unmap(ops, iova, size) != size) - return __FAIL(ops, i); + if (ops->unmap(iop, iova, size) != size) + return __FAIL(iop, i); - if (ops->iova_to_phys(ops, iova + 42)) - return __FAIL(ops, i); + if (ops->iova_to_phys(iop, iova + 42)) + return __FAIL(iop, i); /* Remap full block */ - if (ops->map(ops, iova, iova, size, IOMMU_WRITE)) - return __FAIL(ops, i); + if (ops->map(iop, iova, iova, size, IOMMU_WRITE)) + return __FAIL(iop, i); - if (ops->iova_to_phys(ops, iova + 42) != (iova + 42)) - return __FAIL(ops, i); + if (ops->iova_to_phys(iop, iova + 42) != (iova + 42)) + return __FAIL(iop, i); iova += SZ_1G; j++; j = find_next_bit(&cfg->pgsize_bitmap, BITS_PER_LONG, j); } - free_io_pgtable_ops(ops); + free_io_pgtable(iop); } selftest_running = false; diff --git a/drivers/iommu/io-pgtable.c b/drivers/iommu/io-pgtable.c index 6f2e319..c24d09a 100644 --- a/drivers/iommu/io-pgtable.c +++ b/drivers/iommu/io-pgtable.c @@ -35,7 +35,7 @@ io_pgtable_init_table[IO_PGTABLE_NUM_FMTS] = #endif }; -struct io_pgtable_ops *alloc_io_pgtable_ops(enum io_pgtable_fmt fmt, +struct io_pgtable *alloc_io_pgtable(enum io_pgtable_fmt fmt, struct io_pgtable_cfg *cfg, void *cookie) { @@ -57,21 +57,18 @@ struct io_pgtable_ops *alloc_io_pgtable_ops(enum io_pgtable_fmt fmt, iop->cookie = cookie; iop->cfg = *cfg; - return &iop->ops; + return iop; } /* * It is the IOMMU driver's responsibility to ensure that the page table * is no longer accessible to the walker by this point. */ -void free_io_pgtable_ops(struct io_pgtable_ops *ops) +void free_io_pgtable(struct io_pgtable *iop) { - struct io_pgtable *iop; - - if (!ops) + if (!iop) return; - iop = container_of(ops, struct io_pgtable, ops); iop->cfg.tlb->tlb_flush_all(iop->cookie); io_pgtable_init_table[iop->fmt]->free(iop); } diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h index ac9e234..a2f206e 100644 --- a/drivers/iommu/io-pgtable.h +++ b/drivers/iommu/io-pgtable.h @@ -78,17 +78,18 @@ struct io_pgtable_cfg { * These functions map directly onto the iommu_ops member functions with * the same names. */ +struct io_pgtable; struct io_pgtable_ops { - int (*map)(struct io_pgtable_ops *ops, unsigned long iova, + int (*map)(struct io_pgtable *iop, unsigned long iova, phys_addr_t paddr, size_t size, int prot); - int (*unmap)(struct io_pgtable_ops *ops, unsigned long iova, + int (*unmap)(struct io_pgtable *iop, unsigned long iova, size_t size); - phys_addr_t (*iova_to_phys)(struct io_pgtable_ops *ops, + phys_addr_t (*iova_to_phys)(struct io_pgtable *iop, unsigned long iova); }; /** - * alloc_io_pgtable_ops() - Allocate a page table allocator for use by an IOMMU. + * alloc_io_pgtable() - Allocate a page table allocator for use by an IOMMU. * * @fmt: The page table format. * @cfg: The page table configuration. This will be modified to represent @@ -97,9 +98,9 @@ struct io_pgtable_ops { * @cookie: An opaque token provided by the IOMMU driver and passed back to * the callback routines in cfg->tlb. */ -struct io_pgtable_ops *alloc_io_pgtable_ops(enum io_pgtable_fmt fmt, - struct io_pgtable_cfg *cfg, - void *cookie); +struct io_pgtable *alloc_io_pgtable(enum io_pgtable_fmt fmt, + struct io_pgtable_cfg *cfg, + void *cookie); /** * free_io_pgtable_ops() - Free an io_pgtable_ops structure. The caller @@ -108,7 +109,7 @@ struct io_pgtable_ops *alloc_io_pgtable_ops(enum io_pgtable_fmt fmt, * * @ops: The ops returned from alloc_io_pgtable_ops. */ -void free_io_pgtable_ops(struct io_pgtable_ops *ops); +void free_io_pgtable(struct io_pgtable *iop); /* @@ -128,7 +129,7 @@ struct io_pgtable { enum io_pgtable_fmt fmt; void *cookie; struct io_pgtable_cfg cfg; - struct io_pgtable_ops ops; + const struct io_pgtable_ops *ops; }; /** diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 049df49..da1f16d 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -934,7 +934,7 @@ static int iommu_bus_notifier(struct notifier_block *nb, static int iommu_bus_init(struct bus_type *bus, const struct iommu_ops *ops) { int err; - struct notifier_block *nb; + notifier_block_no_const *nb; struct iommu_callback_data cb = { .ops = ops, }; diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index 8cf605f..388b01f 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -41,7 +41,7 @@ struct ipmmu_vmsa_domain { struct iommu_domain io_domain; struct io_pgtable_cfg cfg; - struct io_pgtable_ops *iop; + struct io_pgtable *iop; unsigned int context_id; spinlock_t lock; /* Protects mappings */ @@ -319,8 +319,7 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) */ domain->cfg.iommu_dev = domain->mmu->dev; - domain->iop = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &domain->cfg, - domain); + domain->iop = alloc_io_pgtable(ARM_32_LPAE_S1, &domain->cfg, domain); if (!domain->iop) return -EINVAL; @@ -478,7 +477,7 @@ static void ipmmu_domain_free(struct iommu_domain *io_domain) * been detached. */ ipmmu_domain_destroy_context(domain); - free_io_pgtable_ops(domain->iop); + free_io_pgtable(domain->iop); kfree(domain); } @@ -547,7 +546,7 @@ static int ipmmu_map(struct iommu_domain *io_domain, unsigned long iova, if (!domain) return -ENODEV; - return domain->iop->map(domain->iop, iova, paddr, size, prot); + return domain->iop->ops->map(domain->iop, iova, paddr, size, prot); } static size_t ipmmu_unmap(struct iommu_domain *io_domain, unsigned long iova, @@ -555,7 +554,7 @@ static size_t ipmmu_unmap(struct iommu_domain *io_domain, unsigned long iova, { struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); - return domain->iop->unmap(domain->iop, iova, size); + return domain->iop->ops->unmap(domain->iop, iova, size); } static phys_addr_t ipmmu_iova_to_phys(struct iommu_domain *io_domain, @@ -565,7 +564,7 @@ static phys_addr_t ipmmu_iova_to_phys(struct iommu_domain *io_domain, /* TODO: Is locking needed ? */ - return domain->iop->iova_to_phys(domain->iop, iova); + return domain->iop->ops->iova_to_phys(domain->iop, iova); } static int ipmmu_find_utlbs(struct ipmmu_vmsa_device *mmu, struct device *dev, diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 913455a..d7e8048 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -149,7 +149,7 @@ int __init irq_remap_enable_fault_handling(void) void panic_if_irq_remap(const char *msg) { if (irq_remapping_enabled) - panic(msg); + panic("%s", msg); } void ir_ack_apic_edge(struct irq_data *data) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 982c09c..47e1aa8 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -368,7 +368,7 @@ static void gic_handle_cascade_irq(struct irq_desc *desc) chained_irq_exit(chip, desc); } -static struct irq_chip gic_chip = { +static irq_chip_no_const gic_chip __read_only = { .name = "GIC", .irq_mask = gic_mask_irq, .irq_unmask = gic_unmask_irq, diff --git a/drivers/irqchip/irq-i8259.c b/drivers/irqchip/irq-i8259.c index e484fd2..b6cdf69 100644 --- a/drivers/irqchip/irq-i8259.c +++ b/drivers/irqchip/irq-i8259.c @@ -204,7 +204,7 @@ spurious_8259A_irq: printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq); spurious_irq_mask |= irqmask; } - atomic_inc(&irq_err_count); + atomic_inc_unchecked(&irq_err_count); /* * Theoretically we do not have to handle this IRQ, * but in Linux this does not cause problems and is diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c index 9525335..f0322eb 100644 --- a/drivers/irqchip/irq-renesas-intc-irqpin.c +++ b/drivers/irqchip/irq-renesas-intc-irqpin.c @@ -382,7 +382,7 @@ static int intc_irqpin_probe(struct platform_device *pdev) struct intc_irqpin_iomem *i; struct resource *io[INTC_IRQPIN_REG_NR]; struct resource *irq; - struct irq_chip *irq_chip; + irq_chip_no_const *irq_chip; void (*enable_fn)(struct irq_data *d); void (*disable_fn)(struct irq_data *d); const char *name = dev_name(dev); diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 35bf97b..7b361c00 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -181,7 +181,7 @@ static int irqc_probe(struct platform_device *pdev) struct irqc_priv *p; struct resource *io; struct resource *irq; - struct irq_chip *irq_chip; + irq_chip_no_const *irq_chip; const char *name = dev_name(&pdev->dev); int ret; int k; diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 6a2df32..dc962f1 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -81,8 +81,8 @@ struct capiminor { struct capi20_appl *ap; u32 ncci; - atomic_t datahandle; - atomic_t msgid; + atomic_unchecked_t datahandle; + atomic_unchecked_t msgid; struct tty_port port; int ttyinstop; @@ -391,7 +391,7 @@ gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb) capimsg_setu16(s, 2, mp->ap->applid); capimsg_setu8 (s, 4, CAPI_DATA_B3); capimsg_setu8 (s, 5, CAPI_RESP); - capimsg_setu16(s, 6, atomic_inc_return(&mp->msgid)); + capimsg_setu16(s, 6, atomic_inc_return_unchecked(&mp->msgid)); capimsg_setu32(s, 8, mp->ncci); capimsg_setu16(s, 12, datahandle); } @@ -512,14 +512,14 @@ static void handle_minor_send(struct capiminor *mp) mp->outbytes -= len; spin_unlock_bh(&mp->outlock); - datahandle = atomic_inc_return(&mp->datahandle); + datahandle = atomic_inc_return_unchecked(&mp->datahandle); skb_push(skb, CAPI_DATA_B3_REQ_LEN); memset(skb->data, 0, CAPI_DATA_B3_REQ_LEN); capimsg_setu16(skb->data, 0, CAPI_DATA_B3_REQ_LEN); capimsg_setu16(skb->data, 2, mp->ap->applid); capimsg_setu8 (skb->data, 4, CAPI_DATA_B3); capimsg_setu8 (skb->data, 5, CAPI_REQ); - capimsg_setu16(skb->data, 6, atomic_inc_return(&mp->msgid)); + capimsg_setu16(skb->data, 6, atomic_inc_return_unchecked(&mp->msgid)); capimsg_setu32(skb->data, 8, mp->ncci); /* NCCI */ capimsg_setu32(skb->data, 12, (u32)(long)skb->data);/* Data32 */ capimsg_setu16(skb->data, 16, len); /* Data length */ diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index aecec6d..11e13c5 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -2565,22 +2565,22 @@ static int gigaset_post_reset(struct usb_interface *intf) static const struct gigaset_ops gigops = { - gigaset_write_cmd, - gigaset_write_room, - gigaset_chars_in_buffer, - gigaset_brkchars, - gigaset_init_bchannel, - gigaset_close_bchannel, - gigaset_initbcshw, - gigaset_freebcshw, - gigaset_reinitbcshw, - gigaset_initcshw, - gigaset_freecshw, - gigaset_set_modem_ctrl, - gigaset_baud_rate, - gigaset_set_line_ctrl, - gigaset_isoc_send_skb, - gigaset_isoc_input, + .write_cmd = gigaset_write_cmd, + .write_room = gigaset_write_room, + .chars_in_buffer = gigaset_chars_in_buffer, + .brkchars = gigaset_brkchars, + .init_bchannel = gigaset_init_bchannel, + .close_bchannel = gigaset_close_bchannel, + .initbcshw = gigaset_initbcshw, + .freebcshw = gigaset_freebcshw, + .reinitbcshw = gigaset_reinitbcshw, + .initcshw = gigaset_initcshw, + .freecshw = gigaset_freecshw, + .set_modem_ctrl = gigaset_set_modem_ctrl, + .baud_rate = gigaset_baud_rate, + .set_line_ctrl = gigaset_set_line_ctrl, + .send_skb = gigaset_isoc_send_skb, + .handle_input = gigaset_isoc_input, }; /* bas_gigaset_init diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index 600c79b..3752bab 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -130,9 +130,9 @@ static int if_open(struct tty_struct *tty, struct file *filp) } tty->driver_data = cs; - ++cs->port.count; + atomic_inc(&cs->port.count); - if (cs->port.count == 1) { + if (atomic_read(&cs->port.count) == 1) { tty_port_tty_set(&cs->port, tty); cs->port.low_latency = 1; } @@ -156,9 +156,9 @@ static void if_close(struct tty_struct *tty, struct file *filp) if (!cs->connected) gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */ - else if (!cs->port.count) + else if (!atomic_read(&cs->port.count)) dev_warn(cs->dev, "%s: device not opened\n", __func__); - else if (!--cs->port.count) + else if (!atomic_dec_return(&cs->port.count)) tty_port_tty_set(&cs->port, NULL); mutex_unlock(&cs->mutex); diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c index 375be50..675293c 100644 --- a/drivers/isdn/gigaset/ser-gigaset.c +++ b/drivers/isdn/gigaset/ser-gigaset.c @@ -453,22 +453,22 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) } static const struct gigaset_ops ops = { - gigaset_write_cmd, - gigaset_write_room, - gigaset_chars_in_buffer, - gigaset_brkchars, - gigaset_init_bchannel, - gigaset_close_bchannel, - gigaset_initbcshw, - gigaset_freebcshw, - gigaset_reinitbcshw, - gigaset_initcshw, - gigaset_freecshw, - gigaset_set_modem_ctrl, - gigaset_baud_rate, - gigaset_set_line_ctrl, - gigaset_m10x_send_skb, /* asyncdata.c */ - gigaset_m10x_input, /* asyncdata.c */ + .write_cmd = gigaset_write_cmd, + .write_room = gigaset_write_room, + .chars_in_buffer = gigaset_chars_in_buffer, + .brkchars = gigaset_brkchars, + .init_bchannel = gigaset_init_bchannel, + .close_bchannel = gigaset_close_bchannel, + .initbcshw = gigaset_initbcshw, + .freebcshw = gigaset_freebcshw, + .reinitbcshw = gigaset_reinitbcshw, + .initcshw = gigaset_initcshw, + .freecshw = gigaset_freecshw, + .set_modem_ctrl = gigaset_set_modem_ctrl, + .baud_rate = gigaset_baud_rate, + .set_line_ctrl = gigaset_set_line_ctrl, + .send_skb = gigaset_m10x_send_skb, /* asyncdata.c */ + .handle_input = gigaset_m10x_input, /* asyncdata.c */ }; diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index 5f306e2..5342f88 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -543,7 +543,7 @@ static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]) gigaset_dbg_buffer(DEBUG_USBREQ, "brkchars", 6, buf); memcpy(cs->hw.usb->bchars, buf, 6); return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x19, 0x41, - 0, 0, &buf, 6, 2000); + 0, 0, buf, 6, 2000); } static void gigaset_freebcshw(struct bc_state *bcs) @@ -862,22 +862,22 @@ static int gigaset_pre_reset(struct usb_interface *intf) } static const struct gigaset_ops ops = { - gigaset_write_cmd, - gigaset_write_room, - gigaset_chars_in_buffer, - gigaset_brkchars, - gigaset_init_bchannel, - gigaset_close_bchannel, - gigaset_initbcshw, - gigaset_freebcshw, - gigaset_reinitbcshw, - gigaset_initcshw, - gigaset_freecshw, - gigaset_set_modem_ctrl, - gigaset_baud_rate, - gigaset_set_line_ctrl, - gigaset_m10x_send_skb, - gigaset_m10x_input, + .write_cmd = gigaset_write_cmd, + .write_room = gigaset_write_room, + .chars_in_buffer = gigaset_chars_in_buffer, + .brkchars = gigaset_brkchars, + .init_bchannel = gigaset_init_bchannel, + .close_bchannel = gigaset_close_bchannel, + .initbcshw = gigaset_initbcshw, + .freebcshw = gigaset_freebcshw, + .reinitbcshw = gigaset_reinitbcshw, + .initcshw = gigaset_initcshw, + .freecshw = gigaset_freecshw, + .set_modem_ctrl = gigaset_set_modem_ctrl, + .baud_rate = gigaset_baud_rate, + .set_line_ctrl = gigaset_set_line_ctrl, + .send_skb = gigaset_m10x_send_skb, + .handle_input = gigaset_m10x_input, }; /* diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c index 4d9b195..455075c 100644 --- a/drivers/isdn/hardware/avm/b1.c +++ b/drivers/isdn/hardware/avm/b1.c @@ -176,7 +176,7 @@ int b1_load_t4file(avmcard *card, capiloaddatapart *t4file) } if (left) { if (t4file->user) { - if (copy_from_user(buf, dp, left)) + if (left > sizeof buf || copy_from_user(buf, dp, left)) return -EFAULT; } else { memcpy(buf, dp, left); @@ -224,7 +224,7 @@ int b1_load_config(avmcard *card, capiloaddatapart *config) } if (left) { if (config->user) { - if (copy_from_user(buf, dp, left)) + if (left > sizeof buf || copy_from_user(buf, dp, left)) return -EFAULT; } else { memcpy(buf, dp, left); diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index b33f53b..bf04d2a 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -1896,7 +1896,7 @@ static void EChannel_proc_rcv(struct hisax_d_if *d_if) ptr--; *ptr++ = '\n'; *ptr = 0; - HiSax_putstatus(cs, NULL, "%s", cs->dlog); + HiSax_putstatus(cs, NULL, cs->dlog); } else HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index 4a48255..90449e1 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -901,7 +901,7 @@ Begin: ptr--; *ptr++ = '\n'; *ptr = 0; - HiSax_putstatus(cs, NULL, "%s", cs->dlog); + HiSax_putstatus(cs, NULL, cs->dlog); } else HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", total - 3); } diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c index b1fad81..13b2151 100644 --- a/drivers/isdn/hisax/hfc_sx.c +++ b/drivers/isdn/hisax/hfc_sx.c @@ -674,7 +674,7 @@ receive_emsg(struct IsdnCardState *cs) ptr--; *ptr++ = '\n'; *ptr = 0; - HiSax_putstatus(cs, NULL, "%s", cs->dlog); + HiSax_putstatus(cs, NULL, cs->dlog); } else HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len); } diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c index b420f8b..ba4beb2 100644 --- a/drivers/isdn/hisax/q931.c +++ b/drivers/isdn/hisax/q931.c @@ -1179,7 +1179,7 @@ LogFrame(struct IsdnCardState *cs, u_char *buf, int size) dp--; *dp++ = '\n'; *dp = 0; - HiSax_putstatus(cs, NULL, "%s", cs->dlog); + HiSax_putstatus(cs, NULL, cs->dlog); } else HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size); } @@ -1246,7 +1246,7 @@ dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir) } if (finish) { *dp = 0; - HiSax_putstatus(cs, NULL, "%s", cs->dlog); + HiSax_putstatus(cs, NULL, cs->dlog); return; } if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */ @@ -1509,5 +1509,5 @@ dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir) dp += sprintf(dp, "Unknown protocol %x!", buf[0]); } *dp = 0; - HiSax_putstatus(cs, NULL, "%s", cs->dlog); + HiSax_putstatus(cs, NULL, cs->dlog); } diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index 9b856e1..fa03c92 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -1654,6 +1654,8 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg) } else return -EINVAL; case IIOCDBGVAR: + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; if (arg) { if (copy_to_user(argp, &dev, sizeof(ulong))) return -EFAULT; diff --git a/drivers/isdn/i4l/isdn_concap.c b/drivers/isdn/i4l/isdn_concap.c index 91d5730..336523e 100644 --- a/drivers/isdn/i4l/isdn_concap.c +++ b/drivers/isdn/i4l/isdn_concap.c @@ -80,9 +80,9 @@ static int isdn_concap_dl_disconn_req(struct concap_proto *concap) } struct concap_device_ops isdn_concap_reliable_dl_dops = { - &isdn_concap_dl_data_req, - &isdn_concap_dl_connect_req, - &isdn_concap_dl_disconn_req + .data_req = &isdn_concap_dl_data_req, + .connect_req = &isdn_concap_dl_connect_req, + .disconn_req = &isdn_concap_dl_disconn_req }; /* The following should better go into a dedicated source file such that diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index bc91261..2ef7e36 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1503,9 +1503,9 @@ isdn_tty_open(struct tty_struct *tty, struct file *filp) #ifdef ISDN_DEBUG_MODEM_OPEN printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name, - port->count); + atomic_read(&port->count)); #endif - port->count++; + atomic_inc(&port->count); port->tty = tty; /* * Start up serial port @@ -1549,7 +1549,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp) #endif return; } - if ((tty->count == 1) && (port->count != 1)) { + if ((tty->count == 1) && (atomic_read(&port->count) != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always @@ -1558,15 +1558,15 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp) * serial port won't be shutdown. */ printk(KERN_ERR "isdn_tty_close: bad port count; tty->count is 1, " - "info->count is %d\n", port->count); - port->count = 1; + "info->count is %d\n", atomic_read(&port->count)); + atomic_set(&port->count, 1); } - if (--port->count < 0) { + if (atomic_dec_return(&port->count) < 0) { printk(KERN_ERR "isdn_tty_close: bad port count for ttyi%d: %d\n", - info->line, port->count); - port->count = 0; + info->line, atomic_read(&port->count)); + atomic_set(&port->count, 0); } - if (port->count) { + if (atomic_read(&port->count)) { #ifdef ISDN_DEBUG_MODEM_OPEN printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n"); #endif @@ -1620,7 +1620,7 @@ isdn_tty_hangup(struct tty_struct *tty) if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_hangup")) return; isdn_tty_shutdown(info); - port->count = 0; + atomic_set(&port->count, 0); port->flags &= ~ASYNC_NORMAL_ACTIVE; port->tty = NULL; wake_up_interruptible(&port->open_wait); @@ -1965,7 +1965,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup) for (i = 0; i < ISDN_MAX_CHANNELS; i++) { modem_info *info = &dev->mdm.info[i]; - if (info->port.count == 0) + if (atomic_read(&info->port.count) == 0) continue; if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */ (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */ diff --git a/drivers/isdn/i4l/isdn_x25iface.c b/drivers/isdn/i4l/isdn_x25iface.c index e2d4e58..40cd045 100644 --- a/drivers/isdn/i4l/isdn_x25iface.c +++ b/drivers/isdn/i4l/isdn_x25iface.c @@ -53,14 +53,14 @@ static int isdn_x25iface_disconn_ind(struct concap_proto *); static struct concap_proto_ops ix25_pops = { - &isdn_x25iface_proto_new, - &isdn_x25iface_proto_del, - &isdn_x25iface_proto_restart, - &isdn_x25iface_proto_close, - &isdn_x25iface_xmit, - &isdn_x25iface_receive, - &isdn_x25iface_connect_ind, - &isdn_x25iface_disconn_ind + .proto_new = &isdn_x25iface_proto_new, + .proto_del = &isdn_x25iface_proto_del, + .restart = &isdn_x25iface_proto_restart, + .close = &isdn_x25iface_proto_close, + .encap_and_xmit = &isdn_x25iface_xmit, + .data_ind = &isdn_x25iface_receive, + .connect_ind = &isdn_x25iface_connect_ind, + .disconn_ind = &isdn_x25iface_disconn_ind }; /* error message helper function */ diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c index 358a574..b4987ea 100644 --- a/drivers/isdn/icn/icn.c +++ b/drivers/isdn/icn/icn.c @@ -1045,7 +1045,7 @@ icn_writecmd(const u_char *buf, int len, int user, icn_card *card) if (count > len) count = len; if (user) { - if (copy_from_user(msg, buf, count)) + if (count > sizeof msg || copy_from_user(msg, buf, count)) return -EFAULT; } else memcpy(msg, buf, count); diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index 8e3aa00..65200ac 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -1625,7 +1625,7 @@ unsigned long dsp_spl_jiffies; /* calculate the next time to fire */ static u16 dsp_count; /* last sample count */ static int dsp_count_valid; /* if we have last sample count */ -void +void __intentional_overflow(-1) dsp_cmx_send(void *arg) { struct dsp_conf *conf; diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c index 312ffd3..d060510 100644 --- a/drivers/lguest/core.c +++ b/drivers/lguest/core.c @@ -96,9 +96,17 @@ static __init int map_switcher(void) * The end address needs +1 because __get_vm_area allocates an * extra guard page, so we need space for that. */ + +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) + switcher_vma = __get_vm_area(TOTAL_SWITCHER_PAGES * PAGE_SIZE, + VM_ALLOC | VM_KERNEXEC, switcher_addr, switcher_addr + + (TOTAL_SWITCHER_PAGES+1) * PAGE_SIZE); +#else switcher_vma = __get_vm_area(TOTAL_SWITCHER_PAGES * PAGE_SIZE, VM_ALLOC, switcher_addr, switcher_addr + (TOTAL_SWITCHER_PAGES+1) * PAGE_SIZE); +#endif + if (!switcher_vma) { err = -ENOMEM; printk("lguest: could not map switcher pages high\n"); @@ -121,7 +129,7 @@ static __init int map_switcher(void) * Now the Switcher is mapped at the right address, we can't fail! * Copy in the compiled-in Switcher code (from x86/switcher_32.S). */ - memcpy(switcher_vma->addr, start_switcher_text, + memcpy(switcher_vma->addr, (void *)ktla_ktva((unsigned long)start_switcher_text), end_switcher_text - start_switcher_text); printk(KERN_INFO "lguest: mapped switcher at %p\n", diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c index e3abebc9..6a35328 100644 --- a/drivers/lguest/page_tables.c +++ b/drivers/lguest/page_tables.c @@ -585,7 +585,7 @@ void pin_page(struct lg_cpu *cpu, unsigned long vaddr) /*:*/ #ifdef CONFIG_X86_PAE -static void release_pmd(pmd_t *spmd) +static void __intentional_overflow(-1) release_pmd(pmd_t *spmd) { /* If the entry's not present, there's nothing to release. */ if (pmd_flags(*spmd) & _PAGE_PRESENT) { diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c index 6a4cd77..c9e2d9f 100644 --- a/drivers/lguest/x86/core.c +++ b/drivers/lguest/x86/core.c @@ -60,7 +60,7 @@ static struct { /* Offset from where switcher.S was compiled to where we've copied it */ static unsigned long switcher_offset(void) { - return switcher_addr - (unsigned long)start_switcher_text; + return switcher_addr - ktla_ktva((unsigned long)start_switcher_text); } /* This cpu's struct lguest_pages (after the Switcher text page) */ @@ -100,7 +100,13 @@ static void copy_in_guest_info(struct lg_cpu *cpu, struct lguest_pages *pages) * These copies are pretty cheap, so we do them unconditionally: */ /* Save the current Host top-level page directory. */ + +#ifdef CONFIG_PAX_PER_CPU_PGD + pages->state.host_cr3 = read_cr3(); +#else pages->state.host_cr3 = __pa(current->mm->pgd); +#endif + /* * Set up the Guest's page tables to see this CPU's pages (and no * other CPU's pages). @@ -494,7 +500,7 @@ void __init lguest_arch_host_init(void) * compiled-in switcher code and the high-mapped copy we just made. */ for (i = 0; i < IDT_ENTRIES; i++) - default_idt_entries[i] += switcher_offset(); + default_idt_entries[i] = ktla_ktva(default_idt_entries[i]) + switcher_offset(); /* * Set up the Switcher's per-cpu areas. @@ -577,7 +583,7 @@ void __init lguest_arch_host_init(void) * it will be undisturbed when we switch. To change %cs and jump we * need this structure to feed to Intel's "lcall" instruction. */ - lguest_entry.offset = (long)switch_to_guest + switcher_offset(); + lguest_entry.offset = ktla_ktva((unsigned long)switch_to_guest) + switcher_offset(); lguest_entry.segment = LGUEST_CS; /* diff --git a/drivers/lguest/x86/switcher_32.S b/drivers/lguest/x86/switcher_32.S index 40634b0..4f5855e 100644 --- a/drivers/lguest/x86/switcher_32.S +++ b/drivers/lguest/x86/switcher_32.S @@ -87,6 +87,7 @@ #include #include #include +#include // We mark the start of the code to copy // It's placed in .text tho it's never run here @@ -149,6 +150,13 @@ ENTRY(switch_to_guest) // Changes type when we load it: damn Intel! // For after we switch over our page tables // That entry will be read-only: we'd crash. + +#ifdef CONFIG_PAX_KERNEXEC + mov %cr0, %edx + xor $X86_CR0_WP, %edx + mov %edx, %cr0 +#endif + movl $(GDT_ENTRY_TSS*8), %edx ltr %dx @@ -157,9 +165,15 @@ ENTRY(switch_to_guest) // Let's clear it again for our return. // The GDT descriptor of the Host // Points to the table after two "size" bytes - movl (LGUEST_PAGES_host_gdt_desc+2)(%eax), %edx + movl (LGUEST_PAGES_host_gdt_desc+2)(%eax), %eax // Clear "used" from type field (byte 5, bit 2) - andb $0xFD, (GDT_ENTRY_TSS*8 + 5)(%edx) + andb $0xFD, (GDT_ENTRY_TSS*8 + 5)(%eax) + +#ifdef CONFIG_PAX_KERNEXEC + mov %cr0, %eax + xor $X86_CR0_WP, %eax + mov %eax, %cr0 +#endif // Once our page table's switched, the Guest is live! // The Host fades as we run this final step. @@ -295,13 +309,12 @@ deliver_to_host: // I consulted gcc, and it gave // These instructions, which I gladly credit: leal (%edx,%ebx,8), %eax - movzwl (%eax),%edx - movl 4(%eax), %eax - xorw %ax, %ax - orl %eax, %edx + movl 4(%eax), %edx + movw (%eax), %dx // Now the address of the handler's in %edx // We call it now: its "iret" drops us home. - jmp *%edx + ljmp $__KERNEL_CS, $1f +1: jmp *%edx // Every interrupt can come to us here // But we must truly tell each apart. diff --git a/drivers/md/bcache/Kconfig b/drivers/md/bcache/Kconfig index 4d20088..de60cb2 100644 --- a/drivers/md/bcache/Kconfig +++ b/drivers/md/bcache/Kconfig @@ -20,6 +20,7 @@ config BCACHE_CLOSURES_DEBUG bool "Debug closures" depends on BCACHE select DEBUG_FS + depends on !GRKERNSEC_KMEM ---help--- Keeps all active closures in a linked list and provides a debugfs interface to list them, which makes it possible to see asynchronous diff --git a/drivers/md/bcache/closure.h b/drivers/md/bcache/closure.h index 782cc2c..4fdd593 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, struct workqueue_struct *wq) { - BUG_ON(object_is_on_stack(cl)); + BUG_ON(object_starts_on_stack(cl)); closure_set_ip(cl); cl->fn = fn; cl->wq = wq; diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 48b5890..b0af0ca 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1933,7 +1933,7 @@ void bitmap_status(struct seq_file *seq, struct bitmap *bitmap) chunk_kb ? "KB" : "B"); if (bitmap->storage.file) { seq_printf(seq, ", file: "); - seq_file_path(seq, bitmap->storage.file, " \t\n"); + seq_file_path(seq, bitmap->storage.file, " \t\n\\"); } seq_printf(seq, "\n"); diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 80a4395..a5a8981 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1773,7 +1773,7 @@ static int validate_params(uint cmd, struct dm_ioctl *param) cmd == DM_LIST_VERSIONS_CMD) return 0; - if ((cmd == DM_DEV_CREATE_CMD)) { + if (cmd == DM_DEV_CREATE_CMD) { if (!*param->name) { DMWARN("name not supplied when creating device"); return -EINVAL; diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index f2a363a..9f4763b 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -42,7 +42,7 @@ enum dm_raid1_error { struct mirror { struct mirror_set *ms; - atomic_t error_count; + atomic_unchecked_t error_count; unsigned long error_type; struct dm_dev *dev; sector_t offset; @@ -188,7 +188,7 @@ static struct mirror *get_valid_mirror(struct mirror_set *ms) struct mirror *m; for (m = ms->mirror; m < ms->mirror + ms->nr_mirrors; m++) - if (!atomic_read(&m->error_count)) + if (!atomic_read_unchecked(&m->error_count)) return m; return NULL; @@ -220,7 +220,7 @@ static void fail_mirror(struct mirror *m, enum dm_raid1_error error_type) * simple way to tell if a device has encountered * errors. */ - atomic_inc(&m->error_count); + atomic_inc_unchecked(&m->error_count); if (test_and_set_bit(error_type, &m->error_type)) return; @@ -378,7 +378,7 @@ static void reset_ms_flags(struct mirror_set *ms) ms->leg_failure = 0; for (m = 0; m < ms->nr_mirrors; m++) { - atomic_set(&(ms->mirror[m].error_count), 0); + atomic_set_unchecked(&(ms->mirror[m].error_count), 0); ms->mirror[m].error_type = 0; } } @@ -423,7 +423,7 @@ static struct mirror *choose_mirror(struct mirror_set *ms, sector_t sector) struct mirror *m = get_default_mirror(ms); do { - if (likely(!atomic_read(&m->error_count))) + if (likely(!atomic_read_unchecked(&m->error_count))) return m; if (m-- == ms->mirror) @@ -437,7 +437,7 @@ static int default_ok(struct mirror *m) { struct mirror *default_mirror = get_default_mirror(m->ms); - return !atomic_read(&default_mirror->error_count); + return !atomic_read_unchecked(&default_mirror->error_count); } static int mirror_available(struct mirror_set *ms, struct bio *bio) @@ -576,7 +576,7 @@ static void do_reads(struct mirror_set *ms, struct bio_list *reads) */ if (likely(region_in_sync(ms, region, 1))) m = choose_mirror(ms, bio->bi_iter.bi_sector); - else if (m && atomic_read(&m->error_count)) + else if (m && atomic_read_unchecked(&m->error_count)) m = NULL; if (likely(m)) @@ -960,7 +960,7 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti, } ms->mirror[mirror].ms = ms; - atomic_set(&(ms->mirror[mirror].error_count), 0); + atomic_set_unchecked(&(ms->mirror[mirror].error_count), 0); ms->mirror[mirror].error_type = 0; ms->mirror[mirror].offset = offset; @@ -1384,7 +1384,7 @@ static void mirror_resume(struct dm_target *ti) */ static char device_status_char(struct mirror *m) { - if (!atomic_read(&(m->error_count))) + if (!atomic_read_unchecked(&(m->error_count))) return 'A'; return (test_bit(DM_RAID1_FLUSH_ERROR, &(m->error_type))) ? 'F' : diff --git a/drivers/md/dm-stats.c b/drivers/md/dm-stats.c index 8289804..12db118 100644 --- a/drivers/md/dm-stats.c +++ b/drivers/md/dm-stats.c @@ -435,7 +435,7 @@ do_sync_free: synchronize_rcu_expedited(); dm_stat_free(&s->rcu_head); } else { - ACCESS_ONCE(dm_stat_need_rcu_barrier) = 1; + ACCESS_ONCE_RW(dm_stat_need_rcu_barrier) = 1; call_rcu(&s->rcu_head, dm_stat_free); } return 0; @@ -648,8 +648,8 @@ void dm_stats_account_io(struct dm_stats *stats, unsigned long bi_rw, ((bi_rw & (REQ_WRITE | REQ_DISCARD)) == (ACCESS_ONCE(last->last_rw) & (REQ_WRITE | REQ_DISCARD))) )); - ACCESS_ONCE(last->last_sector) = end_sector; - ACCESS_ONCE(last->last_rw) = bi_rw; + ACCESS_ONCE_RW(last->last_sector) = end_sector; + ACCESS_ONCE_RW(last->last_rw) = bi_rw; } rcu_read_lock(); diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index 797ddb9..9595c24 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c @@ -21,7 +21,7 @@ struct stripe { struct dm_dev *dev; sector_t physical_start; - atomic_t error_count; + atomic_unchecked_t error_count; }; struct stripe_c { @@ -190,7 +190,7 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) kfree(sc); return r; } - atomic_set(&(sc->stripe[i].error_count), 0); + atomic_set_unchecked(&(sc->stripe[i].error_count), 0); } ti->private = sc; @@ -334,7 +334,7 @@ static void stripe_status(struct dm_target *ti, status_type_t type, DMEMIT("%d ", sc->stripes); for (i = 0; i < sc->stripes; i++) { DMEMIT("%s ", sc->stripe[i].dev->name); - buffer[i] = atomic_read(&(sc->stripe[i].error_count)) ? + buffer[i] = atomic_read_unchecked(&(sc->stripe[i].error_count)) ? 'D' : 'A'; } buffer[i] = '\0'; @@ -379,8 +379,8 @@ static int stripe_end_io(struct dm_target *ti, struct bio *bio, int error) */ for (i = 0; i < sc->stripes; i++) if (!strcmp(sc->stripe[i].dev->name, major_minor)) { - atomic_inc(&(sc->stripe[i].error_count)); - if (atomic_read(&(sc->stripe[i].error_count)) < + atomic_inc_unchecked(&(sc->stripe[i].error_count)); + if (atomic_read_unchecked(&(sc->stripe[i].error_count)) < DM_IO_ERROR_THRESHOLD) schedule_work(&sc->trigger_event); } diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index e76ed00..aee345b 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -305,7 +305,7 @@ static int device_area_is_invalid(struct dm_target *ti, struct dm_dev *dev, if (!dev_size) return 0; - if ((start >= dev_size) || (start + len > dev_size)) { + if ((start >= dev_size) || (len > dev_size - start)) { DMWARN("%s: %s too small for target: " "start=%llu, len=%llu, dev_size=%llu", dm_device_name(ti->table->md), bdevname(bdev, b), diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c index 6ba47cf..a870ba2 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -403,7 +403,7 @@ static void __setup_btree_details(struct dm_pool_metadata *pmd) { pmd->info.tm = pmd->tm; pmd->info.levels = 2; - pmd->info.value_type.context = pmd->data_sm; + pmd->info.value_type.context = (dm_space_map_no_const *)pmd->data_sm; pmd->info.value_type.size = sizeof(__le64); pmd->info.value_type.inc = data_block_inc; pmd->info.value_type.dec = data_block_dec; @@ -422,7 +422,7 @@ static void __setup_btree_details(struct dm_pool_metadata *pmd) pmd->bl_info.tm = pmd->tm; pmd->bl_info.levels = 1; - pmd->bl_info.value_type.context = pmd->data_sm; + pmd->bl_info.value_type.context = (dm_space_map_no_const *)pmd->data_sm; pmd->bl_info.value_type.size = sizeof(__le64); pmd->bl_info.value_type.inc = data_block_inc; pmd->bl_info.value_type.dec = data_block_dec; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 1b5c604..cd00629 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -193,9 +193,9 @@ struct mapped_device { /* * Event handling. */ - atomic_t event_nr; + atomic_unchecked_t event_nr; wait_queue_head_t eventq; - atomic_t uevent_seq; + atomic_unchecked_t uevent_seq; struct list_head uevent_list; spinlock_t uevent_lock; /* Protect access to uevent_list */ @@ -704,14 +704,16 @@ static void queue_io(struct mapped_device *md, struct bio *bio) * function to access the md->map field, and make sure they call * dm_put_live_table() when finished. */ -struct dm_table *dm_get_live_table(struct mapped_device *md, int *srcu_idx) __acquires(md->io_barrier) +struct dm_table *dm_get_live_table(struct mapped_device *md, int *srcu_idx) __acquires(&md->io_barrier); +struct dm_table *dm_get_live_table(struct mapped_device *md, int *srcu_idx) { *srcu_idx = srcu_read_lock(&md->io_barrier); return srcu_dereference(md->map, &md->io_barrier); } -void dm_put_live_table(struct mapped_device *md, int srcu_idx) __releases(md->io_barrier) +void dm_put_live_table(struct mapped_device *md, int srcu_idx) __releases(&md->io_barrier); +void dm_put_live_table(struct mapped_device *md, int srcu_idx) { srcu_read_unlock(&md->io_barrier, srcu_idx); } @@ -726,13 +728,15 @@ void dm_sync_table(struct mapped_device *md) * A fast alternative to dm_get_live_table/dm_put_live_table. * The caller must not block between these two functions. */ -static struct dm_table *dm_get_live_table_fast(struct mapped_device *md) __acquires(RCU) +static struct dm_table *dm_get_live_table_fast(struct mapped_device *md) __acquires(RCU); +static struct dm_table *dm_get_live_table_fast(struct mapped_device *md) { rcu_read_lock(); return rcu_dereference(md->map); } -static void dm_put_live_table_fast(struct mapped_device *md) __releases(RCU) +static void dm_put_live_table_fast(struct mapped_device *md) __releases(RCU); +static void dm_put_live_table_fast(struct mapped_device *md) { rcu_read_unlock(); } @@ -2286,8 +2290,8 @@ static struct mapped_device *alloc_dev(int minor) spin_lock_init(&md->deferred_lock); atomic_set(&md->holders, 1); atomic_set(&md->open_count, 0); - atomic_set(&md->event_nr, 0); - atomic_set(&md->uevent_seq, 0); + atomic_set_unchecked(&md->event_nr, 0); + atomic_set_unchecked(&md->uevent_seq, 0); INIT_LIST_HEAD(&md->uevent_list); INIT_LIST_HEAD(&md->table_devices); spin_lock_init(&md->uevent_lock); @@ -2428,7 +2432,7 @@ static void event_callback(void *context) dm_send_uevents(&uevents, &disk_to_dev(md->disk)->kobj); - atomic_inc(&md->event_nr); + atomic_inc_unchecked(&md->event_nr); wake_up(&md->eventq); } @@ -3365,18 +3369,18 @@ int dm_kobject_uevent(struct mapped_device *md, enum kobject_action action, uint32_t dm_next_uevent_seq(struct mapped_device *md) { - return atomic_add_return(1, &md->uevent_seq); + return atomic_add_return_unchecked(1, &md->uevent_seq); } uint32_t dm_get_event_nr(struct mapped_device *md) { - return atomic_read(&md->event_nr); + return atomic_read_unchecked(&md->event_nr); } int dm_wait_event(struct mapped_device *md, int event_nr) { return wait_event_interruptible(md->eventq, - (event_nr != atomic_read(&md->event_nr))); + (event_nr != atomic_read_unchecked(&md->event_nr))); } void dm_uevent_add(struct mapped_device *md, struct list_head *elist) diff --git a/drivers/md/md.c b/drivers/md/md.c index 3fe3d04..e7adf83 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -197,10 +197,10 @@ EXPORT_SYMBOL_GPL(bio_clone_mddev); * start build, activate spare */ static DECLARE_WAIT_QUEUE_HEAD(md_event_waiters); -static atomic_t md_event_count; +static atomic_unchecked_t md_event_count; void md_new_event(struct mddev *mddev) { - atomic_inc(&md_event_count); + atomic_inc_unchecked(&md_event_count); wake_up(&md_event_waiters); } EXPORT_SYMBOL_GPL(md_new_event); @@ -210,7 +210,7 @@ EXPORT_SYMBOL_GPL(md_new_event); */ static void md_new_event_inintr(struct mddev *mddev) { - atomic_inc(&md_event_count); + atomic_inc_unchecked(&md_event_count); wake_up(&md_event_waiters); } @@ -1431,7 +1431,7 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_ if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE) && (le32_to_cpu(sb->feature_map) & MD_FEATURE_NEW_OFFSET)) rdev->new_data_offset += (s32)le32_to_cpu(sb->new_offset); - atomic_set(&rdev->corrected_errors, le32_to_cpu(sb->cnt_corrected_read)); + atomic_set_unchecked(&rdev->corrected_errors, le32_to_cpu(sb->cnt_corrected_read)); rdev->sb_size = le32_to_cpu(sb->max_dev) * 2 + 256; bmask = queue_logical_block_size(rdev->bdev->bd_disk->queue)-1; @@ -1682,7 +1682,7 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev) else sb->resync_offset = cpu_to_le64(0); - sb->cnt_corrected_read = cpu_to_le32(atomic_read(&rdev->corrected_errors)); + sb->cnt_corrected_read = cpu_to_le32(atomic_read_unchecked(&rdev->corrected_errors)); sb->raid_disks = cpu_to_le32(mddev->raid_disks); sb->size = cpu_to_le64(mddev->dev_sectors); @@ -2604,7 +2604,7 @@ __ATTR_PREALLOC(state, S_IRUGO|S_IWUSR, state_show, state_store); static ssize_t errors_show(struct md_rdev *rdev, char *page) { - return sprintf(page, "%d\n", atomic_read(&rdev->corrected_errors)); + return sprintf(page, "%d\n", atomic_read_unchecked(&rdev->corrected_errors)); } static ssize_t @@ -2616,7 +2616,7 @@ errors_store(struct md_rdev *rdev, const char *buf, size_t len) rv = kstrtouint(buf, 10, &n); if (rv < 0) return rv; - atomic_set(&rdev->corrected_errors, n); + atomic_set_unchecked(&rdev->corrected_errors, n); return len; } static struct rdev_sysfs_entry rdev_errors = @@ -3053,8 +3053,8 @@ int md_rdev_init(struct md_rdev *rdev) rdev->sb_loaded = 0; rdev->bb_page = NULL; atomic_set(&rdev->nr_pending, 0); - atomic_set(&rdev->read_errors, 0); - atomic_set(&rdev->corrected_errors, 0); + atomic_set_unchecked(&rdev->read_errors, 0); + atomic_set_unchecked(&rdev->corrected_errors, 0); INIT_LIST_HEAD(&rdev->same_set); init_waitqueue_head(&rdev->blocked_wait); @@ -5709,9 +5709,10 @@ static int get_array_info(struct mddev *mddev, void __user *arg) info.patch_version = MD_PATCHLEVEL_VERSION; info.ctime = mddev->ctime; info.level = mddev->level; - info.size = mddev->dev_sectors / 2; - if (info.size != mddev->dev_sectors / 2) /* overflow */ + if (2 * (sector_t)INT_MAX < mddev->dev_sectors) /* overflow */ info.size = -1; + else + info.size = mddev->dev_sectors / 2; info.nr_disks = nr; info.raid_disks = mddev->raid_disks; info.md_minor = mddev->md_minor; @@ -7257,7 +7258,7 @@ static int md_seq_show(struct seq_file *seq, void *v) spin_unlock(&pers_lock); seq_printf(seq, "\n"); - seq->poll_event = atomic_read(&md_event_count); + seq->poll_event = atomic_read_unchecked(&md_event_count); return 0; } if (v == (void*)2) { @@ -7355,7 +7356,7 @@ static int md_seq_open(struct inode *inode, struct file *file) return error; seq = file->private_data; - seq->poll_event = atomic_read(&md_event_count); + seq->poll_event = atomic_read_unchecked(&md_event_count); return error; } @@ -7372,7 +7373,7 @@ static unsigned int mdstat_poll(struct file *filp, poll_table *wait) /* always allow read */ mask = POLLIN | POLLRDNORM; - if (seq->poll_event != atomic_read(&md_event_count)) + if (seq->poll_event != atomic_read_unchecked(&md_event_count)) mask |= POLLERR | POLLPRI; return mask; } @@ -7472,7 +7473,7 @@ static int is_mddev_idle(struct mddev *mddev, int init) struct gendisk *disk = rdev->bdev->bd_contains->bd_disk; curr_events = (int)part_stat_read(&disk->part0, sectors[0]) + (int)part_stat_read(&disk->part0, sectors[1]) - - atomic_read(&disk->sync_io); + atomic_read_unchecked(&disk->sync_io); /* sync IO will cause sync_io to increase before the disk_stats * as sync_io is counted when a request starts, and * disk_stats is counted when it completes. diff --git a/drivers/md/md.h b/drivers/md/md.h index ab33957..126a644 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -96,13 +96,13 @@ struct md_rdev { * only maintained for arrays that * support hot removal */ - atomic_t read_errors; /* number of consecutive read errors that + atomic_unchecked_t read_errors; /* number of consecutive read errors that * we have tried to ignore. */ struct timespec last_read_error; /* monotonic time since our * last read error */ - atomic_t corrected_errors; /* number of corrected read errors, + atomic_unchecked_t corrected_errors; /* number of corrected read errors, * for reporting to userspace and storing * in superblock. */ @@ -479,7 +479,7 @@ extern void mddev_unlock(struct mddev *mddev); static inline void md_sync_acct(struct block_device *bdev, unsigned long nr_sectors) { - atomic_add(nr_sectors, &bdev->bd_contains->bd_disk->sync_io); + atomic_add_unchecked(nr_sectors, &bdev->bd_contains->bd_disk->sync_io); } struct md_personality diff --git a/drivers/md/persistent-data/dm-space-map-metadata.c b/drivers/md/persistent-data/dm-space-map-metadata.c index 5309129..7fb096e 100644 --- a/drivers/md/persistent-data/dm-space-map-metadata.c +++ b/drivers/md/persistent-data/dm-space-map-metadata.c @@ -691,7 +691,7 @@ static int sm_metadata_extend(struct dm_space_map *sm, dm_block_t extra_blocks) * Flick into a mode where all blocks get allocated in the new area. */ smm->begin = old_len; - memcpy(sm, &bootstrap_ops, sizeof(*sm)); + memcpy((void *)sm, &bootstrap_ops, sizeof(*sm)); /* * Extend. @@ -728,7 +728,7 @@ out: /* * Switch back to normal behaviour. */ - memcpy(sm, &ops, sizeof(*sm)); + memcpy((void *)sm, &ops, sizeof(*sm)); return r; } diff --git a/drivers/md/persistent-data/dm-space-map.h b/drivers/md/persistent-data/dm-space-map.h index 3e6d115..ffecdeb 100644 --- a/drivers/md/persistent-data/dm-space-map.h +++ b/drivers/md/persistent-data/dm-space-map.h @@ -71,6 +71,7 @@ struct dm_space_map { dm_sm_threshold_fn fn, void *context); }; +typedef struct dm_space_map __no_const dm_space_map_no_const; /*----------------------------------------------------------------*/ diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index d9d031e..38e5356 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1061,7 +1061,7 @@ static void make_request(struct mddev *mddev, struct bio * bio) struct blk_plug_cb *cb; struct raid1_plug_cb *plug = NULL; int first_clone; - int sectors_handled; + sector_t sectors_handled; int max_sectors; sector_t start_next_window; @@ -1884,7 +1884,7 @@ static int fix_sync_read_error(struct r1bio *r1_bio) if (r1_sync_page_io(rdev, sect, s, bio->bi_io_vec[idx].bv_page, READ) != 0) - atomic_add(s, &rdev->corrected_errors); + atomic_add_unchecked(s, &rdev->corrected_errors); } sectors -= s; sect += s; @@ -2116,7 +2116,7 @@ static void fix_read_error(struct r1conf *conf, int read_disk, !test_bit(Faulty, &rdev->flags)) { if (r1_sync_page_io(rdev, sect, s, conf->tmppage, READ)) { - atomic_add(s, &rdev->corrected_errors); + atomic_add_unchecked(s, &rdev->corrected_errors); printk(KERN_INFO "md/raid1:%s: read error corrected " "(%d sectors at %llu on %s)\n", diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 96f3659..38437f5 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1068,7 +1068,7 @@ static void __make_request(struct mddev *mddev, struct bio *bio) struct md_rdev *blocked_rdev; struct blk_plug_cb *cb; struct raid10_plug_cb *plug = NULL; - int sectors_handled; + sector_t sectors_handled; int max_sectors; int sectors; @@ -1827,7 +1827,7 @@ static void end_sync_read(struct bio *bio) /* The write handler will notice the lack of * R10BIO_Uptodate and record any errors etc */ - atomic_add(r10_bio->sectors, + atomic_add_unchecked(r10_bio->sectors, &conf->mirrors[d].rdev->corrected_errors); /* for reconstruct, we always reschedule after a read. @@ -2173,7 +2173,7 @@ static void check_decay_read_errors(struct mddev *mddev, struct md_rdev *rdev) { struct timespec cur_time_mon; unsigned long hours_since_last; - unsigned int read_errors = atomic_read(&rdev->read_errors); + unsigned int read_errors = atomic_read_unchecked(&rdev->read_errors); ktime_get_ts(&cur_time_mon); @@ -2195,9 +2195,9 @@ static void check_decay_read_errors(struct mddev *mddev, struct md_rdev *rdev) * overflowing the shift of read_errors by hours_since_last. */ if (hours_since_last >= 8 * sizeof(read_errors)) - atomic_set(&rdev->read_errors, 0); + atomic_set_unchecked(&rdev->read_errors, 0); else - atomic_set(&rdev->read_errors, read_errors >> hours_since_last); + atomic_set_unchecked(&rdev->read_errors, read_errors >> hours_since_last); } static int r10_sync_page_io(struct md_rdev *rdev, sector_t sector, @@ -2251,8 +2251,8 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10 return; check_decay_read_errors(mddev, rdev); - atomic_inc(&rdev->read_errors); - if (atomic_read(&rdev->read_errors) > max_read_errors) { + atomic_inc_unchecked(&rdev->read_errors); + if (atomic_read_unchecked(&rdev->read_errors) > max_read_errors) { char b[BDEVNAME_SIZE]; bdevname(rdev->bdev, b); @@ -2260,7 +2260,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10 "md/raid10:%s: %s: Raid device exceeded " "read_error threshold [cur %d:max %d]\n", mdname(mddev), b, - atomic_read(&rdev->read_errors), max_read_errors); + atomic_read_unchecked(&rdev->read_errors), max_read_errors); printk(KERN_NOTICE "md/raid10:%s: %s: Failing raid device\n", mdname(mddev), b); @@ -2413,7 +2413,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10 sect + choose_data_offset(r10_bio, rdev)), bdevname(rdev->bdev, b)); - atomic_add(s, &rdev->corrected_errors); + atomic_add_unchecked(s, &rdev->corrected_errors); } rdev_dec_pending(rdev, mddev); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 45933c1..831da5f 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1115,23 +1115,23 @@ async_copy_data(int frombio, struct bio *bio, struct page **page, struct bio_vec bvl; struct bvec_iter iter; struct page *bio_page; - int page_offset; + s64 page_offset; struct async_submit_ctl submit; enum async_tx_flags flags = 0; if (bio->bi_iter.bi_sector >= sector) - page_offset = (signed)(bio->bi_iter.bi_sector - sector) * 512; + page_offset = (s64)(bio->bi_iter.bi_sector - sector) * 512; else - page_offset = (signed)(sector - bio->bi_iter.bi_sector) * -512; + page_offset = (s64)(sector - bio->bi_iter.bi_sector) * -512; if (frombio) flags |= ASYNC_TX_FENCE; init_async_submit(&submit, flags, tx, NULL, NULL, NULL); bio_for_each_segment(bvl, bio, iter) { - int len = bvl.bv_len; - int clen; - int b_offset = 0; + s64 len = bvl.bv_len; + s64 clen; + s64 b_offset = 0; if (page_offset < 0) { b_offset = -page_offset; @@ -2022,6 +2022,10 @@ static int grow_one_stripe(struct r5conf *conf, gfp_t gfp) return 1; } +#ifdef CONFIG_GRKERNSEC_HIDESYM +static atomic_unchecked_t raid5_cache_id = ATOMIC_INIT(0); +#endif + static int grow_stripes(struct r5conf *conf, int num) { struct kmem_cache *sc; @@ -2032,7 +2036,11 @@ static int grow_stripes(struct r5conf *conf, int num) "raid%d-%s", conf->level, mdname(conf->mddev)); else sprintf(conf->cache_name[0], +#ifdef CONFIG_GRKERNSEC_HIDESYM + "raid%d-%08lx", conf->level, atomic_inc_return_unchecked(&raid5_cache_id)); +#else "raid%d-%p", conf->level, conf->mddev); +#endif sprintf(conf->cache_name[1], "%s-alt", conf->cache_name[0]); conf->active_name = 0; @@ -2323,21 +2331,21 @@ static void raid5_end_read_request(struct bio * bi) mdname(conf->mddev), STRIPE_SECTORS, (unsigned long long)s, bdevname(rdev->bdev, b)); - atomic_add(STRIPE_SECTORS, &rdev->corrected_errors); + atomic_add_unchecked(STRIPE_SECTORS, &rdev->corrected_errors); clear_bit(R5_ReadError, &sh->dev[i].flags); clear_bit(R5_ReWrite, &sh->dev[i].flags); } else if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) clear_bit(R5_ReadNoMerge, &sh->dev[i].flags); - if (atomic_read(&rdev->read_errors)) - atomic_set(&rdev->read_errors, 0); + if (atomic_read_unchecked(&rdev->read_errors)) + atomic_set_unchecked(&rdev->read_errors, 0); } else { const char *bdn = bdevname(rdev->bdev, b); int retry = 0; int set_bad = 0; clear_bit(R5_UPTODATE, &sh->dev[i].flags); - atomic_inc(&rdev->read_errors); + atomic_inc_unchecked(&rdev->read_errors); if (test_bit(R5_ReadRepl, &sh->dev[i].flags)) printk_ratelimited( KERN_WARNING @@ -2365,7 +2373,7 @@ static void raid5_end_read_request(struct bio * bi) mdname(conf->mddev), (unsigned long long)s, bdn); - } else if (atomic_read(&rdev->read_errors) + } else if (atomic_read_unchecked(&rdev->read_errors) > conf->max_nr_stripes) printk(KERN_WARNING "md/raid:%s: Too many read errors, failing device %s.\n", diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index 13bb57f..0ca21b2 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -272,7 +272,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, const struct dvb_device *template, void *priv, int type) { struct dvb_device *dvbdev; - struct file_operations *dvbdevfops; + file_operations_no_const *dvbdevfops; struct device *clsdev; int minor; int id; diff --git a/drivers/media/dvb-frontends/af9033.h b/drivers/media/dvb-frontends/af9033.h index 6ad22b6..6e90e2a 100644 --- a/drivers/media/dvb-frontends/af9033.h +++ b/drivers/media/dvb-frontends/af9033.h @@ -96,6 +96,6 @@ struct af9033_ops { int (*pid_filter_ctrl)(struct dvb_frontend *fe, int onoff); int (*pid_filter)(struct dvb_frontend *fe, int index, u16 pid, int onoff); -}; +} __no_const; #endif /* AF9033_H */ diff --git a/drivers/media/dvb-frontends/dib3000.h b/drivers/media/dvb-frontends/dib3000.h index 6ae9899..07d8543 100644 --- a/drivers/media/dvb-frontends/dib3000.h +++ b/drivers/media/dvb-frontends/dib3000.h @@ -39,7 +39,7 @@ struct dib_fe_xfer_ops int (*fifo_ctrl)(struct dvb_frontend *fe, int onoff); int (*pid_ctrl)(struct dvb_frontend *fe, int index, int pid, int onoff); int (*tuner_pass_ctrl)(struct dvb_frontend *fe, int onoff, u8 pll_ctrl); -}; +} __no_const; #if IS_REACHABLE(CONFIG_DVB_DIB3000MB) extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, diff --git a/drivers/media/dvb-frontends/dib7000p.h b/drivers/media/dvb-frontends/dib7000p.h index baa2789..c8de7fe 100644 --- a/drivers/media/dvb-frontends/dib7000p.h +++ b/drivers/media/dvb-frontends/dib7000p.h @@ -64,7 +64,7 @@ struct dib7000p_ops { int (*get_adc_power)(struct dvb_frontend *fe); int (*slave_reset)(struct dvb_frontend *fe); struct dvb_frontend *(*init)(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg); -}; +} __no_const; #if IS_REACHABLE(CONFIG_DVB_DIB7000P) void *dib7000p_attach(struct dib7000p_ops *ops); diff --git a/drivers/media/dvb-frontends/dib8000.h b/drivers/media/dvb-frontends/dib8000.h index 2b8b4b1..8cef451 100644 --- a/drivers/media/dvb-frontends/dib8000.h +++ b/drivers/media/dvb-frontends/dib8000.h @@ -61,7 +61,7 @@ struct dib8000_ops { int (*pid_filter_ctrl)(struct dvb_frontend *fe, u8 onoff); int (*pid_filter)(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff); struct dvb_frontend *(*init)(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg); -}; +} __no_const; #if IS_REACHABLE(CONFIG_DVB_DIB8000) void *dib8000_attach(struct dib8000_ops *ops); diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index 400e5ca..f69f748 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -50,9 +50,9 @@ MODULE_VERSION(CX88_VERSION); /* ------------------------------------------------------------------ */ -static unsigned int video_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; -static unsigned int vbi_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; +static int video_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; +static int vbi_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; +static int radio_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; module_param_array(video_nr, int, NULL, 0444); module_param_array(vbi_nr, int, NULL, 0444); diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index 8616fa8..e16eeaf 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -83,7 +83,7 @@ static struct pci_device_id ivtv_pci_tbl[] = { MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl); /* ivtv instance counter */ -static atomic_t ivtv_instance = ATOMIC_INIT(0); +static atomic_unchecked_t ivtv_instance = ATOMIC_INIT(0); /* Parameter declarations */ static int cardtype[IVTV_MAX_CARDS]; diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c index f50d072..0214f25 100644 --- a/drivers/media/pci/solo6x10/solo6x10-core.c +++ b/drivers/media/pci/solo6x10/solo6x10-core.c @@ -411,7 +411,7 @@ static void solo_device_release(struct device *dev) static int solo_sysfs_init(struct solo_dev *solo_dev) { - struct bin_attribute *sdram_attr = &solo_dev->sdram_attr; + bin_attribute_no_const *sdram_attr = &solo_dev->sdram_attr; struct device *dev = &solo_dev->dev; const char *driver; int i; diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c index 4a37a1c..7e82dfd 100644 --- a/drivers/media/pci/solo6x10/solo6x10-g723.c +++ b/drivers/media/pci/solo6x10/solo6x10-g723.c @@ -350,7 +350,7 @@ static int solo_snd_pcm_init(struct solo_dev *solo_dev) int solo_g723_init(struct solo_dev *solo_dev) { - static struct snd_device_ops ops = { NULL }; + static struct snd_device_ops ops = { }; struct snd_card *card; struct snd_kcontrol_new kctl; char name[32]; diff --git a/drivers/media/pci/solo6x10/solo6x10-p2m.c b/drivers/media/pci/solo6x10/solo6x10-p2m.c index 8c84846..27b4f83 100644 --- a/drivers/media/pci/solo6x10/solo6x10-p2m.c +++ b/drivers/media/pci/solo6x10/solo6x10-p2m.c @@ -73,7 +73,7 @@ int solo_p2m_dma_desc(struct solo_dev *solo_dev, /* Get next ID. According to Softlogic, 6110 has problems on !=0 P2M */ if (solo_dev->type != SOLO_DEV_6110 && multi_p2m) { - p2m_id = atomic_inc_return(&solo_dev->p2m_count) % SOLO_NR_P2M; + p2m_id = atomic_inc_return_unchecked(&solo_dev->p2m_count) % SOLO_NR_P2M; if (p2m_id < 0) p2m_id = -p2m_id; } diff --git a/drivers/media/pci/solo6x10/solo6x10.h b/drivers/media/pci/solo6x10/solo6x10.h index 27423d7..c3332fd 100644 --- a/drivers/media/pci/solo6x10/solo6x10.h +++ b/drivers/media/pci/solo6x10/solo6x10.h @@ -217,7 +217,7 @@ struct solo_dev { /* P2M DMA Engine */ struct solo_p2m_dev p2m_dev[SOLO_NR_P2M]; - atomic_t p2m_count; + atomic_unchecked_t p2m_count; int p2m_jiffies; unsigned int p2m_timeouts; diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c index 04706cc..23ae0ae 100644 --- a/drivers/media/pci/tw68/tw68-core.c +++ b/drivers/media/pci/tw68/tw68-core.c @@ -61,7 +61,7 @@ static unsigned int card[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; module_param_array(card, int, NULL, 0444); MODULE_PARM_DESC(card, "card type"); -static atomic_t tw68_instance = ATOMIC_INIT(0); +static atomic_unchecked_t tw68_instance = ATOMIC_INIT(0); /* ------------------------------------------------------------------ */ 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 +++ b/drivers/media/platform/omap/omap_vout.c @@ -63,7 +63,6 @@ enum omap_vout_channels { OMAP_VIDEO2, }; -static struct videobuf_queue_ops video_vbq_ops; /* Variables configurable through module params*/ static u32 video1_numbuffers = 3; static u32 video2_numbuffers = 3; @@ -1001,6 +1000,12 @@ static int omap_vout_open(struct file *file) { struct videobuf_queue *q; struct omap_vout_device *vout = NULL; + static struct videobuf_queue_ops video_vbq_ops = { + .buf_setup = omap_vout_buffer_setup, + .buf_prepare = omap_vout_buffer_prepare, + .buf_release = omap_vout_buffer_release, + .buf_queue = omap_vout_buffer_queue, + }; vout = video_drvdata(file); v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__); @@ -1018,10 +1023,6 @@ static int omap_vout_open(struct file *file) vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; q = &vout->vbq; - video_vbq_ops.buf_setup = omap_vout_buffer_setup; - video_vbq_ops.buf_prepare = omap_vout_buffer_prepare; - video_vbq_ops.buf_release = omap_vout_buffer_release; - video_vbq_ops.buf_queue = omap_vout_buffer_queue; spin_lock_init(&vout->vbq_lock); videobuf_queue_dma_contig_init(q, &video_vbq_ops, q->dev, diff --git a/drivers/media/platform/s5p-tv/mixer.h b/drivers/media/platform/s5p-tv/mixer.h index fb2acc5..a2fcbdc4 100644 --- a/drivers/media/platform/s5p-tv/mixer.h +++ b/drivers/media/platform/s5p-tv/mixer.h @@ -156,7 +156,7 @@ struct mxr_layer { /** layer index (unique identifier) */ int idx; /** callbacks for layer methods */ - struct mxr_layer_ops ops; + struct mxr_layer_ops *ops; /** format array */ const struct mxr_format **fmt_array; /** size of format array */ diff --git a/drivers/media/platform/s5p-tv/mixer_grp_layer.c b/drivers/media/platform/s5p-tv/mixer_grp_layer.c index 74344c7..a39e70e 100644 --- a/drivers/media/platform/s5p-tv/mixer_grp_layer.c +++ b/drivers/media/platform/s5p-tv/mixer_grp_layer.c @@ -235,7 +235,7 @@ struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx) { struct mxr_layer *layer; int ret; - struct mxr_layer_ops ops = { + static struct mxr_layer_ops ops = { .release = mxr_graph_layer_release, .buffer_set = mxr_graph_buffer_set, .stream_set = mxr_graph_stream_set, diff --git a/drivers/media/platform/s5p-tv/mixer_reg.c b/drivers/media/platform/s5p-tv/mixer_reg.c index 5127acb..a188d0a 100644 --- a/drivers/media/platform/s5p-tv/mixer_reg.c +++ b/drivers/media/platform/s5p-tv/mixer_reg.c @@ -276,7 +276,7 @@ static void mxr_irq_layer_handle(struct mxr_layer *layer) layer->update_buf = next; } - layer->ops.buffer_set(layer, layer->update_buf); + layer->ops->buffer_set(layer, layer->update_buf); if (done && done != layer->shadow_buf) vb2_buffer_done(&done->vb, VB2_BUF_STATE_DONE); diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index 751f3b6..d829203 100644 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ b/drivers/media/platform/s5p-tv/mixer_video.c @@ -210,7 +210,7 @@ static void mxr_layer_default_geo(struct mxr_layer *layer) layer->geo.src.height = layer->geo.src.full_height; mxr_geometry_dump(mdev, &layer->geo); - layer->ops.fix_geometry(layer, MXR_GEOMETRY_SINK, 0); + layer->ops->fix_geometry(layer, MXR_GEOMETRY_SINK, 0); mxr_geometry_dump(mdev, &layer->geo); } @@ -228,7 +228,7 @@ static void mxr_layer_update_output(struct mxr_layer *layer) layer->geo.dst.full_width = mbus_fmt.width; layer->geo.dst.full_height = mbus_fmt.height; layer->geo.dst.field = mbus_fmt.field; - layer->ops.fix_geometry(layer, MXR_GEOMETRY_SINK, 0); + layer->ops->fix_geometry(layer, MXR_GEOMETRY_SINK, 0); mxr_geometry_dump(mdev, &layer->geo); } @@ -334,7 +334,7 @@ static int mxr_s_fmt(struct file *file, void *priv, /* set source size to highest accepted value */ geo->src.full_width = max(geo->dst.full_width, pix->width); geo->src.full_height = max(geo->dst.full_height, pix->height); - layer->ops.fix_geometry(layer, MXR_GEOMETRY_SOURCE, 0); + layer->ops->fix_geometry(layer, MXR_GEOMETRY_SOURCE, 0); mxr_geometry_dump(mdev, &layer->geo); /* set cropping to total visible screen */ geo->src.width = pix->width; @@ -342,12 +342,12 @@ static int mxr_s_fmt(struct file *file, void *priv, geo->src.x_offset = 0; geo->src.y_offset = 0; /* assure consistency of geometry */ - layer->ops.fix_geometry(layer, MXR_GEOMETRY_CROP, MXR_NO_OFFSET); + layer->ops->fix_geometry(layer, MXR_GEOMETRY_CROP, MXR_NO_OFFSET); mxr_geometry_dump(mdev, &layer->geo); /* set full size to lowest possible value */ geo->src.full_width = 0; geo->src.full_height = 0; - layer->ops.fix_geometry(layer, MXR_GEOMETRY_SOURCE, 0); + layer->ops->fix_geometry(layer, MXR_GEOMETRY_SOURCE, 0); mxr_geometry_dump(mdev, &layer->geo); /* returning results */ @@ -474,7 +474,7 @@ static int mxr_s_selection(struct file *file, void *fh, target->width = s->r.width; target->height = s->r.height; - layer->ops.fix_geometry(layer, stage, s->flags); + layer->ops->fix_geometry(layer, stage, s->flags); /* retrieve update selection rectangle */ res.left = target->x_offset; @@ -938,13 +938,13 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) mxr_output_get(mdev); mxr_layer_update_output(layer); - layer->ops.format_set(layer); + layer->ops->format_set(layer); /* enabling layer in hardware */ spin_lock_irqsave(&layer->enq_slock, flags); layer->state = MXR_LAYER_STREAMING; spin_unlock_irqrestore(&layer->enq_slock, flags); - layer->ops.stream_set(layer, MXR_ENABLE); + layer->ops->stream_set(layer, MXR_ENABLE); mxr_streamer_get(mdev); return 0; @@ -1014,7 +1014,7 @@ static void stop_streaming(struct vb2_queue *vq) spin_unlock_irqrestore(&layer->enq_slock, flags); /* disabling layer in hardware */ - layer->ops.stream_set(layer, MXR_DISABLE); + layer->ops->stream_set(layer, MXR_DISABLE); /* remove one streamer */ mxr_streamer_put(mdev); /* allow changes in output configuration */ @@ -1052,8 +1052,8 @@ void mxr_base_layer_unregister(struct mxr_layer *layer) void mxr_layer_release(struct mxr_layer *layer) { - if (layer->ops.release) - layer->ops.release(layer); + if (layer->ops->release) + layer->ops->release(layer); } void mxr_base_layer_release(struct mxr_layer *layer) @@ -1079,7 +1079,7 @@ struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev, layer->mdev = mdev; layer->idx = idx; - layer->ops = *ops; + layer->ops = ops; spin_lock_init(&layer->enq_slock); INIT_LIST_HEAD(&layer->enq_list); diff --git a/drivers/media/platform/s5p-tv/mixer_vp_layer.c b/drivers/media/platform/s5p-tv/mixer_vp_layer.c index c9388c4..ce71ece 100644 --- a/drivers/media/platform/s5p-tv/mixer_vp_layer.c +++ b/drivers/media/platform/s5p-tv/mixer_vp_layer.c @@ -206,7 +206,7 @@ struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx) { struct mxr_layer *layer; int ret; - struct mxr_layer_ops ops = { + static struct mxr_layer_ops ops = { .release = mxr_vp_layer_release, .buffer_set = mxr_vp_buffer_set, .stream_set = mxr_vp_stream_set, diff --git a/drivers/media/platform/sti/c8sectpfe/Kconfig b/drivers/media/platform/sti/c8sectpfe/Kconfig index 641ad8f..02eacb9 100644 --- a/drivers/media/platform/sti/c8sectpfe/Kconfig +++ b/drivers/media/platform/sti/c8sectpfe/Kconfig @@ -5,6 +5,7 @@ config DVB_C8SECTPFE select FW_LOADER select FW_LOADER_USER_HELPER_FALLBACK select DEBUG_FS + depends on !GRKERNSEC_KMEM select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c index 084d346..e15eef6 100644 --- a/drivers/media/platform/vivid/vivid-osd.c +++ b/drivers/media/platform/vivid/vivid-osd.c @@ -85,6 +85,7 @@ static int vivid_fb_ioctl(struct fb_info *info, unsigned cmd, unsigned long arg) case FBIOGET_VBLANK: { struct fb_vblank vblank; + memset(&vblank, 0, sizeof(vblank)); vblank.flags = FB_VBLANK_HAVE_COUNT | FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VSYNC; vblank.count = 0; diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 82affae..42833ec 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -333,6 +333,8 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo unsigned char readbuf[RDS_BUFFER]; int i = 0; + if (count > RDS_BUFFER) + return -EFAULT; mutex_lock(&dev->lock); if (dev->rdsstat == 0) cadet_start_rds(dev); @@ -349,8 +351,9 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo readbuf[i++] = dev->rdsbuf[dev->rdsout++]; mutex_unlock(&dev->lock); - if (i && copy_to_user(data, readbuf, i)) - return -EFAULT; + if (i > sizeof(readbuf) || (i && copy_to_user(data, readbuf, i))) + i = -EFAULT; + return i; } diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index 5236035..c622c74 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -61,7 +61,7 @@ MODULE_PARM_DESC(radio_nr, "Radio device number"); /* TEA5757 pin mappings */ static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16; -static atomic_t maxiradio_instance = ATOMIC_INIT(0); +static atomic_unchecked_t maxiradio_instance = ATOMIC_INIT(0); #define PCI_VENDOR_ID_GUILLEMOT 0x5046 #define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001 diff --git a/drivers/media/radio/radio-shark.c b/drivers/media/radio/radio-shark.c index 050b3bb..79f62b9 100644 --- a/drivers/media/radio/radio-shark.c +++ b/drivers/media/radio/radio-shark.c @@ -79,7 +79,7 @@ struct shark_device { u32 last_val; }; -static atomic_t shark_instance = ATOMIC_INIT(0); +static atomic_unchecked_t shark_instance = ATOMIC_INIT(0); static void shark_write_val(struct snd_tea575x *tea, u32 val) { diff --git a/drivers/media/radio/radio-shark2.c b/drivers/media/radio/radio-shark2.c index 8654e0d..0608a64 100644 --- a/drivers/media/radio/radio-shark2.c +++ b/drivers/media/radio/radio-shark2.c @@ -74,7 +74,7 @@ struct shark_device { u8 *transfer_buffer; }; -static atomic_t shark_instance = ATOMIC_INIT(0); +static atomic_unchecked_t shark_instance = ATOMIC_INIT(0); static int shark_write_reg(struct radio_tea5777 *tea, u64 reg) { diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c index 9cbb8cd..2bf2ff3 100644 --- a/drivers/media/radio/radio-si476x.c +++ b/drivers/media/radio/radio-si476x.c @@ -1445,7 +1445,7 @@ static int si476x_radio_probe(struct platform_device *pdev) struct si476x_radio *radio; struct v4l2_ctrl *ctrl; - static atomic_t instance = ATOMIC_INIT(0); + static atomic_unchecked_t instance = ATOMIC_INIT(0); radio = devm_kzalloc(&pdev->dev, sizeof(*radio), GFP_KERNEL); if (!radio) diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index ebc73b0..ca6babf 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -71,7 +71,7 @@ module_param(default_rds_buf, uint, 0444); MODULE_PARM_DESC(rds_buf, "RDS buffer entries"); /* Radio Nr */ -static u32 radio_nr = -1; +static int radio_nr = -1; module_param(radio_nr, int, 0444); MODULE_PARM_DESC(radio_nr, "Radio Nr"); diff --git a/drivers/media/usb/dvb-usb/cinergyT2-core.c b/drivers/media/usb/dvb-usb/cinergyT2-core.c index 9fd1527..8927230 100644 --- a/drivers/media/usb/dvb-usb/cinergyT2-core.c +++ b/drivers/media/usb/dvb-usb/cinergyT2-core.c @@ -50,29 +50,73 @@ static struct dvb_usb_device_properties cinergyt2_properties; static int cinergyt2_streaming_ctrl(struct dvb_usb_adapter *adap, int enable) { - char buf[] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 }; - char result[64]; - return dvb_usb_generic_rw(adap->dev, buf, sizeof(buf), result, - sizeof(result), 0); + char *buf; + char *result; + int retval; + + buf = kmalloc(2, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + result = kmalloc(64, GFP_KERNEL); + if (result == NULL) { + kfree(buf); + return -ENOMEM; + } + + buf[0] = CINERGYT2_EP1_CONTROL_STREAM_TRANSFER; + buf[1] = enable ? 1 : 0; + + retval = dvb_usb_generic_rw(adap->dev, buf, 2, result, 64, 0); + + kfree(buf); + kfree(result); + return retval; } static int cinergyt2_power_ctrl(struct dvb_usb_device *d, int enable) { - char buf[] = { CINERGYT2_EP1_SLEEP_MODE, enable ? 0 : 1 }; - char state[3]; - return dvb_usb_generic_rw(d, buf, sizeof(buf), state, sizeof(state), 0); + char *buf; + char *state; + int retval; + + buf = kmalloc(2, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + state = kmalloc(3, GFP_KERNEL); + if (state == NULL) { + kfree(buf); + return -ENOMEM; + } + + buf[0] = CINERGYT2_EP1_SLEEP_MODE; + buf[1] = enable ? 1 : 0; + + retval = dvb_usb_generic_rw(d, buf, 2, state, 3, 0); + + kfree(buf); + kfree(state); + return retval; } static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap) { - char query[] = { CINERGYT2_EP1_GET_FIRMWARE_VERSION }; - char state[3]; + char *query; + char *state; int ret; + query = kmalloc(1, GFP_KERNEL); + if (query == NULL) + return -ENOMEM; + state = kmalloc(3, GFP_KERNEL); + if (state == NULL) { + kfree(query); + return -ENOMEM; + } + + query[0] = CINERGYT2_EP1_GET_FIRMWARE_VERSION; adap->fe_adap[0].fe = cinergyt2_fe_attach(adap->dev); - ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state, - sizeof(state), 0); + ret = dvb_usb_generic_rw(adap->dev, query, 1, state, 3, 0); if (ret < 0) { deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep " "state info\n"); @@ -80,7 +124,8 @@ static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap) /* Copy this pointer as we are gonna need it in the release phase */ cinergyt2_usb_device = adap->dev; - + kfree(query); + kfree(state); return 0; } @@ -141,12 +186,23 @@ static int repeatable_keys[] = { static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { struct cinergyt2_state *st = d->priv; - u8 key[5] = {0, 0, 0, 0, 0}, cmd = CINERGYT2_EP1_GET_RC_EVENTS; + u8 *key, *cmd; int i; + cmd = kmalloc(1, GFP_KERNEL); + if (cmd == NULL) + return -EINVAL; + key = kzalloc(5, GFP_KERNEL); + if (key == NULL) { + kfree(cmd); + return -EINVAL; + } + + cmd[0] = CINERGYT2_EP1_GET_RC_EVENTS; + *state = REMOTE_NO_KEY_PRESSED; - dvb_usb_generic_rw(d, &cmd, 1, key, sizeof(key), 0); + dvb_usb_generic_rw(d, cmd, 1, key, 5, 0); if (key[4] == 0xff) { /* key repeat */ st->rc_counter++; @@ -157,12 +213,12 @@ static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state) *event = d->last_event; deb_rc("repeat key, event %x\n", *event); - return 0; + goto out; } } deb_rc("repeated key (non repeatable)\n"); } - return 0; + goto out; } /* hack to pass checksum on the custom field */ @@ -174,6 +230,9 @@ static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state) deb_rc("key: %*ph\n", 5, key); } +out: + kfree(cmd); + kfree(key); return 0; } diff --git a/drivers/media/usb/dvb-usb/cinergyT2-fe.c b/drivers/media/usb/dvb-usb/cinergyT2-fe.c index b3ec743..9c0e418 100644 --- a/drivers/media/usb/dvb-usb/cinergyT2-fe.c +++ b/drivers/media/usb/dvb-usb/cinergyT2-fe.c @@ -145,103 +145,176 @@ static int cinergyt2_fe_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct cinergyt2_fe_state *state = fe->demodulator_priv; - struct dvbt_get_status_msg result; - u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + struct dvbt_get_status_msg *result; + u8 *cmd; int ret; - ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&result, - sizeof(result), 0); + cmd = kmalloc(1, GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + result = kmalloc(sizeof(*result), GFP_KERNEL); + if (result == NULL) { + kfree(cmd); + return -ENOMEM; + } + + cmd[0] = CINERGYT2_EP1_GET_TUNER_STATUS; + + ret = dvb_usb_generic_rw(state->d, cmd, 1, (u8 *)result, + sizeof(*result), 0); if (ret < 0) - return ret; + goto out; *status = 0; - if (0xffff - le16_to_cpu(result.gain) > 30) + if (0xffff - le16_to_cpu(result->gain) > 30) *status |= FE_HAS_SIGNAL; - if (result.lock_bits & (1 << 6)) + if (result->lock_bits & (1 << 6)) *status |= FE_HAS_LOCK; - if (result.lock_bits & (1 << 5)) + if (result->lock_bits & (1 << 5)) *status |= FE_HAS_SYNC; - if (result.lock_bits & (1 << 4)) + if (result->lock_bits & (1 << 4)) *status |= FE_HAS_CARRIER; - if (result.lock_bits & (1 << 1)) + if (result->lock_bits & (1 << 1)) *status |= FE_HAS_VITERBI; if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) *status &= ~FE_HAS_LOCK; - return 0; +out: + kfree(cmd); + kfree(result); + return ret; } static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber) { struct cinergyt2_fe_state *state = fe->demodulator_priv; - struct dvbt_get_status_msg status; - char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + struct dvbt_get_status_msg *status; + char *cmd; int ret; - ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, - sizeof(status), 0); + cmd = kmalloc(1, GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + status = kmalloc(sizeof(*status), GFP_KERNEL); + if (status == NULL) { + kfree(cmd); + return -ENOMEM; + } + + cmd[0] = CINERGYT2_EP1_GET_TUNER_STATUS; + + ret = dvb_usb_generic_rw(state->d, cmd, 1, (char *)status, + sizeof(*status), 0); if (ret < 0) - return ret; + goto out; - *ber = le32_to_cpu(status.viterbi_error_rate); + *ber = le32_to_cpu(status->viterbi_error_rate); +out: + kfree(cmd); + kfree(status); return 0; } static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) { struct cinergyt2_fe_state *state = fe->demodulator_priv; - struct dvbt_get_status_msg status; - u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + struct dvbt_get_status_msg *status; + u8 *cmd; int ret; - ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&status, - sizeof(status), 0); + cmd = kmalloc(1, GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + status = kmalloc(sizeof(*status), GFP_KERNEL); + if (status == NULL) { + kfree(cmd); + return -ENOMEM; + } + + cmd[0] = CINERGYT2_EP1_GET_TUNER_STATUS; + + ret = dvb_usb_generic_rw(state->d, cmd, 1, (u8 *)status, + sizeof(*status), 0); if (ret < 0) { err("cinergyt2_fe_read_unc_blocks() Failed! (Error=%d)\n", ret); - return ret; + goto out; } - *unc = le32_to_cpu(status.uncorrected_block_count); - return 0; + *unc = le32_to_cpu(status->uncorrected_block_count); + +out: + kfree(cmd); + kfree(status); + return ret; } static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { struct cinergyt2_fe_state *state = fe->demodulator_priv; - struct dvbt_get_status_msg status; - char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + struct dvbt_get_status_msg *status; + char *cmd; int ret; - ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, - sizeof(status), 0); + cmd = kmalloc(1, GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + status = kmalloc(sizeof(*status), GFP_KERNEL); + if (status == NULL) { + kfree(cmd); + return -ENOMEM; + } + + cmd[0] = CINERGYT2_EP1_GET_TUNER_STATUS; + + ret = dvb_usb_generic_rw(state->d, cmd, 1, (char *)status, + sizeof(*status), 0); if (ret < 0) { err("cinergyt2_fe_read_signal_strength() Failed!" " (Error=%d)\n", ret); - return ret; + goto out; } - *strength = (0xffff - le16_to_cpu(status.gain)); + *strength = (0xffff - le16_to_cpu(status->gain)); + +out: + kfree(cmd); + kfree(status); return 0; } static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr) { struct cinergyt2_fe_state *state = fe->demodulator_priv; - struct dvbt_get_status_msg status; - char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + struct dvbt_get_status_msg *status; + char *cmd; int ret; - ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, - sizeof(status), 0); + cmd = kmalloc(1, GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + status = kmalloc(sizeof(*status), GFP_KERNEL); + if (status == NULL) { + kfree(cmd); + return -ENOMEM; + } + + cmd[0] = CINERGYT2_EP1_GET_TUNER_STATUS; + + ret = dvb_usb_generic_rw(state->d, cmd, 1, (char *)status, + sizeof(*status), 0); if (ret < 0) { err("cinergyt2_fe_read_snr() Failed! (Error=%d)\n", ret); - return ret; + goto out; } - *snr = (status.snr << 8) | status.snr; - return 0; + *snr = (status->snr << 8) | status->snr; + +out: + kfree(cmd); + kfree(status); + return ret; } static int cinergyt2_fe_init(struct dvb_frontend *fe) @@ -266,35 +339,46 @@ static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe) { struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct cinergyt2_fe_state *state = fe->demodulator_priv; - struct dvbt_set_parameters_msg param; - char result[2]; + struct dvbt_set_parameters_msg *param; + char *result; int err; - param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; - param.tps = cpu_to_le16(compute_tps(fep)); - param.freq = cpu_to_le32(fep->frequency / 1000); - param.flags = 0; + result = kmalloc(2, GFP_KERNEL); + if (result == NULL) + return -ENOMEM; + param = kmalloc(sizeof(*param), GFP_KERNEL); + if (param == NULL) { + kfree(result); + return -ENOMEM; + } + + param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; + param->tps = cpu_to_le16(compute_tps(fep)); + param->freq = cpu_to_le32(fep->frequency / 1000); + param->flags = 0; switch (fep->bandwidth_hz) { default: case 8000000: - param.bandwidth = 8; + param->bandwidth = 8; break; case 7000000: - param.bandwidth = 7; + param->bandwidth = 7; break; case 6000000: - param.bandwidth = 6; + param->bandwidth = 6; break; } err = dvb_usb_generic_rw(state->d, - (char *)¶m, sizeof(param), - result, sizeof(result), 0); + (char *)param, sizeof(*param), + result, 2, 0); if (err < 0) err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err); - return (err < 0) ? err : 0; + kfree(result); + kfree(param); + return err; } static void cinergyt2_fe_release(struct dvb_frontend *fe) diff --git a/drivers/media/usb/dvb-usb/dvb-usb-firmware.c b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c index 733a7ff..f8b52e3 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-firmware.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c @@ -35,42 +35,57 @@ static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 le int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type) { - struct hexline hx; - u8 reset; + struct hexline *hx; + u8 *reset; int ret,pos=0; + reset = kmalloc(1, GFP_KERNEL); + if (reset == NULL) + return -ENOMEM; + + hx = kmalloc(sizeof(struct hexline), GFP_KERNEL); + if (hx == NULL) { + kfree(reset); + return -ENOMEM; + } + /* stop the CPU */ - reset = 1; - if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1) + reset[0] = 1; + if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,reset,1)) != 1) err("could not stop the USB controller CPU."); - while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) { - deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk); - ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len); + while ((ret = dvb_usb_get_hexline(fw,hx,&pos)) > 0) { + deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx->addr,hx->len,hx->chk); + ret = usb_cypress_writemem(udev,hx->addr,hx->data,hx->len); - if (ret != hx.len) { + if (ret != hx->len) { err("error while transferring firmware " "(transferred size: %d, block size: %d)", - ret,hx.len); + ret,hx->len); ret = -EINVAL; break; } } if (ret < 0) { err("firmware download failed at %d with %d",pos,ret); + kfree(reset); + kfree(hx); return ret; } if (ret == 0) { /* restart the CPU */ - reset = 0; - if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) { + reset[0] = 0; + if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,reset,1) != 1) { err("could not restart the USB controller CPU."); ret = -EINVAL; } } else ret = -EIO; + kfree(reset); + kfree(hx); + return ret; } EXPORT_SYMBOL(usb_cypress_load_firmware); diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c index 6c3c477..6c435a4 100644 --- a/drivers/media/usb/dvb-usb/technisat-usb2.c +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c @@ -87,8 +87,11 @@ struct technisat_usb2_state { static int technisat_usb2_i2c_access(struct usb_device *udev, u8 device_addr, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) { - u8 b[64]; - int ret, actual_length; + u8 *b = kmalloc(64, GFP_KERNEL); + int ret, actual_length, error = 0; + + if (b == NULL) + return -ENOMEM; deb_i2c("i2c-access: %02x, tx: ", device_addr); debug_dump(tx, txlen, deb_i2c); @@ -121,7 +124,8 @@ static int technisat_usb2_i2c_access(struct usb_device *udev, if (ret < 0) { err("i2c-error: out failed %02x = %d", device_addr, ret); - return -ENODEV; + error = -ENODEV; + goto out; } ret = usb_bulk_msg(udev, @@ -129,7 +133,8 @@ static int technisat_usb2_i2c_access(struct usb_device *udev, b, 64, &actual_length, 1000); if (ret < 0) { err("i2c-error: in failed %02x = %d", device_addr, ret); - return -ENODEV; + error = -ENODEV; + goto out; } if (b[0] != I2C_STATUS_OK) { @@ -137,8 +142,10 @@ static int technisat_usb2_i2c_access(struct usb_device *udev, /* handle tuner-i2c-nak */ if (!(b[0] == I2C_STATUS_NAK && device_addr == 0x60 - /* && device_is_technisat_usb2 */)) - return -ENODEV; + /* && device_is_technisat_usb2 */)) { + error = -ENODEV; + goto out; + } } deb_i2c("status: %d, ", b[0]); @@ -152,7 +159,9 @@ static int technisat_usb2_i2c_access(struct usb_device *udev, deb_i2c("\n"); - return 0; +out: + kfree(b); + return error; } static int technisat_usb2_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, @@ -224,14 +233,16 @@ static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum techni { int ret; - u8 led[8] = { - red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST, - 0 - }; + u8 *led = kzalloc(8, GFP_KERNEL); + + if (led == NULL) + return -ENOMEM; if (disable_led_control && state != TECH_LED_OFF) return 0; + led[0] = red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST; + switch (state) { case TECH_LED_ON: led[1] = 0x82; @@ -263,16 +274,22 @@ static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum techni red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, - led, sizeof(led), 500); + led, 8, 500); mutex_unlock(&d->i2c_mutex); + + kfree(led); + return ret; } static int technisat_usb2_set_led_timer(struct dvb_usb_device *d, u8 red, u8 green) { int ret; - u8 b = 0; + u8 *b = kzalloc(1, GFP_KERNEL); + + if (b == NULL) + return -ENOMEM; if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; @@ -281,10 +298,12 @@ static int technisat_usb2_set_led_timer(struct dvb_usb_device *d, u8 red, u8 gre SET_LED_TIMER_DIVIDER_VENDOR_REQUEST, USB_TYPE_VENDOR | USB_DIR_OUT, (red << 8) | green, 0, - &b, 1, 500); + b, 1, 500); mutex_unlock(&d->i2c_mutex); + kfree(b); + return ret; } @@ -328,7 +347,7 @@ static int technisat_usb2_identify_state(struct usb_device *udev, struct dvb_usb_device_description **desc, int *cold) { int ret; - u8 version[3]; + u8 *version = kmalloc(3, GFP_KERNEL); /* first select the interface */ if (usb_set_interface(udev, 0, 1) != 0) @@ -338,11 +357,14 @@ static int technisat_usb2_identify_state(struct usb_device *udev, *cold = 0; /* by default do not download a firmware - just in case something is wrong */ + if (version == NULL) + return 0; + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), GET_VERSION_INFO_VENDOR_REQUEST, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, - version, sizeof(version), 500); + version, 3, 500); if (ret < 0) *cold = 1; @@ -351,6 +373,8 @@ static int technisat_usb2_identify_state(struct usb_device *udev, *cold = 0; } + kfree(version); + return 0; } @@ -594,10 +618,15 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a) static int technisat_usb2_get_ir(struct dvb_usb_device *d) { - u8 buf[62], *b; + u8 *buf, *b; int ret; struct ir_raw_event ev; + buf = kmalloc(62, GFP_KERNEL); + + if (buf == NULL) + return -ENOMEM; + buf[0] = GET_IR_DATA_VENDOR_REQUEST; buf[1] = 0x08; buf[2] = 0x8f; @@ -620,16 +649,20 @@ static int technisat_usb2_get_ir(struct dvb_usb_device *d) GET_IR_DATA_VENDOR_REQUEST, USB_TYPE_VENDOR | USB_DIR_IN, 0x8080, 0, - buf, sizeof(buf), 500); + buf, 62, 500); unlock: mutex_unlock(&d->i2c_mutex); - if (ret < 0) + if (ret < 0) { + kfree(buf); return ret; + } - if (ret == 1) + if (ret == 1) { + kfree(buf); return 0; /* no key pressed */ + } /* decoding */ b = buf+1; @@ -656,6 +689,8 @@ unlock: ir_raw_event_handle(d->rc_dev); + kfree(buf); + return 1; } diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index af63543..0436f20 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -429,7 +429,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user * by passing a very big num_planes value */ uplane = compat_alloc_user_space(num_planes * sizeof(struct v4l2_plane)); - kp->m.planes = (__force struct v4l2_plane *)uplane; + kp->m.planes = (__force_kernel struct v4l2_plane *)uplane; while (--num_planes >= 0) { ret = get_v4l2_plane32(uplane, uplane32, kp->memory); @@ -500,7 +500,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user if (num_planes == 0) return 0; - uplane = (__force struct v4l2_plane __user *)kp->m.planes; + uplane = (struct v4l2_plane __force_user *)kp->m.planes; if (get_user(p, &up->m.planes)) return -EFAULT; uplane32 = compat_ptr(p); @@ -564,7 +564,7 @@ static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame get_user(kp->flags, &up->flags) || copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt))) return -EFAULT; - kp->base = (__force void *)compat_ptr(tmp); + kp->base = (__force_kernel void *)compat_ptr(tmp); return 0; } @@ -669,7 +669,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext n * sizeof(struct v4l2_ext_control32))) return -EFAULT; kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); - kp->controls = (__force struct v4l2_ext_control *)kcontrols; + kp->controls = (__force_kernel struct v4l2_ext_control *)kcontrols; while (--n >= 0) { u32 id; @@ -696,7 +696,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext { struct v4l2_ext_control32 __user *ucontrols; struct v4l2_ext_control __user *kcontrols = - (__force struct v4l2_ext_control __user *)kp->controls; + (struct v4l2_ext_control __force_user *)kp->controls; int n = kp->count; compat_caddr_t p; @@ -780,7 +780,7 @@ static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) get_user(tmp, &up->edid) || copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) return -EFAULT; - kp->edid = (__force u8 *)compat_ptr(tmp); + kp->edid = (__force_kernel u8 *)compat_ptr(tmp); return 0; } diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c index 5b0a30b..1974b38 100644 --- a/drivers/media/v4l2-core/v4l2-device.c +++ b/drivers/media/v4l2-core/v4l2-device.c @@ -74,9 +74,9 @@ int v4l2_device_put(struct v4l2_device *v4l2_dev) EXPORT_SYMBOL_GPL(v4l2_device_put); int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename, - atomic_t *instance) + atomic_unchecked_t *instance) { - int num = atomic_inc_return(instance) - 1; + int num = atomic_inc_return_unchecked(instance) - 1; int len = strlen(basename); if (basename[len - 1] >= '0' && basename[len - 1] <= '9') diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 4a384fc..4b562e4 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2341,7 +2341,8 @@ struct v4l2_ioctl_info { struct file *file, void *fh, void *p); } u; void (*debug)(const void *arg, bool write_only); -}; +} __do_const; +typedef struct v4l2_ioctl_info __no_const v4l2_ioctl_info_no_const; /* This control needs a priority check */ #define INFO_FL_PRIO (1 << 0) @@ -2525,7 +2526,7 @@ static long __video_do_ioctl(struct file *file, struct video_device *vfd = video_devdata(file); const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; bool write_only = false; - struct v4l2_ioctl_info default_info; + v4l2_ioctl_info_no_const default_info; const struct v4l2_ioctl_info *info; void *fh = file->private_data; struct v4l2_fh *vfh = NULL; @@ -2616,7 +2617,7 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, ret = -EINVAL; break; } - *user_ptr = (void __user *)buf->m.planes; + *user_ptr = (void __force_user *)buf->m.planes; *kernel_ptr = (void **)&buf->m.planes; *array_size = sizeof(struct v4l2_plane) * buf->length; ret = 1; @@ -2633,7 +2634,7 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, ret = -EINVAL; break; } - *user_ptr = (void __user *)edid->edid; + *user_ptr = (void __force_user *)edid->edid; *kernel_ptr = (void **)&edid->edid; *array_size = edid->blocks * 128; ret = 1; @@ -2651,7 +2652,7 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, ret = -EINVAL; break; } - *user_ptr = (void __user *)ctrls->controls; + *user_ptr = (void __force_user *)ctrls->controls; *kernel_ptr = (void **)&ctrls->controls; *array_size = sizeof(struct v4l2_ext_control) * ctrls->count; @@ -2752,7 +2753,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, } if (has_array_args) { - *kernel_ptr = (void __force *)user_ptr; + *kernel_ptr = (void __force_kernel *)user_ptr; if (copy_to_user(user_ptr, mbuf, array_size)) err = -EFAULT; goto out_array_args; diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c index 6515dfc..3d39b80 100644 --- a/drivers/memory/omap-gpmc.c +++ b/drivers/memory/omap-gpmc.c @@ -232,7 +232,6 @@ struct omap3_gpmc_regs { }; static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ]; -static struct irq_chip gpmc_irq_chip; static int gpmc_irq_start; static struct resource gpmc_mem_root; @@ -1145,6 +1144,17 @@ static void gpmc_irq_noop(struct irq_data *data) { } static unsigned int gpmc_irq_noop_ret(struct irq_data *data) { return 0; } +static struct irq_chip gpmc_irq_chip = { + .name = "gpmc", + .irq_startup = gpmc_irq_noop_ret, + .irq_enable = gpmc_irq_enable, + .irq_disable = gpmc_irq_disable, + .irq_shutdown = gpmc_irq_noop, + .irq_ack = gpmc_irq_noop, + .irq_mask = gpmc_irq_noop, + .irq_unmask = gpmc_irq_noop, +}; + static int gpmc_setup_irq(void) { int i; @@ -1159,15 +1169,6 @@ static int gpmc_setup_irq(void) return gpmc_irq_start; } - gpmc_irq_chip.name = "gpmc"; - gpmc_irq_chip.irq_startup = gpmc_irq_noop_ret; - gpmc_irq_chip.irq_enable = gpmc_irq_enable; - gpmc_irq_chip.irq_disable = gpmc_irq_disable; - gpmc_irq_chip.irq_shutdown = gpmc_irq_noop; - gpmc_irq_chip.irq_ack = gpmc_irq_noop; - gpmc_irq_chip.irq_mask = gpmc_irq_noop; - gpmc_irq_chip.irq_unmask = gpmc_irq_noop; - gpmc_client_irq[0].bitmask = GPMC_IRQ_FIFOEVENTENABLE; gpmc_client_irq[1].bitmask = GPMC_IRQ_COUNT_EVENT; diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 5dcc031..e08ecd2 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -6722,8 +6722,13 @@ static int mpt_iocinfo_proc_show(struct seq_file *m, void *v) seq_printf(m, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth); seq_printf(m, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize); +#ifdef CONFIG_GRKERNSEC_HIDESYM + seq_printf(m, " RequestFrames @ 0x%p (Dma @ 0x%p)\n", NULL, NULL); +#else seq_printf(m, " RequestFrames @ 0x%p (Dma @ 0x%p)\n", (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma); +#endif + /* * Rounding UP to nearest 4-kB boundary here... */ @@ -6736,7 +6741,11 @@ static int mpt_iocinfo_proc_show(struct seq_file *m, void *v) ioc->facts.GlobalCredits); seq_printf(m, " Frames @ 0x%p (Dma @ 0x%p)\n", +#ifdef CONFIG_GRKERNSEC_HIDESYM + NULL, NULL); +#else (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma); +#endif sz = (ioc->reply_sz * ioc->reply_depth) + 128; seq_printf(m, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n", ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz); diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 005a88b..5a90fbb 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -446,6 +446,23 @@ mptsas_is_end_device(struct mptsas_devinfo * attached) return 0; } +static inline void +mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy) +{ + if (phy_info->port_details) { + phy_info->port_details->rphy = rphy; + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n", + ioc->name, rphy)); + } + + if (rphy) { + dsaswideprintk(ioc, dev_printk(KERN_DEBUG, + &rphy->dev, MYIOC_s_FMT "add:", ioc->name)); + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n", + ioc->name, rphy, rphy->dev.release)); + } +} + /* no mutex */ static void mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details) @@ -484,23 +501,6 @@ mptsas_get_rphy(struct mptsas_phyinfo *phy_info) return NULL; } -static inline void -mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy) -{ - if (phy_info->port_details) { - phy_info->port_details->rphy = rphy; - dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n", - ioc->name, rphy)); - } - - if (rphy) { - dsaswideprintk(ioc, dev_printk(KERN_DEBUG, - &rphy->dev, MYIOC_s_FMT "add:", ioc->name)); - dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n", - ioc->name, rphy, rphy->dev.release)); - } -} - static inline struct sas_port * mptsas_get_port(struct mptsas_phyinfo *phy_info) { diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index 0236cd7..53b10d7 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -100,7 +100,7 @@ static int irq_last; static u32 *irq_count; static int num_irqs; -static struct device_attribute **dev_attr; +static device_attribute_no_const **dev_attr; static char **event_name; static u8 avg_sample = SAMPLE_16; diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c index 463f4ea..1624d49 100644 --- a/drivers/mfd/kempld-core.c +++ b/drivers/mfd/kempld-core.c @@ -499,7 +499,7 @@ static struct platform_driver kempld_driver = { .remove = kempld_remove, }; -static struct dmi_system_id kempld_dmi_table[] __initdata = { +static const struct dmi_system_id kempld_dmi_table[] __initconst = { { .ident = "BBL6", .matches = { diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c index b0fe810..eee08c4 100644 --- a/drivers/mfd/max8925-i2c.c +++ b/drivers/mfd/max8925-i2c.c @@ -152,7 +152,7 @@ static int max8925_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct max8925_platform_data *pdata = dev_get_platdata(&client->dev); - static struct max8925_chip *chip; + struct max8925_chip *chip; struct device_node *node = client->dev.of_node; if (node && !pdata) { diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index f7ab115..16b2087 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -230,7 +230,7 @@ static int tps65910_irq_init(struct tps65910 *tps65910, int irq, struct tps65910_platform_data *pdata) { int ret = 0; - static struct regmap_irq_chip *tps6591x_irqs_chip; + struct regmap_irq_chip *tps6591x_irqs_chip; 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 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "twl-core.h" @@ -720,10 +721,12 @@ int twl4030_init_irq(struct device *dev, int irq_num) * Install an irq handler for each of the SIH modules; * clone dummy irq_chip since PIH can't *do* anything */ - twl4030_irq_chip = dummy_irq_chip; - 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"; - twl4030_sih_irq_chip.irq_ack = dummy_irq_chip.irq_ack; + *(void **)&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/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index c4b9374..9afdda4 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -250,7 +250,7 @@ static const struct reg_sequence wm5110_revd_patch[] = { }; /* Add extra headphone write sequence locations */ -static const struct reg_default wm5110_reve_patch[] = { +static const struct reg_sequence wm5110_reve_patch[] = { { 0x80, 0x3 }, { 0x80, 0x3 }, { 0x4b, 0x138 }, diff --git a/drivers/mfd/wm8998-tables.c b/drivers/mfd/wm8998-tables.c index e6de3cd..607640c 100644 --- a/drivers/mfd/wm8998-tables.c +++ b/drivers/mfd/wm8998-tables.c @@ -21,7 +21,7 @@ #define WM8998_NUM_AOD_ISR 2 #define WM8998_NUM_ISR 5 -static const struct reg_default wm8998_rev_a_patch[] = { +static const struct reg_sequence wm8998_rev_a_patch[] = { { 0x0212, 0x0000 }, { 0x0211, 0x0014 }, { 0x04E4, 0x0E0D }, diff --git a/drivers/misc/c2port/core.c b/drivers/misc/c2port/core.c index 464419b..64bae8d 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, goto error_idr_alloc; c2dev->id = ret; - 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; + pax_close_kernel(); c2dev->dev = device_create(c2port_class, NULL, 0, c2dev, "c2port%d", c2dev->id); diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 9a60bd4..cee2069 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -834,7 +834,7 @@ static void run_plant_and_detach_test(int is_early) char before[BREAK_INSTR_SIZE]; char after[BREAK_INSTR_SIZE]; - probe_kernel_read(before, (char *)kgdbts_break_test, + probe_kernel_read(before, (void *)ktla_ktva((unsigned long)kgdbts_break_test), BREAK_INSTR_SIZE); init_simple_test(); ts.tst = plant_and_detach_test; @@ -842,7 +842,7 @@ static void run_plant_and_detach_test(int is_early) /* Activate test with initial breakpoint */ if (!is_early) kgdb_breakpoint(); - probe_kernel_read(after, (char *)kgdbts_break_test, + probe_kernel_read(after, (void *)ktla_ktva((unsigned long)kgdbts_break_test), BREAK_INSTR_SIZE); if (memcmp(before, after, BREAK_INSTR_SIZE)) { printk(KERN_CRIT "kgdbts: ERROR kgdb corrupted memory\n"); diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c index fb8705f..dc2f679 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d.c +++ b/drivers/misc/lis3lv02d/lis3lv02d.c @@ -497,7 +497,7 @@ static irqreturn_t lis302dl_interrupt(int irq, void *data) * the lid is closed. This leads to interrupts as soon as a little move * is done. */ - atomic_inc(&lis3->count); + atomic_inc_unchecked(&lis3->count); wake_up_interruptible(&lis3->misc_wait); kill_fasync(&lis3->async_queue, SIGIO, POLL_IN); @@ -583,7 +583,7 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file) if (lis3->pm_dev) pm_runtime_get_sync(lis3->pm_dev); - atomic_set(&lis3->count, 0); + atomic_set_unchecked(&lis3->count, 0); return 0; } @@ -615,7 +615,7 @@ static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf, add_wait_queue(&lis3->misc_wait, &wait); while (true) { set_current_state(TASK_INTERRUPTIBLE); - data = atomic_xchg(&lis3->count, 0); + data = atomic_xchg_unchecked(&lis3->count, 0); if (data) break; @@ -656,7 +656,7 @@ static unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait) struct lis3lv02d, miscdev); poll_wait(file, &lis3->misc_wait, wait); - if (atomic_read(&lis3->count)) + if (atomic_read_unchecked(&lis3->count)) return POLLIN | POLLRDNORM; return 0; } diff --git a/drivers/misc/lis3lv02d/lis3lv02d.h b/drivers/misc/lis3lv02d/lis3lv02d.h index c439c82..1f20f57 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d.h +++ b/drivers/misc/lis3lv02d/lis3lv02d.h @@ -297,7 +297,7 @@ struct lis3lv02d { struct input_polled_dev *idev; /* input device */ struct platform_device *pdev; /* platform device */ struct regulator_bulk_data regulators[2]; - atomic_t count; /* interrupt count after last read */ + atomic_unchecked_t count; /* interrupt count after last read */ union axis_conversion ac; /* hw -> logical axis */ int mapped_btns[3]; diff --git a/drivers/misc/mic/scif/scif_rb.c b/drivers/misc/mic/scif/scif_rb.c index 637cc46..4fb1267 100644 --- a/drivers/misc/mic/scif/scif_rb.c +++ b/drivers/misc/mic/scif/scif_rb.c @@ -138,7 +138,7 @@ void scif_rb_commit(struct scif_rb *rb) * the read barrier in scif_rb_count(..) */ wmb(); - ACCESS_ONCE(*rb->write_ptr) = rb->current_write_offset; + ACCESS_ONCE_RW(*rb->write_ptr) = rb->current_write_offset; #ifdef CONFIG_INTEL_MIC_CARD /* * X100 Si bug: For the case where a Core is performing an EXT_WR @@ -147,7 +147,7 @@ void scif_rb_commit(struct scif_rb *rb) * This way, if ordering is violated for the Interrupt Message, it will * fall just behind the first Posted associated with the first EXT_WR. */ - ACCESS_ONCE(*rb->write_ptr) = rb->current_write_offset; + ACCESS_ONCE_RW(*rb->write_ptr) = rb->current_write_offset; #endif } @@ -210,7 +210,7 @@ void scif_rb_update_read_ptr(struct scif_rb *rb) * scif_rb_space(..) */ mb(); - ACCESS_ONCE(*rb->read_ptr) = new_offset; + ACCESS_ONCE_RW(*rb->read_ptr) = new_offset; #ifdef CONFIG_INTEL_MIC_CARD /* * X100 Si Bug: For the case where a Core is performing an EXT_WR @@ -219,7 +219,7 @@ void scif_rb_update_read_ptr(struct scif_rb *rb) * This way, if ordering is violated for the Interrupt Message, it will * fall just behind the first Posted associated with the first EXT_WR. */ - ACCESS_ONCE(*rb->read_ptr) = new_offset; + ACCESS_ONCE_RW(*rb->read_ptr) = new_offset; #endif } diff --git a/drivers/misc/sgi-gru/gruhandles.c b/drivers/misc/sgi-gru/gruhandles.c index 2f30bad..c4c13d0 100644 --- a/drivers/misc/sgi-gru/gruhandles.c +++ b/drivers/misc/sgi-gru/gruhandles.c @@ -44,8 +44,8 @@ static void update_mcs_stats(enum mcs_op op, unsigned long clks) unsigned long nsec; nsec = CLKS2NSEC(clks); - atomic_long_inc(&mcs_op_statistics[op].count); - atomic_long_add(nsec, &mcs_op_statistics[op].total); + atomic_long_inc_unchecked(&mcs_op_statistics[op].count); + atomic_long_add_unchecked(nsec, &mcs_op_statistics[op].total); if (mcs_op_statistics[op].max < nsec) mcs_op_statistics[op].max = nsec; } diff --git a/drivers/misc/sgi-gru/gruprocfs.c b/drivers/misc/sgi-gru/gruprocfs.c index 4f76359..cdfcb2e 100644 --- a/drivers/misc/sgi-gru/gruprocfs.c +++ b/drivers/misc/sgi-gru/gruprocfs.c @@ -32,9 +32,9 @@ #define printstat(s, f) printstat_val(s, &gru_stats.f, #f) -static void printstat_val(struct seq_file *s, atomic_long_t *v, char *id) +static void printstat_val(struct seq_file *s, atomic_long_unchecked_t *v, char *id) { - unsigned long val = atomic_long_read(v); + unsigned long val = atomic_long_read_unchecked(v); seq_printf(s, "%16lu %s\n", val, id); } @@ -134,8 +134,8 @@ static int mcs_statistics_show(struct seq_file *s, void *p) seq_printf(s, "%-20s%12s%12s%12s\n", "#id", "count", "aver-clks", "max-clks"); for (op = 0; op < mcsop_last; op++) { - count = atomic_long_read(&mcs_op_statistics[op].count); - total = atomic_long_read(&mcs_op_statistics[op].total); + count = atomic_long_read_unchecked(&mcs_op_statistics[op].count); + total = atomic_long_read_unchecked(&mcs_op_statistics[op].total); max = mcs_op_statistics[op].max; seq_printf(s, "%-20s%12ld%12ld%12ld\n", id[op], count, count ? total / count : 0, max); diff --git a/drivers/misc/sgi-gru/grutables.h b/drivers/misc/sgi-gru/grutables.h index 5c3ce24..4915ccb 100644 --- a/drivers/misc/sgi-gru/grutables.h +++ b/drivers/misc/sgi-gru/grutables.h @@ -167,82 +167,82 @@ extern unsigned int gru_max_gids; * GRU statistics. */ struct gru_stats_s { - atomic_long_t vdata_alloc; - atomic_long_t vdata_free; - atomic_long_t gts_alloc; - atomic_long_t gts_free; - atomic_long_t gms_alloc; - atomic_long_t gms_free; - atomic_long_t gts_double_allocate; - atomic_long_t assign_context; - atomic_long_t assign_context_failed; - atomic_long_t free_context; - atomic_long_t load_user_context; - atomic_long_t load_kernel_context; - atomic_long_t lock_kernel_context; - atomic_long_t unlock_kernel_context; - atomic_long_t steal_user_context; - atomic_long_t steal_kernel_context; - atomic_long_t steal_context_failed; - atomic_long_t nopfn; - atomic_long_t asid_new; - atomic_long_t asid_next; - atomic_long_t asid_wrap; - atomic_long_t asid_reuse; - atomic_long_t intr; - atomic_long_t intr_cbr; - atomic_long_t intr_tfh; - atomic_long_t intr_spurious; - atomic_long_t intr_mm_lock_failed; - atomic_long_t call_os; - atomic_long_t call_os_wait_queue; - atomic_long_t user_flush_tlb; - atomic_long_t user_unload_context; - atomic_long_t user_exception; - atomic_long_t set_context_option; - atomic_long_t check_context_retarget_intr; - atomic_long_t check_context_unload; - atomic_long_t tlb_dropin; - atomic_long_t tlb_preload_page; - atomic_long_t tlb_dropin_fail_no_asid; - atomic_long_t tlb_dropin_fail_upm; - atomic_long_t tlb_dropin_fail_invalid; - atomic_long_t tlb_dropin_fail_range_active; - atomic_long_t tlb_dropin_fail_idle; - atomic_long_t tlb_dropin_fail_fmm; - atomic_long_t tlb_dropin_fail_no_exception; - atomic_long_t tfh_stale_on_fault; - atomic_long_t mmu_invalidate_range; - atomic_long_t mmu_invalidate_page; - atomic_long_t flush_tlb; - atomic_long_t flush_tlb_gru; - atomic_long_t flush_tlb_gru_tgh; - atomic_long_t flush_tlb_gru_zero_asid; + atomic_long_unchecked_t vdata_alloc; + atomic_long_unchecked_t vdata_free; + atomic_long_unchecked_t gts_alloc; + atomic_long_unchecked_t gts_free; + atomic_long_unchecked_t gms_alloc; + atomic_long_unchecked_t gms_free; + atomic_long_unchecked_t gts_double_allocate; + atomic_long_unchecked_t assign_context; + atomic_long_unchecked_t assign_context_failed; + atomic_long_unchecked_t free_context; + atomic_long_unchecked_t load_user_context; + atomic_long_unchecked_t load_kernel_context; + atomic_long_unchecked_t lock_kernel_context; + atomic_long_unchecked_t unlock_kernel_context; + atomic_long_unchecked_t steal_user_context; + atomic_long_unchecked_t steal_kernel_context; + atomic_long_unchecked_t steal_context_failed; + atomic_long_unchecked_t nopfn; + atomic_long_unchecked_t asid_new; + atomic_long_unchecked_t asid_next; + atomic_long_unchecked_t asid_wrap; + atomic_long_unchecked_t asid_reuse; + atomic_long_unchecked_t intr; + atomic_long_unchecked_t intr_cbr; + atomic_long_unchecked_t intr_tfh; + atomic_long_unchecked_t intr_spurious; + atomic_long_unchecked_t intr_mm_lock_failed; + atomic_long_unchecked_t call_os; + atomic_long_unchecked_t call_os_wait_queue; + atomic_long_unchecked_t user_flush_tlb; + atomic_long_unchecked_t user_unload_context; + atomic_long_unchecked_t user_exception; + atomic_long_unchecked_t set_context_option; + atomic_long_unchecked_t check_context_retarget_intr; + atomic_long_unchecked_t check_context_unload; + atomic_long_unchecked_t tlb_dropin; + atomic_long_unchecked_t tlb_preload_page; + atomic_long_unchecked_t tlb_dropin_fail_no_asid; + atomic_long_unchecked_t tlb_dropin_fail_upm; + atomic_long_unchecked_t tlb_dropin_fail_invalid; + atomic_long_unchecked_t tlb_dropin_fail_range_active; + atomic_long_unchecked_t tlb_dropin_fail_idle; + atomic_long_unchecked_t tlb_dropin_fail_fmm; + atomic_long_unchecked_t tlb_dropin_fail_no_exception; + atomic_long_unchecked_t tfh_stale_on_fault; + atomic_long_unchecked_t mmu_invalidate_range; + atomic_long_unchecked_t mmu_invalidate_page; + atomic_long_unchecked_t flush_tlb; + atomic_long_unchecked_t flush_tlb_gru; + atomic_long_unchecked_t flush_tlb_gru_tgh; + atomic_long_unchecked_t flush_tlb_gru_zero_asid; - atomic_long_t copy_gpa; - atomic_long_t read_gpa; + atomic_long_unchecked_t copy_gpa; + atomic_long_unchecked_t read_gpa; - atomic_long_t mesq_receive; - atomic_long_t mesq_receive_none; - atomic_long_t mesq_send; - atomic_long_t mesq_send_failed; - atomic_long_t mesq_noop; - atomic_long_t mesq_send_unexpected_error; - atomic_long_t mesq_send_lb_overflow; - atomic_long_t mesq_send_qlimit_reached; - atomic_long_t mesq_send_amo_nacked; - atomic_long_t mesq_send_put_nacked; - atomic_long_t mesq_page_overflow; - atomic_long_t mesq_qf_locked; - atomic_long_t mesq_qf_noop_not_full; - atomic_long_t mesq_qf_switch_head_failed; - atomic_long_t mesq_qf_unexpected_error; - atomic_long_t mesq_noop_unexpected_error; - atomic_long_t mesq_noop_lb_overflow; - atomic_long_t mesq_noop_qlimit_reached; - atomic_long_t mesq_noop_amo_nacked; - atomic_long_t mesq_noop_put_nacked; - atomic_long_t mesq_noop_page_overflow; + atomic_long_unchecked_t mesq_receive; + atomic_long_unchecked_t mesq_receive_none; + atomic_long_unchecked_t mesq_send; + atomic_long_unchecked_t mesq_send_failed; + atomic_long_unchecked_t mesq_noop; + atomic_long_unchecked_t mesq_send_unexpected_error; + atomic_long_unchecked_t mesq_send_lb_overflow; + atomic_long_unchecked_t mesq_send_qlimit_reached; + atomic_long_unchecked_t mesq_send_amo_nacked; + atomic_long_unchecked_t mesq_send_put_nacked; + atomic_long_unchecked_t mesq_page_overflow; + atomic_long_unchecked_t mesq_qf_locked; + atomic_long_unchecked_t mesq_qf_noop_not_full; + atomic_long_unchecked_t mesq_qf_switch_head_failed; + atomic_long_unchecked_t mesq_qf_unexpected_error; + atomic_long_unchecked_t mesq_noop_unexpected_error; + atomic_long_unchecked_t mesq_noop_lb_overflow; + atomic_long_unchecked_t mesq_noop_qlimit_reached; + atomic_long_unchecked_t mesq_noop_amo_nacked; + atomic_long_unchecked_t mesq_noop_put_nacked; + atomic_long_unchecked_t mesq_noop_page_overflow; }; @@ -251,8 +251,8 @@ enum mcs_op {cchop_allocate, cchop_start, cchop_interrupt, cchop_interrupt_sync, tghop_invalidate, mcsop_last}; struct mcs_op_statistic { - atomic_long_t count; - atomic_long_t total; + atomic_long_unchecked_t count; + atomic_long_unchecked_t total; unsigned long max; }; @@ -275,7 +275,7 @@ extern struct mcs_op_statistic mcs_op_statistics[mcsop_last]; #define STAT(id) do { \ if (gru_options & OPT_STATS) \ - atomic_long_inc(&gru_stats.id); \ + atomic_long_inc_unchecked(&gru_stats.id); \ } while (0) #ifdef CONFIG_SGI_GRU_DEBUG diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index c862cd4..0d176fe 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -288,7 +288,7 @@ struct xpc_interface { xpc_notify_func, void *); void (*received) (short, int, void *); enum xp_retval (*partid_to_nasids) (short, void *); -}; +} __no_const; extern struct xpc_interface xpc_interface; diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c index 01be66d..e3a0c7e 100644 --- a/drivers/misc/sgi-xp/xp_main.c +++ b/drivers/misc/sgi-xp/xp_main.c @@ -78,13 +78,13 @@ xpc_notloaded(void) } struct xpc_interface xpc_interface = { - (void (*)(int))xpc_notloaded, - (void (*)(int))xpc_notloaded, - (enum xp_retval(*)(short, int, u32, void *, u16))xpc_notloaded, - (enum xp_retval(*)(short, int, u32, void *, u16, xpc_notify_func, + .connect = (void (*)(int))xpc_notloaded, + .disconnect = (void (*)(int))xpc_notloaded, + .send = (enum xp_retval(*)(short, int, u32, void *, u16))xpc_notloaded, + .send_notify = (enum xp_retval(*)(short, int, u32, void *, u16, xpc_notify_func, void *))xpc_notloaded, - (void (*)(short, int, void *))xpc_notloaded, - (enum xp_retval(*)(short, void *))xpc_notloaded + .received = (void (*)(short, int, void *))xpc_notloaded, + .partid_to_nasids = (enum xp_retval(*)(short, void *))xpc_notloaded }; EXPORT_SYMBOL_GPL(xpc_interface); diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index b94d5f7..7f494c5 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -835,6 +835,7 @@ struct xpc_arch_operations { void (*received_payload) (struct xpc_channel *, void *); void (*notify_senders_of_disconnect) (struct xpc_channel *); }; +typedef struct xpc_arch_operations __no_const xpc_arch_operations_no_const; /* struct xpc_partition act_state values (for XPC HB) */ @@ -876,7 +877,7 @@ extern struct xpc_registration xpc_registrations[]; /* found in xpc_main.c */ extern struct device *xpc_part; extern struct device *xpc_chan; -extern struct xpc_arch_operations xpc_arch_ops; +extern xpc_arch_operations_no_const xpc_arch_ops; extern int xpc_disengage_timelimit; extern int xpc_disengage_timedout; extern int xpc_activate_IRQ_rcvd; diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index 7f32712..8539ab2 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -166,7 +166,7 @@ static struct notifier_block xpc_die_notifier = { .notifier_call = xpc_system_die, }; -struct xpc_arch_operations xpc_arch_ops; +xpc_arch_operations_no_const xpc_arch_ops; /* * Timer function to enforce the timelimit on the partition disengage. diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index c742cfd..805f5e1 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -582,7 +582,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, if (idata->ic.postsleep_min_us) usleep_range(idata->ic.postsleep_min_us, idata->ic.postsleep_max_us); - if (copy_to_user(&(ic_ptr->response), cmd.resp, sizeof(cmd.resp))) { + if (copy_to_user(ic_ptr->response, cmd.resp, sizeof(cmd.resp))) { err = -EFAULT; goto cmd_rel_host; } diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 8ce4674..a23c858 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -286,5 +286,5 @@ struct dw_mci_drv_data { struct mmc_ios *ios); int (*switch_voltage)(struct mmc_host *mmc, struct mmc_ios *ios); -}; +} __do_const; #endif /* _DW_MMC_H_ */ diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index fb26674..3172c2b 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1633,7 +1633,9 @@ static int mmci_probe(struct amba_device *dev, mmc->caps |= MMC_CAP_CMD23; if (variant->busy_detect) { - mmci_ops.card_busy = mmci_card_busy; + pax_open_kernel(); + *(void **)&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 7fb0753..ad156f0 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) if (host->pdata->controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ) { 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; + 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 886d230..289d769 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -1191,9 +1191,12 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) host->ioaddr + 0x6c); } - if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) - 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 = esdhc_executing_tuning; + pax_close_kernel(); + } 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 --- 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) * we can use overriding functions instead of default. */ if (sc->no_divider) { - sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock; - 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; + pax_close_kernel(); } /* It supports additional host capabilities if needed */ diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 9a1a6ff..b8f1a57 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -666,7 +666,7 @@ cfi_staa_writev(struct mtd_info *mtd, const struct kvec *vecs, size_t totlen = 0, thislen; int ret = 0; size_t buflen = 0; - static char *buffer; + char *buffer; if (!ECCBUF_SIZE) { /* We should fall back to a general writev implementation. diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 870c7fc..c7d6440 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "denali.h" diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 1b8f350..990f2e9 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -386,7 +386,7 @@ void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr) /* first try to map the upper buffer directly */ if (virt_addr_valid(this->upper_buf) && - !object_is_on_stack(this->upper_buf)) { + !object_starts_on_stack(this->upper_buf)) { sg_init_one(sgl, this->upper_buf, this->upper_len); ret = dma_map_sg(this->dev, sgl, 1, dr); if (ret == 0) diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index a5dfbfb..8042ab4 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index c23184a..4115c41 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -56,7 +56,7 @@ static ssize_t sm_attr_show(struct device *dev, struct device_attribute *attr, #define SM_CIS_VENDOR_OFFSET 0x59 static struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl) { - struct attribute_group *attr_group; + attribute_group_no_const *attr_group; struct attribute **attributes; struct sm_sysfs_attribute *vendor_attribute; char *vendor; diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index db760e8..d53ca99 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -662,7 +662,7 @@ nla_put_failure: return -EMSGSIZE; } -struct rtnl_link_ops bond_link_ops __read_mostly = { +struct rtnl_link_ops bond_link_ops = { .kind = "bond", .priv_size = sizeof(struct bonding), .setup = bond_setup, diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c index 615c65d..c6c0439 100644 --- a/drivers/net/caif/caif_hsi.c +++ b/drivers/net/caif/caif_hsi.c @@ -1444,7 +1444,7 @@ err: return -ENODEV; } -static struct rtnl_link_ops caif_hsi_link_ops __read_mostly = { +static struct rtnl_link_ops caif_hsi_link_ops = { .kind = "cfhsi", .priv_size = sizeof(struct cfhsi), .setup = cfhsi_setup, diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index e8c96b8..516a96c 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -98,7 +98,7 @@ config CAN_JANZ_ICAN3 config CAN_FLEXCAN tristate "Support for Freescale FLEXCAN based chips" - depends on ARM || PPC + depends on (ARM && CPU_LITTLE_ENDIAN) || PPC ---help--- Say Y here if you want to support for Freescale FlexCAN. diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 141c2a4..ca734ed 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -961,7 +961,7 @@ static int can_newlink(struct net *src_net, struct net_device *dev, return -EOPNOTSUPP; } -static struct rtnl_link_ops can_link_ops __read_mostly = { +static struct rtnl_link_ops can_link_ops = { .kind = "can", .maxtype = IFLA_CAN_MAX, .policy = can_policy, diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c index 674f367..ec3a31f 100644 --- a/drivers/net/can/vcan.c +++ b/drivers/net/can/vcan.c @@ -163,7 +163,7 @@ static void vcan_setup(struct net_device *dev) dev->destructor = free_netdev; } -static struct rtnl_link_ops vcan_link_ops __read_mostly = { +static struct rtnl_link_ops vcan_link_ops = { .kind = "vcan", .setup = vcan_setup, }; diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 815eb94..38ef9b7 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -163,7 +163,7 @@ static int dummy_validate(struct nlattr *tb[], struct nlattr *data[]) return 0; } -static struct rtnl_link_ops dummy_link_ops __read_mostly = { +static struct rtnl_link_ops dummy_link_ops = { .kind = DRV_NAME, .setup = dummy_setup, .validate = dummy_validate, diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 0443654..4f0aa18 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -889,9 +889,11 @@ static int ax_probe(struct platform_device *pdev) if (ax->plat->reg_offsets) ei_local->reg_offset = ax->plat->reg_offsets; else { + resource_size_t _mem_size = mem_size; + do_div(_mem_size, 0x18); ei_local->reg_offset = ax->reg_offsets; for (ret = 0; ret < 0x18; ret++) - ax->reg_offsets[ret] = (mem_size / 0x18) * ret; + ax->reg_offsets[ret] = _mem_size * ret; } if (!request_mem_region(mem->start, mem_size, pdev->name)) { diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c index fe64482..9a24726 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -1255,7 +1255,7 @@ static int tse_shutdown(struct net_device *dev) return 0; } -static struct net_device_ops altera_tse_netdev_ops = { +static net_device_ops_no_const altera_tse_netdev_ops __read_only = { .ndo_open = tse_open, .ndo_stop = tse_shutdown, .ndo_start_xmit = tse_start_xmit, @@ -1492,11 +1492,13 @@ static int altera_tse_probe(struct platform_device *pdev) ndev->netdev_ops = &altera_tse_netdev_ops; altera_tse_set_ethtool_ops(ndev); + pax_open_kernel(); altera_tse_netdev_ops.ndo_set_rx_mode = tse_set_rx_mode; if (priv->hash_filter) altera_tse_netdev_ops.ndo_set_rx_mode = tse_set_rx_mode_hashfilter; + pax_close_kernel(); /* Scatter/gather IO is not supported, * so it is turned off diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index b6fa891..31ef157 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -1279,14 +1279,14 @@ do { \ * operations, everything works on mask values. */ #define XMDIO_READ(_pdata, _mmd, _reg) \ - ((_pdata)->hw_if.read_mmd_regs((_pdata), 0, \ + ((_pdata)->hw_if->read_mmd_regs((_pdata), 0, \ MII_ADDR_C45 | (_mmd << 16) | ((_reg) & 0xffff))) #define XMDIO_READ_BITS(_pdata, _mmd, _reg, _mask) \ (XMDIO_READ((_pdata), _mmd, _reg) & _mask) #define XMDIO_WRITE(_pdata, _mmd, _reg, _val) \ - ((_pdata)->hw_if.write_mmd_regs((_pdata), 0, \ + ((_pdata)->hw_if->write_mmd_regs((_pdata), 0, \ MII_ADDR_C45 | (_mmd << 16) | ((_reg) & 0xffff), (_val))) #define XMDIO_WRITE_BITS(_pdata, _mmd, _reg, _mask, _val) \ diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dcb.c b/drivers/net/ethernet/amd/xgbe/xgbe-dcb.c index a6b9899..2e5e972 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dcb.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dcb.c @@ -190,7 +190,7 @@ static int xgbe_dcb_ieee_setets(struct net_device *netdev, memcpy(pdata->ets, ets, sizeof(*pdata->ets)); - pdata->hw_if.config_dcb_tc(pdata); + pdata->hw_if->config_dcb_tc(pdata); return 0; } @@ -230,7 +230,7 @@ static int xgbe_dcb_ieee_setpfc(struct net_device *netdev, memcpy(pdata->pfc, pfc, sizeof(*pdata->pfc)); - pdata->hw_if.config_dcb_pfc(pdata); + pdata->hw_if->config_dcb_pfc(pdata); return 0; } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c index b3bc87f..5bdfdd3 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c @@ -353,7 +353,7 @@ static int xgbe_map_rx_buffer(struct xgbe_prv_data *pdata, static void xgbe_wrapper_tx_descriptor_init(struct xgbe_prv_data *pdata) { - struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; struct xgbe_channel *channel; struct xgbe_ring *ring; struct xgbe_ring_data *rdata; @@ -394,7 +394,7 @@ static void xgbe_wrapper_tx_descriptor_init(struct xgbe_prv_data *pdata) static void xgbe_wrapper_rx_descriptor_init(struct xgbe_prv_data *pdata) { - struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; struct xgbe_channel *channel; struct xgbe_ring *ring; struct xgbe_ring_desc *rdesc; @@ -628,17 +628,12 @@ err_out: return 0; } -void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *desc_if) -{ - DBGPR("-->xgbe_init_function_ptrs_desc\n"); - - desc_if->alloc_ring_resources = xgbe_alloc_ring_resources; - desc_if->free_ring_resources = xgbe_free_ring_resources; - desc_if->map_tx_skb = xgbe_map_tx_skb; - desc_if->map_rx_buffer = xgbe_map_rx_buffer; - desc_if->unmap_rdata = xgbe_unmap_rdata; - desc_if->wrapper_tx_desc_init = xgbe_wrapper_tx_descriptor_init; - desc_if->wrapper_rx_desc_init = xgbe_wrapper_rx_descriptor_init; - - DBGPR("<--xgbe_init_function_ptrs_desc\n"); -} +const struct xgbe_desc_if default_xgbe_desc_if = { + .alloc_ring_resources = xgbe_alloc_ring_resources, + .free_ring_resources = xgbe_free_ring_resources, + .map_tx_skb = xgbe_map_tx_skb, + .map_rx_buffer = xgbe_map_rx_buffer, + .unmap_rdata = xgbe_unmap_rdata, + .wrapper_tx_desc_init = xgbe_wrapper_tx_descriptor_init, + .wrapper_rx_desc_init = xgbe_wrapper_rx_descriptor_init, +}; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index f672dba3..d71818d 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -2776,7 +2776,7 @@ static void xgbe_powerdown_rx(struct xgbe_prv_data *pdata) static int xgbe_init(struct xgbe_prv_data *pdata) { - struct xgbe_desc_if *desc_if = &pdata->desc_if; + struct xgbe_desc_if *desc_if = pdata->desc_if; int ret; DBGPR("-->xgbe_init\n"); @@ -2842,106 +2842,101 @@ static int xgbe_init(struct xgbe_prv_data *pdata) return 0; } -void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if) -{ - DBGPR("-->xgbe_init_function_ptrs\n"); - - hw_if->tx_complete = xgbe_tx_complete; - - hw_if->set_mac_address = xgbe_set_mac_address; - hw_if->config_rx_mode = xgbe_config_rx_mode; - - hw_if->enable_rx_csum = xgbe_enable_rx_csum; - hw_if->disable_rx_csum = xgbe_disable_rx_csum; - - hw_if->enable_rx_vlan_stripping = xgbe_enable_rx_vlan_stripping; - hw_if->disable_rx_vlan_stripping = xgbe_disable_rx_vlan_stripping; - hw_if->enable_rx_vlan_filtering = xgbe_enable_rx_vlan_filtering; - hw_if->disable_rx_vlan_filtering = xgbe_disable_rx_vlan_filtering; - hw_if->update_vlan_hash_table = xgbe_update_vlan_hash_table; - - hw_if->read_mmd_regs = xgbe_read_mmd_regs; - hw_if->write_mmd_regs = xgbe_write_mmd_regs; - - hw_if->set_gmii_speed = xgbe_set_gmii_speed; - hw_if->set_gmii_2500_speed = xgbe_set_gmii_2500_speed; - hw_if->set_xgmii_speed = xgbe_set_xgmii_speed; - - hw_if->enable_tx = xgbe_enable_tx; - hw_if->disable_tx = xgbe_disable_tx; - hw_if->enable_rx = xgbe_enable_rx; - hw_if->disable_rx = xgbe_disable_rx; - - hw_if->powerup_tx = xgbe_powerup_tx; - hw_if->powerdown_tx = xgbe_powerdown_tx; - hw_if->powerup_rx = xgbe_powerup_rx; - hw_if->powerdown_rx = xgbe_powerdown_rx; - - hw_if->dev_xmit = xgbe_dev_xmit; - hw_if->dev_read = xgbe_dev_read; - hw_if->enable_int = xgbe_enable_int; - hw_if->disable_int = xgbe_disable_int; - hw_if->init = xgbe_init; - hw_if->exit = xgbe_exit; +const struct xgbe_hw_if default_xgbe_hw_if = { + .tx_complete = xgbe_tx_complete, + + .set_mac_address = xgbe_set_mac_address, + .config_rx_mode = xgbe_config_rx_mode, + + .enable_rx_csum = xgbe_enable_rx_csum, + .disable_rx_csum = xgbe_disable_rx_csum, + + .enable_rx_vlan_stripping = xgbe_enable_rx_vlan_stripping, + .disable_rx_vlan_stripping = xgbe_disable_rx_vlan_stripping, + .enable_rx_vlan_filtering = xgbe_enable_rx_vlan_filtering, + .disable_rx_vlan_filtering = xgbe_disable_rx_vlan_filtering, + .update_vlan_hash_table = xgbe_update_vlan_hash_table, + + .read_mmd_regs = xgbe_read_mmd_regs, + .write_mmd_regs = xgbe_write_mmd_regs, + + .set_gmii_speed = xgbe_set_gmii_speed, + .set_gmii_2500_speed = xgbe_set_gmii_2500_speed, + .set_xgmii_speed = xgbe_set_xgmii_speed, + + .enable_tx = xgbe_enable_tx, + .disable_tx = xgbe_disable_tx, + .enable_rx = xgbe_enable_rx, + .disable_rx = xgbe_disable_rx, + + .powerup_tx = xgbe_powerup_tx, + .powerdown_tx = xgbe_powerdown_tx, + .powerup_rx = xgbe_powerup_rx, + .powerdown_rx = xgbe_powerdown_rx, + + .dev_xmit = xgbe_dev_xmit, + .dev_read = xgbe_dev_read, + .enable_int = xgbe_enable_int, + .disable_int = xgbe_disable_int, + .init = xgbe_init, + .exit = xgbe_exit, /* Descriptor related Sequences have to be initialized here */ - hw_if->tx_desc_init = xgbe_tx_desc_init; - hw_if->rx_desc_init = xgbe_rx_desc_init; - hw_if->tx_desc_reset = xgbe_tx_desc_reset; - hw_if->rx_desc_reset = xgbe_rx_desc_reset; - hw_if->is_last_desc = xgbe_is_last_desc; - hw_if->is_context_desc = xgbe_is_context_desc; - hw_if->tx_start_xmit = xgbe_tx_start_xmit; + .tx_desc_init = xgbe_tx_desc_init, + .rx_desc_init = xgbe_rx_desc_init, + .tx_desc_reset = xgbe_tx_desc_reset, + .rx_desc_reset = xgbe_rx_desc_reset, + .is_last_desc = xgbe_is_last_desc, + .is_context_desc = xgbe_is_context_desc, + .tx_start_xmit = xgbe_tx_start_xmit, /* For FLOW ctrl */ - hw_if->config_tx_flow_control = xgbe_config_tx_flow_control; - hw_if->config_rx_flow_control = xgbe_config_rx_flow_control; + .config_tx_flow_control = xgbe_config_tx_flow_control, + .config_rx_flow_control = xgbe_config_rx_flow_control, /* For RX coalescing */ - hw_if->config_rx_coalesce = xgbe_config_rx_coalesce; - hw_if->config_tx_coalesce = xgbe_config_tx_coalesce; - hw_if->usec_to_riwt = xgbe_usec_to_riwt; - hw_if->riwt_to_usec = xgbe_riwt_to_usec; + .config_rx_coalesce = xgbe_config_rx_coalesce, + .config_tx_coalesce = xgbe_config_tx_coalesce, + .usec_to_riwt = xgbe_usec_to_riwt, + .riwt_to_usec = xgbe_riwt_to_usec, /* For RX and TX threshold config */ - hw_if->config_rx_threshold = xgbe_config_rx_threshold; - hw_if->config_tx_threshold = xgbe_config_tx_threshold; + .config_rx_threshold = xgbe_config_rx_threshold, + .config_tx_threshold = xgbe_config_tx_threshold, /* For RX and TX Store and Forward Mode config */ - hw_if->config_rsf_mode = xgbe_config_rsf_mode; - hw_if->config_tsf_mode = xgbe_config_tsf_mode; + .config_rsf_mode = xgbe_config_rsf_mode, + .config_tsf_mode = xgbe_config_tsf_mode, /* For TX DMA Operating on Second Frame config */ - hw_if->config_osp_mode = xgbe_config_osp_mode; + .config_osp_mode = xgbe_config_osp_mode, /* For RX and TX PBL config */ - hw_if->config_rx_pbl_val = xgbe_config_rx_pbl_val; - hw_if->get_rx_pbl_val = xgbe_get_rx_pbl_val; - hw_if->config_tx_pbl_val = xgbe_config_tx_pbl_val; - hw_if->get_tx_pbl_val = xgbe_get_tx_pbl_val; - hw_if->config_pblx8 = xgbe_config_pblx8; + .config_rx_pbl_val = xgbe_config_rx_pbl_val, + .get_rx_pbl_val = xgbe_get_rx_pbl_val, + .config_tx_pbl_val = xgbe_config_tx_pbl_val, + .get_tx_pbl_val = xgbe_get_tx_pbl_val, + .config_pblx8 = xgbe_config_pblx8, /* For MMC statistics support */ - hw_if->tx_mmc_int = xgbe_tx_mmc_int; - hw_if->rx_mmc_int = xgbe_rx_mmc_int; - hw_if->read_mmc_stats = xgbe_read_mmc_stats; + .tx_mmc_int = xgbe_tx_mmc_int, + .rx_mmc_int = xgbe_rx_mmc_int, + .read_mmc_stats = xgbe_read_mmc_stats, /* For PTP config */ - hw_if->config_tstamp = xgbe_config_tstamp; - hw_if->update_tstamp_addend = xgbe_update_tstamp_addend; - hw_if->set_tstamp_time = xgbe_set_tstamp_time; - hw_if->get_tstamp_time = xgbe_get_tstamp_time; - hw_if->get_tx_tstamp = xgbe_get_tx_tstamp; + .config_tstamp = xgbe_config_tstamp, + .update_tstamp_addend = xgbe_update_tstamp_addend, + .set_tstamp_time = xgbe_set_tstamp_time, + .get_tstamp_time = xgbe_get_tstamp_time, + .get_tx_tstamp = xgbe_get_tx_tstamp, /* For Data Center Bridging config */ - hw_if->config_dcb_tc = xgbe_config_dcb_tc; - hw_if->config_dcb_pfc = xgbe_config_dcb_pfc; + .config_dcb_tc = xgbe_config_dcb_tc, + .config_dcb_pfc = xgbe_config_dcb_pfc, /* For Receive Side Scaling */ - hw_if->enable_rss = xgbe_enable_rss; - hw_if->disable_rss = xgbe_disable_rss; - hw_if->set_rss_hash_key = xgbe_set_rss_hash_key; - hw_if->set_rss_lookup_table = xgbe_set_rss_lookup_table; - - DBGPR("<--xgbe_init_function_ptrs\n"); -} + .enable_rss = xgbe_enable_rss, + .disable_rss = xgbe_disable_rss, + .set_rss_hash_key = xgbe_set_rss_hash_key, + .set_rss_lookup_table = xgbe_set_rss_lookup_table, +}; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index dde0486..831e127 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -245,7 +245,7 @@ static int xgbe_maybe_stop_tx_queue(struct xgbe_channel *channel, * support, tell it now */ if (ring->tx.xmit_more) - pdata->hw_if.tx_start_xmit(channel, ring); + pdata->hw_if->tx_start_xmit(channel, ring); return NETDEV_TX_BUSY; } @@ -273,7 +273,7 @@ static int xgbe_calc_rx_buf_size(struct net_device *netdev, unsigned int mtu) static void xgbe_enable_rx_tx_ints(struct xgbe_prv_data *pdata) { - struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; struct xgbe_channel *channel; enum xgbe_int int_id; unsigned int i; @@ -295,7 +295,7 @@ static void xgbe_enable_rx_tx_ints(struct xgbe_prv_data *pdata) static void xgbe_disable_rx_tx_ints(struct xgbe_prv_data *pdata) { - struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; struct xgbe_channel *channel; enum xgbe_int int_id; unsigned int i; @@ -318,7 +318,7 @@ static void xgbe_disable_rx_tx_ints(struct xgbe_prv_data *pdata) static irqreturn_t xgbe_isr(int irq, void *data) { struct xgbe_prv_data *pdata = data; - struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; struct xgbe_channel *channel; unsigned int dma_isr, dma_ch_isr; unsigned int mac_isr, mac_tssr; @@ -443,7 +443,7 @@ static void xgbe_service(struct work_struct *work) struct xgbe_prv_data, service_work); - pdata->phy_if.phy_status(pdata); + pdata->phy_if->phy_status(pdata); } static void xgbe_service_timer(unsigned long data) @@ -702,7 +702,7 @@ static void xgbe_free_irqs(struct xgbe_prv_data *pdata) void xgbe_init_tx_coalesce(struct xgbe_prv_data *pdata) { - struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; DBGPR("-->xgbe_init_tx_coalesce\n"); @@ -716,7 +716,7 @@ void xgbe_init_tx_coalesce(struct xgbe_prv_data *pdata) void xgbe_init_rx_coalesce(struct xgbe_prv_data *pdata) { - struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; DBGPR("-->xgbe_init_rx_coalesce\n"); @@ -731,7 +731,7 @@ void xgbe_init_rx_coalesce(struct xgbe_prv_data *pdata) static void xgbe_free_tx_data(struct xgbe_prv_data *pdata) { - struct xgbe_desc_if *desc_if = &pdata->desc_if; + struct xgbe_desc_if *desc_if = pdata->desc_if; struct xgbe_channel *channel; struct xgbe_ring *ring; struct xgbe_ring_data *rdata; @@ -756,7 +756,7 @@ static void xgbe_free_tx_data(struct xgbe_prv_data *pdata) static void xgbe_free_rx_data(struct xgbe_prv_data *pdata) { - struct xgbe_desc_if *desc_if = &pdata->desc_if; + struct xgbe_desc_if *desc_if = pdata->desc_if; struct xgbe_channel *channel; struct xgbe_ring *ring; struct xgbe_ring_data *rdata; @@ -784,13 +784,13 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) pdata->phy_link = -1; pdata->phy_speed = SPEED_UNKNOWN; - return pdata->phy_if.phy_reset(pdata); + return pdata->phy_if->phy_reset(pdata); } int xgbe_powerdown(struct net_device *netdev, unsigned int caller) { struct xgbe_prv_data *pdata = netdev_priv(netdev); - struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; unsigned long flags; DBGPR("-->xgbe_powerdown\n"); @@ -829,7 +829,7 @@ int xgbe_powerdown(struct net_device *netdev, unsigned int caller) int xgbe_powerup(struct net_device *netdev, unsigned int caller) { struct xgbe_prv_data *pdata = netdev_priv(netdev); - struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; unsigned long flags; DBGPR("-->xgbe_powerup\n"); @@ -866,8 +866,8 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller) static int xgbe_start(struct xgbe_prv_data *pdata) { - struct xgbe_hw_if *hw_if = &pdata->hw_if; - struct xgbe_phy_if *phy_if = &pdata->phy_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; + struct xgbe_phy_if *phy_if = pdata->phy_if; struct net_device *netdev = pdata->netdev; int ret; @@ -910,8 +910,8 @@ err_phy: static void xgbe_stop(struct xgbe_prv_data *pdata) { - struct xgbe_hw_if *hw_if = &pdata->hw_if; - struct xgbe_phy_if *phy_if = &pdata->phy_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; + struct xgbe_phy_if *phy_if = pdata->phy_if; struct xgbe_channel *channel; struct net_device *netdev = pdata->netdev; struct netdev_queue *txq; @@ -1139,7 +1139,7 @@ static int xgbe_set_hwtstamp_settings(struct xgbe_prv_data *pdata, return -ERANGE; } - pdata->hw_if.config_tstamp(pdata, mac_tscr); + pdata->hw_if->config_tstamp(pdata, mac_tscr); memcpy(&pdata->tstamp_config, &config, sizeof(config)); @@ -1288,7 +1288,7 @@ static void xgbe_packet_info(struct xgbe_prv_data *pdata, static int xgbe_open(struct net_device *netdev) { struct xgbe_prv_data *pdata = netdev_priv(netdev); - struct xgbe_desc_if *desc_if = &pdata->desc_if; + struct xgbe_desc_if *desc_if = pdata->desc_if; int ret; DBGPR("-->xgbe_open\n"); @@ -1360,7 +1360,7 @@ err_sysclk: static int xgbe_close(struct net_device *netdev) { struct xgbe_prv_data *pdata = netdev_priv(netdev); - struct xgbe_desc_if *desc_if = &pdata->desc_if; + struct xgbe_desc_if *desc_if = pdata->desc_if; DBGPR("-->xgbe_close\n"); @@ -1387,8 +1387,8 @@ static int xgbe_close(struct net_device *netdev) static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) { struct xgbe_prv_data *pdata = netdev_priv(netdev); - struct xgbe_hw_if *hw_if = &pdata->hw_if; - struct xgbe_desc_if *desc_if = &pdata->desc_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; + struct xgbe_desc_if *desc_if = pdata->desc_if; struct xgbe_channel *channel; struct xgbe_ring *ring; struct xgbe_packet_data *packet; @@ -1457,7 +1457,7 @@ tx_netdev_return: static void xgbe_set_rx_mode(struct net_device *netdev) { struct xgbe_prv_data *pdata = netdev_priv(netdev); - struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; DBGPR("-->xgbe_set_rx_mode\n"); @@ -1469,7 +1469,7 @@ static void xgbe_set_rx_mode(struct net_device *netdev) static int xgbe_set_mac_address(struct net_device *netdev, void *addr) { struct xgbe_prv_data *pdata = netdev_priv(netdev); - struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; struct sockaddr *saddr = addr; DBGPR("-->xgbe_set_mac_address\n"); @@ -1544,7 +1544,7 @@ static struct rtnl_link_stats64 *xgbe_get_stats64(struct net_device *netdev, DBGPR("-->%s\n", __func__); - pdata->hw_if.read_mmc_stats(pdata); + pdata->hw_if->read_mmc_stats(pdata); s->rx_packets = pstats->rxframecount_gb; s->rx_bytes = pstats->rxoctetcount_gb; @@ -1571,7 +1571,7 @@ static int xgbe_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid) { struct xgbe_prv_data *pdata = netdev_priv(netdev); - struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; DBGPR("-->%s\n", __func__); @@ -1587,7 +1587,7 @@ static int xgbe_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid) { struct xgbe_prv_data *pdata = netdev_priv(netdev); - struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; DBGPR("-->%s\n", __func__); @@ -1654,7 +1654,7 @@ static int xgbe_set_features(struct net_device *netdev, netdev_features_t features) { struct xgbe_prv_data *pdata = netdev_priv(netdev); - struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; netdev_features_t rxhash, rxcsum, rxvlan, rxvlan_filter; int ret = 0; @@ -1720,8 +1720,8 @@ struct net_device_ops *xgbe_get_netdev_ops(void) static void xgbe_rx_refresh(struct xgbe_channel *channel) { struct xgbe_prv_data *pdata = channel->pdata; - struct xgbe_hw_if *hw_if = &pdata->hw_if; - struct xgbe_desc_if *desc_if = &pdata->desc_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; + struct xgbe_desc_if *desc_if = pdata->desc_if; struct xgbe_ring *ring = channel->rx_ring; struct xgbe_ring_data *rdata; @@ -1798,8 +1798,8 @@ static struct sk_buff *xgbe_create_skb(struct xgbe_prv_data *pdata, static int xgbe_tx_poll(struct xgbe_channel *channel) { struct xgbe_prv_data *pdata = channel->pdata; - struct xgbe_hw_if *hw_if = &pdata->hw_if; - struct xgbe_desc_if *desc_if = &pdata->desc_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; + struct xgbe_desc_if *desc_if = pdata->desc_if; struct xgbe_ring *ring = channel->tx_ring; struct xgbe_ring_data *rdata; struct xgbe_ring_desc *rdesc; @@ -1869,7 +1869,7 @@ static int xgbe_tx_poll(struct xgbe_channel *channel) static int xgbe_rx_poll(struct xgbe_channel *channel, int budget) { struct xgbe_prv_data *pdata = channel->pdata; - struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; struct xgbe_ring *ring = channel->rx_ring; struct xgbe_ring_data *rdata; struct xgbe_packet_data *packet; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c index 59e090e..90bc0b4 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c @@ -211,7 +211,7 @@ static void xgbe_get_ethtool_stats(struct net_device *netdev, DBGPR("-->%s\n", __func__); - pdata->hw_if.read_mmc_stats(pdata); + pdata->hw_if->read_mmc_stats(pdata); for (i = 0; i < XGBE_STATS_COUNT; i++) { stat = (u8 *)pdata + xgbe_gstring_stats[i].stat_offset; *data++ = *(u64 *)stat; @@ -284,7 +284,7 @@ static int xgbe_set_pauseparam(struct net_device *netdev, pdata->phy.advertising ^= ADVERTISED_Asym_Pause; if (netif_running(netdev)) - ret = pdata->phy_if.phy_config_aneg(pdata); + ret = pdata->phy_if->phy_config_aneg(pdata); DBGPR("<--xgbe_set_pauseparam\n"); @@ -364,7 +364,7 @@ static int xgbe_set_settings(struct net_device *netdev, pdata->phy.advertising &= ~ADVERTISED_Autoneg; if (netif_running(netdev)) - ret = pdata->phy_if.phy_config_aneg(pdata); + ret = pdata->phy_if->phy_config_aneg(pdata); DBGPR("<--xgbe_set_settings\n"); @@ -411,7 +411,7 @@ static int xgbe_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec) { struct xgbe_prv_data *pdata = netdev_priv(netdev); - struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; unsigned int rx_frames, rx_riwt, rx_usecs; unsigned int tx_frames; @@ -536,7 +536,7 @@ static int xgbe_set_rxfh(struct net_device *netdev, const u32 *indir, const u8 *key, const u8 hfunc) { struct xgbe_prv_data *pdata = netdev_priv(netdev); - struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_hw_if *hw_if = pdata->hw_if; unsigned int ret; if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index e83bd76..f2d5d56 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -202,13 +202,6 @@ static void xgbe_default_config(struct xgbe_prv_data *pdata) DBGPR("<--xgbe_default_config\n"); } -static void xgbe_init_all_fptrs(struct xgbe_prv_data *pdata) -{ - xgbe_init_function_ptrs_dev(&pdata->hw_if); - xgbe_init_function_ptrs_phy(&pdata->phy_if); - xgbe_init_function_ptrs_desc(&pdata->desc_if); -} - #ifdef CONFIG_ACPI static int xgbe_acpi_support(struct xgbe_prv_data *pdata) { @@ -641,10 +634,12 @@ static int xgbe_probe(struct platform_device *pdev) memcpy(netdev->dev_addr, pdata->mac_addr, netdev->addr_len); /* Set all the function pointers */ - xgbe_init_all_fptrs(pdata); + pdata->hw_if = &default_xgbe_hw_if; + pdata->phy_if = &default_xgbe_phy_if; + pdata->desc_if = &default_xgbe_desc_if; /* Issue software reset to device */ - pdata->hw_if.exit(pdata); + pdata->hw_if->exit(pdata); /* Populate the hardware features */ xgbe_get_all_hw_features(pdata); @@ -698,7 +693,7 @@ static int xgbe_probe(struct platform_device *pdev) XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, UDP4TE, 1); /* Call MDIO/PHY initialization routine */ - pdata->phy_if.phy_init(pdata); + pdata->phy_if->phy_init(pdata); /* Set device operations */ netdev->netdev_ops = xgbe_get_netdev_ops(); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index 9088c3a..2ffe7c4 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -202,7 +202,7 @@ static void xgbe_xgmii_mode(struct xgbe_prv_data *pdata) xgbe_an_enable_kr_training(pdata); /* Set MAC to 10G speed */ - pdata->hw_if.set_xgmii_speed(pdata); + pdata->hw_if->set_xgmii_speed(pdata); /* Set PCS to KR/10G speed */ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); @@ -250,7 +250,7 @@ static void xgbe_gmii_2500_mode(struct xgbe_prv_data *pdata) xgbe_an_disable_kr_training(pdata); /* Set MAC to 2.5G speed */ - pdata->hw_if.set_gmii_2500_speed(pdata); + pdata->hw_if->set_gmii_2500_speed(pdata); /* Set PCS to KX/1G speed */ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); @@ -298,7 +298,7 @@ static void xgbe_gmii_mode(struct xgbe_prv_data *pdata) xgbe_an_disable_kr_training(pdata); /* Set MAC to 1G speed */ - pdata->hw_if.set_gmii_speed(pdata); + pdata->hw_if->set_gmii_speed(pdata); /* Set PCS to KX/1G speed */ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); @@ -872,13 +872,13 @@ static void xgbe_phy_adjust_link(struct xgbe_prv_data *pdata) if (pdata->tx_pause != pdata->phy.tx_pause) { new_state = 1; - pdata->hw_if.config_tx_flow_control(pdata); + pdata->hw_if->config_tx_flow_control(pdata); pdata->tx_pause = pdata->phy.tx_pause; } if (pdata->rx_pause != pdata->phy.rx_pause) { new_state = 1; - pdata->hw_if.config_rx_flow_control(pdata); + pdata->hw_if->config_rx_flow_control(pdata); pdata->rx_pause = pdata->phy.rx_pause; } @@ -1351,14 +1351,13 @@ static void xgbe_phy_init(struct xgbe_prv_data *pdata) xgbe_dump_phy_registers(pdata); } -void xgbe_init_function_ptrs_phy(struct xgbe_phy_if *phy_if) -{ - phy_if->phy_init = xgbe_phy_init; +const struct xgbe_phy_if default_xgbe_phy_if = { + .phy_init = xgbe_phy_init, - phy_if->phy_reset = xgbe_phy_reset; - phy_if->phy_start = xgbe_phy_start; - phy_if->phy_stop = xgbe_phy_stop; + .phy_reset = xgbe_phy_reset, + .phy_start = xgbe_phy_start, + .phy_stop = xgbe_phy_stop, - phy_if->phy_status = xgbe_phy_status; - phy_if->phy_config_aneg = xgbe_phy_config_aneg; -} + .phy_status = xgbe_phy_status, + .phy_config_aneg = xgbe_phy_config_aneg, +}; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c index b03e4f5..78e4cc4 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c @@ -129,7 +129,7 @@ static cycle_t xgbe_cc_read(const struct cyclecounter *cc) tstamp_cc); u64 nsec; - nsec = pdata->hw_if.get_tstamp_time(pdata); + nsec = pdata->hw_if->get_tstamp_time(pdata); return nsec; } @@ -158,7 +158,7 @@ static int xgbe_adjfreq(struct ptp_clock_info *info, s32 delta) spin_lock_irqsave(&pdata->tstamp_lock, flags); - pdata->hw_if.update_tstamp_addend(pdata, addend); + pdata->hw_if->update_tstamp_addend(pdata, addend); spin_unlock_irqrestore(&pdata->tstamp_lock, flags); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 8c9d01e..8c7bd644 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -801,9 +801,9 @@ struct xgbe_prv_data { int dev_irq; unsigned int per_channel_irq; - struct xgbe_hw_if hw_if; - struct xgbe_phy_if phy_if; - struct xgbe_desc_if desc_if; + struct xgbe_hw_if *hw_if; + struct xgbe_phy_if *phy_if; + struct xgbe_desc_if *desc_if; /* AXI DMA settings */ unsigned int coherent; @@ -964,6 +964,10 @@ struct xgbe_prv_data { #endif }; +extern const struct xgbe_hw_if default_xgbe_hw_if; +extern const struct xgbe_phy_if default_xgbe_phy_if; +extern const struct xgbe_desc_if default_xgbe_desc_if; + /* Function prototypes*/ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index b7d32e8..ea5b559 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -1122,7 +1122,7 @@ static inline u8 bnx2x_get_path_func_num(struct bnx2x *bp) static inline void bnx2x_init_bp_objs(struct bnx2x *bp) { /* RX_MODE controlling object */ - bnx2x_init_rx_mode_obj(bp, &bp->rx_mode_obj); + bnx2x_init_rx_mode_obj(bp); /* multicast configuration controlling object */ bnx2x_init_mcast_obj(bp, &bp->mcast_obj, bp->fp->cl_id, bp->fp->cid, diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c index ff702a7..cb3ae16 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c @@ -2576,15 +2576,14 @@ int bnx2x_config_rx_mode(struct bnx2x *bp, return rc; } -void bnx2x_init_rx_mode_obj(struct bnx2x *bp, - struct bnx2x_rx_mode_obj *o) +void bnx2x_init_rx_mode_obj(struct bnx2x *bp) { if (CHIP_IS_E1x(bp)) { - o->wait_comp = bnx2x_empty_rx_mode_wait; - o->config_rx_mode = bnx2x_set_rx_mode_e1x; + bp->rx_mode_obj.wait_comp = bnx2x_empty_rx_mode_wait; + bp->rx_mode_obj.config_rx_mode = bnx2x_set_rx_mode_e1x; } else { - o->wait_comp = bnx2x_wait_rx_mode_comp_e2; - o->config_rx_mode = bnx2x_set_rx_mode_e2; + bp->rx_mode_obj.wait_comp = bnx2x_wait_rx_mode_comp_e2; + bp->rx_mode_obj.config_rx_mode = bnx2x_set_rx_mode_e2; } } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h index 4048fc5..333809f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h @@ -1436,8 +1436,7 @@ int bnx2x_vlan_mac_move(struct bnx2x *bp, /********************* RX MODE ****************/ -void bnx2x_init_rx_mode_obj(struct bnx2x *bp, - struct bnx2x_rx_mode_obj *o); +void bnx2x_init_rx_mode_obj(struct bnx2x *bp); /** * bnx2x_config_rx_mode - Send and RX_MODE ramrod according to the provided parameters. diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index 31c9f82..e65e986 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -150,6 +150,7 @@ #define CHIPREV_ID_5750_A0 0x4000 #define CHIPREV_ID_5750_A1 0x4001 #define CHIPREV_ID_5750_A3 0x4003 +#define CHIPREV_ID_5750_C1 0x4201 #define CHIPREV_ID_5750_C2 0x4202 #define CHIPREV_ID_5752_A0_HW 0x5000 #define CHIPREV_ID_5752_A0 0x6000 diff --git a/drivers/net/ethernet/brocade/bna/bna_enet.c b/drivers/net/ethernet/brocade/bna/bna_enet.c index 4e5c387..bba8173 100644 --- a/drivers/net/ethernet/brocade/bna/bna_enet.c +++ b/drivers/net/ethernet/brocade/bna/bna_enet.c @@ -1676,10 +1676,10 @@ bna_cb_ioceth_reset(void *arg) } static struct bfa_ioc_cbfn bna_ioceth_cbfn = { - bna_cb_ioceth_enable, - bna_cb_ioceth_disable, - bna_cb_ioceth_hbfail, - bna_cb_ioceth_reset + .enable_cbfn = bna_cb_ioceth_enable, + .disable_cbfn = bna_cb_ioceth_disable, + .hbfail_cbfn = bna_cb_ioceth_hbfail, + .reset_cbfn = bna_cb_ioceth_reset }; static void bna_attr_init(struct bna_ioceth *ioceth) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c index 29f3308..b594c38 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c @@ -265,9 +265,9 @@ static void octnet_mdio_resp_callback(struct octeon_device *oct, if (status) { dev_err(&oct->pci_dev->dev, "MIDO instruction failed. Status: %llx\n", CVM_CAST64(status)); - ACCESS_ONCE(mdio_cmd_ctx->cond) = -1; + ACCESS_ONCE_RW(mdio_cmd_ctx->cond) = -1; } else { - ACCESS_ONCE(mdio_cmd_ctx->cond) = 1; + ACCESS_ONCE_RW(mdio_cmd_ctx->cond) = 1; } wake_up_interruptible(&mdio_cmd_ctx->wc); } @@ -298,7 +298,7 @@ octnet_mdio45_access(struct lio *lio, int op, int loc, int *value) mdio_cmd_rsp = (struct oct_mdio_cmd_resp *)sc->virtrptr; mdio_cmd = (struct oct_mdio_cmd *)sc->virtdptr; - ACCESS_ONCE(mdio_cmd_ctx->cond) = 0; + ACCESS_ONCE_RW(mdio_cmd_ctx->cond) = 0; mdio_cmd_ctx->octeon_id = lio_get_device_id(oct_dev); 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 f683d97..8c4419a 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -1726,7 +1726,7 @@ static void if_cfg_callback(struct octeon_device *oct, if (resp->status) dev_err(&oct->pci_dev->dev, "nic if cfg instruction failed. Status: %llx\n", CVM_CAST64(resp->status)); - ACCESS_ONCE(ctx->cond) = 1; + ACCESS_ONCE_RW(ctx->cond) = 1; /* This barrier is required to be sure that the response has been * written fully before waking up the handler @@ -3176,7 +3176,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) dev_dbg(&octeon_dev->pci_dev->dev, "requesting config for interface %d, iqs %d, oqs %d\n", i, num_iqueues, num_oqueues); - ACCESS_ONCE(ctx->cond) = 0; + ACCESS_ONCE_RW(ctx->cond) = 0; ctx->octeon_id = lio_get_device_id(octeon_dev); init_waitqueue_head(&ctx->wc); @@ -3239,8 +3239,11 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) props = &octeon_dev->props[i]; props->netdev = netdev; - if (num_iqueues > 1) - lionetdevops.ndo_select_queue = select_q; + if (num_iqueues > 1) { + pax_open_kernel(); + *(void **)&lionetdevops.ndo_select_queue = select_q; + pax_close_kernel(); + } /* Associate the routines that will handle different * netdev tasks. diff --git a/drivers/net/ethernet/chelsio/cxgb3/l2t.h b/drivers/net/ethernet/chelsio/cxgb3/l2t.h index 8cffcdf..aadf043 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/l2t.h +++ b/drivers/net/ethernet/chelsio/cxgb3/l2t.h @@ -87,7 +87,7 @@ typedef void (*arp_failure_handler_func)(struct t3cdev * dev, */ struct l2t_skb_cb { arp_failure_handler_func arp_failure_handler; -}; +} __no_const; #define L2T_SKB_CB(skb) ((struct l2t_skb_cb *)(skb)->cb) diff --git a/drivers/net/ethernet/dec/tulip/de4x5.c b/drivers/net/ethernet/dec/tulip/de4x5.c index 8966f31..e15a101 100644 --- a/drivers/net/ethernet/dec/tulip/de4x5.c +++ b/drivers/net/ethernet/dec/tulip/de4x5.c @@ -5373,7 +5373,7 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) for (i=0; idev_addr[i]; } - if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT; + if (ioc->len > sizeof tmp.addr || copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT; break; case DE4X5_SET_HWADDR: /* Set the hardware address */ @@ -5413,7 +5413,7 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) spin_lock_irqsave(&lp->lock, flags); memcpy(&statbuf, &lp->pktStats, ioc->len); spin_unlock_irqrestore(&lp->lock, flags); - if (copy_to_user(ioc->data, &statbuf, ioc->len)) + if (ioc->len > sizeof statbuf || copy_to_user(ioc->data, &statbuf, ioc->len)) return -EFAULT; break; } diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index eb48a97..60c72cd 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -551,7 +551,7 @@ static void accumulate_16bit_val(u32 *acc, u16 val) if (wrapped) newacc += 65536; - ACCESS_ONCE(*acc) = newacc; + ACCESS_ONCE_RW(*acc) = newacc; } static void populate_erx_stats(struct be_adapter *adapter, diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index 6d0c5d5..55be363 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include "ftgmac100.h" diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c index dce5f7b..2433466 100644 --- a/drivers/net/ethernet/faraday/ftmac100.c +++ b/drivers/net/ethernet/faraday/ftmac100.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include "ftmac100.h" diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 8c40d6e..87ecdb3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -418,7 +418,7 @@ void i40e_ptp_set_increment(struct i40e_pf *pf) wr32(hw, I40E_PRTTSYN_INC_H, incval >> 32); /* Update the base adjustement value. */ - ACCESS_ONCE(pf->ptp_base_adj) = incval; + ACCESS_ONCE_RW(pf->ptp_base_adj) = incval; smp_mb(); /* Force the above update. */ } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c index e5ba040..d47531c 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c @@ -782,7 +782,7 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter) } /* update the base incval used to calculate frequency adjustment */ - ACCESS_ONCE(adapter->base_incval) = incval; + ACCESS_ONCE_RW(adapter->base_incval) = incval; smp_mb(); /* need lock to prevent incorrect read while modifying cyclecounter */ diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 4421bf54..c07afb0 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -475,8 +475,8 @@ static bool mlx4_en_process_tx_cq(struct net_device *dev, wmb(); /* we want to dirty this cache line once */ - ACCESS_ONCE(ring->last_nr_txbb) = last_nr_txbb; - ACCESS_ONCE(ring->cons) = ring_cons + txbbs_skipped; + ACCESS_ONCE_RW(ring->last_nr_txbb) = last_nr_txbb; + ACCESS_ONCE_RW(ring->cons) = ring_cons + txbbs_skipped; netdev_tx_completed_queue(ring->tx_queue, packets, bytes); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 443632d..7b43236 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -2025,8 +2025,11 @@ static void mlx5e_build_netdev(struct net_device *netdev) SET_NETDEV_DEV(netdev, &mdev->pdev->dev); - if (priv->params.num_tc > 1) - mlx5e_netdev_ops.ndo_select_queue = mlx5e_select_queue; + if (priv->params.num_tc > 1) { + pax_open_kernel(); + *(void **)&mlx5e_netdev_ops.ndo_select_queue = mlx5e_select_queue; + pax_close_kernel(); + } netdev->netdev_ops = &mlx5e_netdev_ops; netdev->watchdog_timeo = 15 * HZ; diff --git a/drivers/net/ethernet/neterion/vxge/vxge-config.c b/drivers/net/ethernet/neterion/vxge/vxge-config.c index 6223930..975033d 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-config.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-config.c @@ -3457,7 +3457,10 @@ __vxge_hw_fifo_create(struct __vxge_hw_vpath_handle *vp, struct __vxge_hw_fifo *fifo; struct vxge_hw_fifo_config *config; u32 txdl_size, txdl_per_memblock; - struct vxge_hw_mempool_cbs fifo_mp_callback; + static struct vxge_hw_mempool_cbs fifo_mp_callback = { + .item_func_alloc = __vxge_hw_fifo_mempool_item_alloc, + }; + struct __vxge_hw_virtualpath *vpath; if ((vp == NULL) || (attr == NULL)) { @@ -3540,8 +3543,6 @@ __vxge_hw_fifo_create(struct __vxge_hw_vpath_handle *vp, goto exit; } - fifo_mp_callback.item_func_alloc = __vxge_hw_fifo_mempool_item_alloc; - fifo->mempool = __vxge_hw_mempool_create(vpath->hldev, fifo->config->memblock_size, diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index 75e88f4..1db3bf6 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -357,8 +357,8 @@ struct ring_desc { }; struct ring_desc_ex { - __le32 bufhigh; - __le32 buflow; + __le32 bufhigh __intentional_overflow(0); + __le32 buflow __intentional_overflow(0); __le32 txvlan; __le32 flaglen; }; 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 --- 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) max_tx_rings = QLCNIC_MAX_VNIC_TX_RINGS; } else if (ret == QLC_83XX_DEFAULT_OPMODE) { 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; + 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 be7d7a6..a8983f8 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) case QLCNIC_NON_PRIV_FUNC: ahw->op_mode = QLCNIC_NON_PRIV_FUNC; 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; + pax_close_kernel(); break; case QLCNIC_PRIV_FUNC: ahw->op_mode = QLCNIC_PRIV_FUNC; 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; + pax_close_kernel(); break; case QLCNIC_MGMT_FUNC: ahw->op_mode = QLCNIC_MGMT_FUNC; 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; + pax_close_kernel(); break; default: dev_err(&adapter->pdev->dev, "Invalid Virtual NIC opmode\n"); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c index cda9e60..4019992 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c @@ -1285,7 +1285,7 @@ flash_temp: int qlcnic_dump_fw(struct qlcnic_adapter *adapter) { struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; - static const struct qlcnic_dump_operations *fw_dump_ops; + const struct qlcnic_dump_operations *fw_dump_ops; struct qlcnic_83xx_dump_template_hdr *hdr_83xx; u32 entry_offset, dump, no_entries, buf_offset = 0; int i, k, ops_cnt, ops_index, dump_size = 0; diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 79ef799..59bbd1f 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -798,22 +798,22 @@ struct rtl8169_private { struct mdio_ops { void (*write)(struct rtl8169_private *, int, int); int (*read)(struct rtl8169_private *, int); - } mdio_ops; + } __no_const mdio_ops; struct pll_power_ops { void (*down)(struct rtl8169_private *); void (*up)(struct rtl8169_private *); - } pll_power_ops; + } __no_const pll_power_ops; struct jumbo_ops { void (*enable)(struct rtl8169_private *); void (*disable)(struct rtl8169_private *); - } jumbo_ops; + } __no_const jumbo_ops; struct csi_ops { void (*write)(struct rtl8169_private *, int, int); u32 (*read)(struct rtl8169_private *, int); - } csi_ops; + } __no_const csi_ops; int (*set_speed)(struct net_device *, u8 aneg, u16 sp, u8 dpx, u32 adv); int (*get_settings)(struct net_device *, struct ethtool_cmd *); diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c index ad62615..a4c124d 100644 --- a/drivers/net/ethernet/sfc/ptp.c +++ b/drivers/net/ethernet/sfc/ptp.c @@ -832,7 +832,7 @@ static int efx_ptp_synchronize(struct efx_nic *efx, unsigned int num_readings) ptp->start.dma_addr); /* Clear flag that signals MC ready */ - ACCESS_ONCE(*start) = 0; + ACCESS_ONCE_RW(*start) = 0; rc = efx_mcdi_rpc_start(efx, MC_CMD_PTP, synch_buf, MC_CMD_PTP_IN_SYNCHRONIZE_LEN); EFX_BUG_ON_PARANOID(rc); diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c index 3f20bb1..59add41 100644 --- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c @@ -140,8 +140,8 @@ void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode) writel(value, ioaddr + MMC_CNTRL); - pr_debug("stmmac: MMC ctrl register (offset 0x%x): 0x%08x\n", - MMC_CNTRL, value); +// pr_debug("stmmac: MMC ctrl register (offset 0x%x): 0x%08x\n", +// MMC_CNTRL, value); } /* To mask all all interrupts.*/ diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c index 2b7550c..f75bc6c 100644 --- a/drivers/net/ethernet/via/via-rhine.c +++ b/drivers/net/ethernet/via/via-rhine.c @@ -2600,7 +2600,7 @@ static struct platform_driver rhine_driver_platform = { } }; -static struct dmi_system_id rhine_dmi_table[] __initdata = { +static const struct dmi_system_id rhine_dmi_table[] __initconst = { { .ident = "EPIA-M", .matches = { diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 445071c..6be9e60 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -971,7 +971,7 @@ nla_put_failure: return -EMSGSIZE; } -static struct rtnl_link_ops geneve_link_ops __read_mostly = { +static struct rtnl_link_ops geneve_link_ops = { .kind = "geneve", .maxtype = IFLA_GENEVE_MAX, .policy = geneve_policy, diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 5fa98f5..322f0f8 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -178,7 +178,7 @@ struct rndis_device { enum rndis_device_state state; bool link_state; bool link_change; - atomic_t new_req_id; + atomic_unchecked_t new_req_id; spinlock_t request_lock; struct list_head req_list; diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 5931a79..134ce31 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -101,7 +101,7 @@ static struct rndis_request *get_rndis_request(struct rndis_device *dev, * template */ set = &rndis_msg->msg.set_req; - set->req_id = atomic_inc_return(&dev->new_req_id); + set->req_id = atomic_inc_return_unchecked(&dev->new_req_id); /* Add to the request list */ spin_lock_irqsave(&dev->request_lock, flags); @@ -924,7 +924,7 @@ static void rndis_filter_halt_device(struct rndis_device *dev) /* Setup the rndis set */ halt = &request->request_msg.msg.halt_req; - halt->req_id = atomic_inc_return(&dev->new_req_id); + halt->req_id = atomic_inc_return_unchecked(&dev->new_req_id); /* Ignore return since this msg is optional. */ rndis_filter_send_request(dev, request); @@ -1138,8 +1138,7 @@ int rndis_filter_device_add(struct hv_device *dev, if (net_device->num_chn == 1) goto out; - net_device->sub_cb_buf = vzalloc((net_device->num_chn - 1) * - NETVSC_PACKET_SIZE); + net_device->sub_cb_buf = vzalloc(net_device->num_sc_offered * NETVSC_PACKET_SIZE); if (!net_device->sub_cb_buf) { net_device->num_chn = 1; dev_info(&dev->device, "No memory for subchannels.\n"); diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index cc56fac..c15b884 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -287,7 +287,7 @@ static int ifb_validate(struct nlattr *tb[], struct nlattr *data[]) return 0; } -static struct rtnl_link_ops ifb_link_ops __read_mostly = { +static struct rtnl_link_ops ifb_link_ops = { .kind = "ifb", .priv_size = sizeof(struct ifb_dev_private), .setup = ifb_setup, diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index 207f62e..af3f5e5 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -466,7 +466,7 @@ static void ipvlan_multicast_enqueue(struct ipvl_port *port, schedule_work(&port->wq); } else { spin_unlock(&port->backlog.lock); - atomic_long_inc(&skb->dev->rx_dropped); + atomic_long_inc_unchecked(&skb->dev->rx_dropped); kfree_skb(skb); } } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 47da435..a4a7bd8 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -335,7 +335,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port, free_nskb: kfree_skb(nskb); err: - atomic_long_inc(&skb->dev->rx_dropped); + atomic_long_inc_unchecked(&skb->dev->rx_dropped); } static void macvlan_flush_sources(struct macvlan_port *port, @@ -1481,13 +1481,15 @@ static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = { int macvlan_link_register(struct rtnl_link_ops *ops) { /* common fields */ - ops->priv_size = sizeof(struct macvlan_dev); - ops->validate = macvlan_validate; - ops->maxtype = IFLA_MACVLAN_MAX; - ops->policy = macvlan_policy; - ops->changelink = macvlan_changelink; - 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; + pax_close_kernel(); return rtnl_link_register(ops); }; @@ -1573,7 +1575,7 @@ static int macvlan_device_event(struct notifier_block *unused, return NOTIFY_DONE; } -static struct notifier_block macvlan_notifier_block __read_mostly = { +static struct notifier_block macvlan_notifier_block = { .notifier_call = macvlan_device_event, }; diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 197c939..5f7bee5 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -485,7 +485,7 @@ static void macvtap_setup(struct net_device *dev) dev->tx_queue_len = TUN_READQ_SIZE; } -static struct rtnl_link_ops macvtap_link_ops __read_mostly = { +static struct rtnl_link_ops macvtap_link_ops = { .kind = "macvtap", .setup = macvtap_setup, .newlink = macvtap_newlink, @@ -1090,7 +1090,7 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, ret = 0; u = q->flags; - if (copy_to_user(&ifr->ifr_name, vlan->dev->name, IFNAMSIZ) || + if (copy_to_user(ifr->ifr_name, vlan->dev->name, IFNAMSIZ) || put_user(u, &ifr->ifr_flags)) ret = -EFAULT; macvtap_put_vlan(vlan); @@ -1173,8 +1173,8 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, } ret = 0; u = vlan->dev->type; - if (copy_to_user(&ifr->ifr_name, vlan->dev->name, IFNAMSIZ) || - copy_to_user(&ifr->ifr_hwaddr.sa_data, vlan->dev->dev_addr, ETH_ALEN) || + if (copy_to_user(ifr->ifr_name, vlan->dev->name, IFNAMSIZ) || + copy_to_user(ifr->ifr_hwaddr.sa_data, vlan->dev->dev_addr, ETH_ALEN) || put_user(u, &ifr->ifr_hwaddr.sa_family)) ret = -EFAULT; macvtap_put_vlan(vlan); @@ -1308,7 +1308,7 @@ static int macvtap_device_event(struct notifier_block *unused, return NOTIFY_DONE; } -static struct notifier_block macvtap_notifier_block __read_mostly = { +static struct notifier_block macvtap_notifier_block = { .notifier_call = macvtap_device_event, }; diff --git a/drivers/net/nlmon.c b/drivers/net/nlmon.c index 7b7c70e..a92dc83 100644 --- a/drivers/net/nlmon.c +++ b/drivers/net/nlmon.c @@ -154,7 +154,7 @@ static int nlmon_validate(struct nlattr *tb[], struct nlattr *data[]) return 0; } -static struct rtnl_link_ops nlmon_link_ops __read_mostly = { +static struct rtnl_link_ops nlmon_link_ops = { .kind = "nlmon", .priv_size = sizeof(struct nlmon), .setup = nlmon_setup, diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index f761288..a1024be 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -218,7 +218,7 @@ EXPORT_SYMBOL(phy_device_create); * zero on success. * */ -static int get_phy_c45_ids(struct mii_bus *bus, int addr, u32 *phy_id, +static int get_phy_c45_ids(struct mii_bus *bus, int addr, int *phy_id, struct phy_c45_device_ids *c45_ids) { int phy_reg; int i, reg_addr; @@ -296,7 +296,7 @@ retry: reg_addr = MII_ADDR_C45 | i << 16 | MDIO_DEVS2; * its return value is in turn returned. * */ -static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id, +static int get_phy_id(struct mii_bus *bus, int addr, int *phy_id, bool is_c45, struct phy_c45_device_ids *c45_ids) { int phy_reg; @@ -334,7 +334,7 @@ static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id, struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45) { struct phy_c45_device_ids c45_ids = {0}; - u32 phy_id = 0; + int phy_id = 0; int r; r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids); diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index ed00446..943fe2c 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -1047,7 +1047,6 @@ ppp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) void __user *addr = (void __user *) ifr->ifr_ifru.ifru_data; struct ppp_stats stats; struct ppp_comp_stats cstats; - char *vers; switch (cmd) { case SIOCGPPPSTATS: @@ -1069,8 +1068,7 @@ ppp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) break; case SIOCGPPPVER: - vers = PPP_VERSION; - if (copy_to_user(addr, vers, strlen(vers) + 1)) + if (copy_to_user(addr, PPP_VERSION, sizeof(PPP_VERSION))) break; err = 0; break; diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index 5e0b432..0a37f84 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -568,6 +568,9 @@ static int pppoe_create(struct net *net, struct socket *sock, int kern) sk->sk_family = PF_PPPOX; sk->sk_protocol = PX_PROTO_OE; + INIT_WORK(&pppox_sk(sk)->proto.pppoe.padt_work, + pppoe_unbind_sock_work); + return 0; } @@ -632,8 +635,6 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, lock_sock(sk); - INIT_WORK(&po->proto.pppoe.padt_work, pppoe_unbind_sock_work); - error = -EINVAL; if (sp->sa_protocol != PX_PROTO_OE) goto end; @@ -663,8 +664,13 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, po->pppoe_dev = NULL; } - memset(sk_pppox(po) + 1, 0, - sizeof(struct pppox_sock) - sizeof(struct sock)); + po->pppoe_ifindex = 0; + memset(&po->pppoe_pa, 0, sizeof(po->pppoe_pa)); + memset(&po->pppoe_relay, 0, sizeof(po->pppoe_relay)); + memset(&po->chan, 0, sizeof(po->chan)); + po->next = NULL; + po->num = 0; + sk->sk_state = PPPOX_NONE; } diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index 686f37d..b910cae 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -418,6 +418,9 @@ static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr, struct pptp_opt *opt = &po->proto.pptp; int error = 0; + if (sockaddr_len < sizeof(struct sockaddr_pppox)) + return -EINVAL; + lock_sock(sk); opt->src_addr = sp->sa_addr.pptp; @@ -439,6 +442,9 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, struct flowi4 fl4; int error = 0; + if (sockaddr_len < sizeof(struct sockaddr_pppox)) + return -EINVAL; + if (sp->sa_protocol != PX_PROTO_PPTP) return -EINVAL; diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c index 079f7ad..7e59810 100644 --- a/drivers/net/slip/slhc.c +++ b/drivers/net/slip/slhc.c @@ -94,6 +94,9 @@ slhc_init(int rslots, int tslots) register struct cstate *ts; struct slcompress *comp; + if (rslots <= 0 || tslots <= 0 || rslots >= 256 || tslots >= 256) + goto out_fail; + comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); if (! comp) goto out_fail; @@ -487,7 +490,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) register struct tcphdr *thp; register struct iphdr *ip; register struct cstate *cs; - int len, hdrlen; + long len, hdrlen; unsigned char *cp = icp; /* We've got a compressed packet; read the change byte */ diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 651d35e..4249181 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -2107,7 +2107,7 @@ static unsigned int team_get_num_rx_queues(void) return TEAM_DEFAULT_NUM_RX_QUEUES; } -static struct rtnl_link_ops team_link_ops __read_mostly = { +static struct rtnl_link_ops team_link_ops = { .kind = DRV_NAME, .priv_size = sizeof(struct team), .setup = team_setup, @@ -2897,7 +2897,7 @@ static int team_device_event(struct notifier_block *unused, return NOTIFY_DONE; } -static struct notifier_block team_notifier_block __read_mostly = { +static struct notifier_block team_notifier_block = { .notifier_call = team_device_event, }; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 976aa97..c1efed2 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1473,7 +1473,7 @@ static int tun_validate(struct nlattr *tb[], struct nlattr *data[]) return -EINVAL; } -static struct rtnl_link_ops tun_link_ops __read_mostly = { +static struct rtnl_link_ops tun_link_ops = { .kind = DRV_NAME, .priv_size = sizeof(struct tun_struct), .setup = tun_setup, @@ -1872,7 +1872,7 @@ unlock: } static long __tun_chr_ioctl(struct file *file, unsigned int cmd, - unsigned long arg, int ifreq_len) + unsigned long arg, size_t ifreq_len) { struct tun_file *tfile = file->private_data; struct tun_struct *tun; @@ -1886,6 +1886,9 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, int le; int ret; + if (ifreq_len > sizeof ifr) + return -EFAULT; + if (cmd == TUNSETIFF || cmd == TUNSETQUEUE || _IOC_TYPE(cmd) == 0x89) { if (copy_from_user(&ifr, argp, ifreq_len)) return -EFAULT; diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 111d907..1ee643e 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -70,7 +70,7 @@ #include #include #include - +#include #define MOD_AUTHOR "Option Wireless" #define MOD_DESCRIPTION "USB High Speed Option driver" @@ -1183,7 +1183,7 @@ static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial) struct urb *urb; urb = serial->rx_urb[0]; - if (serial->port.count > 0) { + if (atomic_read(&serial->port.count) > 0) { count = put_rxbuf_data(urb, serial); if (count == -1) return; @@ -1221,7 +1221,7 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb) DUMP1(urb->transfer_buffer, urb->actual_length); /* Anyone listening? */ - if (serial->port.count == 0) + if (atomic_read(&serial->port.count) == 0) return; if (serial->parent->port_spec & HSO_INFO_CRC_BUG) @@ -1282,8 +1282,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) tty_port_tty_set(&serial->port, tty); /* check for port already opened, if not set the termios */ - serial->port.count++; - if (serial->port.count == 1) { + if (atomic_inc_return(&serial->port.count) == 1) { serial->rx_state = RX_IDLE; /* Force default termio settings */ _hso_serial_set_termios(tty, NULL); @@ -1293,7 +1292,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) result = hso_start_serial_device(serial->parent, GFP_KERNEL); if (result) { hso_stop_serial_device(serial->parent); - serial->port.count--; + atomic_dec(&serial->port.count); } else { kref_get(&serial->parent->ref); } @@ -1331,10 +1330,10 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) /* reset the rts and dtr */ /* do the actual close */ - serial->port.count--; + atomic_dec(&serial->port.count); - if (serial->port.count <= 0) { - serial->port.count = 0; + if (atomic_read(&serial->port.count) <= 0) { + atomic_set(&serial->port.count, 0); tty_port_tty_set(&serial->port, NULL); if (!usb_gone) hso_stop_serial_device(serial->parent); @@ -1417,7 +1416,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) /* the actual setup */ spin_lock_irqsave(&serial->serial_lock, flags); - if (serial->port.count) + if (atomic_read(&serial->port.count)) _hso_serial_set_termios(tty, old); else tty->termios = *old; @@ -1891,7 +1890,7 @@ static void intr_callback(struct urb *urb) D1("Pending read interrupt on port %d\n", i); spin_lock(&serial->serial_lock); if (serial->rx_state == RX_IDLE && - serial->port.count > 0) { + atomic_read(&serial->port.count) > 0) { /* Setup and send a ctrl req read on * port i */ if (!serial->rx_urb_filled[0]) { @@ -3058,7 +3057,7 @@ static int hso_resume(struct usb_interface *iface) /* Start all serial ports */ for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { if (serial_table[i] && (serial_table[i]->interface == iface)) { - if (dev2ser(serial_table[i])->port.count) { + if (atomic_read(&dev2ser(serial_table[i])->port.count)) { result = hso_start_serial_device(serial_table[i], GFP_NOIO); hso_kick_transmit(dev2ser(serial_table[i])); diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index d9427ca..37520a8 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -615,7 +615,7 @@ struct r8152 { int (*eee_get)(struct r8152 *, struct ethtool_eee *); int (*eee_set)(struct r8152 *, struct ethtool_eee *); bool (*in_nway)(struct r8152 *); - } rtl_ops; + } __no_const rtl_ops; int intr_interval; u32 saved_wolopts; diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c index a2515887..6d13233 100644 --- a/drivers/net/usb/sierra_net.c +++ b/drivers/net/usb/sierra_net.c @@ -51,7 +51,7 @@ static const char driver_name[] = "sierra_net"; /* atomic counter partially included in MAC address to make sure 2 devices * do not end up with the same MAC - concept breaks in case of > 255 ifaces */ -static atomic_t iface_counter = ATOMIC_INIT(0); +static atomic_unchecked_t iface_counter = ATOMIC_INIT(0); /* * SYNC Timer Delay definition used to set the expiry time @@ -697,7 +697,7 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->netdev_ops = &sierra_net_device_ops; /* change MAC addr to include, ifacenum, and to be unique */ - dev->net->dev_addr[ETH_ALEN-2] = atomic_inc_return(&iface_counter); + dev->net->dev_addr[ETH_ALEN-2] = atomic_inc_return_unchecked(&iface_counter); dev->net->dev_addr[ETH_ALEN-1] = ifacenum; /* we will have to manufacture ethernet headers, prepare template */ diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index d8838ded..6c93f77 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -48,7 +48,7 @@ module_param(gso, bool, 0444); DECLARE_EWMA(pkt_len, 1, 64) /* Minimum alignment for mergeable packet buffers. */ -#define MERGEABLE_BUFFER_ALIGN max(L1_CACHE_BYTES, 256) +#define MERGEABLE_BUFFER_ALIGN max(L1_CACHE_BYTES, 256UL) #define VIRTNET_DRIVER_VERSION "1.0.0" diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index c9e309c..745a638 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -618,7 +618,7 @@ static const struct nla_policy vrf_nl_policy[IFLA_VRF_MAX + 1] = { [IFLA_VRF_TABLE] = { .type = NLA_U32 }, }; -static struct rtnl_link_ops vrf_link_ops __read_mostly = { +static struct rtnl_link_ops vrf_link_ops = { .kind = DRV_NAME, .priv_size = sizeof(struct net_vrf), diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index c1587ec..dcd13ca 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -3037,7 +3037,7 @@ static struct net *vxlan_get_link_net(const struct net_device *dev) return vxlan->net; } -static struct rtnl_link_ops vxlan_link_ops __read_mostly = { +static struct rtnl_link_ops vxlan_link_ops = { .kind = "vxlan", .maxtype = IFLA_VXLAN_MAX, .policy = vxlan_policy, @@ -3085,7 +3085,7 @@ static int vxlan_lowerdev_event(struct notifier_block *unused, return NOTIFY_DONE; } -static struct notifier_block vxlan_notifier_block __read_mostly = { +static struct notifier_block vxlan_notifier_block = { .notifier_call = vxlan_lowerdev_event, }; diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c index 5920c99..ff2e4a5 100644 --- a/drivers/net/wan/lmc/lmc_media.c +++ b/drivers/net/wan/lmc/lmc_media.c @@ -95,62 +95,63 @@ static inline void write_av9110_bit (lmc_softc_t *, int); static void write_av9110(lmc_softc_t *, u32, u32, u32, u32, u32); lmc_media_t lmc_ds3_media = { - lmc_ds3_init, /* special media init stuff */ - lmc_ds3_default, /* reset to default state */ - lmc_ds3_set_status, /* reset status to state provided */ - lmc_dummy_set_1, /* set clock source */ - lmc_dummy_set2_1, /* set line speed */ - lmc_ds3_set_100ft, /* set cable length */ - lmc_ds3_set_scram, /* set scrambler */ - lmc_ds3_get_link_status, /* get link status */ - lmc_dummy_set_1, /* set link status */ - lmc_ds3_set_crc_length, /* set CRC length */ - lmc_dummy_set_1, /* set T1 or E1 circuit type */ - lmc_ds3_watchdog + .init = lmc_ds3_init, /* special media init stuff */ + .defaults = lmc_ds3_default, /* reset to default state */ + .set_status = lmc_ds3_set_status, /* reset status to state provided */ + .set_clock_source = lmc_dummy_set_1, /* set clock source */ + .set_speed = lmc_dummy_set2_1, /* set line speed */ + .set_cable_length = lmc_ds3_set_100ft, /* set cable length */ + .set_scrambler = lmc_ds3_set_scram, /* set scrambler */ + .get_link_status = lmc_ds3_get_link_status, /* get link status */ + .set_link_status = lmc_dummy_set_1, /* set link status */ + .set_crc_length = lmc_ds3_set_crc_length, /* set CRC length */ + .set_circuit_type = lmc_dummy_set_1, /* set T1 or E1 circuit type */ + .watchdog = lmc_ds3_watchdog }; lmc_media_t lmc_hssi_media = { - lmc_hssi_init, /* special media init stuff */ - lmc_hssi_default, /* reset to default state */ - lmc_hssi_set_status, /* reset status to state provided */ - lmc_hssi_set_clock, /* set clock source */ - lmc_dummy_set2_1, /* set line speed */ - lmc_dummy_set_1, /* set cable length */ - lmc_dummy_set_1, /* set scrambler */ - lmc_hssi_get_link_status, /* get link status */ - lmc_hssi_set_link_status, /* set link status */ - lmc_hssi_set_crc_length, /* set CRC length */ - lmc_dummy_set_1, /* set T1 or E1 circuit type */ - lmc_hssi_watchdog + .init = lmc_hssi_init, /* special media init stuff */ + .defaults = lmc_hssi_default, /* reset to default state */ + .set_status = lmc_hssi_set_status, /* reset status to state provided */ + .set_clock_source = lmc_hssi_set_clock, /* set clock source */ + .set_speed = lmc_dummy_set2_1, /* set line speed */ + .set_cable_length = lmc_dummy_set_1, /* set cable length */ + .set_scrambler = lmc_dummy_set_1, /* set scrambler */ + .get_link_status = lmc_hssi_get_link_status, /* get link status */ + .set_link_status = lmc_hssi_set_link_status, /* set link status */ + .set_crc_length = lmc_hssi_set_crc_length, /* set CRC length */ + .set_circuit_type = lmc_dummy_set_1, /* set T1 or E1 circuit type */ + .watchdog = lmc_hssi_watchdog }; -lmc_media_t lmc_ssi_media = { lmc_ssi_init, /* special media init stuff */ - lmc_ssi_default, /* reset to default state */ - lmc_ssi_set_status, /* reset status to state provided */ - lmc_ssi_set_clock, /* set clock source */ - lmc_ssi_set_speed, /* set line speed */ - lmc_dummy_set_1, /* set cable length */ - lmc_dummy_set_1, /* set scrambler */ - lmc_ssi_get_link_status, /* get link status */ - lmc_ssi_set_link_status, /* set link status */ - lmc_ssi_set_crc_length, /* set CRC length */ - lmc_dummy_set_1, /* set T1 or E1 circuit type */ - lmc_ssi_watchdog +lmc_media_t lmc_ssi_media = { + .init = lmc_ssi_init, /* special media init stuff */ + .defaults = lmc_ssi_default, /* reset to default state */ + .set_status = lmc_ssi_set_status, /* reset status to state provided */ + .set_clock_source = lmc_ssi_set_clock, /* set clock source */ + .set_speed = lmc_ssi_set_speed, /* set line speed */ + .set_cable_length = lmc_dummy_set_1, /* set cable length */ + .set_scrambler = lmc_dummy_set_1, /* set scrambler */ + .get_link_status = lmc_ssi_get_link_status, /* get link status */ + .set_link_status = lmc_ssi_set_link_status, /* set link status */ + .set_crc_length = lmc_ssi_set_crc_length, /* set CRC length */ + .set_circuit_type = lmc_dummy_set_1, /* set T1 or E1 circuit type */ + .watchdog = lmc_ssi_watchdog }; lmc_media_t lmc_t1_media = { - lmc_t1_init, /* special media init stuff */ - lmc_t1_default, /* reset to default state */ - lmc_t1_set_status, /* reset status to state provided */ - lmc_t1_set_clock, /* set clock source */ - lmc_dummy_set2_1, /* set line speed */ - lmc_dummy_set_1, /* set cable length */ - lmc_dummy_set_1, /* set scrambler */ - lmc_t1_get_link_status, /* get link status */ - lmc_dummy_set_1, /* set link status */ - lmc_t1_set_crc_length, /* set CRC length */ - lmc_t1_set_circuit_type, /* set T1 or E1 circuit type */ - lmc_t1_watchdog + .init = lmc_t1_init, /* special media init stuff */ + .defaults = lmc_t1_default, /* reset to default state */ + .set_status = lmc_t1_set_status, /* reset status to state provided */ + .set_clock_source = lmc_t1_set_clock, /* set clock source */ + .set_speed = lmc_dummy_set2_1, /* set line speed */ + .set_cable_length = lmc_dummy_set_1, /* set cable length */ + .set_scrambler = lmc_dummy_set_1, /* set scrambler */ + .get_link_status = lmc_t1_get_link_status, /* get link status */ + .set_link_status = lmc_dummy_set_1, /* set link status */ + .set_crc_length = lmc_t1_set_crc_length, /* set CRC length */ + .set_circuit_type = lmc_t1_set_circuit_type, /* set T1 or E1 circuit type */ + .watchdog = lmc_t1_watchdog }; static void diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index 5c47b01..cd39025 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -549,16 +549,12 @@ static void x25_asy_receive_buf(struct tty_struct *tty, static int x25_asy_open_tty(struct tty_struct *tty) { - struct x25_asy *sl = tty->disc_data; + struct x25_asy *sl; int err; if (tty->ops->write == NULL) return -EOPNOTSUPP; - /* First make sure we're not already connected. */ - if (sl && sl->magic == X25_ASY_MAGIC) - return -EEXIST; - /* OK. Find a free X.25 channel to use. */ sl = x25_asy_alloc(); if (sl == NULL) diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c index 2f0bd69..e46ed7b 100644 --- a/drivers/net/wan/z85230.c +++ b/drivers/net/wan/z85230.c @@ -485,9 +485,9 @@ static void z8530_status(struct z8530_channel *chan) struct z8530_irqhandler z8530_sync = { - z8530_rx, - z8530_tx, - z8530_status + .rx = z8530_rx, + .tx = z8530_tx, + .status = z8530_status }; EXPORT_SYMBOL(z8530_sync); @@ -605,15 +605,15 @@ static void z8530_dma_status(struct z8530_channel *chan) } static struct z8530_irqhandler z8530_dma_sync = { - z8530_dma_rx, - z8530_dma_tx, - z8530_dma_status + .rx = z8530_dma_rx, + .tx = z8530_dma_tx, + .status = z8530_dma_status }; static struct z8530_irqhandler z8530_txdma_sync = { - z8530_rx, - z8530_dma_tx, - z8530_dma_status + .rx = z8530_rx, + .tx = z8530_dma_tx, + .status = z8530_dma_status }; /** @@ -680,9 +680,9 @@ static void z8530_status_clear(struct z8530_channel *chan) struct z8530_irqhandler z8530_nop= { - z8530_rx_clear, - z8530_tx_clear, - z8530_status_clear + .rx = z8530_rx_clear, + .tx = z8530_tx_clear, + .status = z8530_status_clear }; diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c index 0b60295..b8bfa5b 100644 --- a/drivers/net/wimax/i2400m/rx.c +++ b/drivers/net/wimax/i2400m/rx.c @@ -1359,7 +1359,7 @@ int i2400m_rx_setup(struct i2400m *i2400m) if (i2400m->rx_roq == NULL) goto error_roq_alloc; - rd = kcalloc(I2400M_RO_CIN + 1, sizeof(*i2400m->rx_roq[0].log), + rd = kcalloc(sizeof(*i2400m->rx_roq[0].log), I2400M_RO_CIN + 1, GFP_KERNEL); if (rd == NULL) { result = -ENOMEM; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index d0c97c2..108f59b 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -7846,7 +7846,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) { struct airo_info *ai = dev->ml_priv; int ridcode; int enabled; - static int (* writer)(struct airo_info *, u16 rid, const void *, int, int); + int (* writer)(struct airo_info *, u16 rid, const void *, int, int); unsigned char *iobuf; /* Only super-user can write RIDs */ diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index dab2513..4c4b65d 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -353,7 +353,7 @@ static int at76_dfu_get_state(struct usb_device *udev, u8 *state) } /* Convert timeout from the DFU status to jiffies */ -static inline unsigned long at76_get_timeout(struct dfu_status *s) +static inline unsigned long __intentional_overflow(-1) at76_get_timeout(struct dfu_status *s) { return msecs_to_jiffies((s->poll_timeout[2] << 16) | (s->poll_timeout[1] << 8) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index cf28fbe..a63dd1b 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -897,12 +897,12 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar, return 0; } -static struct ath10k_ce_ring * +static struct ath10k_ce_ring * __intentional_overflow(-1) ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id, const struct ce_attr *attr) { struct ath10k_ce_ring *src_ring; - u32 nentries = attr->src_nentries; + unsigned long nentries = attr->src_nentries; dma_addr_t base_addr; nentries = roundup_pow_of_two(nentries); @@ -969,7 +969,7 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id, const struct ce_attr *attr) { struct ath10k_ce_ring *dest_ring; - u32 nentries; + unsigned long nentries; dma_addr_t base_addr; nentries = roundup_pow_of_two(attr->dest_nentries); diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 32d9ff1..0952b33 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -841,7 +841,10 @@ int ath10k_htc_start(struct ath10k_htc *htc) /* registered target arrival callback from the HIF layer */ int ath10k_htc_init(struct ath10k *ar) { - struct ath10k_hif_cb htc_callbacks; + static struct ath10k_hif_cb htc_callbacks = { + .rx_completion = ath10k_htc_rx_completion_handler, + .tx_completion = ath10k_htc_tx_completion_handler, + }; struct ath10k_htc_ep *ep = NULL; struct ath10k_htc *htc = &ar->htc; @@ -850,8 +853,6 @@ int ath10k_htc_init(struct ath10k *ar) ath10k_htc_reset_endpoint_states(htc); /* setup HIF layer callbacks */ - htc_callbacks.rx_completion = ath10k_htc_rx_completion_handler; - htc_callbacks.tx_completion = ath10k_htc_tx_completion_handler; htc->ar = ar; /* Get HIF default pipe for HTC message exchange */ diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index 527179c..a890150 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -270,13 +270,13 @@ enum ath10k_htc_ep_id { struct ath10k_htc_ops { void (*target_send_suspend_complete)(struct ath10k *ar); -}; +} __no_const; struct ath10k_htc_ep_ops { void (*ep_tx_complete)(struct ath10k *, struct sk_buff *); void (*ep_rx_complete)(struct ath10k *, struct sk_buff *); void (*ep_tx_credits)(struct ath10k *); -}; +} __no_const; /* service connection information */ struct ath10k_htc_svc_conn_req { diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index fee0cad..a7a3b63 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -3,7 +3,6 @@ config ATH9K_HW config ATH9K_COMMON tristate select ATH_COMMON - select DEBUG_FS select RELAY config ATH9K_DFS_DEBUGFS def_bool y diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index f816909..e56cd8b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -220,8 +220,8 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) ads->ds_txstatus6 = ads->ds_txstatus7 = 0; ads->ds_txstatus8 = ads->ds_txstatus9 = 0; - ACCESS_ONCE(ads->ds_link) = i->link; - ACCESS_ONCE(ads->ds_data) = i->buf_addr[0]; + ACCESS_ONCE_RW(ads->ds_link) = i->link; + ACCESS_ONCE_RW(ads->ds_data) = i->buf_addr[0]; ctl1 = i->buf_len[0] | (i->is_last ? 0 : AR_TxMore); ctl6 = SM(i->keytype, AR_EncrType); @@ -235,26 +235,26 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) if ((i->is_first || i->is_last) && i->aggr != AGGR_BUF_MIDDLE && i->aggr != AGGR_BUF_LAST) { - ACCESS_ONCE(ads->ds_ctl2) = set11nTries(i->rates, 0) + ACCESS_ONCE_RW(ads->ds_ctl2) = set11nTries(i->rates, 0) | set11nTries(i->rates, 1) | set11nTries(i->rates, 2) | set11nTries(i->rates, 3) | (i->dur_update ? AR_DurUpdateEna : 0) | SM(0, AR_BurstDur); - ACCESS_ONCE(ads->ds_ctl3) = set11nRate(i->rates, 0) + ACCESS_ONCE_RW(ads->ds_ctl3) = set11nRate(i->rates, 0) | set11nRate(i->rates, 1) | set11nRate(i->rates, 2) | set11nRate(i->rates, 3); } else { - ACCESS_ONCE(ads->ds_ctl2) = 0; - ACCESS_ONCE(ads->ds_ctl3) = 0; + ACCESS_ONCE_RW(ads->ds_ctl2) = 0; + ACCESS_ONCE_RW(ads->ds_ctl3) = 0; } if (!i->is_first) { - ACCESS_ONCE(ads->ds_ctl0) = 0; - ACCESS_ONCE(ads->ds_ctl1) = ctl1; - ACCESS_ONCE(ads->ds_ctl6) = ctl6; + ACCESS_ONCE_RW(ads->ds_ctl0) = 0; + ACCESS_ONCE_RW(ads->ds_ctl1) = ctl1; + ACCESS_ONCE_RW(ads->ds_ctl6) = ctl6; return; } @@ -279,7 +279,7 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) break; } - ACCESS_ONCE(ads->ds_ctl0) = (i->pkt_len & AR_FrameLen) + ACCESS_ONCE_RW(ads->ds_ctl0) = (i->pkt_len & AR_FrameLen) | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) | SM(i->txpower[0], AR_XmitPower0) | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) @@ -289,27 +289,27 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) | (i->flags & ATH9K_TXDESC_RTSENA ? AR_RTSEnable : (i->flags & ATH9K_TXDESC_CTSENA ? AR_CTSEnable : 0)); - ACCESS_ONCE(ads->ds_ctl1) = ctl1; - ACCESS_ONCE(ads->ds_ctl6) = ctl6; + ACCESS_ONCE_RW(ads->ds_ctl1) = ctl1; + ACCESS_ONCE_RW(ads->ds_ctl6) = ctl6; if (i->aggr == AGGR_BUF_MIDDLE || i->aggr == AGGR_BUF_LAST) return; - ACCESS_ONCE(ads->ds_ctl4) = set11nPktDurRTSCTS(i->rates, 0) + ACCESS_ONCE_RW(ads->ds_ctl4) = set11nPktDurRTSCTS(i->rates, 0) | set11nPktDurRTSCTS(i->rates, 1); - ACCESS_ONCE(ads->ds_ctl5) = set11nPktDurRTSCTS(i->rates, 2) + ACCESS_ONCE_RW(ads->ds_ctl5) = set11nPktDurRTSCTS(i->rates, 2) | set11nPktDurRTSCTS(i->rates, 3); - ACCESS_ONCE(ads->ds_ctl7) = set11nRateFlags(i->rates, 0) + ACCESS_ONCE_RW(ads->ds_ctl7) = set11nRateFlags(i->rates, 0) | set11nRateFlags(i->rates, 1) | set11nRateFlags(i->rates, 2) | set11nRateFlags(i->rates, 3) | SM(i->rtscts_rate, AR_RTSCTSRate); - ACCESS_ONCE(ads->ds_ctl9) = SM(i->txpower[1], AR_XmitPower1); - ACCESS_ONCE(ads->ds_ctl10) = SM(i->txpower[2], AR_XmitPower2); - ACCESS_ONCE(ads->ds_ctl11) = SM(i->txpower[3], AR_XmitPower3); + ACCESS_ONCE_RW(ads->ds_ctl9) = SM(i->txpower[1], AR_XmitPower1); + ACCESS_ONCE_RW(ads->ds_ctl10) = SM(i->txpower[2], AR_XmitPower2); + ACCESS_ONCE_RW(ads->ds_ctl11) = SM(i->txpower[3], AR_XmitPower3); } static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index da84b70..83e4978 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -39,47 +39,47 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) (i->qcu << AR_TxQcuNum_S) | desc_len; checksum += val; - ACCESS_ONCE(ads->info) = val; + ACCESS_ONCE_RW(ads->info) = val; checksum += i->link; - ACCESS_ONCE(ads->link) = i->link; + ACCESS_ONCE_RW(ads->link) = i->link; checksum += i->buf_addr[0]; - ACCESS_ONCE(ads->data0) = i->buf_addr[0]; + ACCESS_ONCE_RW(ads->data0) = i->buf_addr[0]; checksum += i->buf_addr[1]; - ACCESS_ONCE(ads->data1) = i->buf_addr[1]; + ACCESS_ONCE_RW(ads->data1) = i->buf_addr[1]; checksum += i->buf_addr[2]; - ACCESS_ONCE(ads->data2) = i->buf_addr[2]; + ACCESS_ONCE_RW(ads->data2) = i->buf_addr[2]; checksum += i->buf_addr[3]; - ACCESS_ONCE(ads->data3) = i->buf_addr[3]; + ACCESS_ONCE_RW(ads->data3) = i->buf_addr[3]; checksum += (val = (i->buf_len[0] << AR_BufLen_S) & AR_BufLen); - ACCESS_ONCE(ads->ctl3) = val; + ACCESS_ONCE_RW(ads->ctl3) = val; checksum += (val = (i->buf_len[1] << AR_BufLen_S) & AR_BufLen); - ACCESS_ONCE(ads->ctl5) = val; + ACCESS_ONCE_RW(ads->ctl5) = val; checksum += (val = (i->buf_len[2] << AR_BufLen_S) & AR_BufLen); - ACCESS_ONCE(ads->ctl7) = val; + ACCESS_ONCE_RW(ads->ctl7) = val; checksum += (val = (i->buf_len[3] << AR_BufLen_S) & AR_BufLen); - ACCESS_ONCE(ads->ctl9) = val; + ACCESS_ONCE_RW(ads->ctl9) = val; checksum = (u16) (((checksum & 0xffff) + (checksum >> 16)) & 0xffff); - ACCESS_ONCE(ads->ctl10) = checksum; + ACCESS_ONCE_RW(ads->ctl10) = checksum; if (i->is_first || i->is_last) { - ACCESS_ONCE(ads->ctl13) = set11nTries(i->rates, 0) + ACCESS_ONCE_RW(ads->ctl13) = set11nTries(i->rates, 0) | set11nTries(i->rates, 1) | set11nTries(i->rates, 2) | set11nTries(i->rates, 3) | (i->dur_update ? AR_DurUpdateEna : 0) | SM(0, AR_BurstDur); - ACCESS_ONCE(ads->ctl14) = set11nRate(i->rates, 0) + ACCESS_ONCE_RW(ads->ctl14) = set11nRate(i->rates, 0) | set11nRate(i->rates, 1) | set11nRate(i->rates, 2) | set11nRate(i->rates, 3); } else { - ACCESS_ONCE(ads->ctl13) = 0; - ACCESS_ONCE(ads->ctl14) = 0; + ACCESS_ONCE_RW(ads->ctl13) = 0; + ACCESS_ONCE_RW(ads->ctl14) = 0; } ads->ctl20 = 0; @@ -89,17 +89,17 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) ctl17 = SM(i->keytype, AR_EncrType); if (!i->is_first) { - ACCESS_ONCE(ads->ctl11) = 0; - ACCESS_ONCE(ads->ctl12) = i->is_last ? 0 : AR_TxMore; - ACCESS_ONCE(ads->ctl15) = 0; - ACCESS_ONCE(ads->ctl16) = 0; - ACCESS_ONCE(ads->ctl17) = ctl17; - ACCESS_ONCE(ads->ctl18) = 0; - ACCESS_ONCE(ads->ctl19) = 0; + ACCESS_ONCE_RW(ads->ctl11) = 0; + ACCESS_ONCE_RW(ads->ctl12) = i->is_last ? 0 : AR_TxMore; + ACCESS_ONCE_RW(ads->ctl15) = 0; + ACCESS_ONCE_RW(ads->ctl16) = 0; + ACCESS_ONCE_RW(ads->ctl17) = ctl17; + ACCESS_ONCE_RW(ads->ctl18) = 0; + ACCESS_ONCE_RW(ads->ctl19) = 0; return; } - ACCESS_ONCE(ads->ctl11) = (i->pkt_len & AR_FrameLen) + ACCESS_ONCE_RW(ads->ctl11) = (i->pkt_len & AR_FrameLen) | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) | SM(i->txpower[0], AR_XmitPower0) | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) @@ -135,26 +135,26 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) val = (i->flags & ATH9K_TXDESC_PAPRD) >> ATH9K_TXDESC_PAPRD_S; ctl12 |= SM(val, AR_PAPRDChainMask); - ACCESS_ONCE(ads->ctl12) = ctl12; - ACCESS_ONCE(ads->ctl17) = ctl17; + ACCESS_ONCE_RW(ads->ctl12) = ctl12; + ACCESS_ONCE_RW(ads->ctl17) = ctl17; - ACCESS_ONCE(ads->ctl15) = set11nPktDurRTSCTS(i->rates, 0) + ACCESS_ONCE_RW(ads->ctl15) = set11nPktDurRTSCTS(i->rates, 0) | set11nPktDurRTSCTS(i->rates, 1); - ACCESS_ONCE(ads->ctl16) = set11nPktDurRTSCTS(i->rates, 2) + ACCESS_ONCE_RW(ads->ctl16) = set11nPktDurRTSCTS(i->rates, 2) | set11nPktDurRTSCTS(i->rates, 3); - ACCESS_ONCE(ads->ctl18) = set11nRateFlags(i->rates, 0) + ACCESS_ONCE_RW(ads->ctl18) = set11nRateFlags(i->rates, 0) | set11nRateFlags(i->rates, 1) | set11nRateFlags(i->rates, 2) | set11nRateFlags(i->rates, 3) | SM(i->rtscts_rate, AR_RTSCTSRate); - ACCESS_ONCE(ads->ctl19) = AR_Not_Sounding; + ACCESS_ONCE_RW(ads->ctl19) = AR_Not_Sounding; - ACCESS_ONCE(ads->ctl20) = SM(i->txpower[1], AR_XmitPower1); - ACCESS_ONCE(ads->ctl21) = SM(i->txpower[2], AR_XmitPower2); - ACCESS_ONCE(ads->ctl22) = SM(i->txpower[3], AR_XmitPower3); + ACCESS_ONCE_RW(ads->ctl20) = SM(i->txpower[1], AR_XmitPower1); + ACCESS_ONCE_RW(ads->ctl21) = SM(i->txpower[2], AR_XmitPower2); + ACCESS_ONCE_RW(ads->ctl22) = SM(i->txpower[3], AR_XmitPower3); } static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index e8454db..c7b26fe 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -671,7 +671,7 @@ struct ath_hw_private_ops { #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT bool (*is_aic_enabled)(struct ath_hw *ah); #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ -}; +} __no_const; /** * struct ath_spec_scan - parameters for Atheros spectral scan @@ -747,7 +747,7 @@ struct ath_hw_ops { #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT void (*set_bt_ant_diversity)(struct ath_hw *hw, bool enable); #endif -}; +} __no_const; 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 c27143b..bd90160 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2579,16 +2579,18 @@ void ath9k_fill_chanctx_ops(void) if (!ath9k_is_chanctx_enabled()) return; - ath9k_ops.hw_scan = ath9k_hw_scan; - ath9k_ops.cancel_hw_scan = ath9k_cancel_hw_scan; - ath9k_ops.remain_on_channel = ath9k_remain_on_channel; - ath9k_ops.cancel_remain_on_channel = ath9k_cancel_remain_on_channel; - ath9k_ops.add_chanctx = ath9k_add_chanctx; - ath9k_ops.remove_chanctx = ath9k_remove_chanctx; - ath9k_ops.change_chanctx = ath9k_change_chanctx; - ath9k_ops.assign_vif_chanctx = ath9k_assign_vif_chanctx; - 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; + pax_close_kernel(); } #endif diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h index d7fa19b..6d84263 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.h +++ b/drivers/net/wireless/ath/wil6210/wil_platform.h @@ -27,7 +27,7 @@ struct wil_platform_ops { int (*suspend)(void *handle); int (*resume)(void *handle); void (*uninit)(void *handle); -}; +} __no_const; void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops); diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 058a9f2..d5cb1ba 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -2502,7 +2502,7 @@ static int lpphy_b2063_tune(struct b43_wldev *dev, { struct ssb_bus *bus = dev->dev->sdev->bus; - static const struct b206x_channel *chandata = NULL; + const struct b206x_channel *chandata = NULL; u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; u32 freqref, vco_freq, val1, val2, val3, timeout, timeoutref, count; u16 old_comm15, scale; diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index af1b3e6..d5d82713 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -3633,7 +3633,9 @@ il3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) */ if (il3945_mod_params.disable_hw_scan) { D_INFO("Disabling hw_scan\n"); - il3945_mac_ops.hw_scan = NULL; + pax_open_kernel(); + *(void **)&il3945_mac_ops.hw_scan = NULL; + pax_close_kernel(); } D_INFO("*** LOAD DRIVER ***\n"); diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index b15e44f..8658af2 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c @@ -188,7 +188,7 @@ static ssize_t iwl_dbgfs_sram_write(struct file *file, { struct iwl_priv *priv = file->private_data; char buf[64]; - int buf_size; + size_t buf_size; u32 offset, len; memset(buf, 0, sizeof(buf)); @@ -454,7 +454,7 @@ static ssize_t iwl_dbgfs_rx_handlers_write(struct file *file, struct iwl_priv *priv = file->private_data; char buf[8]; - int buf_size; + size_t buf_size; u32 reset_flag; memset(buf, 0, sizeof(buf)); @@ -535,7 +535,7 @@ static ssize_t iwl_dbgfs_disable_ht40_write(struct file *file, { struct iwl_priv *priv = file->private_data; char buf[8]; - int buf_size; + size_t buf_size; int ht40; memset(buf, 0, sizeof(buf)); @@ -587,7 +587,7 @@ static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file, { struct iwl_priv *priv = file->private_data; char buf[8]; - int buf_size; + size_t buf_size; int value; memset(buf, 0, sizeof(buf)); @@ -679,10 +679,10 @@ DEBUGFS_READ_FILE_OPS(temperature); DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override); DEBUGFS_READ_FILE_OPS(current_sleep_command); -static const char *fmt_value = " %-30s %10u\n"; -static const char *fmt_hex = " %-30s 0x%02X\n"; -static const char *fmt_table = " %-30s %10u %10u %10u %10u\n"; -static const char *fmt_header = +static const char fmt_value[] = " %-30s %10u\n"; +static const char fmt_hex[] = " %-30s 0x%02X\n"; +static const char fmt_table[] = " %-30s %10u %10u %10u %10u\n"; +static const char fmt_header[] = "%-32s current cumulative delta max\n"; static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) @@ -1852,7 +1852,7 @@ static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file, { struct iwl_priv *priv = file->private_data; char buf[8]; - int buf_size; + size_t buf_size; int clear; memset(buf, 0, sizeof(buf)); @@ -1897,7 +1897,7 @@ static ssize_t iwl_dbgfs_ucode_tracing_write(struct file *file, { struct iwl_priv *priv = file->private_data; char buf[8]; - int buf_size; + size_t buf_size; int trace; memset(buf, 0, sizeof(buf)); @@ -1968,7 +1968,7 @@ static ssize_t iwl_dbgfs_missed_beacon_write(struct file *file, { struct iwl_priv *priv = file->private_data; char buf[8]; - int buf_size; + size_t buf_size; int missed; memset(buf, 0, sizeof(buf)); @@ -2009,7 +2009,7 @@ static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file, struct iwl_priv *priv = file->private_data; char buf[8]; - int buf_size; + size_t buf_size; int plcp; memset(buf, 0, sizeof(buf)); @@ -2069,7 +2069,7 @@ static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file, struct iwl_priv *priv = file->private_data; char buf[8]; - int buf_size; + size_t buf_size; int flush; memset(buf, 0, sizeof(buf)); @@ -2159,7 +2159,7 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file, struct iwl_priv *priv = file->private_data; char buf[8]; - int buf_size; + size_t buf_size; int rts; if (!priv->cfg->ht_params) @@ -2200,7 +2200,7 @@ static ssize_t iwl_dbgfs_echo_test_write(struct file *file, { struct iwl_priv *priv = file->private_data; char buf[8]; - int buf_size; + size_t buf_size; memset(buf, 0, sizeof(buf)); buf_size = min(count, sizeof(buf) - 1); @@ -2234,7 +2234,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, struct iwl_priv *priv = file->private_data; u32 event_log_flag; char buf[8]; - int buf_size; + size_t buf_size; /* check that the interface is up */ if (!iwl_is_ready(priv)) @@ -2288,7 +2288,7 @@ static ssize_t iwl_dbgfs_calib_disabled_write(struct file *file, struct iwl_priv *priv = file->private_data; char buf[8]; u32 calib_disabled; - int buf_size; + size_t buf_size; memset(buf, 0, sizeof(buf)); buf_size = min(count, sizeof(buf) - 1); diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 9028345..5b66ca3 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -2049,7 +2049,7 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file, struct isr_statistics *isr_stats = &trans_pcie->isr_stats; char buf[8]; - int buf_size; + size_t buf_size; u32 reset_flag; memset(buf, 0, sizeof(buf)); @@ -2070,7 +2070,7 @@ static ssize_t iwl_dbgfs_csr_write(struct file *file, { struct iwl_trans *trans = file->private_data; char buf[8]; - int buf_size; + size_t buf_size; int csr; memset(buf, 0, sizeof(buf)); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 520bef8..67e3bdf 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -3151,20 +3151,20 @@ static int __init init_mac80211_hwsim(void) if (channels < 1) return -EINVAL; - mac80211_hwsim_mchan_ops = mac80211_hwsim_ops; - mac80211_hwsim_mchan_ops.hw_scan = mac80211_hwsim_hw_scan; - mac80211_hwsim_mchan_ops.cancel_hw_scan = mac80211_hwsim_cancel_hw_scan; - mac80211_hwsim_mchan_ops.sw_scan_start = NULL; - mac80211_hwsim_mchan_ops.sw_scan_complete = NULL; - mac80211_hwsim_mchan_ops.remain_on_channel = mac80211_hwsim_roc; - mac80211_hwsim_mchan_ops.cancel_remain_on_channel = mac80211_hwsim_croc; - mac80211_hwsim_mchan_ops.add_chanctx = mac80211_hwsim_add_chanctx; - mac80211_hwsim_mchan_ops.remove_chanctx = mac80211_hwsim_remove_chanctx; - mac80211_hwsim_mchan_ops.change_chanctx = mac80211_hwsim_change_chanctx; - mac80211_hwsim_mchan_ops.assign_vif_chanctx = - mac80211_hwsim_assign_vif_chanctx; - mac80211_hwsim_mchan_ops.unassign_vif_chanctx = - 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; + pax_close_kernel(); spin_lock_init(&hwsim_radio_lock); INIT_LIST_HEAD(&hwsim_radios); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 71a825c..ce7d6c3 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1236,7 +1236,7 @@ static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold) netdev_dbg(usbdev->net, "%s(): %i\n", __func__, rts_threshold); - if (rts_threshold < 0 || rts_threshold > 2347) + if (rts_threshold > 2347) rts_threshold = 2347; tmp = cpu_to_le32(rts_threshold); diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 3282ddb..26aabb5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -377,7 +377,7 @@ struct rt2x00_intf { * for hardware which doesn't support hardware * sequence counting. */ - atomic_t seqno; + atomic_unchecked_t seqno; }; static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 68b620b..92ecd9e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -224,9 +224,9 @@ static void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev, * sequence counter given by mac80211. */ if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)) - seqno = atomic_add_return(0x10, &intf->seqno); + seqno = atomic_add_return_unchecked(0x10, &intf->seqno); else - seqno = atomic_read(&intf->seqno); + seqno = atomic_read_unchecked(&intf->seqno); hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); hdr->seq_ctrl |= cpu_to_le16(seqno); diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c index b661f896..ddf7d2b 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, irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); - 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; + pax_close_kernel(); wl1251_info("using dedicated interrupt line"); } else { - 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; + 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 af0fe2e..d04986b 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -655,7 +655,9 @@ static int wl12xx_identify_chip(struct wl1271 *wl) sizeof(wl->conf.mem)); /* 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; + pax_close_kernel(); wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, WL127X_IFTYPE_SR_VER, WL127X_MAJOR_SR_VER, @@ -680,7 +682,9 @@ static int wl12xx_identify_chip(struct wl1271 *wl) sizeof(wl->conf.mem)); /* 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; + 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 abbf054..6ad2ddb 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -2005,8 +2005,10 @@ static int wl18xx_setup(struct wl1271 *wl) } if (!checksum_param) { - 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; + pax_close_kernel(); } /* Enable 11a Band only if we have 5G antennas */ diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index a912dc0..a8225ba 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -385,7 +385,7 @@ static inline void handle_regs_int(struct urb *urb) { struct zd_usb *usb = urb->context; struct zd_usb_interrupt *intr = &usb->intr; - int len; + unsigned int len; u16 int_num; ZD_ASSERT(in_interrupt()); diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c index ce2e2cf..f81e500 100644 --- a/drivers/nfc/nfcwilink.c +++ b/drivers/nfc/nfcwilink.c @@ -497,7 +497,7 @@ static struct nci_ops nfcwilink_ops = { static int nfcwilink_probe(struct platform_device *pdev) { - static struct nfcwilink *drv; + struct nfcwilink *drv; int rc; __u32 protocols; diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 6e82bc42..ab4145c 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -1161,7 +1161,9 @@ static int __init of_fdt_raw_init(void) pr_warn("fdt: not creating '/sys/firmware/fdt': CRC check failed\n"); return 0; } - 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); + pax_close_kernel(); return sysfs_create_bin_file(firmware_kobj, &of_fdt_raw_attr); } late_initcall(of_fdt_raw_init); diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 82f7000..d6d0447 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -345,7 +345,7 @@ static void add_data(struct op_entry *entry, struct mm_struct *mm) if (cookie == NO_COOKIE) offset = pc; if (cookie == INVALID_COOKIE) { - atomic_inc(&oprofile_stats.sample_lost_no_mapping); + atomic_inc_unchecked(&oprofile_stats.sample_lost_no_mapping); offset = pc; } if (cookie != last_cookie) { @@ -389,14 +389,14 @@ add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel) /* add userspace sample */ if (!mm) { - atomic_inc(&oprofile_stats.sample_lost_no_mm); + atomic_inc_unchecked(&oprofile_stats.sample_lost_no_mm); return 0; } cookie = lookup_dcookie(mm, s->eip, &offset); if (cookie == INVALID_COOKIE) { - atomic_inc(&oprofile_stats.sample_lost_no_mapping); + atomic_inc_unchecked(&oprofile_stats.sample_lost_no_mapping); return 0; } @@ -554,7 +554,7 @@ void sync_buffer(int cpu) /* ignore backtraces if failed to add a sample */ if (state == sb_bt_start) { state = sb_bt_ignore; - atomic_inc(&oprofile_stats.bt_lost_no_mapping); + atomic_inc_unchecked(&oprofile_stats.bt_lost_no_mapping); } } release_mm(mm); diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c index c0cc4e7..44d4e54 100644 --- a/drivers/oprofile/event_buffer.c +++ b/drivers/oprofile/event_buffer.c @@ -53,7 +53,7 @@ void add_event_entry(unsigned long value) } if (buffer_pos == buffer_size) { - atomic_inc(&oprofile_stats.event_lost_overflow); + atomic_inc_unchecked(&oprofile_stats.event_lost_overflow); return; } diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index ed2c3ec..deda85a 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -110,7 +110,7 @@ static void switch_worker(struct work_struct *work) if (oprofile_ops.switch_events()) return; - atomic_inc(&oprofile_stats.multiplex_counter); + atomic_inc_unchecked(&oprofile_stats.multiplex_counter); start_switch_worker(); } diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index 59659ce..6c860a0 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c @@ -30,11 +30,11 @@ void oprofile_reset_stats(void) cpu_buf->sample_invalid_eip = 0; } - atomic_set(&oprofile_stats.sample_lost_no_mm, 0); - atomic_set(&oprofile_stats.sample_lost_no_mapping, 0); - atomic_set(&oprofile_stats.event_lost_overflow, 0); - atomic_set(&oprofile_stats.bt_lost_no_mapping, 0); - atomic_set(&oprofile_stats.multiplex_counter, 0); + atomic_set_unchecked(&oprofile_stats.sample_lost_no_mm, 0); + atomic_set_unchecked(&oprofile_stats.sample_lost_no_mapping, 0); + atomic_set_unchecked(&oprofile_stats.event_lost_overflow, 0); + atomic_set_unchecked(&oprofile_stats.bt_lost_no_mapping, 0); + atomic_set_unchecked(&oprofile_stats.multiplex_counter, 0); } diff --git a/drivers/oprofile/oprofile_stats.h b/drivers/oprofile/oprofile_stats.h index 1fc622b..8c48fc3 100644 --- a/drivers/oprofile/oprofile_stats.h +++ b/drivers/oprofile/oprofile_stats.h @@ -13,11 +13,11 @@ #include struct oprofile_stat_struct { - atomic_t sample_lost_no_mm; - atomic_t sample_lost_no_mapping; - atomic_t bt_lost_no_mapping; - atomic_t event_lost_overflow; - atomic_t multiplex_counter; + atomic_unchecked_t sample_lost_no_mm; + atomic_unchecked_t sample_lost_no_mapping; + atomic_unchecked_t bt_lost_no_mapping; + atomic_unchecked_t event_lost_overflow; + atomic_unchecked_t multiplex_counter; }; extern struct oprofile_stat_struct oprofile_stats; diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index dd92c5e..dfc04b5 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -176,8 +176,8 @@ int oprofilefs_create_ro_ulong(struct dentry *root, static ssize_t atomic_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset) { - atomic_t *val = file->private_data; - return oprofilefs_ulong_to_user(atomic_read(val), buf, count, offset); + atomic_unchecked_t *val = file->private_data; + return oprofilefs_ulong_to_user(atomic_read_unchecked(val), buf, count, offset); } @@ -189,7 +189,7 @@ static const struct file_operations atomic_ro_fops = { int oprofilefs_create_ro_atomic(struct dentry *root, - char const *name, atomic_t *val) + char const *name, atomic_unchecked_t *val) { return __oprofilefs_create_file(root, name, &atomic_ro_fops, 0444, val); diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c index bdef916..88c7dee 100644 --- a/drivers/oprofile/timer_int.c +++ b/drivers/oprofile/timer_int.c @@ -93,7 +93,7 @@ static int oprofile_cpu_notify(struct notifier_block *self, return NOTIFY_OK; } -static struct notifier_block __refdata oprofile_cpu_notifier = { +static struct notifier_block oprofile_cpu_notifier = { .notifier_call = oprofile_cpu_notify, }; diff --git a/drivers/parport/procfs.c b/drivers/parport/procfs.c index c776333..aa6b325 100644 --- a/drivers/parport/procfs.c +++ b/drivers/parport/procfs.c @@ -65,7 +65,7 @@ static int do_active_device(struct ctl_table *table, int write, *ppos += len; - return copy_to_user(result, buffer, len) ? -EFAULT : 0; + return (len > sizeof buffer || copy_to_user(result, buffer, len)) ? -EFAULT : 0; } #ifdef CONFIG_PARPORT_1284 @@ -107,7 +107,7 @@ static int do_autoprobe(struct ctl_table *table, int write, *ppos += len; - return copy_to_user (result, buffer, len) ? -EFAULT : 0; + return (len > sizeof buffer || copy_to_user (result, buffer, len)) ? -EFAULT : 0; } #endif /* IEEE1284.3 support. */ diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c index 265dd25..41a02dd 100644 --- a/drivers/pci/host/pci-host-generic.c +++ b/drivers/pci/host/pci-host-generic.c @@ -26,9 +26,9 @@ #include struct gen_pci_cfg_bus_ops { + struct pci_ops ops; u32 bus_shift; - void __iomem *(*map_bus)(struct pci_bus *, unsigned int, int); -}; +} __do_const; struct gen_pci_cfg_windows { struct resource res; @@ -64,8 +64,12 @@ static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus, } static struct gen_pci_cfg_bus_ops gen_pci_cfg_cam_bus_ops = { + .ops = { + .map_bus = gen_pci_map_cfg_bus_cam, + .read = pci_generic_config_read, + .write = pci_generic_config_write, + }, .bus_shift = 16, - .map_bus = gen_pci_map_cfg_bus_cam, }; static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus, @@ -79,13 +83,12 @@ static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus, } static struct gen_pci_cfg_bus_ops gen_pci_cfg_ecam_bus_ops = { + .ops = { + .map_bus = gen_pci_map_cfg_bus_ecam, + .read = pci_generic_config_read, + .write = pci_generic_config_write, + }, .bus_shift = 20, - .map_bus = gen_pci_map_cfg_bus_ecam, -}; - -static struct pci_ops gen_pci_ops = { - .read = pci_generic_config_read, - .write = pci_generic_config_write, }; static const struct of_device_id gen_pci_of_match[] = { @@ -235,7 +238,6 @@ static int gen_pci_probe(struct platform_device *pdev) of_id = of_match_node(gen_pci_of_match, np); pci->cfg.ops = of_id->data; - gen_pci_ops.map_bus = pci->cfg.ops->map_bus; pci->host.dev.parent = dev; INIT_LIST_HEAD(&pci->host.windows); INIT_LIST_HEAD(&pci->resources); @@ -256,7 +258,7 @@ static int gen_pci_probe(struct platform_device *pdev) if (!pci_has_flag(PCI_PROBE_ONLY)) pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS); - bus = pci_scan_root_bus(dev, 0, &gen_pci_ops, pci, &pci->resources); + bus = pci_scan_root_bus(dev, 0, &pci->cfg.ops->ops, pci, &pci->resources); if (!bus) { dev_err(dev, "Scanning rootbus failed"); return -ENODEV; diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index 6ca2399..68d866b 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -452,7 +452,9 @@ static int __init ibm_acpiphp_init(void) goto init_cleanup; } - 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); + pax_close_kernel(); retval = sysfs_create_bin_file(sysdir, &ibm_apci_table_attr); return retval; diff --git a/drivers/pci/hotplug/cpcihp_generic.c b/drivers/pci/hotplug/cpcihp_generic.c index 66b7bbe..26bee78 100644 --- a/drivers/pci/hotplug/cpcihp_generic.c +++ b/drivers/pci/hotplug/cpcihp_generic.c @@ -73,7 +73,6 @@ static u16 port; static unsigned int enum_bit; static u8 enum_mask; -static struct cpci_hp_controller_ops generic_hpc_ops; static struct cpci_hp_controller generic_hpc; static int __init validate_parameters(void) @@ -139,6 +138,10 @@ static int query_enum(void) return ((value & enum_mask) == enum_mask); } +static struct cpci_hp_controller_ops generic_hpc_ops = { + .query_enum = query_enum, +}; + static int __init cpcihp_generic_init(void) { int status; @@ -165,7 +168,6 @@ static int __init cpcihp_generic_init(void) pci_dev_put(dev); memset(&generic_hpc, 0, sizeof (struct cpci_hp_controller)); - generic_hpc_ops.query_enum = query_enum; generic_hpc.ops = &generic_hpc_ops; status = cpci_hp_register_controller(&generic_hpc); diff --git a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c index 7ecf34e..effed62 100644 --- a/drivers/pci/hotplug/cpcihp_zt5550.c +++ b/drivers/pci/hotplug/cpcihp_zt5550.c @@ -59,7 +59,6 @@ /* local variables */ static bool debug; static bool poll; -static struct cpci_hp_controller_ops zt5550_hpc_ops; static struct cpci_hp_controller zt5550_hpc; /* Primary cPCI bus bridge device */ @@ -204,6 +203,10 @@ static int zt5550_hc_disable_irq(void) return 0; } +static struct cpci_hp_controller_ops zt5550_hpc_ops = { + .query_enum = zt5550_hc_query_enum, +}; + static int zt5550_hc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { int status; @@ -215,16 +218,17 @@ static int zt5550_hc_init_one (struct pci_dev *pdev, const struct pci_device_id dbg("returned from zt5550_hc_config"); memset(&zt5550_hpc, 0, sizeof (struct cpci_hp_controller)); - zt5550_hpc_ops.query_enum = zt5550_hc_query_enum; zt5550_hpc.ops = &zt5550_hpc_ops; if (!poll) { zt5550_hpc.irq = hc_dev->irq; zt5550_hpc.irq_flags = IRQF_SHARED; zt5550_hpc.dev_id = hc_dev; - zt5550_hpc_ops.enable_irq = zt5550_hc_enable_irq; - 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; + pax_open_kernel(); } else { info("using ENUM# polling mode"); } diff --git a/drivers/pci/hotplug/cpqphp_nvram.c b/drivers/pci/hotplug/cpqphp_nvram.c index 1e08ff8c..3cd145f 100644 --- a/drivers/pci/hotplug/cpqphp_nvram.c +++ b/drivers/pci/hotplug/cpqphp_nvram.c @@ -425,8 +425,10 @@ static u32 store_HRT (void __iomem *rom_start) void compaq_nvram_init (void __iomem *rom_start) { +#ifndef CONFIG_PAX_KERNEXEC if (rom_start) compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR); +#endif 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 d1fab97..71d04bf 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -436,8 +436,10 @@ int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, return -EINVAL; } - 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; + pax_close_kernel(); mutex_lock(&pci_hp_mutex); /* diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 612b21a..9494a5e 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -87,7 +87,7 @@ static int init_slot(struct controller *ctrl) struct slot *slot = ctrl->slot; struct hotplug_slot *hotplug = NULL; struct hotplug_slot_info *info = NULL; - struct hotplug_slot_ops *ops = NULL; + hotplug_slot_ops_no_const *ops = NULL; char name[SLOT_NAME_SIZE]; int retval = -ENOMEM; diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 4a7da3c..74dbaf1 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -468,8 +468,8 @@ static int populate_msi_sysfs(struct pci_dev *pdev) { struct attribute **msi_attrs; struct attribute *msi_attr; - struct device_attribute *msi_dev_attr; - struct attribute_group *msi_irq_group; + device_attribute_no_const *msi_dev_attr; + attribute_group_no_const *msi_irq_group; const struct attribute_group **msi_irq_groups; struct msi_desc *entry; int ret = -ENOMEM; @@ -528,7 +528,7 @@ error_attrs: count = 0; msi_attr = msi_attrs[count]; while (msi_attr) { - msi_dev_attr = container_of(msi_attr, struct device_attribute, attr); + msi_dev_attr = container_of(msi_attr, device_attribute_no_const, attr); kfree(msi_attr->name); kfree(msi_dev_attr); ++count; @@ -1227,12 +1227,14 @@ static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info) if (ops == NULL) { info->ops = &pci_msi_domain_ops_default; } else { + 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; if (ops->msi_check == NULL) - ops->msi_check = pci_msi_domain_check_cap; + *(void **)&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; + pax_close_kernel(); } } @@ -1241,12 +1243,14 @@ static void pci_msi_domain_update_chip_ops(struct msi_domain_info *info) struct irq_chip *chip = info->chip; BUG_ON(!chip); + 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; if (!chip->irq_mask) - chip->irq_mask = pci_msi_mask_irq; + *(void **)&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; + pax_close_kernel(); } /** diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 9261868..8b7d036 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -216,7 +216,7 @@ static ssize_t numa_node_store(struct device *dev, if (ret) return ret; - if (node >= MAX_NUMNODES || !node_online(node)) + if (node < 0 || node >= MAX_NUMNODES || !node_online(node)) return -EINVAL; add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); @@ -1140,7 +1140,7 @@ static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine) { /* allocate attribute structure, piggyback attribute name */ int name_len = write_combine ? 13 : 10; - struct bin_attribute *res_attr; + bin_attribute_no_const *res_attr; int retval; res_attr = kzalloc(sizeof(*res_attr) + name_len, GFP_ATOMIC); @@ -1317,7 +1317,7 @@ static struct device_attribute reset_attr = __ATTR(reset, 0200, NULL, reset_stor static int pci_create_capabilities_sysfs(struct pci_dev *dev) { int retval; - struct bin_attribute *attr; + bin_attribute_no_const *attr; /* If the device has VPD, try to expose it in sysfs. */ if (dev->vpd) { @@ -1364,7 +1364,7 @@ int __must_check pci_create_sysfs_dev_files(struct pci_dev *pdev) { int retval; int rom_size = 0; - struct bin_attribute *attr; + bin_attribute_no_const *attr; if (!sysfs_initialized) return -EACCES; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 24ba9dc..d2711f9 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -101,7 +101,7 @@ struct pci_vpd_ops { struct pci_vpd { unsigned int len; const struct pci_vpd_ops *ops; - struct bin_attribute *attr; /* descriptor for sysfs VPD entry */ + bin_attribute_no_const *attr; /* descriptor for sysfs VPD entry */ }; int pci_vpd_pci22_init(struct pci_dev *dev); diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 317e355..21f7b91 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -27,9 +27,9 @@ #define MODULE_PARAM_PREFIX "pcie_aspm." /* Note: those are not register definitions */ -#define ASPM_STATE_L0S_UP (1) /* Upstream direction L0s state */ -#define ASPM_STATE_L0S_DW (2) /* Downstream direction L0s state */ -#define ASPM_STATE_L1 (4) /* L1 state */ +#define ASPM_STATE_L0S_UP (1U) /* Upstream direction L0s state */ +#define ASPM_STATE_L0S_DW (2U) /* Downstream direction L0s state */ +#define ASPM_STATE_L1 (4U) /* L1 state */ #define ASPM_STATE_L0S (ASPM_STATE_L0S_UP | ASPM_STATE_L0S_DW) #define ASPM_STATE_ALL (ASPM_STATE_L0S | ASPM_STATE_L1) diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index be35da2..ec16cdb 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -324,7 +324,7 @@ static int __init dmi_pcie_pme_disable_msi(const struct dmi_system_id *d) return 0; } -static struct dmi_system_id __initdata pcie_portdrv_dmi_table[] = { +static const struct dmi_system_id __initconst pcie_portdrv_dmi_table[] = { /* * Boxes that should not use MSI for PCIe PME signaling. */ diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 8361d27..d81f096 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -176,7 +176,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, u16 orig_cmd; struct pci_bus_region region, inverted_region; - mask = type ? PCI_ROM_ADDRESS_MASK : ~0; + mask = type ? (u32)PCI_ROM_ADDRESS_MASK : ~0; /* No printks while decoding is disabled! */ if (!dev->mmio_always_on) { diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 3f155e7..0f4b1f0 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -434,7 +434,16 @@ static const struct file_operations proc_bus_pci_dev_operations = { static int __init pci_proc_init(void) { struct pci_dev *dev = NULL; + +#ifdef CONFIG_GRKERNSEC_PROC_ADD +#ifdef CONFIG_GRKERNSEC_PROC_USER + proc_bus_pci_dir = proc_mkdir_mode("bus/pci", S_IRUSR | S_IXUSR, NULL); +#elif defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + proc_bus_pci_dir = proc_mkdir_mode("bus/pci", S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP, NULL); +#endif +#else proc_bus_pci_dir = proc_mkdir("bus/pci", NULL); +#endif proc_create("devices", 0, proc_bus_pci_dir, &proc_bus_pci_dev_operations); proc_initialized = 1; diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index 96cf039..ad82396 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -1230,7 +1230,7 @@ static int nmk_gpio_probe(struct platform_device *dev) struct device_node *np = dev->dev.of_node; struct nmk_gpio_chip *nmk_chip; struct gpio_chip *chip; - struct irq_chip *irqchip; + irq_chip_no_const *irqchip; int latent_irq; bool supports_sleepmode; int irq; diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index b0fde0f..70d6a7b 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -24,6 +24,7 @@ #include /* Since we request GPIOs from ourself */ #include +#include #include "pinctrl-at91.h" #include "core.h" @@ -1632,7 +1633,9 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev, at91_gpio->pioc_hwirq = irqd_to_hwirq(d); /* 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; + pax_close_kernel(); /* Disable irqs of this PIO controller */ writel_relaxed(~0, at91_gpio->regbase + PIO_IDR); diff --git a/drivers/platform/chrome/chromeos_pstore.c b/drivers/platform/chrome/chromeos_pstore.c index 3474920..acc9581 100644 --- a/drivers/platform/chrome/chromeos_pstore.c +++ b/drivers/platform/chrome/chromeos_pstore.c @@ -13,7 +13,7 @@ #include #include -static struct dmi_system_id chromeos_pstore_dmi_table[] __initdata = { +static const struct dmi_system_id chromeos_pstore_dmi_table[] __initconst = { { /* * Today all Chromebooks/boxes ship with Google_* as version and diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index 1e1e594..8fe59c5 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -150,7 +150,7 @@ struct wmax_led_args { } __packed; static struct platform_device *platform_device; -static struct device_attribute *zone_dev_attrs; +static device_attribute_no_const *zone_dev_attrs; static struct attribute **zone_attrs; static struct platform_zone *zone_data; @@ -160,7 +160,7 @@ static struct platform_driver platform_driver = { } }; -static struct attribute_group zone_attribute_group = { +static attribute_group_no_const zone_attribute_group = { .name = "rgb_zones", }; diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index efbc3f0..18ae682 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1868,6 +1868,10 @@ static int show_dsts(struct seq_file *m, void *data) int err; u32 retval = -1; +#ifdef CONFIG_GRKERNSEC_KMEM + return -EPERM; +#endif + err = asus_wmi_get_devstate(asus, asus->debug.dev_id, &retval); if (err < 0) @@ -1884,6 +1888,10 @@ static int show_devs(struct seq_file *m, void *data) int err; u32 retval = -1; +#ifdef CONFIG_GRKERNSEC_KMEM + return -EPERM; +#endif + err = asus_wmi_set_devstate(asus->debug.dev_id, asus->debug.ctrl_param, &retval); @@ -1908,6 +1916,10 @@ static int show_call(struct seq_file *m, void *data) union acpi_object *obj; acpi_status status; +#ifdef CONFIG_GRKERNSEC_KMEM + return -EPERM; +#endif + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1, asus->debug.method_id, &input, &output); diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index f2706d2..850edfa4 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c @@ -765,7 +765,7 @@ static int dmi_check_cb_extra(const struct dmi_system_id *id) return 1; } -static struct dmi_system_id __initdata compal_dmi_table[] = { +static const struct dmi_system_id __initconst compal_dmi_table[] = { { .ident = "FL90/IFL90", .matches = { diff --git a/drivers/platform/x86/hdaps.c b/drivers/platform/x86/hdaps.c index 458e6c9..089aee7 100644 --- a/drivers/platform/x86/hdaps.c +++ b/drivers/platform/x86/hdaps.c @@ -514,7 +514,7 @@ static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id) "ThinkPad T42p", so the order of the entries matters. If your ThinkPad is not recognized, please update to latest BIOS. This is especially the case for some R52 ThinkPads. */ -static struct dmi_system_id __initdata hdaps_whitelist[] = { +static const struct dmi_system_id __initconst hdaps_whitelist[] = { HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R50p", HDAPS_BOTH_AXES), HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R50"), HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R51"), diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c index 97c2be1..2ee50ce 100644 --- a/drivers/platform/x86/ibm_rtl.c +++ b/drivers/platform/x86/ibm_rtl.c @@ -227,7 +227,7 @@ static void rtl_teardown_sysfs(void) { } -static struct dmi_system_id __initdata ibm_rtl_dmi_table[] = { +static const struct dmi_system_id __initconst ibm_rtl_dmi_table[] = { { \ .matches = { \ DMI_MATCH(DMI_SYS_VENDOR, "IBM"), \ diff --git a/drivers/platform/x86/intel_oaktrail.c b/drivers/platform/x86/intel_oaktrail.c index 6aa33c4..cfb5425 100644 --- a/drivers/platform/x86/intel_oaktrail.c +++ b/drivers/platform/x86/intel_oaktrail.c @@ -299,7 +299,7 @@ static int dmi_check_cb(const struct dmi_system_id *id) return 0; } -static struct dmi_system_id __initdata oaktrail_dmi_table[] = { +static const struct dmi_system_id __initconst oaktrail_dmi_table[] = { { .ident = "OakTrail platform", .matches = { diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 4231770..10a6caf 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) return 1; } -static struct dmi_system_id __initdata msi_dmi_table[] = { +static const struct dmi_system_id __initconst msi_dmi_table[] = { { .ident = "MSI S270", .matches = { @@ -1000,12 +1000,14 @@ static int __init load_scm_model_init(struct platform_device *sdev) if (!quirks->ec_read_only) { /* allow userland write sysfs file */ - dev_attr_bluetooth.store = store_bluetooth; - dev_attr_wlan.store = store_wlan; - dev_attr_threeg.store = store_threeg; - dev_attr_bluetooth.attr.mode |= S_IWUSR; - 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; + pax_close_kernel(); } /* disable hardware control by fn key */ diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c index 978e6d6..1f0b37d 100644 --- a/drivers/platform/x86/msi-wmi.c +++ b/drivers/platform/x86/msi-wmi.c @@ -184,7 +184,7 @@ static const struct backlight_ops msi_backlight_ops = { static void msi_wmi_notify(u32 value, void *context) { struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; - static struct key_entry *key; + struct key_entry *key; union acpi_object *obj; acpi_status status; diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 8c146e2..356c62e 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -1567,7 +1567,7 @@ static int __init samsung_dmi_matched(const struct dmi_system_id *d) return 0; } -static struct dmi_system_id __initdata samsung_dmi_table[] = { +static const struct dmi_system_id __initconst samsung_dmi_table[] = { { .matches = { DMI_MATCH(DMI_SYS_VENDOR, diff --git a/drivers/platform/x86/samsung-q10.c b/drivers/platform/x86/samsung-q10.c index e6aac72..e11ff24 100644 --- a/drivers/platform/x86/samsung-q10.c +++ b/drivers/platform/x86/samsung-q10.c @@ -95,7 +95,7 @@ static int __init dmi_check_callback(const struct dmi_system_id *id) return 1; } -static struct dmi_system_id __initdata samsungq10_dmi_table[] = { +static const struct dmi_system_id __initconst samsungq10_dmi_table[] = { { .ident = "Samsung Q10", .matches = { diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index aeb80d1..3eb376b 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -2527,7 +2527,7 @@ static void sony_nc_gfx_switch_cleanup(struct platform_device *pd) } /* High speed charging function */ -static struct device_attribute *hsc_handle; +static device_attribute_no_const *hsc_handle; static ssize_t sony_nc_highspeed_charging_store(struct device *dev, struct device_attribute *attr, @@ -2601,7 +2601,7 @@ static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd) } /* low battery function */ -static struct device_attribute *lowbatt_handle; +static device_attribute_no_const *lowbatt_handle; static ssize_t sony_nc_lowbatt_store(struct device *dev, struct device_attribute *attr, @@ -2667,7 +2667,7 @@ static void sony_nc_lowbatt_cleanup(struct platform_device *pd) } /* fan speed function */ -static struct device_attribute *fan_handle, *hsf_handle; +static device_attribute_no_const *fan_handle, *hsf_handle; static ssize_t sony_nc_hsfan_store(struct device *dev, struct device_attribute *attr, @@ -2774,7 +2774,7 @@ static void sony_nc_fanspeed_cleanup(struct platform_device *pd) } /* USB charge function */ -static struct device_attribute *uc_handle; +static device_attribute_no_const *uc_handle; static ssize_t sony_nc_usb_charge_store(struct device *dev, struct device_attribute *attr, @@ -2848,7 +2848,7 @@ static void sony_nc_usb_charge_cleanup(struct platform_device *pd) } /* Panel ID function */ -static struct device_attribute *panel_handle; +static device_attribute_no_const *panel_handle; static ssize_t sony_nc_panelid_show(struct device *dev, struct device_attribute *attr, char *buffer) @@ -2895,7 +2895,7 @@ static void sony_nc_panelid_cleanup(struct platform_device *pd) } /* smart connect function */ -static struct device_attribute *sc_handle; +static device_attribute_no_const *sc_handle; static ssize_t sony_nc_smart_conn_store(struct device *dev, struct device_attribute *attr, @@ -4851,7 +4851,7 @@ static struct acpi_driver sony_pic_driver = { .drv.pm = &sony_pic_pm, }; -static struct dmi_system_id __initdata sonypi_dmi_table[] = { +static const struct dmi_system_id __initconst sonypi_dmi_table[] = { { .ident = "Sony Vaio", .matches = { diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 131dd74..d7deb43 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2460,10 +2460,10 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, && !tp_features.bright_unkfw) TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME); } +} #undef TPACPI_COMPARE_KEY #undef TPACPI_MAY_SEND_KEY -} /* * Polling driver diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c index 438d4c7..ca8a2fb 100644 --- a/drivers/pnp/pnpbios/bioscalls.c +++ b/drivers/pnp/pnpbios/bioscalls.c @@ -59,7 +59,7 @@ do { \ set_desc_limit(&gdt[(selname) >> 3], (size) - 1); \ } while(0) -static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092, +static const struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4093, (unsigned long)__va(0x400UL), PAGE_SIZE - 0x400 - 1); /* @@ -96,7 +96,10 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3, cpu = get_cpu(); save_desc_40 = get_cpu_gdt_table(cpu)[0x40 / 8]; + + pax_open_kernel(); get_cpu_gdt_table(cpu)[0x40 / 8] = bad_bios_desc; + pax_close_kernel(); /* On some boxes IRQ's during PnP BIOS calls are deadly. */ spin_lock_irqsave(&pnp_bios_lock, flags); @@ -134,7 +137,10 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3, :"memory"); spin_unlock_irqrestore(&pnp_bios_lock, flags); + pax_open_kernel(); get_cpu_gdt_table(cpu)[0x40 / 8] = save_desc_40; + pax_close_kernel(); + put_cpu(); /* If we get here and this is set then the PnP BIOS faulted on us. */ @@ -468,7 +474,7 @@ int pnp_bios_read_escd(char *data, u32 nvram_base) return status; } -void pnpbios_calls_init(union pnp_bios_install_struct *header) +void __init pnpbios_calls_init(union pnp_bios_install_struct *header) { int i; @@ -476,6 +482,8 @@ void pnpbios_calls_init(union pnp_bios_install_struct *header) pnp_bios_callpoint.offset = header->fields.pm16offset; pnp_bios_callpoint.segment = PNP_CS16; + pax_open_kernel(); + for_each_possible_cpu(i) { struct desc_struct *gdt = get_cpu_gdt_table(i); if (!gdt) @@ -487,4 +495,6 @@ void pnpbios_calls_init(union pnp_bios_install_struct *header) set_desc_base(&gdt[GDT_ENTRY_PNPBIOS_DS], (unsigned long)__va(header->fields.pm16dseg)); } + + pax_close_kernel(); } diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index facd43b..b291260 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -494,7 +494,7 @@ static int __init exploding_pnp_bios(const struct dmi_system_id *d) return 0; } -static struct dmi_system_id pnpbios_dmi_table[] __initdata = { +static const struct dmi_system_id pnpbios_dmi_table[] __initconst = { { /* PnPBIOS GPF on boot */ .callback = exploding_pnp_bios, .ident = "Higraded P14H", diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c index dfe1ee8..67e820c 100644 --- a/drivers/power/pda_power.c +++ b/drivers/power/pda_power.c @@ -38,7 +38,11 @@ static struct power_supply *pda_psy_ac, *pda_psy_usb; #if IS_ENABLED(CONFIG_USB_PHY) static struct usb_phy *transceiver; -static struct notifier_block otg_nb; +static int otg_handle_notification(struct notifier_block *nb, + unsigned long event, void *unused); +static struct notifier_block otg_nb = { + .notifier_call = otg_handle_notification +}; #endif static struct regulator *ac_draw; @@ -373,7 +377,6 @@ static int pda_power_probe(struct platform_device *pdev) #if IS_ENABLED(CONFIG_USB_PHY) if (!IS_ERR_OR_NULL(transceiver) && pdata->use_otg_notifier) { - otg_nb.notifier_call = otg_handle_notification; ret = usb_register_notifier(transceiver, &otg_nb); if (ret) { dev_err(dev, "failure to register otg notifier\n"); diff --git a/drivers/power/power_supply.h b/drivers/power/power_supply.h index cc439fd..8fa30df 100644 --- a/drivers/power/power_supply.h +++ b/drivers/power/power_supply.h @@ -16,12 +16,12 @@ struct power_supply; #ifdef CONFIG_SYSFS -extern void power_supply_init_attrs(struct device_type *dev_type); +extern void power_supply_init_attrs(void); extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env); #else -static inline void power_supply_init_attrs(struct device_type *dev_type) {} +static inline void power_supply_init_attrs(void) {} #define power_supply_uevent NULL #endif /* CONFIG_SYSFS */ diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 456987c..45396a3 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -28,7 +28,10 @@ EXPORT_SYMBOL_GPL(power_supply_class); ATOMIC_NOTIFIER_HEAD(power_supply_notifier); EXPORT_SYMBOL_GPL(power_supply_notifier); -static struct device_type power_supply_dev_type; +extern const struct attribute_group *power_supply_attr_groups[]; +static struct device_type power_supply_dev_type = { + .groups = power_supply_attr_groups, +}; #define POWER_SUPPLY_DEFERRED_REGISTER_TIME msecs_to_jiffies(10) @@ -960,7 +963,7 @@ static int __init power_supply_class_init(void) return PTR_ERR(power_supply_class); power_supply_class->dev_uevent = power_supply_uevent; - power_supply_init_attrs(&power_supply_dev_type); + power_supply_init_attrs(); return 0; } diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index ed2d7fd..266b28f 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -238,17 +238,15 @@ static struct attribute_group power_supply_attr_group = { .is_visible = power_supply_attr_is_visible, }; -static const struct attribute_group *power_supply_attr_groups[] = { +const struct attribute_group *power_supply_attr_groups[] = { &power_supply_attr_group, NULL, }; -void power_supply_init_attrs(struct device_type *dev_type) +void power_supply_init_attrs(void) { int i; - dev_type->groups = power_supply_attr_groups; - for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++) __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 c378d4e..f7946c3 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -203,7 +204,9 @@ static int at91_reset_of_probe(struct platform_device *pdev) } 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; + pax_close_kernel(); return register_restart_handler(&at91_restart_nb); } @@ -231,9 +234,11 @@ static int at91_reset_platform_probe(struct platform_device *pdev) } match = platform_get_device_id(pdev); - at91_restart_nb.notifier_call = + pax_open_kernel(); + *(void **)&at91_restart_nb.notifier_call = (int (*)(struct notifier_block *, unsigned long, void *)) match->driver_data; + pax_close_kernel(); return register_restart_handler(&at91_restart_nb); } diff --git a/drivers/powercap/powercap_sys.c b/drivers/powercap/powercap_sys.c index 84419af..268ede8 100644 --- a/drivers/powercap/powercap_sys.c +++ b/drivers/powercap/powercap_sys.c @@ -154,8 +154,77 @@ struct powercap_constraint_attr { struct device_attribute name_attr; }; +static ssize_t show_constraint_name(struct device *dev, + struct device_attribute *dev_attr, + char *buf); + static struct powercap_constraint_attr - constraint_attrs[MAX_CONSTRAINTS_PER_ZONE]; + constraint_attrs[MAX_CONSTRAINTS_PER_ZONE] = { + [0 ... MAX_CONSTRAINTS_PER_ZONE - 1] = { + .power_limit_attr = { + .attr = { + .name = NULL, + .mode = S_IWUSR | S_IRUGO + }, + .show = show_constraint_power_limit_uw, + .store = store_constraint_power_limit_uw + }, + + .time_window_attr = { + .attr = { + .name = NULL, + .mode = S_IWUSR | S_IRUGO + }, + .show = show_constraint_time_window_us, + .store = store_constraint_time_window_us + }, + + .max_power_attr = { + .attr = { + .name = NULL, + .mode = S_IRUGO + }, + .show = show_constraint_max_power_uw, + .store = NULL + }, + + .min_power_attr = { + .attr = { + .name = NULL, + .mode = S_IRUGO + }, + .show = show_constraint_min_power_uw, + .store = NULL + }, + + .max_time_window_attr = { + .attr = { + .name = NULL, + .mode = S_IRUGO + }, + .show = show_constraint_max_time_window_us, + .store = NULL + }, + + .min_time_window_attr = { + .attr = { + .name = NULL, + .mode = S_IRUGO + }, + .show = show_constraint_min_time_window_us, + .store = NULL + }, + + .name_attr = { + .attr = { + .name = NULL, + .mode = S_IRUGO + }, + .show = show_constraint_name, + .store = NULL + } + } +}; /* A list of powercap control_types */ static LIST_HEAD(powercap_cntrl_list); @@ -193,23 +262,16 @@ static ssize_t show_constraint_name(struct device *dev, } static int create_constraint_attribute(int id, const char *name, - int mode, - struct device_attribute *dev_attr, - ssize_t (*show)(struct device *, - struct device_attribute *, char *), - ssize_t (*store)(struct device *, - struct device_attribute *, - const char *, size_t) - ) + struct device_attribute *dev_attr) { + name = kasprintf(GFP_KERNEL, "constraint_%d_%s", id, name); - dev_attr->attr.name = kasprintf(GFP_KERNEL, "constraint_%d_%s", - id, name); - if (!dev_attr->attr.name) + if (!name) return -ENOMEM; - dev_attr->attr.mode = mode; - dev_attr->show = show; - dev_attr->store = store; + + pax_open_kernel(); + *(const char **)&dev_attr->attr.name = name; + pax_close_kernel(); return 0; } @@ -236,49 +298,31 @@ static int seed_constraint_attributes(void) for (i = 0; i < MAX_CONSTRAINTS_PER_ZONE; ++i) { ret = create_constraint_attribute(i, "power_limit_uw", - S_IWUSR | S_IRUGO, - &constraint_attrs[i].power_limit_attr, - show_constraint_power_limit_uw, - store_constraint_power_limit_uw); + &constraint_attrs[i].power_limit_attr); if (ret) goto err_alloc; ret = create_constraint_attribute(i, "time_window_us", - S_IWUSR | S_IRUGO, - &constraint_attrs[i].time_window_attr, - show_constraint_time_window_us, - store_constraint_time_window_us); + &constraint_attrs[i].time_window_attr); if (ret) goto err_alloc; - ret = create_constraint_attribute(i, "name", S_IRUGO, - &constraint_attrs[i].name_attr, - show_constraint_name, - NULL); + ret = create_constraint_attribute(i, "name", + &constraint_attrs[i].name_attr); if (ret) goto err_alloc; - ret = create_constraint_attribute(i, "max_power_uw", S_IRUGO, - &constraint_attrs[i].max_power_attr, - show_constraint_max_power_uw, - NULL); + ret = create_constraint_attribute(i, "max_power_uw", + &constraint_attrs[i].max_power_attr); if (ret) goto err_alloc; - ret = create_constraint_attribute(i, "min_power_uw", S_IRUGO, - &constraint_attrs[i].min_power_attr, - show_constraint_min_power_uw, - NULL); + ret = create_constraint_attribute(i, "min_power_uw", + &constraint_attrs[i].min_power_attr); if (ret) goto err_alloc; ret = create_constraint_attribute(i, "max_time_window_us", - S_IRUGO, - &constraint_attrs[i].max_time_window_attr, - show_constraint_max_time_window_us, - NULL); + &constraint_attrs[i].max_time_window_attr); if (ret) goto err_alloc; ret = create_constraint_attribute(i, "min_time_window_us", - S_IRUGO, - &constraint_attrs[i].min_time_window_attr, - show_constraint_min_time_window_us, - NULL); + &constraint_attrs[i].min_time_window_attr); if (ret) goto err_alloc; @@ -378,10 +422,12 @@ static void create_power_zone_common_attributes( power_zone->zone_dev_attrs[count++] = &dev_attr_max_energy_range_uj.attr; if (power_zone->ops->get_energy_uj) { + 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; else - dev_attr_energy_uj.attr.mode = S_IRUGO; + *(umode_t *)&dev_attr_energy_uj.attr.mode = S_IRUGO; + pax_close_kernel(); power_zone->zone_dev_attrs[count++] = &dev_attr_energy_uj.attr; } diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h index 9c5d414..c7900ce 100644 --- a/drivers/ptp/ptp_private.h +++ b/drivers/ptp/ptp_private.h @@ -51,7 +51,7 @@ struct ptp_clock { struct mutex pincfg_mux; /* protect concurrent info->pin_config access */ wait_queue_head_t tsev_wq; int defunct; /* tells readers to go away when clock is being removed */ - struct device_attribute *pin_dev_attr; + device_attribute_no_const *pin_dev_attr; struct attribute **pin_attr; struct attribute_group pin_attr_group; }; diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c index 302e626..12579af 100644 --- a/drivers/ptp/ptp_sysfs.c +++ b/drivers/ptp/ptp_sysfs.c @@ -280,7 +280,7 @@ static int ptp_populate_pins(struct ptp_clock *ptp) goto no_pin_attr; for (i = 0; i < n_pins; i++) { - struct device_attribute *da = &ptp->pin_dev_attr[i]; + device_attribute_no_const *da = &ptp->pin_dev_attr[i]; sysfs_attr_init(&da->attr); da->attr.name = info->pin_config[i].name; da->attr.mode = 0644; diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 8a34f6a..e4b3e44 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3681,7 +3681,7 @@ regulator_register(const struct regulator_desc *regulator_desc, const struct regulation_constraints *constraints = NULL; const struct regulator_init_data *init_data; struct regulator_config *config = NULL; - static atomic_t regulator_no = ATOMIC_INIT(-1); + static atomic_unchecked_t regulator_no = ATOMIC_INIT(-1); struct regulator_dev *rdev; struct device *dev; int ret, i; @@ -3764,7 +3764,7 @@ regulator_register(const struct regulator_desc *regulator_desc, rdev->dev.class = ®ulator_class; rdev->dev.parent = dev; dev_set_name(&rdev->dev, "regulator.%lu", - (unsigned long) atomic_inc_return(®ulator_no)); + (unsigned long) atomic_inc_return_unchecked(®ulator_no)); ret = device_register(&rdev->dev); if (ret != 0) { put_device(&rdev->dev); diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index b87f62d..345b9a1 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -423,8 +423,10 @@ static int max8660_probe(struct i2c_client *client, max8660->shadow_regs[MAX8660_OVER1] = 5; } else { /* Otherwise devices can be toggled via software */ - 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; + pax_close_kernel(); } /* diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 5b75b7c..142c226 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, if (!pdata->enable_ext_control) { max->desc.enable_reg = MAX8973_VOUT; max->desc.enable_mask = MAX8973_VOUT_ENABLE; - max->ops.enable = regulator_enable_regmap; - 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; + pax_close_kernel(); break; } @@ -688,9 +690,11 @@ static int max8973_probe(struct i2c_client *client, max->desc.enable_reg = MAX8973_VOUT; max->desc.enable_mask = MAX8973_VOUT_ENABLE; - max->ops.enable = regulator_enable_regmap; - 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; + 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 --- 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) mc13xxx_unlock(mc13892); /* update mc13892_vcam ops */ - memcpy(&mc13892_vcam_ops, mc13892_regulators[MC13892_VCAM].desc.ops, + pax_open_kernel(); + memcpy((void *)&mc13892_vcam_ops, mc13892_regulators[MC13892_VCAM].desc.ops, 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, + pax_close_kernel(); mc13892_regulators[MC13892_VCAM].desc.ops = &mc13892_vcam_ops; mc13xxx_data = mc13xxx_parse_regulators_dt(pdev, mc13892_regulators, diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c index 9a3f2a6..604f463 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -18,6 +18,7 @@ #include #include #include +#include #define RTC_STATUS 0x0 #define RTC_STATUS_ALARM1 BIT(0) @@ -246,8 +247,10 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev) * If there is no interrupt available then we can't * use the alarm */ - 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; + 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 8f7034b..2ddd4b3 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) hpet_rtc_timer_init(); /* 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; + pax_close_kernel(); retval = sysfs_create_bin_file(&dev->kobj, &nvram); if (retval < 0) { dev_dbg(dev, "can't create nvram file? %d\n", retval); diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index a6d9434..dc26b71 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "rtc-core.h" static dev_t rtc_devt; @@ -347,6 +348,8 @@ static long rtc_dev_ioctl(struct file *file, if (copy_from_user(&tm, uarg, sizeof(tm))) return -EFAULT; + gr_log_timechange(); + return rtc_set_time(rtc, &tm); case RTC_PIE_ON: diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index a705e64..7710ad0 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -110,7 +110,7 @@ struct ds1307 { u8 offset; /* register's offset */ u8 regs[11]; u16 nvram_offset; - struct bin_attribute *nvram; + bin_attribute_no_const *nvram; enum ds_type type; 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 --- 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) if (IS_ERR(m48t59->rtc)) return PTR_ERR(m48t59->rtc); - m48t59_nvram_attr.size = pdata->offset; + pax_open_kernel(); + *(size_t *)&m48t59_nvram_attr.size = pdata->offset; + pax_close_kernel(); ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); if (ret) diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index 3a2da4c..e88493c 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) struct rtc_device *rtc; if (test_mmss64) { - 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; + pax_close_kernel(); } rtc = devm_rtc_device_register(&plat_dev->dev, "test", diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 7a6dbfb..5cdcd29 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3184,7 +3184,7 @@ be_sgl_create_contiguous(void *virtual_address, { WARN_ON(!virtual_address); WARN_ON(!physical_address); - WARN_ON(!length > 0); + WARN_ON(!length); WARN_ON(!sgl); sgl->va = virtual_address; diff --git a/drivers/scsi/bfa/bfa_fcpim.h b/drivers/scsi/bfa/bfa_fcpim.h index e693af6..2e525b6 100644 --- a/drivers/scsi/bfa/bfa_fcpim.h +++ b/drivers/scsi/bfa/bfa_fcpim.h @@ -36,7 +36,7 @@ struct bfa_iotag_s { struct bfa_itn_s { bfa_isr_func_t isr; -}; +} __no_const; void bfa_itn_create(struct bfa_s *bfa, struct bfa_rport_s *rport, void (*isr)(struct bfa_s *bfa, struct bfi_msg_s *m)); diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c index 0f19455..ef7adb5 100644 --- a/drivers/scsi/bfa/bfa_fcs.c +++ b/drivers/scsi/bfa/bfa_fcs.c @@ -38,10 +38,21 @@ struct bfa_fcs_mod_s { #define BFA_FCS_MODULE(_mod) { _mod ## _modinit, _mod ## _modexit } static struct bfa_fcs_mod_s fcs_modules[] = { - { bfa_fcs_port_attach, NULL, NULL }, - { bfa_fcs_uf_attach, NULL, NULL }, - { bfa_fcs_fabric_attach, bfa_fcs_fabric_modinit, - bfa_fcs_fabric_modexit }, + { + .attach = bfa_fcs_port_attach, + .modinit = NULL, + .modexit = NULL + }, + { + .attach = bfa_fcs_uf_attach, + .modinit = NULL, + .modexit = NULL + }, + { + .attach = bfa_fcs_fabric_attach, + .modinit = bfa_fcs_fabric_modinit, + .modexit = bfa_fcs_fabric_modexit + }, }; /* diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c index ff75ef8..2dfe00a 100644 --- a/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/drivers/scsi/bfa/bfa_fcs_lport.c @@ -89,15 +89,26 @@ static struct { void (*offline) (struct bfa_fcs_lport_s *port); } __port_action[] = { { - bfa_fcs_lport_unknown_init, bfa_fcs_lport_unknown_online, - bfa_fcs_lport_unknown_offline}, { - bfa_fcs_lport_fab_init, bfa_fcs_lport_fab_online, - bfa_fcs_lport_fab_offline}, { - bfa_fcs_lport_n2n_init, bfa_fcs_lport_n2n_online, - bfa_fcs_lport_n2n_offline}, { - bfa_fcs_lport_loop_init, bfa_fcs_lport_loop_online, - bfa_fcs_lport_loop_offline}, - }; + .init = bfa_fcs_lport_unknown_init, + .online = bfa_fcs_lport_unknown_online, + .offline = bfa_fcs_lport_unknown_offline + }, + { + .init = bfa_fcs_lport_fab_init, + .online = bfa_fcs_lport_fab_online, + .offline = bfa_fcs_lport_fab_offline + }, + { + .init = bfa_fcs_lport_n2n_init, + .online = bfa_fcs_lport_n2n_online, + .offline = bfa_fcs_lport_n2n_offline + }, + { + .init = bfa_fcs_lport_loop_init, + .online = bfa_fcs_lport_loop_online, + .offline = bfa_fcs_lport_loop_offline + }, +}; /* * fcs_port_sm FCS logical port state machine diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h index a38aafa0..fe8f03b 100644 --- a/drivers/scsi/bfa/bfa_ioc.h +++ b/drivers/scsi/bfa/bfa_ioc.h @@ -258,7 +258,7 @@ struct bfa_ioc_cbfn_s { bfa_ioc_disable_cbfn_t disable_cbfn; bfa_ioc_hbfail_cbfn_t hbfail_cbfn; bfa_ioc_reset_cbfn_t reset_cbfn; -}; +} __no_const; /* * IOC event notification mechanism. @@ -352,7 +352,7 @@ struct bfa_ioc_hwif_s { void (*ioc_set_alt_fwstate) (struct bfa_ioc_s *ioc, enum bfi_ioc_state fwstate); enum bfi_ioc_state (*ioc_get_alt_fwstate) (struct bfa_ioc_s *ioc); -}; +} __no_const; /* * Queue element to wait for room in request queue. FIFO order is diff --git a/drivers/scsi/bfa/bfa_modules.h b/drivers/scsi/bfa/bfa_modules.h index a14c784..6de6790 100644 --- a/drivers/scsi/bfa/bfa_modules.h +++ b/drivers/scsi/bfa/bfa_modules.h @@ -78,12 +78,12 @@ enum { \ extern struct bfa_module_s hal_mod_ ## __mod; \ struct bfa_module_s hal_mod_ ## __mod = { \ - bfa_ ## __mod ## _meminfo, \ - bfa_ ## __mod ## _attach, \ - bfa_ ## __mod ## _detach, \ - bfa_ ## __mod ## _start, \ - bfa_ ## __mod ## _stop, \ - bfa_ ## __mod ## _iocdisable, \ + .meminfo = bfa_ ## __mod ## _meminfo, \ + .attach = bfa_ ## __mod ## _attach, \ + .detach = bfa_ ## __mod ## _detach, \ + .start = bfa_ ## __mod ## _start, \ + .stop = bfa_ ## __mod ## _stop, \ + .iocdisable = bfa_ ## __mod ## _iocdisable, \ } #define BFA_CACHELINE_SZ (256) diff --git a/drivers/scsi/fcoe/fcoe_sysfs.c b/drivers/scsi/fcoe/fcoe_sysfs.c index 045c4e1..13de803 100644 --- a/drivers/scsi/fcoe/fcoe_sysfs.c +++ b/drivers/scsi/fcoe/fcoe_sysfs.c @@ -33,8 +33,8 @@ */ #include "libfcoe.h" -static atomic_t ctlr_num; -static atomic_t fcf_num; +static atomic_unchecked_t ctlr_num; +static atomic_unchecked_t fcf_num; /* * fcoe_fcf_dev_loss_tmo: the default number of seconds that fcoe sysfs @@ -685,7 +685,7 @@ struct fcoe_ctlr_device *fcoe_ctlr_device_add(struct device *parent, if (!ctlr) goto out; - ctlr->id = atomic_inc_return(&ctlr_num) - 1; + ctlr->id = atomic_inc_return_unchecked(&ctlr_num) - 1; ctlr->f = f; ctlr->mode = FIP_CONN_TYPE_FABRIC; INIT_LIST_HEAD(&ctlr->fcfs); @@ -902,7 +902,7 @@ struct fcoe_fcf_device *fcoe_fcf_device_add(struct fcoe_ctlr_device *ctlr, fcf->dev.parent = &ctlr->dev; fcf->dev.bus = &fcoe_bus_type; fcf->dev.type = &fcoe_fcf_device_type; - fcf->id = atomic_inc_return(&fcf_num) - 1; + fcf->id = atomic_inc_return_unchecked(&fcf_num) - 1; fcf->state = FCOE_FCF_STATE_UNKNOWN; fcf->dev_loss_tmo = ctlr->fcf_dev_loss_tmo; @@ -938,8 +938,8 @@ int __init fcoe_sysfs_setup(void) { int error; - atomic_set(&ctlr_num, 0); - atomic_set(&fcf_num, 0); + atomic_set_unchecked(&ctlr_num, 0); + atomic_set_unchecked(&fcf_num, 0); error = bus_register(&fcoe_bus_type); if (error) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 8bb173e..20236b4 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -42,7 +42,7 @@ #include "scsi_logging.h" -static atomic_t scsi_host_next_hn = ATOMIC_INIT(0); /* host_no for next new host */ +static atomic_unchecked_t scsi_host_next_hn = ATOMIC_INIT(0); /* host_no for next new host */ static void scsi_host_cls_release(struct device *dev) @@ -392,7 +392,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) * subtract one because we increment first then return, but we need to * know what the next host number was before increment */ - shost->host_no = atomic_inc_return(&scsi_host_next_hn) - 1; + shost->host_no = atomic_inc_return_unchecked(&scsi_host_next_hn) - 1; shost->dma_channel = 0xff; /* These three are default values which can be overridden */ diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 40669f8..826df08 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -897,10 +897,10 @@ static inline u32 next_command(struct ctlr_info *h, u8 q) struct reply_queue_buffer *rq = &h->reply_queue[q]; if (h->transMethod & CFGTBL_Trans_io_accel1) - return h->access.command_completed(h, q); + return h->access->command_completed(h, q); if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant))) - return h->access.command_completed(h, q); + return h->access->command_completed(h, q); if ((rq->head[rq->current_entry] & 1) == rq->wraparound) { a = rq->head[rq->current_entry]; @@ -1082,7 +1082,7 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h, break; default: set_performant_mode(h, c, reply_queue); - h->access.submit_command(h, c); + h->access->submit_command(h, c); } } @@ -6406,17 +6406,17 @@ static void __iomem *remap_pci_mem(ulong base, ulong size) static inline unsigned long get_next_completion(struct ctlr_info *h, u8 q) { - return h->access.command_completed(h, q); + return h->access->command_completed(h, q); } static inline bool interrupt_pending(struct ctlr_info *h) { - return h->access.intr_pending(h); + return h->access->intr_pending(h); } static inline long interrupt_not_for_us(struct ctlr_info *h) { - return (h->access.intr_pending(h) == 0) || + return (h->access->intr_pending(h) == 0) || (h->interrupts_enabled == 0); } @@ -7354,7 +7354,7 @@ static int hpsa_pci_init(struct ctlr_info *h) if (prod_index < 0) return prod_index; h->product_name = products[prod_index].product_name; - h->access = *(products[prod_index].access); + h->access = products[prod_index].access; h->needs_abort_tags_swizzled = ctlr_needs_abort_tags_swizzled(h->board_id); @@ -7753,7 +7753,7 @@ static void controller_lockup_detected(struct ctlr_info *h) unsigned long flags; u32 lockup_detected; - h->access.set_intr_mask(h, HPSA_INTR_OFF); + h->access->set_intr_mask(h, HPSA_INTR_OFF); spin_lock_irqsave(&h->lock, flags); lockup_detected = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); if (!lockup_detected) { @@ -8036,7 +8036,7 @@ reinit_after_soft_reset: } /* make sure the board interrupts are off */ - h->access.set_intr_mask(h, HPSA_INTR_OFF); + h->access->set_intr_mask(h, HPSA_INTR_OFF); rc = hpsa_request_irqs(h, do_hpsa_intr_msi, do_hpsa_intr_intx); if (rc) @@ -8094,7 +8094,7 @@ reinit_after_soft_reset: * fake ones to scoop up any residual completions. */ spin_lock_irqsave(&h->lock, flags); - h->access.set_intr_mask(h, HPSA_INTR_OFF); + h->access->set_intr_mask(h, HPSA_INTR_OFF); spin_unlock_irqrestore(&h->lock, flags); hpsa_free_irqs(h); rc = hpsa_request_irqs(h, hpsa_msix_discard_completions, @@ -8124,9 +8124,9 @@ reinit_after_soft_reset: dev_info(&h->pdev->dev, "Board READY.\n"); dev_info(&h->pdev->dev, "Waiting for stale completions to drain.\n"); - h->access.set_intr_mask(h, HPSA_INTR_ON); + h->access->set_intr_mask(h, HPSA_INTR_ON); msleep(10000); - h->access.set_intr_mask(h, HPSA_INTR_OFF); + h->access->set_intr_mask(h, HPSA_INTR_OFF); rc = controller_reset_failed(h->cfgtable); if (rc) @@ -8151,7 +8151,7 @@ reinit_after_soft_reset: /* Turn the interrupts on so we can service requests */ - h->access.set_intr_mask(h, HPSA_INTR_ON); + h->access->set_intr_mask(h, HPSA_INTR_ON); hpsa_hba_inquiry(h); @@ -8167,7 +8167,7 @@ reinit_after_soft_reset: clean7: /* perf, sg, cmd, irq, shost, pci, lu, aer/h */ hpsa_free_performant_mode(h); - h->access.set_intr_mask(h, HPSA_INTR_OFF); + h->access->set_intr_mask(h, HPSA_INTR_OFF); clean6: /* sg, cmd, irq, pci, lockup, wq/aer/h */ hpsa_free_sg_chain_blocks(h); clean5: /* cmd, irq, shost, pci, lu, aer/h */ @@ -8237,7 +8237,7 @@ static void hpsa_shutdown(struct pci_dev *pdev) * To write all data in the battery backed cache to disks */ hpsa_flush_cache(h); - h->access.set_intr_mask(h, HPSA_INTR_OFF); + h->access->set_intr_mask(h, HPSA_INTR_OFF); hpsa_free_irqs(h); /* init_one 4 */ hpsa_disable_interrupt_mode(h); /* pci_init 2 */ } @@ -8375,7 +8375,7 @@ static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) CFGTBL_Trans_enable_directed_msix | (trans_support & (CFGTBL_Trans_io_accel1 | CFGTBL_Trans_io_accel2)); - struct access_method access = SA5_performant_access; + struct access_method *access = &SA5_performant_access; /* This is a bit complicated. There are 8 registers on * the controller which we write to to tell it 8 different @@ -8417,7 +8417,7 @@ static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) * perform the superfluous readl() after each command submission. */ if (trans_support & (CFGTBL_Trans_io_accel1 | CFGTBL_Trans_io_accel2)) - access = SA5_performant_access_no_read; + access = &SA5_performant_access_no_read; /* Controller spec: zero out this buffer. */ for (i = 0; i < h->nreply_queues; i++) @@ -8447,12 +8447,12 @@ static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) * enable outbound interrupt coalescing in accelerator mode; */ if (trans_support & CFGTBL_Trans_io_accel1) { - access = SA5_ioaccel_mode1_access; + access = &SA5_ioaccel_mode1_access; writel(10, &h->cfgtable->HostWrite.CoalIntDelay); writel(4, &h->cfgtable->HostWrite.CoalIntCount); } else { if (trans_support & CFGTBL_Trans_io_accel2) { - access = SA5_ioaccel_mode2_access; + access = &SA5_ioaccel_mode2_access; writel(10, &h->cfgtable->HostWrite.CoalIntDelay); writel(4, &h->cfgtable->HostWrite.CoalIntCount); } diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 27debb3..394d998 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -153,7 +153,7 @@ struct ctlr_info { unsigned int msix_vector; unsigned int msi_vector; int intr_mode; /* either PERF_MODE_INT or SIMPLE_MODE_INT */ - struct access_method access; + struct access_method *access; /* queue and queue Info */ unsigned int Qdepth; @@ -542,38 +542,38 @@ static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q) } static struct access_method SA5_access = { - SA5_submit_command, - SA5_intr_mask, - SA5_intr_pending, - SA5_completed, + .submit_command = SA5_submit_command, + .set_intr_mask = SA5_intr_mask, + .intr_pending = SA5_intr_pending, + .command_completed = SA5_completed, }; static struct access_method SA5_ioaccel_mode1_access = { - SA5_submit_command, - SA5_performant_intr_mask, - SA5_ioaccel_mode1_intr_pending, - SA5_ioaccel_mode1_completed, + .submit_command = SA5_submit_command, + .set_intr_mask = SA5_performant_intr_mask, + .intr_pending = SA5_ioaccel_mode1_intr_pending, + .command_completed = SA5_ioaccel_mode1_completed, }; static struct access_method SA5_ioaccel_mode2_access = { - SA5_submit_command_ioaccel2, - SA5_performant_intr_mask, - SA5_performant_intr_pending, - SA5_performant_completed, + .submit_command = SA5_submit_command_ioaccel2, + .set_intr_mask = SA5_performant_intr_mask, + .intr_pending = SA5_performant_intr_pending, + .command_completed = SA5_performant_completed, }; static struct access_method SA5_performant_access = { - SA5_submit_command, - SA5_performant_intr_mask, - SA5_performant_intr_pending, - SA5_performant_completed, + .submit_command = SA5_submit_command, + .set_intr_mask = SA5_performant_intr_mask, + .intr_pending = SA5_performant_intr_pending, + .command_completed = SA5_performant_completed, }; static struct access_method SA5_performant_access_no_read = { - SA5_submit_command_no_read, - SA5_performant_intr_mask, - SA5_performant_intr_pending, - SA5_performant_completed, + .submit_command = SA5_submit_command_no_read, + .set_intr_mask = SA5_performant_intr_mask, + .intr_pending = SA5_performant_intr_pending, + .command_completed = SA5_performant_completed, }; struct board_type { diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 30f9ef0..a1e29ac 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -101,12 +101,12 @@ struct fc_exch_mgr { u16 pool_max_index; struct { - atomic_t no_free_exch; - atomic_t no_free_exch_xid; - atomic_t xid_not_found; - atomic_t xid_busy; - atomic_t seq_not_found; - atomic_t non_bls_resp; + atomic_unchecked_t no_free_exch; + atomic_unchecked_t no_free_exch_xid; + atomic_unchecked_t xid_not_found; + atomic_unchecked_t xid_busy; + atomic_unchecked_t seq_not_found; + atomic_unchecked_t non_bls_resp; } stats; }; @@ -809,7 +809,7 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, /* allocate memory for exchange */ ep = mempool_alloc(mp->ep_pool, GFP_ATOMIC); if (!ep) { - atomic_inc(&mp->stats.no_free_exch); + atomic_inc_unchecked(&mp->stats.no_free_exch); goto out; } memset(ep, 0, sizeof(*ep)); @@ -872,7 +872,7 @@ out: return ep; err: spin_unlock_bh(&pool->lock); - atomic_inc(&mp->stats.no_free_exch_xid); + atomic_inc_unchecked(&mp->stats.no_free_exch_xid); mempool_free(ep, mp->ep_pool); return NULL; } @@ -1021,7 +1021,7 @@ static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport, xid = ntohs(fh->fh_ox_id); /* we originated exch */ ep = fc_exch_find(mp, xid); if (!ep) { - atomic_inc(&mp->stats.xid_not_found); + atomic_inc_unchecked(&mp->stats.xid_not_found); reject = FC_RJT_OX_ID; goto out; } @@ -1051,7 +1051,7 @@ static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport, ep = fc_exch_find(mp, xid); if ((f_ctl & FC_FC_FIRST_SEQ) && fc_sof_is_init(fr_sof(fp))) { if (ep) { - atomic_inc(&mp->stats.xid_busy); + atomic_inc_unchecked(&mp->stats.xid_busy); reject = FC_RJT_RX_ID; goto rel; } @@ -1062,7 +1062,7 @@ static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport, } xid = ep->xid; /* get our XID */ } else if (!ep) { - atomic_inc(&mp->stats.xid_not_found); + atomic_inc_unchecked(&mp->stats.xid_not_found); reject = FC_RJT_RX_ID; /* XID not found */ goto out; } @@ -1080,7 +1080,7 @@ static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport, } else { sp = &ep->seq; if (sp->id != fh->fh_seq_id) { - atomic_inc(&mp->stats.seq_not_found); + atomic_inc_unchecked(&mp->stats.seq_not_found); if (f_ctl & FC_FC_END_SEQ) { /* * Update sequence_id based on incoming last @@ -1531,22 +1531,22 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) ep = fc_exch_find(mp, ntohs(fh->fh_ox_id)); if (!ep) { - atomic_inc(&mp->stats.xid_not_found); + atomic_inc_unchecked(&mp->stats.xid_not_found); goto out; } if (ep->esb_stat & ESB_ST_COMPLETE) { - atomic_inc(&mp->stats.xid_not_found); + atomic_inc_unchecked(&mp->stats.xid_not_found); goto rel; } if (ep->rxid == FC_XID_UNKNOWN) ep->rxid = ntohs(fh->fh_rx_id); if (ep->sid != 0 && ep->sid != ntoh24(fh->fh_d_id)) { - atomic_inc(&mp->stats.xid_not_found); + atomic_inc_unchecked(&mp->stats.xid_not_found); goto rel; } if (ep->did != ntoh24(fh->fh_s_id) && ep->did != FC_FID_FLOGI) { - atomic_inc(&mp->stats.xid_not_found); + atomic_inc_unchecked(&mp->stats.xid_not_found); goto rel; } sof = fr_sof(fp); @@ -1555,7 +1555,7 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) sp->ssb_stat |= SSB_ST_RESP; sp->id = fh->fh_seq_id; } else if (sp->id != fh->fh_seq_id) { - atomic_inc(&mp->stats.seq_not_found); + atomic_inc_unchecked(&mp->stats.seq_not_found); goto rel; } @@ -1618,9 +1618,9 @@ static void fc_exch_recv_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) sp = fc_seq_lookup_orig(mp, fp); /* doesn't hold sequence */ if (!sp) - atomic_inc(&mp->stats.xid_not_found); + atomic_inc_unchecked(&mp->stats.xid_not_found); else - atomic_inc(&mp->stats.non_bls_resp); + atomic_inc_unchecked(&mp->stats.non_bls_resp); fc_frame_free(fp); } @@ -2261,13 +2261,13 @@ void fc_exch_update_stats(struct fc_lport *lport) list_for_each_entry(ema, &lport->ema_list, ema_list) { mp = ema->mp; - st->fc_no_free_exch += atomic_read(&mp->stats.no_free_exch); + st->fc_no_free_exch += atomic_read_unchecked(&mp->stats.no_free_exch); st->fc_no_free_exch_xid += - atomic_read(&mp->stats.no_free_exch_xid); - st->fc_xid_not_found += atomic_read(&mp->stats.xid_not_found); - st->fc_xid_busy += atomic_read(&mp->stats.xid_busy); - st->fc_seq_not_found += atomic_read(&mp->stats.seq_not_found); - st->fc_non_bls_resp += atomic_read(&mp->stats.non_bls_resp); + atomic_read_unchecked(&mp->stats.no_free_exch_xid); + st->fc_xid_not_found += atomic_read_unchecked(&mp->stats.xid_not_found); + st->fc_xid_busy += atomic_read_unchecked(&mp->stats.xid_busy); + st->fc_seq_not_found += atomic_read_unchecked(&mp->stats.seq_not_found); + st->fc_non_bls_resp += atomic_read_unchecked(&mp->stats.non_bls_resp); } } EXPORT_SYMBOL(fc_exch_update_stats); diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 9c706d8..d3e3ed2 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -535,7 +535,7 @@ static struct ata_port_operations sas_sata_ops = { .postreset = ata_std_postreset, .error_handler = ata_std_error_handler, .post_internal_cmd = sas_ata_post_internal, - .qc_defer = ata_std_qc_defer, + .qc_defer = ata_std_qc_defer, .qc_prep = ata_noop_qc_prep, .qc_issue = sas_ata_qc_issue, .qc_fill_rtf = sas_ata_qc_fill_rtf, diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index a5a56fa..43499fd 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -435,7 +435,7 @@ struct lpfc_vport { struct dentry *debug_nodelist; struct dentry *vport_debugfs_root; struct lpfc_debugfs_trc *disc_trc; - atomic_t disc_trc_cnt; + atomic_unchecked_t disc_trc_cnt; #endif uint8_t stat_data_enabled; uint8_t stat_data_blocked; @@ -885,8 +885,8 @@ struct lpfc_hba { struct timer_list fabric_block_timer; unsigned long bit_flags; #define FABRIC_COMANDS_BLOCKED 0 - atomic_t num_rsrc_err; - atomic_t num_cmd_success; + atomic_unchecked_t num_rsrc_err; + atomic_unchecked_t num_cmd_success; unsigned long last_rsrc_error_time; unsigned long last_ramp_down_time; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS @@ -921,7 +921,7 @@ struct lpfc_hba { struct dentry *debug_slow_ring_trc; struct lpfc_debugfs_trc *slow_ring_trc; - atomic_t slow_ring_trc_cnt; + atomic_unchecked_t slow_ring_trc_cnt; /* iDiag debugfs sub-directory */ struct dentry *idiag_root; struct dentry *idiag_pci_cfg; diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 25aa9b9..d700a65 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -106,7 +106,7 @@ MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc, #include -static atomic_t lpfc_debugfs_seq_trc_cnt = ATOMIC_INIT(0); +static atomic_unchecked_t lpfc_debugfs_seq_trc_cnt = ATOMIC_INIT(0); static unsigned long lpfc_debugfs_start_time = 0L; /* iDiag */ @@ -147,7 +147,7 @@ lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size) lpfc_debugfs_enable = 0; len = 0; - index = (atomic_read(&vport->disc_trc_cnt) + 1) & + index = (atomic_read_unchecked(&vport->disc_trc_cnt) + 1) & (lpfc_debugfs_max_disc_trc - 1); for (i = index; i < lpfc_debugfs_max_disc_trc; i++) { dtp = vport->disc_trc + i; @@ -213,7 +213,7 @@ lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size) lpfc_debugfs_enable = 0; len = 0; - index = (atomic_read(&phba->slow_ring_trc_cnt) + 1) & + index = (atomic_read_unchecked(&phba->slow_ring_trc_cnt) + 1) & (lpfc_debugfs_max_slow_ring_trc - 1); for (i = index; i < lpfc_debugfs_max_slow_ring_trc; i++) { dtp = phba->slow_ring_trc + i; @@ -646,14 +646,14 @@ lpfc_debugfs_disc_trc(struct lpfc_vport *vport, int mask, char *fmt, !vport || !vport->disc_trc) return; - index = atomic_inc_return(&vport->disc_trc_cnt) & + index = atomic_inc_return_unchecked(&vport->disc_trc_cnt) & (lpfc_debugfs_max_disc_trc - 1); dtp = vport->disc_trc + index; dtp->fmt = fmt; dtp->data1 = data1; dtp->data2 = data2; dtp->data3 = data3; - dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_seq_trc_cnt); + dtp->seq_cnt = atomic_inc_return_unchecked(&lpfc_debugfs_seq_trc_cnt); dtp->jif = jiffies; #endif return; @@ -684,14 +684,14 @@ lpfc_debugfs_slow_ring_trc(struct lpfc_hba *phba, char *fmt, !phba || !phba->slow_ring_trc) return; - index = atomic_inc_return(&phba->slow_ring_trc_cnt) & + index = atomic_inc_return_unchecked(&phba->slow_ring_trc_cnt) & (lpfc_debugfs_max_slow_ring_trc - 1); dtp = phba->slow_ring_trc + index; dtp->fmt = fmt; dtp->data1 = data1; dtp->data2 = data2; dtp->data3 = data3; - dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_seq_trc_cnt); + dtp->seq_cnt = atomic_inc_return_unchecked(&lpfc_debugfs_seq_trc_cnt); dtp->jif = jiffies; #endif return; @@ -4268,7 +4268,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) "slow_ring buffer\n"); goto debug_failed; } - atomic_set(&phba->slow_ring_trc_cnt, 0); + atomic_set_unchecked(&phba->slow_ring_trc_cnt, 0); memset(phba->slow_ring_trc, 0, (sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_slow_ring_trc)); @@ -4314,7 +4314,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) "buffer\n"); goto debug_failed; } - atomic_set(&vport->disc_trc_cnt, 0); + atomic_set_unchecked(&vport->disc_trc_cnt, 0); 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 f962118..6706983 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -11416,8 +11416,10 @@ lpfc_init(void) "misc_register returned with status %d", error); if (lpfc_enable_npiv) { - 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; + pax_close_kernel(); } lpfc_transport_template = fc_attach_transport(&lpfc_transport_functions); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index e5eb40d..056dcd4 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -261,7 +261,7 @@ lpfc_rampdown_queue_depth(struct lpfc_hba *phba) unsigned long expires; spin_lock_irqsave(&phba->hbalock, flags); - atomic_inc(&phba->num_rsrc_err); + atomic_inc_unchecked(&phba->num_rsrc_err); phba->last_rsrc_error_time = jiffies; expires = phba->last_ramp_down_time + QUEUE_RAMP_DOWN_INTERVAL; @@ -303,8 +303,8 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) unsigned long num_rsrc_err, num_cmd_success; int i; - num_rsrc_err = atomic_read(&phba->num_rsrc_err); - num_cmd_success = atomic_read(&phba->num_cmd_success); + num_rsrc_err = atomic_read_unchecked(&phba->num_rsrc_err); + num_cmd_success = atomic_read_unchecked(&phba->num_cmd_success); /* * The error and success command counters are global per @@ -331,8 +331,8 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) } } lpfc_destroy_vport_work_array(phba, vports); - atomic_set(&phba->num_rsrc_err, 0); - atomic_set(&phba->num_cmd_success, 0); + atomic_set_unchecked(&phba->num_rsrc_err, 0); + atomic_set_unchecked(&phba->num_cmd_success, 0); } /** diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 20c3754..1b05e727 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1700,7 +1700,7 @@ struct megasas_instance { s8 init_id; u16 max_num_sge; - u16 max_fw_cmds; + u16 max_fw_cmds __intentional_overflow(-1); u16 max_mfi_cmds; u16 max_scsi_cmds; u32 max_sectors_per_req; diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 0ad09b2..c9e6939 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -1638,7 +1638,7 @@ _scsih_get_resync(struct device *dev) { struct scsi_device *sdev = to_scsi_device(dev); struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); - static struct _raid_device *raid_device; + struct _raid_device *raid_device; unsigned long flags; Mpi2RaidVolPage0_t vol_pg0; Mpi2ConfigReply_t mpi_reply; @@ -1690,7 +1690,7 @@ _scsih_get_state(struct device *dev) { struct scsi_device *sdev = to_scsi_device(dev); struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); - static struct _raid_device *raid_device; + struct _raid_device *raid_device; unsigned long flags; Mpi2RaidVolPage0_t vol_pg0; Mpi2ConfigReply_t mpi_reply; @@ -6830,7 +6830,7 @@ _scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc, Mpi2EventDataIrOperationStatus_t *event_data = (Mpi2EventDataIrOperationStatus_t *) fw_event->event_data; - static struct _raid_device *raid_device; + struct _raid_device *raid_device; unsigned long flags; u16 handle; @@ -7317,7 +7317,7 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc) u64 sas_address; struct _sas_device *sas_device; struct _sas_node *expander_device; - static struct _raid_device *raid_device; + struct _raid_device *raid_device; u8 retry_count; unsigned long flags; diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index ed31d8c..ab856b3 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -200,8 +200,8 @@ static int pmcraid_slave_alloc(struct scsi_device *scsi_dev) res->scsi_dev = scsi_dev; scsi_dev->hostdata = res; res->change_detected = 0; - atomic_set(&res->read_failures, 0); - atomic_set(&res->write_failures, 0); + atomic_set_unchecked(&res->read_failures, 0); + atomic_set_unchecked(&res->write_failures, 0); rc = 0; } spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); @@ -2640,9 +2640,9 @@ static int pmcraid_error_handler(struct pmcraid_cmd *cmd) /* If this was a SCSI read/write command keep count of errors */ if (SCSI_CMD_TYPE(scsi_cmd->cmnd[0]) == SCSI_READ_CMD) - atomic_inc(&res->read_failures); + atomic_inc_unchecked(&res->read_failures); else if (SCSI_CMD_TYPE(scsi_cmd->cmnd[0]) == SCSI_WRITE_CMD) - atomic_inc(&res->write_failures); + atomic_inc_unchecked(&res->write_failures); if (!RES_IS_GSCSI(res->cfg_entry) && masked_ioasc != PMCRAID_IOASC_HW_DEVICE_BUS_STATUS_ERROR) { @@ -3468,7 +3468,7 @@ static int pmcraid_queuecommand_lck( * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses * hrrq_id assigned here in queuecommand */ - ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) % + ioarcb->hrrq_id = atomic_add_return_unchecked(1, &(pinstance->last_message_id)) % pinstance->num_hrrq; cmd->cmd_done = pmcraid_io_done; @@ -3782,7 +3782,7 @@ static long pmcraid_ioctl_passthrough( * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses * hrrq_id assigned here in queuecommand */ - ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) % + ioarcb->hrrq_id = atomic_add_return_unchecked(1, &(pinstance->last_message_id)) % pinstance->num_hrrq; if (request_size) { @@ -4420,7 +4420,7 @@ static void pmcraid_worker_function(struct work_struct *workp) pinstance = container_of(workp, struct pmcraid_instance, worker_q); /* add resources only after host is added into system */ - if (!atomic_read(&pinstance->expose_resources)) + if (!atomic_read_unchecked(&pinstance->expose_resources)) return; fw_version = be16_to_cpu(pinstance->inq_data->fw_version); @@ -5237,8 +5237,8 @@ static int pmcraid_init_instance(struct pci_dev *pdev, struct Scsi_Host *host, init_waitqueue_head(&pinstance->reset_wait_q); atomic_set(&pinstance->outstanding_cmds, 0); - atomic_set(&pinstance->last_message_id, 0); - atomic_set(&pinstance->expose_resources, 0); + atomic_set_unchecked(&pinstance->last_message_id, 0); + atomic_set_unchecked(&pinstance->expose_resources, 0); INIT_LIST_HEAD(&pinstance->free_res_q); INIT_LIST_HEAD(&pinstance->used_res_q); @@ -5951,7 +5951,7 @@ static int pmcraid_probe(struct pci_dev *pdev, /* Schedule worker thread to handle CCN and take care of adding and * removing devices to OS */ - atomic_set(&pinstance->expose_resources, 1); + atomic_set_unchecked(&pinstance->expose_resources, 1); schedule_work(&pinstance->worker_q); return rc; diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h index e1d150f..6c6df44 100644 --- a/drivers/scsi/pmcraid.h +++ b/drivers/scsi/pmcraid.h @@ -748,7 +748,7 @@ struct pmcraid_instance { struct pmcraid_isr_param hrrq_vector[PMCRAID_NUM_MSIX_VECTORS]; /* Message id as filled in last fired IOARCB, used to identify HRRQ */ - atomic_t last_message_id; + atomic_unchecked_t last_message_id; /* configuration table */ struct pmcraid_config_table *cfg_table; @@ -777,7 +777,7 @@ struct pmcraid_instance { atomic_t outstanding_cmds; /* should add/delete resources to mid-layer now ?*/ - atomic_t expose_resources; + atomic_unchecked_t expose_resources; @@ -813,8 +813,8 @@ struct pmcraid_resource_entry { struct pmcraid_config_table_entry_ext cfg_entry_ext; }; struct scsi_device *scsi_dev; /* Link scsi_device structure */ - atomic_t read_failures; /* count of failed READ commands */ - atomic_t write_failures; /* count of failed WRITE commands */ + atomic_unchecked_t read_failures; /* count of failed READ commands */ + atomic_unchecked_t write_failures; /* count of failed WRITE commands */ /* To indicate add/delete/modify during CCN */ u8 change_detected; diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 6b942d9..cd44452 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -2206,7 +2206,7 @@ qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable) return 0; } -struct fc_function_template qla2xxx_transport_functions = { +fc_function_template_no_const qla2xxx_transport_functions = { .show_host_node_name = 1, .show_host_port_name = 1, @@ -2254,7 +2254,7 @@ struct fc_function_template qla2xxx_transport_functions = { .bsg_timeout = qla24xx_bsg_timeout, }; -struct fc_function_template qla2xxx_transport_vport_functions = { +fc_function_template_no_const qla2xxx_transport_vport_functions = { .show_host_node_name = 1, .show_host_port_name = 1, diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 7686bfe..4710893 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -571,8 +571,8 @@ extern void qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *, size_t); struct device_attribute; extern struct device_attribute *qla2x00_host_attrs[]; struct fc_function_template; -extern struct fc_function_template qla2xxx_transport_functions; -extern struct fc_function_template qla2xxx_transport_vport_functions; +extern fc_function_template_no_const qla2xxx_transport_functions; +extern fc_function_template_no_const qla2xxx_transport_vport_functions; extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *); 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 c2dd17b..92bc0e0 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1424,8 +1424,10 @@ qla2x00_config_dma_addressing(struct qla_hw_data *ha) !pci_set_consistent_dma_mask(ha->pdev, DMA_BIT_MASK(64))) { /* Ok, a 64bit DMA mask is applicable. */ ha->flags.enable_64bit_addressing = 1; - 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; + pax_close_kernel(); return; } } diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index a7cfc27..151f483 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -306,7 +306,7 @@ struct ddb_entry { * (4000 only) */ atomic_t relogin_timer; /* Max Time to wait for * relogin to complete */ - atomic_t relogin_retry_count; /* Num of times relogin has been + atomic_unchecked_t relogin_retry_count; /* Num of times relogin has been * retried */ uint32_t default_time2wait; /* Default Min time between * relogins (+aens) */ diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 6d25879..3031a9f 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -4491,12 +4491,12 @@ static void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) */ if (!iscsi_is_session_online(cls_sess)) { /* Reset retry relogin timer */ - atomic_inc(&ddb_entry->relogin_retry_count); + atomic_inc_unchecked(&ddb_entry->relogin_retry_count); DEBUG2(ql4_printk(KERN_INFO, ha, "%s: index[%d] relogin timed out-retrying" " relogin (%d), retry (%d)\n", __func__, ddb_entry->fw_ddb_index, - atomic_read(&ddb_entry->relogin_retry_count), + atomic_read_unchecked(&ddb_entry->relogin_retry_count), ddb_entry->default_time2wait + 4)); set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); atomic_set(&ddb_entry->retry_relogin_timer, @@ -6604,7 +6604,7 @@ static void qla4xxx_setup_flash_ddb_entry(struct scsi_qla_host *ha, atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY); atomic_set(&ddb_entry->relogin_timer, 0); - atomic_set(&ddb_entry->relogin_retry_count, 0); + atomic_set_unchecked(&ddb_entry->relogin_retry_count, 0); def_timeout = le16_to_cpu(ddb_entry->fw_ddb_entry.def_timeout); ddb_entry->default_relogin_timeout = (def_timeout > LOGIN_TOV) && (def_timeout < LOGIN_TOV * 10) ? diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 207d6a7..bf155b5 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -591,7 +591,7 @@ void scsi_finish_command(struct scsi_cmnd *cmd) good_bytes = scsi_bufflen(cmd); if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) { - int old_good_bytes = good_bytes; + unsigned int old_good_bytes = good_bytes; drv = scsi_cmd_to_driver(cmd); if (drv->done) good_bytes = drv->done(cmd); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 126a48c..b38f662 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1597,7 +1597,7 @@ static void scsi_kill_request(struct request *req, struct request_queue *q) shost = sdev->host; scsi_init_cmd_errh(cmd); cmd->result = DID_NO_CONNECT << 16; - atomic_inc(&cmd->device->iorequest_cnt); + atomic_inc_unchecked(&cmd->device->iorequest_cnt); /* * SCSI request completion path will do scsi_device_unbusy(), @@ -1620,9 +1620,9 @@ static void scsi_softirq_done(struct request *rq) INIT_LIST_HEAD(&cmd->eh_entry); - atomic_inc(&cmd->device->iodone_cnt); + atomic_inc_unchecked(&cmd->device->iodone_cnt); if (cmd->result) - atomic_inc(&cmd->device->ioerr_cnt); + atomic_inc_unchecked(&cmd->device->ioerr_cnt); disposition = scsi_decide_disposition(cmd); if (disposition != SUCCESS && @@ -1663,7 +1663,7 @@ static int scsi_dispatch_cmd(struct scsi_cmnd *cmd) struct Scsi_Host *host = cmd->device->host; int rtn = 0; - atomic_inc(&cmd->device->iorequest_cnt); + atomic_inc_unchecked(&cmd->device->iorequest_cnt); /* check if the device is still usable */ if (unlikely(cmd->device->sdev_state == SDEV_DEL)) { diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index dff8faf..28dcc11 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -790,7 +790,7 @@ show_iostat_##field(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ struct scsi_device *sdev = to_scsi_device(dev); \ - unsigned long long count = atomic_read(&sdev->field); \ + unsigned long long count = atomic_read_unchecked(&sdev->field); \ return snprintf(buf, 20, "0x%llx\n", count); \ } \ static DEVICE_ATTR(field, S_IRUGO, show_iostat_##field, NULL) diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 24eaaf6..de30ec9 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -502,7 +502,7 @@ static DECLARE_TRANSPORT_CLASS(fc_vport_class, * Netlink Infrastructure */ -static atomic_t fc_event_seq; +static atomic_unchecked_t fc_event_seq; /** * fc_get_event_number - Obtain the next sequential FC event number @@ -515,7 +515,7 @@ static atomic_t fc_event_seq; u32 fc_get_event_number(void) { - return atomic_add_return(1, &fc_event_seq); + return atomic_add_return_unchecked(1, &fc_event_seq); } EXPORT_SYMBOL(fc_get_event_number); @@ -659,7 +659,7 @@ static __init int fc_transport_init(void) { int error; - atomic_set(&fc_event_seq, 0); + atomic_set_unchecked(&fc_event_seq, 0); error = transport_class_register(&fc_host_class); if (error) @@ -849,7 +849,7 @@ static int fc_str_to_dev_loss(const char *buf, unsigned long *val) char *cp; *val = simple_strtoul(buf, &cp, 0); - if ((*cp && (*cp != '\n')) || (*val < 0)) + if (*cp && (*cp != '\n')) return -EINVAL; /* * Check for overflow; dev_loss_tmo is u32 diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index e4b3d8f..3ab4dad 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -79,7 +79,7 @@ struct iscsi_internal { struct transport_container session_cont; }; -static atomic_t iscsi_session_nr; /* sysfs session id for next new session */ +static atomic_unchecked_t iscsi_session_nr; /* sysfs session id for next new session */ static struct workqueue_struct *iscsi_eh_timer_workq; static DEFINE_IDA(iscsi_sess_ida); @@ -2074,7 +2074,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) int err; ihost = shost->shost_data; - session->sid = atomic_add_return(1, &iscsi_session_nr); + session->sid = atomic_add_return_unchecked(1, &iscsi_session_nr); if (target_id == ISCSI_MAX_TARGET) { id = ida_simple_get(&iscsi_sess_ida, 0, 0, GFP_KERNEL); @@ -4522,7 +4522,7 @@ static __init int iscsi_transport_init(void) printk(KERN_INFO "Loading iSCSI transport class v%s.\n", ISCSI_TRANSPORT_VERSION); - atomic_set(&iscsi_session_nr, 0); + atomic_set_unchecked(&iscsi_session_nr, 0); err = class_register(&iscsi_transport_class); if (err) diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c index e3cd3ec..00560ec 100644 --- a/drivers/scsi/scsi_transport_srp.c +++ b/drivers/scsi/scsi_transport_srp.c @@ -35,7 +35,7 @@ #include "scsi_priv.h" struct srp_host_attrs { - atomic_t next_port_id; + atomic_unchecked_t next_port_id; }; #define to_srp_host_attrs(host) ((struct srp_host_attrs *)(host)->shost_data) @@ -105,7 +105,7 @@ static int srp_host_setup(struct transport_container *tc, struct device *dev, struct Scsi_Host *shost = dev_to_shost(dev); struct srp_host_attrs *srp_host = to_srp_host_attrs(shost); - atomic_set(&srp_host->next_port_id, 0); + atomic_set_unchecked(&srp_host->next_port_id, 0); return 0; } @@ -752,7 +752,7 @@ struct srp_rport *srp_rport_add(struct Scsi_Host *shost, rport_fast_io_fail_timedout); INIT_DELAYED_WORK(&rport->dev_loss_work, rport_dev_loss_timedout); - id = atomic_inc_return(&to_srp_host_attrs(shost)->next_port_id); + id = atomic_inc_return_unchecked(&to_srp_host_attrs(shost)->next_port_id); dev_set_name(&rport->dev, "port-%d:%d", shost->host_no, id); transport_setup_device(&rport->dev); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3f37022..43557f0 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -111,7 +111,7 @@ static int sd_resume(struct device *); static void sd_rescan(struct device *); static int sd_init_command(struct scsi_cmnd *SCpnt); static void sd_uninit_command(struct scsi_cmnd *SCpnt); -static int sd_done(struct scsi_cmnd *); +static unsigned int sd_done(struct scsi_cmnd *); static int sd_eh_action(struct scsi_cmnd *, int); static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer); static void scsi_disk_release(struct device *cdev); @@ -1646,7 +1646,7 @@ static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd) * * Note: potentially run from within an ISR. Must not block. **/ -static int sd_done(struct scsi_cmnd *SCpnt) +static unsigned int sd_done(struct scsi_cmnd *SCpnt) { int result = SCpnt->result; unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt); @@ -2973,7 +2973,7 @@ static int sd_probe(struct device *dev) sdkp->disk = gd; sdkp->index = index; atomic_set(&sdkp->openers, 0); - atomic_set(&sdkp->device->ioerr_cnt, 0); + atomic_set_unchecked(&sdkp->device->ioerr_cnt, 0); if (!sdp->request_queue->rq_timeout) { if (sdp->type != TYPE_MOD) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 9d7b7db..33ecc51 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1083,7 +1083,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) sdp->disk->disk_name, MKDEV(SCSI_GENERIC_MAJOR, sdp->index), NULL, - (char *)arg); + (char __user *)arg); case BLKTRACESTART: return blk_trace_startstop(sdp->device->request_queue, 1); case BLKTRACESTOP: diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 8bd54a6..58fa0d6 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -80,7 +80,7 @@ static DEFINE_MUTEX(sr_mutex); static int sr_probe(struct device *); static int sr_remove(struct device *); static int sr_init_command(struct scsi_cmnd *SCpnt); -static int sr_done(struct scsi_cmnd *); +static unsigned int sr_done(struct scsi_cmnd *); static int sr_runtime_suspend(struct device *dev); static struct dev_pm_ops sr_pm_ops = { @@ -312,13 +312,13 @@ do_tur: * It will be notified on the end of a SCSI read / write, and will take one * of several actions based on success or failure. */ -static int sr_done(struct scsi_cmnd *SCpnt) +static unsigned int sr_done(struct scsi_cmnd *SCpnt) { int result = SCpnt->result; - int this_count = scsi_bufflen(SCpnt); - int good_bytes = (result == 0 ? this_count : 0); - int block_sectors = 0; - long error_sector; + unsigned int this_count = scsi_bufflen(SCpnt); + unsigned int good_bytes = (result == 0 ? this_count : 0); + unsigned int block_sectors = 0; + sector_t error_sector; struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk); #ifdef DEBUG @@ -351,9 +351,12 @@ static int sr_done(struct scsi_cmnd *SCpnt) if (cd->device->sector_size == 2048) error_sector <<= 2; error_sector &= ~(block_sectors - 1); - good_bytes = (error_sector - - blk_rq_pos(SCpnt->request)) << 9; - if (good_bytes < 0 || good_bytes >= this_count) + if (error_sector >= blk_rq_pos(SCpnt->request)) { + good_bytes = (error_sector - + blk_rq_pos(SCpnt->request)) << 9; + if (good_bytes >= this_count) + good_bytes = 0; + } else good_bytes = 0; /* * The SCSI specification allows for the value diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index de2c1bf..60b8563 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -72,7 +72,7 @@ static ssize_t fuse_read(struct file *fd, struct kobject *kobj, return i; } -static struct bin_attribute fuse_bin_attr = { +static bin_attribute_no_const fuse_bin_attr = { .attr = { .name = "fuse", .mode = S_IRUGO, }, .read = fuse_read, }; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index a5f53de..105bfd3 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2414,7 +2414,7 @@ int spi_bus_unlock(struct spi_master *master) EXPORT_SYMBOL_GPL(spi_bus_unlock); /* portable code must never pass more than 32 bytes */ -#define SPI_BUFSIZ max(32, SMP_CACHE_BYTES) +#define SPI_BUFSIZ max(32UL, SMP_CACHE_BYTES) static u8 *buf; diff --git a/drivers/staging/android/timed_output.c b/drivers/staging/android/timed_output.c index b41429f..2de5373 100644 --- a/drivers/staging/android/timed_output.c +++ b/drivers/staging/android/timed_output.c @@ -25,7 +25,7 @@ #include "timed_output.h" static struct class *timed_output_class; -static atomic_t device_count; +static atomic_unchecked_t device_count; static ssize_t enable_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -65,7 +65,7 @@ static int create_timed_output_class(void) timed_output_class = class_create(THIS_MODULE, "timed_output"); if (IS_ERR(timed_output_class)) return PTR_ERR(timed_output_class); - atomic_set(&device_count, 0); + atomic_set_unchecked(&device_count, 0); timed_output_class->dev_groups = timed_output_groups; } @@ -83,7 +83,7 @@ int timed_output_dev_register(struct timed_output_dev *tdev) if (ret < 0) return ret; - tdev->index = atomic_inc_return(&device_count); + tdev->index = atomic_inc_return_unchecked(&device_count); tdev->dev = device_create(timed_output_class, NULL, MKDEV(0, tdev->index), NULL, "%s", tdev->name); if (IS_ERR(tdev->dev)) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 0e8a451..9558241 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -311,8 +311,8 @@ static void comedi_file_reset(struct file *file) } cfp->last_attached = dev->attached; cfp->last_detach_count = dev->detach_count; - ACCESS_ONCE(cfp->read_subdev) = read_s; - ACCESS_ONCE(cfp->write_subdev) = write_s; + ACCESS_ONCE_RW(cfp->read_subdev) = read_s; + ACCESS_ONCE_RW(cfp->write_subdev) = write_s; } static void comedi_file_check(struct file *file) @@ -1980,7 +1980,7 @@ static int do_setrsubd_ioctl(struct comedi_device *dev, unsigned long arg, !(s_old->async->cmd.flags & CMDF_WRITE)) return -EBUSY; - ACCESS_ONCE(cfp->read_subdev) = s_new; + ACCESS_ONCE_RW(cfp->read_subdev) = s_new; return 0; } @@ -2022,7 +2022,7 @@ static int do_setwsubd_ioctl(struct comedi_device *dev, unsigned long arg, (s_old->async->cmd.flags & CMDF_WRITE)) return -EBUSY; - ACCESS_ONCE(cfp->write_subdev) = s_new; + ACCESS_ONCE_RW(cfp->write_subdev) = s_new; return 0; } diff --git a/drivers/staging/dgnc/dgnc_mgmt.c b/drivers/staging/dgnc/dgnc_mgmt.c index b13318a..883e2a8 100644 --- a/drivers/staging/dgnc/dgnc_mgmt.c +++ b/drivers/staging/dgnc/dgnc_mgmt.c @@ -115,6 +115,7 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) spin_lock_irqsave(&dgnc_global_lock, flags); + memset(&ddi, 0, sizeof(ddi)); ddi.dinfo_nboards = dgnc_NumBoards; sprintf(ddi.dinfo_version, "%s", DG_PART); diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index 7f5fa3d..53b5471 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -682,7 +682,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, { struct fb_info *info; struct fbtft_par *par; - struct fb_ops *fbops = NULL; + fb_ops_no_const *fbops = NULL; struct fb_deferred_io *fbdefio = NULL; u8 *vmem = NULL; void *txbuf = NULL; diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h index 7e9a506..d0b0069 100644 --- a/drivers/staging/fbtft/fbtft.h +++ b/drivers/staging/fbtft/fbtft.h @@ -106,7 +106,7 @@ struct fbtft_ops { int (*set_var)(struct fbtft_par *par); int (*set_gamma)(struct fbtft_par *par, unsigned long *curves); -}; +} __no_const; /** * struct fbtft_display - Describes the display properties diff --git a/drivers/staging/gdm724x/gdm_tty.c b/drivers/staging/gdm724x/gdm_tty.c index 001348c..cfaac8a 100644 --- a/drivers/staging/gdm724x/gdm_tty.c +++ b/drivers/staging/gdm724x/gdm_tty.c @@ -44,7 +44,7 @@ #define gdm_tty_send_control(n, r, v, d, l) (\ n->tty_dev->send_control(n->tty_dev->priv_dev, r, v, d, l)) -#define GDM_TTY_READY(gdm) (gdm && gdm->tty_dev && gdm->port.count) +#define GDM_TTY_READY(gdm) (gdm && gdm->tty_dev && atomic_read(&gdm->port.count)) static struct tty_driver *gdm_driver[TTY_MAX_COUNT]; static struct gdm *gdm_table[TTY_MAX_COUNT][GDM_TTY_MINOR]; diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c index b892f2c..9b4898a 100644 --- a/drivers/staging/iio/accel/lis3l02dq_ring.c +++ b/drivers/staging/iio/accel/lis3l02dq_ring.c @@ -118,7 +118,7 @@ static int lis3l02dq_get_buffer_element(struct iio_dev *indio_dev, int scan_count = bitmap_weight(indio_dev->active_scan_mask, indio_dev->masklength); - rx_array = kcalloc(4, scan_count, GFP_KERNEL); + rx_array = kcalloc(scan_count, 4, GFP_KERNEL); if (!rx_array) return -ENOMEM; ret = lis3l02dq_read_all(indio_dev, rx_array); diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index d98e229..9c59bc2 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -547,8 +547,8 @@ static int ad7280_attr_init(struct ad7280_state *st) { int dev, ch, cnt; - st->iio_attr = kcalloc(2, sizeof(*st->iio_attr) * - (st->slave_num + 1) * AD7280A_CELLS_PER_DEV, + st->iio_attr = kcalloc(sizeof(*st->iio_attr) * + (st->slave_num + 1) * AD7280A_CELLS_PER_DEV, 2, GFP_KERNEL); if (st->iio_attr == NULL) return -ENOMEM; diff --git a/drivers/staging/lustre/lnet/selftest/brw_test.c b/drivers/staging/lustre/lnet/selftest/brw_test.c index de11f1b..f7181cf 100644 --- a/drivers/staging/lustre/lnet/selftest/brw_test.c +++ b/drivers/staging/lustre/lnet/selftest/brw_test.c @@ -487,13 +487,11 @@ brw_server_handle(struct srpc_server_rpc *rpc) return 0; } -sfw_test_client_ops_t brw_test_client; -void brw_init_test_client(void) -{ - brw_test_client.tso_init = brw_client_init; - brw_test_client.tso_fini = brw_client_fini; - brw_test_client.tso_prep_rpc = brw_client_prep_rpc; - brw_test_client.tso_done_rpc = brw_client_done_rpc; +sfw_test_client_ops_t brw_test_client = { + .tso_init = brw_client_init, + .tso_fini = brw_client_fini, + .tso_prep_rpc = brw_client_prep_rpc, + .tso_done_rpc = brw_client_done_rpc, }; srpc_service_t brw_test_service; diff --git a/drivers/staging/lustre/lnet/selftest/framework.c b/drivers/staging/lustre/lnet/selftest/framework.c index 257de35..efa188f 100644 --- a/drivers/staging/lustre/lnet/selftest/framework.c +++ b/drivers/staging/lustre/lnet/selftest/framework.c @@ -1630,12 +1630,10 @@ static srpc_service_t sfw_services[] = { extern sfw_test_client_ops_t ping_test_client; extern srpc_service_t ping_test_service; -extern void ping_init_test_client(void); extern void ping_init_test_service(void); extern sfw_test_client_ops_t brw_test_client; extern srpc_service_t brw_test_service; -extern void brw_init_test_client(void); extern void brw_init_test_service(void); @@ -1677,12 +1675,10 @@ sfw_startup(void) INIT_LIST_HEAD(&sfw_data.fw_zombie_rpcs); INIT_LIST_HEAD(&sfw_data.fw_zombie_sessions); - brw_init_test_client(); brw_init_test_service(); rc = sfw_register_test(&brw_test_service, &brw_test_client); LASSERT(rc == 0); - ping_init_test_client(); ping_init_test_service(); rc = sfw_register_test(&ping_test_service, &ping_test_client); LASSERT(rc == 0); diff --git a/drivers/staging/lustre/lnet/selftest/ping_test.c b/drivers/staging/lustre/lnet/selftest/ping_test.c index 1dab998..edfe0ac 100644 --- a/drivers/staging/lustre/lnet/selftest/ping_test.c +++ b/drivers/staging/lustre/lnet/selftest/ping_test.c @@ -211,14 +211,12 @@ ping_server_handle(struct srpc_server_rpc *rpc) return 0; } -sfw_test_client_ops_t ping_test_client; -void ping_init_test_client(void) -{ - ping_test_client.tso_init = ping_client_init; - ping_test_client.tso_fini = ping_client_fini; - ping_test_client.tso_prep_rpc = ping_client_prep_rpc; - ping_test_client.tso_done_rpc = ping_client_done_rpc; -} +sfw_test_client_ops_t ping_test_client = { + .tso_init = ping_client_init, + .tso_fini = ping_client_fini, + .tso_prep_rpc = ping_client_prep_rpc, + .tso_done_rpc = ping_client_done_rpc, +}; srpc_service_t ping_test_service; void ping_init_test_service(void) diff --git a/drivers/staging/lustre/lustre/include/lustre_dlm.h b/drivers/staging/lustre/lustre/include/lustre_dlm.h index 3552546..ce67377 100644 --- a/drivers/staging/lustre/lustre/include/lustre_dlm.h +++ b/drivers/staging/lustre/lustre/include/lustre_dlm.h @@ -1107,7 +1107,7 @@ struct ldlm_callback_suite { ldlm_completion_callback lcs_completion; ldlm_blocking_callback lcs_blocking; ldlm_glimpse_callback lcs_glimpse; -}; +} __no_const; /* ldlm_lockd.c */ int ldlm_del_waiting_lock(struct ldlm_lock *lock); diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h index 9ad8c26..4e3c733 100644 --- a/drivers/staging/lustre/lustre/include/obd.h +++ b/drivers/staging/lustre/lustre/include/obd.h @@ -1364,7 +1364,7 @@ struct md_ops { * lprocfs_alloc_md_stats() in obdclass/lprocfs_status.c. Also, add a * wrapper function in include/linux/obd_class.h. */ -}; +} __no_const; struct lsm_operations { void (*lsm_free)(struct lov_stripe_md *); diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c index a4c252f..b21acac 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c @@ -258,7 +258,7 @@ ldlm_process_flock_lock(struct ldlm_lock *req, __u64 *flags, int first_enq, int added = (mode == LCK_NL); int overlaps = 0; int splitted = 0; - const struct ldlm_callback_suite null_cbs = { NULL }; + const struct ldlm_callback_suite null_cbs = { }; CDEBUG(D_DLMTRACE, "flags %#llx owner %llu pid %u mode %u start %llu end %llu\n", diff --git a/drivers/staging/lustre/lustre/libcfs/module.c b/drivers/staging/lustre/lustre/libcfs/module.c index 806f974..afed877 100644 --- a/drivers/staging/lustre/lustre/libcfs/module.c +++ b/drivers/staging/lustre/lustre/libcfs/module.c @@ -342,11 +342,11 @@ out: struct cfs_psdev_ops libcfs_psdev_ops = { - libcfs_psdev_open, - libcfs_psdev_release, - NULL, - NULL, - libcfs_ioctl + .p_open = libcfs_psdev_open, + .p_close = libcfs_psdev_release, + .p_read = NULL, + .p_write = NULL, + .p_ioctl = libcfs_ioctl }; static int init_libcfs_module(void) diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c index d1a33a9..86e634e 100644 --- a/drivers/staging/octeon/ethernet-rx.c +++ b/drivers/staging/octeon/ethernet-rx.c @@ -363,15 +363,15 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) /* Increment RX stats for virtual ports */ if (port >= CVMX_PIP_NUM_INPUT_PORTS) { #ifdef CONFIG_64BIT - atomic64_add(1, - (atomic64_t *)&priv->stats.rx_packets); - atomic64_add(skb->len, - (atomic64_t *)&priv->stats.rx_bytes); + atomic64_add_unchecked(1, + (atomic64_unchecked_t *)&priv->stats.rx_packets); + atomic64_add_unchecked(skb->len, + (atomic64_unchecked_t *)&priv->stats.rx_bytes); #else - atomic_add(1, - (atomic_t *)&priv->stats.rx_packets); - atomic_add(skb->len, - (atomic_t *)&priv->stats.rx_bytes); + atomic_add_unchecked(1, + (atomic_unchecked_t *)&priv->stats.rx_packets); + atomic_add_unchecked(skb->len, + (atomic_unchecked_t *)&priv->stats.rx_bytes); #endif } netif_receive_skb(skb); @@ -382,10 +382,10 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) dev->name); */ #ifdef CONFIG_64BIT - atomic64_add(1, + atomic64_add_unchecked(1, (atomic64_t *)&priv->stats.rx_dropped); #else - atomic_add(1, + atomic_add_unchecked(1, (atomic_t *)&priv->stats.rx_dropped); #endif dev_kfree_skb_irq(skb); diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c index 7274fda..ff5afcc 100644 --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c @@ -232,11 +232,11 @@ static struct net_device_stats *cvm_oct_common_get_stats(struct net_device *dev) * since the RX tasklet also increments it. */ #ifdef CONFIG_64BIT - atomic64_add(rx_status.dropped_packets, - (atomic64_t *)&priv->stats.rx_dropped); + atomic64_add_unchecked(rx_status.dropped_packets, + (atomic64_unchecked_t *)&priv->stats.rx_dropped); #else - atomic_add(rx_status.dropped_packets, - (atomic_t *)&priv->stats.rx_dropped); + atomic_add_unchecked(rx_status.dropped_packets, + (atomic_unchecked_t *)&priv->stats.rx_dropped); #endif } diff --git a/drivers/staging/rdma/ipath/ipath_rc.c b/drivers/staging/rdma/ipath/ipath_rc.c index 79b3dbc..96e5fcc 100644 --- a/drivers/staging/rdma/ipath/ipath_rc.c +++ b/drivers/staging/rdma/ipath/ipath_rc.c @@ -1868,7 +1868,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, struct ib_atomic_eth *ateth; struct ipath_ack_entry *e; u64 vaddr; - atomic64_t *maddr; + atomic64_unchecked_t *maddr; u64 sdata; u32 rkey; u8 next; @@ -1903,11 +1903,11 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, IB_ACCESS_REMOTE_ATOMIC))) goto nack_acc_unlck; /* Perform atomic OP and save result. */ - maddr = (atomic64_t *) qp->r_sge.sge.vaddr; + maddr = (atomic64_unchecked_t *) qp->r_sge.sge.vaddr; sdata = be64_to_cpu(ateth->swap_data); e = &qp->s_ack_queue[qp->r_head_ack_queue]; e->atomic_data = (opcode == OP(FETCH_ADD)) ? - (u64) atomic64_add_return(sdata, maddr) - sdata : + (u64) atomic64_add_return_unchecked(sdata, maddr) - sdata : (u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr, be64_to_cpu(ateth->compare_data), sdata); diff --git a/drivers/staging/rdma/ipath/ipath_ruc.c b/drivers/staging/rdma/ipath/ipath_ruc.c index 1f95bba..9530f87 100644 --- a/drivers/staging/rdma/ipath/ipath_ruc.c +++ b/drivers/staging/rdma/ipath/ipath_ruc.c @@ -266,7 +266,7 @@ static void ipath_ruc_loopback(struct ipath_qp *sqp) unsigned long flags; struct ib_wc wc; u64 sdata; - atomic64_t *maddr; + atomic64_unchecked_t *maddr; enum ib_wc_status send_status; /* @@ -382,11 +382,11 @@ again: IB_ACCESS_REMOTE_ATOMIC))) goto acc_err; /* Perform atomic OP and save result. */ - maddr = (atomic64_t *) qp->r_sge.sge.vaddr; + maddr = (atomic64_unchecked_t *) qp->r_sge.sge.vaddr; sdata = wqe->wr.wr.atomic.compare_add; *(u64 *) sqp->s_sge.sge.vaddr = (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ? - (u64) atomic64_add_return(sdata, maddr) - sdata : + (u64) atomic64_add_return_unchecked(sdata, maddr) - sdata : (u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr, sdata, wqe->wr.wr.atomic.swap); goto send_comp; diff --git a/drivers/staging/rtl8188eu/include/hal_intf.h b/drivers/staging/rtl8188eu/include/hal_intf.h index e73c634..c835570 100644 --- a/drivers/staging/rtl8188eu/include/hal_intf.h +++ b/drivers/staging/rtl8188eu/include/hal_intf.h @@ -217,7 +217,7 @@ struct hal_ops { void (*hal_notch_filter)(struct adapter *adapter, bool enable); void (*hal_reset_security_engine)(struct adapter *adapter); -}; +} __no_const; enum rt_eeprom_type { EEPROM_93C46, diff --git a/drivers/staging/rtl8712/rtl871x_io.h b/drivers/staging/rtl8712/rtl871x_io.h index 070cc03..6806e37 100644 --- a/drivers/staging/rtl8712/rtl871x_io.h +++ b/drivers/staging/rtl8712/rtl871x_io.h @@ -108,7 +108,7 @@ struct _io_ops { u8 *pmem); u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); -}; +} __no_const; struct io_req { struct list_head list; diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c index 07f8afd..66ea627 100644 --- a/drivers/staging/sm750fb/sm750.c +++ b/drivers/staging/sm750fb/sm750.c @@ -766,6 +766,7 @@ static struct fb_ops lynxfb_ops = { .fb_set_par = lynxfb_ops_set_par, .fb_setcolreg = lynxfb_ops_setcolreg, .fb_blank = lynxfb_ops_blank, + .fb_pan_display = lynxfb_ops_pan_display, .fb_fillrect = cfb_fillrect, .fb_imageblit = cfb_imageblit, .fb_copyarea = cfb_copyarea, @@ -811,7 +812,6 @@ static int lynxfb_set_fbinfo(struct fb_info *info, int index) par->index = index; output->channel = &crtc->channel; sm750fb_set_drv(par); - lynxfb_ops.fb_pan_display = lynxfb_ops_pan_display; /* * set current cursor variable and proc pointer, @@ -834,16 +834,20 @@ static int lynxfb_set_fbinfo(struct fb_info *info, int index) crtc->cursor.share = share; memset_io(crtc->cursor.vstart, 0, crtc->cursor.size); if (!g_hwcursor) { - lynxfb_ops.fb_cursor = NULL; + pax_open_kernel(); + *(void **)&lynxfb_ops.fb_cursor = NULL; + pax_close_kernel(); crtc->cursor.disable(&crtc->cursor); } /* set info->fbops, must be set before fb_find_mode */ if (!share->accel_off) { /* use 2d acceleration */ - lynxfb_ops.fb_fillrect = lynxfb_ops_fillrect; - 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; + pax_close_kernel(); } info->fbops = &lynxfb_ops; diff --git a/drivers/staging/unisys/visorbus/visorbus_private.h b/drivers/staging/unisys/visorbus/visorbus_private.h index 39edd20..d860d0c 100644 --- a/drivers/staging/unisys/visorbus/visorbus_private.h +++ b/drivers/staging/unisys/visorbus/visorbus_private.h @@ -34,7 +34,7 @@ struct visorchipset_busdev_notifiers { void (*device_destroy)(struct visor_device *bus_info); void (*device_pause)(struct visor_device *bus_info); void (*device_resume)(struct visor_device *bus_info); -}; +} __no_const; /* These functions live inside visorchipset, and will be called to indicate * responses to specific events (by code outside of visorchipset). @@ -49,7 +49,7 @@ struct visorchipset_busdev_responders { void (*device_destroy)(struct visor_device *p, int response); void (*device_pause)(struct visor_device *p, int response); void (*device_resume)(struct visor_device *p, int response); -}; +} __no_const; /** Register functions (in the bus driver) to get called by visorchipset * whenever a bus or device appears for which this guest is to be the diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 0edf320..49afe95 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -60,7 +60,7 @@ static const u32 sbp_unit_directory_template[] = { #define SESSION_MAINTENANCE_INTERVAL HZ -static atomic_t login_id = ATOMIC_INIT(0); +static atomic_unchecked_t login_id = ATOMIC_INIT(0); static void session_maintenance_work(struct work_struct *); static int sbp_run_transaction(struct fw_card *, int, int, int, int, @@ -441,7 +441,7 @@ static void sbp_management_request_login( login->login_lun = unpacked_lun; login->status_fifo_addr = sbp2_pointer_to_addr(&req->orb.status_fifo); login->exclusive = LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc)); - login->login_id = atomic_inc_return(&login_id); + login->login_id = atomic_inc_return_unchecked(&login_id); login->tgt_agt = sbp_target_agent_register(login); if (IS_ERR(login->tgt_agt)) { diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 0b4b2a6..98698d8 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -371,7 +371,8 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o return 0; } -static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd, bool success) +static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd, bool success, + int *post_ret) { unsigned char *buf, *addr; struct scatterlist *sg; @@ -437,7 +438,8 @@ sbc_execute_rw(struct se_cmd *cmd) cmd->data_direction); } -static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success) +static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success, + int *post_ret) { struct se_device *dev = cmd->se_dev; @@ -447,8 +449,10 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success) * sent to the backend driver. */ spin_lock_irq(&cmd->t_state_lock); - if ((cmd->transport_state & CMD_T_SENT) && !cmd->scsi_status) + if ((cmd->transport_state & CMD_T_SENT) && !cmd->scsi_status) { cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST; + *post_ret = 1; + } spin_unlock_irq(&cmd->t_state_lock); /* @@ -460,7 +464,8 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success) return TCM_NO_SENSE; } -static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success) +static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success, + int *post_ret) { struct se_device *dev = cmd->se_dev; struct scatterlist *write_sg = NULL, *sg; @@ -556,11 +561,11 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes if (block_size < PAGE_SIZE) { sg_set_page(&write_sg[i], m.page, block_size, - block_size); + m.piter.sg->offset + block_size); } else { sg_miter_next(&m); sg_set_page(&write_sg[i], m.page, block_size, - 0); + m.piter.sg->offset); } len -= block_size; i++; diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 5bacc7b..010b8c4 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1658,7 +1658,7 @@ bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags) void transport_generic_request_failure(struct se_cmd *cmd, sense_reason_t sense_reason) { - int ret = 0; + int ret = 0, post_ret = 0; pr_debug("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08llx" " CDB: 0x%02x\n", cmd, cmd->tag, cmd->t_task_cdb[0]); @@ -1680,7 +1680,7 @@ void transport_generic_request_failure(struct se_cmd *cmd, */ if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) && cmd->transport_complete_callback) - cmd->transport_complete_callback(cmd, false); + cmd->transport_complete_callback(cmd, false, &post_ret); switch (sense_reason) { case TCM_NON_EXISTENT_LUN: @@ -2068,11 +2068,13 @@ static void target_complete_ok_work(struct work_struct *work) */ if (cmd->transport_complete_callback) { sense_reason_t rc; + bool caw = (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE); + bool zero_dl = !(cmd->data_length); + int post_ret = 0; - rc = cmd->transport_complete_callback(cmd, true); - if (!rc && !(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE_POST)) { - if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) && - !cmd->data_length) + rc = cmd->transport_complete_callback(cmd, true, &post_ret); + if (!rc && !post_ret) { + if (caw && zero_dl) goto queue_rsp; return; diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 42c6f71..1c64309 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -838,10 +838,11 @@ __cpufreq_cooling_register(struct device_node *np, cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus); if (capacitance) { - cpufreq_cooling_ops.get_requested_power = - cpufreq_get_requested_power; - 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; + pax_close_kernel(); cpufreq_dev->plat_get_static_power = plat_static_func; ret = build_dyn_power_table(cpufreq_dev, capacitance); diff --git a/drivers/thermal/int340x_thermal/int3400_thermal.c b/drivers/thermal/int340x_thermal/int3400_thermal.c index 5836e55..740ab89 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) platform_set_drvdata(pdev, priv); if (priv->uuid_bitmap & 1 << INT3400_THERMAL_PASSIVE_1) { - 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; + 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 42b7d42..d48c0db 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "thermal_core.h" @@ -417,9 +418,11 @@ thermal_zone_of_add_sensor(struct device_node *zone, tz->ops = ops; tz->sensor_data = data; - tzd->ops->get_temp = of_thermal_get_temp; - 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; + pax_close_kernel(); mutex_unlock(&tzd->lock); return tzd; @@ -549,9 +552,11 @@ void thermal_zone_of_sensor_unregister(struct device *dev, return; mutex_lock(&tzd->lock); - tzd->ops->get_temp = NULL; - 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; + pax_close_kernel(); tz->ops = NULL; tz->sensor_data = NULL; diff --git a/drivers/thermal/x86_pkg_temp_thermal.c b/drivers/thermal/x86_pkg_temp_thermal.c index 7fc919f..19f23a5 100644 --- a/drivers/thermal/x86_pkg_temp_thermal.c +++ b/drivers/thermal/x86_pkg_temp_thermal.c @@ -567,7 +567,7 @@ static int pkg_temp_thermal_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -static struct notifier_block pkg_temp_thermal_notifier __refdata = { +static struct notifier_block pkg_temp_thermal_notifier __refconst = { .notifier_call = pkg_temp_thermal_cpu_callback, }; diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index 87f6578..905c8f8 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -1570,10 +1570,10 @@ static int cy_open(struct tty_struct *tty, struct file *filp) printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line, info->port.count); #endif - info->port.count++; + atomic_inc(&info->port.count); #ifdef CY_DEBUG_COUNT printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n", - current->pid, info->port.count); + current->pid, atomic_read(&info->port.count)); #endif /* @@ -3970,7 +3970,7 @@ static int cyclades_proc_show(struct seq_file *m, void *v) for (j = 0; j < cy_card[i].nports; j++) { info = &cy_card[i].ports[j]; - if (info->port.count) { + if (atomic_read(&info->port.count)) { /* XXX is the ldisc num worth this? */ struct tty_struct *tty; struct tty_ldisc *ld; diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 4e9c4cc..2199d8f 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -343,7 +343,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) spin_lock_irqsave(&hp->port.lock, flags); /* Check and then increment for fast path open. */ - if (hp->port.count++ > 0) { + if (atomic_inc_return(&hp->port.count) > 1) { spin_unlock_irqrestore(&hp->port.lock, flags); hvc_kick(); return 0; @@ -398,7 +398,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) spin_lock_irqsave(&hp->port.lock, flags); - if (--hp->port.count == 0) { + if (atomic_dec_return(&hp->port.count) == 0) { spin_unlock_irqrestore(&hp->port.lock, flags); /* We are done with the tty pointer now. */ tty_port_tty_set(&hp->port, NULL); @@ -420,9 +420,9 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) */ tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT); } else { - if (hp->port.count < 0) + if (atomic_read(&hp->port.count) < 0) printk(KERN_ERR "hvc_close %X: oops, count is %d\n", - hp->vtermno, hp->port.count); + hp->vtermno, atomic_read(&hp->port.count)); spin_unlock_irqrestore(&hp->port.lock, flags); } } @@ -452,12 +452,12 @@ static void hvc_hangup(struct tty_struct *tty) * open->hangup case this can be called after the final close so prevent * that from happening for now. */ - if (hp->port.count <= 0) { + if (atomic_read(&hp->port.count) <= 0) { spin_unlock_irqrestore(&hp->port.lock, flags); return; } - hp->port.count = 0; + atomic_set(&hp->port.count, 0); spin_unlock_irqrestore(&hp->port.lock, flags); tty_port_tty_set(&hp->port, NULL); @@ -505,7 +505,7 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count return -EPIPE; /* FIXME what's this (unprotected) check for? */ - if (hp->port.count <= 0) + if (atomic_read(&hp->port.count) <= 0) return -EIO; spin_lock_irqsave(&hp->lock, flags); diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index f7ff97c..0c0ebbf 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -83,6 +83,7 @@ #include #include #include +#include /* * 1.3.0 -> 1.3.1 In hvcs_open memset(..,0x00,..) instead of memset(..,0x3F,00). @@ -416,7 +417,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribut spin_lock_irqsave(&hvcsd->lock, flags); - if (hvcsd->port.count > 0) { + if (atomic_read(&hvcsd->port.count) > 0) { spin_unlock_irqrestore(&hvcsd->lock, flags); printk(KERN_INFO "HVCS: vterm state unchanged. " "The hvcs device node is still in use.\n"); @@ -1127,7 +1128,7 @@ static int hvcs_install(struct tty_driver *driver, struct tty_struct *tty) } } - hvcsd->port.count = 0; + atomic_set(&hvcsd->port.count, 0); hvcsd->port.tty = tty; tty->driver_data = hvcsd; @@ -1180,7 +1181,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) unsigned long flags; spin_lock_irqsave(&hvcsd->lock, flags); - hvcsd->port.count++; + atomic_inc(&hvcsd->port.count); hvcsd->todo_mask |= HVCS_SCHED_READ; spin_unlock_irqrestore(&hvcsd->lock, flags); @@ -1216,7 +1217,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) hvcsd = tty->driver_data; spin_lock_irqsave(&hvcsd->lock, flags); - if (--hvcsd->port.count == 0) { + if (atomic_dec_and_test(&hvcsd->port.count)) { vio_disable_interrupts(hvcsd->vdev); @@ -1241,10 +1242,10 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) free_irq(irq, hvcsd); return; - } else if (hvcsd->port.count < 0) { + } else if (atomic_read(&hvcsd->port.count) < 0) { printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" " is missmanaged.\n", - hvcsd->vdev->unit_address, hvcsd->port.count); + hvcsd->vdev->unit_address, atomic_read(&hvcsd->port.count)); } spin_unlock_irqrestore(&hvcsd->lock, flags); @@ -1266,7 +1267,7 @@ static void hvcs_hangup(struct tty_struct * tty) spin_lock_irqsave(&hvcsd->lock, flags); /* Preserve this so that we know how many kref refs to put */ - temp_open_count = hvcsd->port.count; + temp_open_count = atomic_read(&hvcsd->port.count); /* * Don't kref put inside the spinlock because the destruction @@ -1281,7 +1282,7 @@ static void hvcs_hangup(struct tty_struct * tty) tty->driver_data = NULL; hvcsd->port.tty = NULL; - hvcsd->port.count = 0; + atomic_set(&hvcsd->port.count, 0); /* This will drop any buffered data on the floor which is OK in a hangup * scenario. */ @@ -1352,7 +1353,7 @@ static int hvcs_write(struct tty_struct *tty, * the middle of a write operation? This is a crummy place to do this * but we want to keep it all in the spinlock. */ - if (hvcsd->port.count <= 0) { + if (atomic_read(&hvcsd->port.count) <= 0) { spin_unlock_irqrestore(&hvcsd->lock, flags); return -ENODEV; } @@ -1426,7 +1427,7 @@ static int hvcs_write_room(struct tty_struct *tty) { struct hvcs_struct *hvcsd = tty->driver_data; - if (!hvcsd || hvcsd->port.count <= 0) + if (!hvcsd || atomic_read(&hvcsd->port.count) <= 0) return 0; return HVCS_BUFF_LEN - hvcsd->chars_in_buffer; diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index a75146f..a52c717 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -85,7 +85,7 @@ struct hvsi_struct { int n_outbuf; uint32_t vtermno; uint32_t virq; - atomic_t seqno; /* HVSI packet sequence number */ + atomic_unchecked_t seqno; /* HVSI packet sequence number */ uint16_t mctrl; uint8_t state; /* HVSI protocol state */ uint8_t flags; @@ -297,7 +297,7 @@ static int hvsi_version_respond(struct hvsi_struct *hp, uint16_t query_seqno) packet.hdr.type = VS_QUERY_RESPONSE_PACKET_HEADER; packet.hdr.len = sizeof(struct hvsi_query_response); - packet.hdr.seqno = cpu_to_be16(atomic_inc_return(&hp->seqno)); + packet.hdr.seqno = cpu_to_be16(atomic_inc_return_unchecked(&hp->seqno)); packet.verb = cpu_to_be16(VSV_SEND_VERSION_NUMBER); packet.u.version = HVSI_VERSION; packet.query_seqno = cpu_to_be16(query_seqno+1); @@ -557,7 +557,7 @@ static int hvsi_query(struct hvsi_struct *hp, uint16_t verb) packet.hdr.type = VS_QUERY_PACKET_HEADER; packet.hdr.len = sizeof(struct hvsi_query); - packet.hdr.seqno = cpu_to_be16(atomic_inc_return(&hp->seqno)); + packet.hdr.seqno = cpu_to_be16(atomic_inc_return_unchecked(&hp->seqno)); packet.verb = cpu_to_be16(verb); pr_debug("%s: sending %i bytes\n", __func__, packet.hdr.len); @@ -599,7 +599,7 @@ static int hvsi_set_mctrl(struct hvsi_struct *hp, uint16_t mctrl) int wrote; packet.hdr.type = VS_CONTROL_PACKET_HEADER; - packet.hdr.seqno = cpu_to_be16(atomic_inc_return(&hp->seqno)); + packet.hdr.seqno = cpu_to_be16(atomic_inc_return_unchecked(&hp->seqno)); packet.hdr.len = sizeof(struct hvsi_control); packet.verb = cpu_to_be16(VSV_SET_MODEM_CTL); packet.mask = cpu_to_be32(HVSI_TSDTR); @@ -682,7 +682,7 @@ static int hvsi_put_chars(struct hvsi_struct *hp, const char *buf, int count) BUG_ON(count > HVSI_MAX_OUTGOING_DATA); packet.hdr.type = VS_DATA_PACKET_HEADER; - packet.hdr.seqno = cpu_to_be16(atomic_inc_return(&hp->seqno)); + packet.hdr.seqno = cpu_to_be16(atomic_inc_return_unchecked(&hp->seqno)); packet.hdr.len = count + sizeof(struct hvsi_header); memcpy(&packet.data, buf, count); @@ -699,7 +699,7 @@ static void hvsi_close_protocol(struct hvsi_struct *hp) struct hvsi_control packet __ALIGNED__; packet.hdr.type = VS_CONTROL_PACKET_HEADER; - packet.hdr.seqno = cpu_to_be16(atomic_inc_return(&hp->seqno)); + packet.hdr.seqno = cpu_to_be16(atomic_inc_return_unchecked(&hp->seqno)); packet.hdr.len = 6; packet.verb = cpu_to_be16(VSV_CLOSE_PROTOCOL); @@ -727,7 +727,7 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp) tty_port_tty_set(&hp->port, tty); spin_lock_irqsave(&hp->lock, flags); - hp->port.count++; + atomic_inc(&hp->port.count); atomic_set(&hp->seqno, 0); h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); spin_unlock_irqrestore(&hp->lock, flags); @@ -784,7 +784,7 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&hp->lock, flags); - if (--hp->port.count == 0) { + if (atomic_dec_return(&hp->port.count) == 0) { tty_port_tty_set(&hp->port, NULL); hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */ @@ -817,9 +817,9 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&hp->lock, flags); } - } else if (hp->port.count < 0) + } else if (atomic_read(&hp->port.count) < 0) printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n", - hp - hvsi_ports, hp->port.count); + hp - hvsi_ports, atomic_read(&hp->port.count)); spin_unlock_irqrestore(&hp->lock, flags); } @@ -834,7 +834,7 @@ static void hvsi_hangup(struct tty_struct *tty) tty_port_tty_set(&hp->port, NULL); spin_lock_irqsave(&hp->lock, flags); - hp->port.count = 0; + atomic_set(&hp->port.count, 0); hp->n_outbuf = 0; spin_unlock_irqrestore(&hp->lock, flags); } diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c index a270f04..7c77b5d 100644 --- a/drivers/tty/hvc/hvsi_lib.c +++ b/drivers/tty/hvc/hvsi_lib.c @@ -8,7 +8,7 @@ static int hvsi_send_packet(struct hvsi_priv *pv, struct hvsi_header *packet) { - packet->seqno = cpu_to_be16(atomic_inc_return(&pv->seqno)); + packet->seqno = cpu_to_be16(atomic_inc_return_unchecked(&pv->seqno)); /* Assumes that always succeeds, works in practice */ return pv->put_chars(pv->termno, (char *)packet, packet->len); @@ -20,7 +20,7 @@ static void hvsi_start_handshake(struct hvsi_priv *pv) /* Reset state */ pv->established = 0; - atomic_set(&pv->seqno, 0); + atomic_set_unchecked(&pv->seqno, 0); pr_devel("HVSI@%x: Handshaking started\n", pv->termno); diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index 345cebb..d5a1e9e 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "tty.h" #include "network.h" @@ -93,10 +94,10 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp) return -ENODEV; mutex_lock(&tty->ipw_tty_mutex); - if (tty->port.count == 0) + if (atomic_read(&tty->port.count) == 0) tty->tx_bytes_queued = 0; - tty->port.count++; + atomic_inc(&tty->port.count); tty->port.tty = linux_tty; linux_tty->driver_data = tty; @@ -112,9 +113,7 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp) static void do_ipw_close(struct ipw_tty *tty) { - tty->port.count--; - - if (tty->port.count == 0) { + if (atomic_dec_return(&tty->port.count) == 0) { struct tty_struct *linux_tty = tty->port.tty; if (linux_tty != NULL) { @@ -135,7 +134,7 @@ static void ipw_hangup(struct tty_struct *linux_tty) return; mutex_lock(&tty->ipw_tty_mutex); - if (tty->port.count == 0) { + if (atomic_read(&tty->port.count) == 0) { mutex_unlock(&tty->ipw_tty_mutex); return; } @@ -158,7 +157,7 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data, mutex_lock(&tty->ipw_tty_mutex); - if (!tty->port.count) { + if (!atomic_read(&tty->port.count)) { mutex_unlock(&tty->ipw_tty_mutex); return; } @@ -197,7 +196,7 @@ static int ipw_write(struct tty_struct *linux_tty, return -ENODEV; mutex_lock(&tty->ipw_tty_mutex); - if (!tty->port.count) { + if (!atomic_read(&tty->port.count)) { mutex_unlock(&tty->ipw_tty_mutex); return -EINVAL; } @@ -237,7 +236,7 @@ static int ipw_write_room(struct tty_struct *linux_tty) if (!tty) return -ENODEV; - if (!tty->port.count) + if (!atomic_read(&tty->port.count)) return -EINVAL; room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; @@ -279,7 +278,7 @@ static int ipw_chars_in_buffer(struct tty_struct *linux_tty) if (!tty) return 0; - if (!tty->port.count) + if (!atomic_read(&tty->port.count)) return 0; return tty->tx_bytes_queued; @@ -360,7 +359,7 @@ static int ipw_tiocmget(struct tty_struct *linux_tty) if (!tty) return -ENODEV; - if (!tty->port.count) + if (!atomic_read(&tty->port.count)) return -EINVAL; return get_control_lines(tty); @@ -376,7 +375,7 @@ ipw_tiocmset(struct tty_struct *linux_tty, if (!tty) return -ENODEV; - if (!tty->port.count) + if (!atomic_read(&tty->port.count)) return -EINVAL; return set_control_lines(tty, set, clear); @@ -390,7 +389,7 @@ static int ipw_ioctl(struct tty_struct *linux_tty, if (!tty) return -ENODEV; - if (!tty->port.count) + if (!atomic_read(&tty->port.count)) return -EINVAL; /* FIXME: Exactly how is the tty object locked here .. */ @@ -546,7 +545,7 @@ void ipwireless_tty_free(struct ipw_tty *tty) * are gone */ mutex_lock(&ttyj->ipw_tty_mutex); } - while (ttyj->port.count) + while (atomic_read(&ttyj->port.count)) do_ipw_close(ttyj); ipwireless_disassociate_network_ttys(network, ttyj->channel_idx); diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 14c54e0..1efd4f2 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -1189,7 +1189,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) } ch = &brd->ports[port % MAX_PORTS_PER_BOARD]; - ch->port.count++; + atomic_inc(&ch->port.count); tty->driver_data = ch; tty_port_tty_set(&ch->port, tty); mutex_lock(&ch->port.mutex); diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index c3fe026..9cfe421 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1644,7 +1644,7 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr) spin_lock_init(&dlci->lock); mutex_init(&dlci->mutex); dlci->fifo = &dlci->_fifo; - if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) { + if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL)) { kfree(dlci); return NULL; } @@ -2957,7 +2957,7 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp) struct gsm_dlci *dlci = tty->driver_data; struct tty_port *port = &dlci->port; - port->count++; + atomic_inc(&port->count); tty_port_tty_set(port, tty); dlci->modem_rx = 0; diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index a0285da..e84f8de 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1514,7 +1514,7 @@ n_tty_receive_char_lnext(struct tty_struct *tty, unsigned char c, char flag) static void n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) + char *fp, size_t count) { struct n_tty_data *ldata = tty->disc_data; size_t n, head; @@ -1534,7 +1534,7 @@ n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp, static void n_tty_receive_buf_raw(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) + char *fp, size_t count) { struct n_tty_data *ldata = tty->disc_data; char flag = TTY_NORMAL; @@ -1551,7 +1551,7 @@ n_tty_receive_buf_raw(struct tty_struct *tty, const unsigned char *cp, static void n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) + char *fp, size_t count) { char flag = TTY_NORMAL; @@ -1567,7 +1567,7 @@ n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp, static void n_tty_receive_buf_standard(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) + char *fp, size_t count) { struct n_tty_data *ldata = tty->disc_data; char flag = TTY_NORMAL; @@ -1601,7 +1601,7 @@ n_tty_receive_buf_standard(struct tty_struct *tty, const unsigned char *cp, static void n_tty_receive_buf_fast(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) + char *fp, size_t count) { struct n_tty_data *ldata = tty->disc_data; char flag = TTY_NORMAL; @@ -1626,7 +1626,7 @@ n_tty_receive_buf_fast(struct tty_struct *tty, const unsigned char *cp, } static void __receive_buf(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) + char *fp, size_t count) { struct n_tty_data *ldata = tty->disc_data; bool preops = I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty)); @@ -1704,10 +1704,10 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp, */ static int n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count, int flow) + char *fp, size_t count, int flow) { struct n_tty_data *ldata = tty->disc_data; - int room, n, rcvd = 0, overflow; + size_t room, n, rcvd = 0, overflow; down_read(&tty->termios_rwsem); @@ -2583,6 +2583,7 @@ void n_tty_inherit_ops(struct tty_ldisc_ops *ops) { *ops = tty_ldisc_N_TTY; ops->owner = NULL; - ops->refcount = ops->flags = 0; + atomic_set(&ops->refcount, 0); + ops->flags = 0; } EXPORT_SYMBOL_GPL(n_tty_inherit_ops); diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 4d5937c..d6ae539 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -857,8 +857,10 @@ static void __init unix98_pty_init(void) panic("Couldn't register Unix98 pts driver"); /* Now create the /dev/ptmx special device */ + pax_open_kernel(); tty_default_fops(&ptmx_fops); - ptmx_fops.open = ptmx_open; + *(void **)&ptmx_fops.open = ptmx_open; + pax_close_kernel(); cdev_init(&ptmx_cdev, &ptmx_fops); if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index c8dd8dc..dca6cfd 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -914,7 +914,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp) tty->driver_data = info; tty_port_tty_set(port, tty); - if (port->count++ == 0) { + if (atomic_inc_return(&port->count) == 1) { atomic_inc(&rp_num_ports_open); #ifdef ROCKET_DEBUG_OPEN @@ -923,7 +923,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp) #endif } #ifdef ROCKET_DEBUG_OPEN - printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->port.count); + printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, atomic-read(&info->port.count)); #endif /* @@ -1515,7 +1515,7 @@ static void rp_hangup(struct tty_struct *tty) spin_unlock_irqrestore(&info->port.lock, flags); return; } - if (info->port.count) + if (atomic_read(&info->port.count)) atomic_dec(&rp_num_ports_open); 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 271d121..f2e750c 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) static void univ8250_rsa_support(struct uart_ops *ops) { - 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; } #else @@ -533,8 +533,10 @@ static void __init serial8250_isa_init_ports(void) } /* chain base port ops to support Remote Supervisor Adapter */ - univ8250_port_ops = *base_ops; + pax_open_kernel(); + memcpy((void *)&univ8250_port_ops, base_ops, sizeof univ8250_port_ops); univ8250_rsa_support(&univ8250_port_ops); + pax_close_kernel(); if (share_irqs) irqflag = IRQF_SHARED; diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 536a33b..1b98f43 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -649,7 +649,7 @@ static void ifx_spi_complete(void *ctx) struct ifx_spi_device *ifx_dev = ctx; int length; int actual_length; - unsigned char more; + unsigned char more = 0; unsigned char cts; int local_write_pending = 0; int queue_length; diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c index e5c42fe..f091b02 100644 --- a/drivers/tty/serial/ioc4_serial.c +++ b/drivers/tty/serial/ioc4_serial.c @@ -437,7 +437,7 @@ struct ioc4_soft { } is_intr_info[MAX_IOC4_INTR_ENTS]; /* Number of entries active in the above array */ - atomic_t is_num_intrs; + atomic_unchecked_t is_num_intrs; } is_intr_type[IOC4_NUM_INTR_TYPES]; /* is_ir_lock must be held while @@ -974,7 +974,7 @@ intr_connect(struct ioc4_soft *soft, int type, BUG_ON(!((type == IOC4_SIO_INTR_TYPE) || (type == IOC4_OTHER_INTR_TYPE))); - i = atomic_inc_return(&soft-> is_intr_type[type].is_num_intrs) - 1; + i = atomic_inc_return_unchecked(&soft-> is_intr_type[type].is_num_intrs) - 1; BUG_ON(!(i < MAX_IOC4_INTR_ENTS || (printk("i %d\n", i), 0))); /* Save off the lower level interrupt handler */ @@ -1001,7 +1001,7 @@ static irqreturn_t ioc4_intr(int irq, void *arg) soft = arg; for (intr_type = 0; intr_type < IOC4_NUM_INTR_TYPES; intr_type++) { - num_intrs = (int)atomic_read( + num_intrs = (int)atomic_read_unchecked( &soft->is_intr_type[intr_type].is_num_intrs); this_mir = this_ir = pending_intrs(soft, intr_type); diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c index 117df15..2f7dfcf 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) * I/O utilities that messages sent to the console will automatically * be displayed on the dbg_io. */ - dbg_io_ops->is_console = true; + pax_open_kernel(); + *(int *)&dbg_io_ops->is_console = true; + pax_close_kernel(); return 0; } diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index a260cde..6b2b5ce 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -24,8 +24,9 @@ #define MAX_CONFIG_LEN 40 static struct kgdb_io kgdboc_io_ops; +static struct kgdb_io kgdboc_io_ops_console; -/* -1 = init not run yet, 0 = unconfigured, 1 = configured. */ +/* -1 = init not run yet, 0 = unconfigured, 1/2 = configured. */ static int configured = -1; static char config[MAX_CONFIG_LEN]; @@ -151,6 +152,8 @@ static void cleanup_kgdboc(void) kgdboc_unregister_kbd(); if (configured == 1) kgdb_unregister_io_module(&kgdboc_io_ops); + else if (configured == 2) + kgdb_unregister_io_module(&kgdboc_io_ops_console); } static int configure_kgdboc(void) @@ -160,13 +163,13 @@ static int configure_kgdboc(void) int err; char *cptr = config; struct console *cons; + int is_console = 0; err = kgdboc_option_setup(config); if (err || !strlen(config) || isspace(config[0])) goto noconfig; err = -ENODEV; - kgdboc_io_ops.is_console = 0; kgdb_tty_driver = NULL; kgdboc_use_kms = 0; @@ -187,7 +190,7 @@ static int configure_kgdboc(void) int idx; if (cons->device && cons->device(cons, &idx) == p && idx == tty_line) { - kgdboc_io_ops.is_console = 1; + is_console = 1; break; } cons = cons->next; @@ -197,7 +200,13 @@ static int configure_kgdboc(void) kgdb_tty_line = tty_line; do_register: - err = kgdb_register_io_module(&kgdboc_io_ops); + if (is_console) { + err = kgdb_register_io_module(&kgdboc_io_ops_console); + configured = 2; + } else { + err = kgdb_register_io_module(&kgdboc_io_ops); + configured = 1; + } if (err) goto noconfig; @@ -205,8 +214,6 @@ do_register: if (err) goto nmi_con_failed; - configured = 1; - return 0; nmi_con_failed: @@ -223,7 +230,7 @@ noconfig: static int __init init_kgdboc(void) { /* Already configured? */ - if (configured == 1) + if (configured >= 1) return 0; return configure_kgdboc(); @@ -272,7 +279,7 @@ static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp) if (config[len - 1] == '\n') config[len - 1] = '\0'; - if (configured == 1) + if (configured >= 1) cleanup_kgdboc(); /* Go and configure with the new params. */ @@ -312,6 +319,15 @@ static struct kgdb_io kgdboc_io_ops = { .post_exception = kgdboc_post_exp_handler, }; +static struct kgdb_io kgdboc_io_ops_console = { + .name = "kgdboc", + .read_char = kgdboc_get_char, + .write_char = kgdboc_put_char, + .pre_exception = kgdboc_pre_exp_handler, + .post_exception = kgdboc_post_exp_handler, + .is_console = 1 +}; + #ifdef CONFIG_KGDB_SERIAL_CONSOLE /* This is only available if kgdboc is a built in for early debugging */ static int __init kgdboc_early_init(char *opt) diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index b73889c..9f74f0a 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -1012,7 +1012,7 @@ static struct uart_driver msm_uart_driver = { .cons = MSM_CONSOLE, }; -static atomic_t msm_uart_next_id = ATOMIC_INIT(0); +static atomic_unchecked_t msm_uart_next_id = ATOMIC_INIT(0); static const struct of_device_id msm_uartdm_table[] = { { .compatible = "qcom,msm-uartdm-v1.1", .data = (void *)UARTDM_1P1 }, @@ -1036,7 +1036,7 @@ static int msm_serial_probe(struct platform_device *pdev) line = pdev->id; if (line < 0) - line = atomic_inc_return(&msm_uart_next_id) - 1; + line = atomic_inc_return_unchecked(&msm_uart_next_id) - 1; if (unlikely(line < 0 || line >= UART_NR)) return -ENXIO; diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 856686d..cd1e114 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -994,11 +994,16 @@ static void s3c24xx_serial_shutdown(struct uart_port *port) ourport->tx_in_progress = 0; } +static int s3c64xx_serial_startup(struct uart_port *port); static int s3c24xx_serial_startup(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); int ret; + /* Startup sequence is different for s3c64xx and higher SoC's */ + if (s3c24xx_serial_has_interrupt_mask(port)) + return s3c64xx_serial_startup(port); + dbg("s3c24xx_serial_startup: port=%p (%08llx,%p)\n", port, (unsigned long long)port->mapbase, port->membase); @@ -1705,10 +1710,6 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, /* setup info for port */ port->dev = &platdev->dev; - /* Startup sequence is different for s3c64xx and higher SoC's */ - if (s3c24xx_serial_has_interrupt_mask(port)) - s3c24xx_serial_ops.startup = s3c64xx_serial_startup; - port->uartclk = 1; if (cfg->uart_flags & UPF_CONS_FLOW) { diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 603d2cc..5033f58 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1384,7 +1384,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) state = drv->state + tty->index; port = &state->port; spin_lock_irq(&port->lock); - --port->count; + atomic_dec(&port->count); spin_unlock_irq(&port->lock); return; } @@ -1394,7 +1394,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) pr_debug("uart_close(%d) called\n", uport ? uport->line : -1); - if (!port->count || tty_port_close_start(port, tty, filp) == 0) + if (!atomic_read(&port->count) || tty_port_close_start(port, tty, filp) == 0) return; /* @@ -1518,7 +1518,7 @@ static void uart_hangup(struct tty_struct *tty) uart_flush_buffer(tty); uart_shutdown(tty, state); spin_lock_irqsave(&port->lock, flags); - port->count = 0; + atomic_set(&port->count, 0); clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); spin_unlock_irqrestore(&port->lock, flags); tty_port_tty_set(port, NULL); @@ -1600,7 +1600,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp) pr_debug("uart_open(%d) called\n", line); spin_lock_irq(&port->lock); - ++port->count; + atomic_inc(&port->count); spin_unlock_irq(&port->lock); /* diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index b1c6bd3..5f038e2 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -341,13 +341,13 @@ static int ulite_request_port(struct uart_port *port) return -EBUSY; } - port->private_data = &uartlite_be; + port->private_data = (void *)&uartlite_be; ret = uart_in32(ULITE_CONTROL, port); uart_out32(ULITE_CONTROL_RST_TX, ULITE_CONTROL, port); ret = uart_in32(ULITE_STATUS, port); /* Endianess detection */ if ((ret & ULITE_STATUS_TXEMPTY) != ULITE_STATUS_TXEMPTY) - port->private_data = &uartlite_le; + port->private_data = (void *)&uartlite_le; return 0; } diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 2fac712..fcd5268 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -3090,7 +3090,7 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp) if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_close(%s) entry, count=%d\n", - __FILE__,__LINE__, info->device_name, info->port.count); + __FILE__,__LINE__, info->device_name, atomic_read(&info->port.count)); if (tty_port_close_start(&info->port, tty, filp) == 0) goto cleanup; @@ -3108,7 +3108,7 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp) cleanup: if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_close(%s) exit, count=%d\n", __FILE__,__LINE__, - tty->driver->name, info->port.count); + tty->driver->name, atomic_read(&info->port.count)); } /* end of mgsl_close() */ @@ -3207,8 +3207,8 @@ static void mgsl_hangup(struct tty_struct *tty) mgsl_flush_buffer(tty); shutdown(info); - - info->port.count = 0; + + atomic_set(&info->port.count, 0); info->port.flags &= ~ASYNC_NORMAL_ACTIVE; info->port.tty = NULL; @@ -3296,10 +3296,10 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):block_til_ready before block on %s count=%d\n", - __FILE__,__LINE__, tty->driver->name, port->count ); + __FILE__,__LINE__, tty->driver->name, atomic_read(&port->count)); spin_lock_irqsave(&info->irq_spinlock, flags); - port->count--; + atomic_dec(&port->count); spin_unlock_irqrestore(&info->irq_spinlock, flags); port->blocked_open++; @@ -3327,7 +3327,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):block_til_ready blocking on %s count=%d\n", - __FILE__,__LINE__, tty->driver->name, port->count ); + __FILE__,__LINE__, tty->driver->name, atomic_read(&port->count)); tty_unlock(tty); schedule(); @@ -3339,12 +3339,12 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, /* FIXME: Racy on hangup during close wait */ if (!tty_hung_up_p(filp)) - port->count++; + atomic_inc(&port->count); port->blocked_open--; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):block_til_ready after blocking on %s count=%d\n", - __FILE__,__LINE__, tty->driver->name, port->count ); + __FILE__,__LINE__, tty->driver->name, atomic_read(&port->count)); if (!retval) port->flags |= ASYNC_NORMAL_ACTIVE; @@ -3396,7 +3396,7 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp) if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_open(%s), old ref count = %d\n", - __FILE__,__LINE__,tty->driver->name, info->port.count); + __FILE__,__LINE__,tty->driver->name, atomic_read(&info->port.count)); /* If port is closing, signal caller to try again */ if (info->port.flags & ASYNC_CLOSING){ @@ -3415,10 +3415,10 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp) spin_unlock_irqrestore(&info->netlock, flags); goto cleanup; } - info->port.count++; + atomic_inc(&info->port.count); spin_unlock_irqrestore(&info->netlock, flags); - if (info->port.count == 1) { + if (atomic_read(&info->port.count) == 1) { /* 1st open on this device, init hardware */ retval = startup(info); if (retval < 0) @@ -3442,8 +3442,8 @@ cleanup: if (retval) { if (tty->count == 1) info->port.tty = NULL; /* tty layer will release tty struct */ - if(info->port.count) - info->port.count--; + if (atomic_read(&info->port.count)) + atomic_dec(&info->port.count); } return retval; @@ -7662,7 +7662,7 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, unsigned short new_crctype; /* return error if TTY interface open */ - if (info->port.count) + if (atomic_read(&info->port.count)) return -EBUSY; switch (encoding) @@ -7758,7 +7758,7 @@ static int hdlcdev_open(struct net_device *dev) /* arbitrate between network and tty opens */ spin_lock_irqsave(&info->netlock, flags); - if (info->port.count != 0 || info->netcount != 0) { + if (atomic_read(&info->port.count) != 0 || info->netcount != 0) { printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name); spin_unlock_irqrestore(&info->netlock, flags); return -EBUSY; @@ -7844,7 +7844,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name); /* return error if TTY interface open */ - if (info->port.count) + if (atomic_read(&info->port.count)) return -EBUSY; if (cmd != SIOCWANDEV) diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 0ea8eee..b3f1b8f 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -670,7 +670,7 @@ static int open(struct tty_struct *tty, struct file *filp) tty->driver_data = info; info->port.tty = tty; - DBGINFO(("%s open, old ref count = %d\n", info->device_name, info->port.count)); + DBGINFO(("%s open, old ref count = %d\n", info->device_name, atomic_read(&info->port.count))); /* If port is closing, signal caller to try again */ if (info->port.flags & ASYNC_CLOSING){ @@ -691,10 +691,10 @@ static int open(struct tty_struct *tty, struct file *filp) mutex_unlock(&info->port.mutex); goto cleanup; } - info->port.count++; + atomic_inc(&info->port.count); spin_unlock_irqrestore(&info->netlock, flags); - if (info->port.count == 1) { + if (atomic_read(&info->port.count) == 1) { /* 1st open on this device, init hardware */ retval = startup(info); if (retval < 0) { @@ -715,8 +715,8 @@ cleanup: if (retval) { if (tty->count == 1) info->port.tty = NULL; /* tty layer will release tty struct */ - if(info->port.count) - info->port.count--; + if(atomic_read(&info->port.count)) + atomic_dec(&info->port.count); } DBGINFO(("%s open rc=%d\n", info->device_name, retval)); @@ -729,7 +729,7 @@ static void close(struct tty_struct *tty, struct file *filp) if (sanity_check(info, tty->name, "close")) return; - DBGINFO(("%s close entry, count=%d\n", info->device_name, info->port.count)); + DBGINFO(("%s close entry, count=%d\n", info->device_name, atomic_read(&info->port.count))); if (tty_port_close_start(&info->port, tty, filp) == 0) goto cleanup; @@ -746,7 +746,7 @@ static void close(struct tty_struct *tty, struct file *filp) tty_port_close_end(&info->port, tty); info->port.tty = NULL; cleanup: - DBGINFO(("%s close exit, count=%d\n", tty->driver->name, info->port.count)); + DBGINFO(("%s close exit, count=%d\n", tty->driver->name, atomic_read(&info->port.count))); } static void hangup(struct tty_struct *tty) @@ -764,7 +764,7 @@ static void hangup(struct tty_struct *tty) shutdown(info); spin_lock_irqsave(&info->port.lock, flags); - info->port.count = 0; + atomic_set(&info->port.count, 0); info->port.flags &= ~ASYNC_NORMAL_ACTIVE; info->port.tty = NULL; spin_unlock_irqrestore(&info->port.lock, flags); @@ -1449,7 +1449,7 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, unsigned short new_crctype; /* return error if TTY interface open */ - if (info->port.count) + if (atomic_read(&info->port.count)) return -EBUSY; DBGINFO(("%s hdlcdev_attach\n", info->device_name)); @@ -1545,7 +1545,7 @@ static int hdlcdev_open(struct net_device *dev) /* arbitrate between network and tty opens */ spin_lock_irqsave(&info->netlock, flags); - if (info->port.count != 0 || info->netcount != 0) { + if (atomic_read(&info->port.count) != 0 || info->netcount != 0) { DBGINFO(("%s hdlc_open busy\n", dev->name)); spin_unlock_irqrestore(&info->netlock, flags); return -EBUSY; @@ -1630,7 +1630,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) DBGINFO(("%s hdlcdev_ioctl\n", dev->name)); /* return error if TTY interface open */ - if (info->port.count) + if (atomic_read(&info->port.count)) return -EBUSY; if (cmd != SIOCWANDEV) @@ -2417,7 +2417,7 @@ static irqreturn_t slgt_interrupt(int dummy, void *dev_id) if (port == NULL) continue; spin_lock(&port->lock); - if ((port->port.count || port->netcount) && + if ((atomic_read(&port->port.count) || port->netcount) && port->pending_bh && !port->bh_running && !port->bh_requested) { DBGISR(("%s bh queued\n", port->device_name)); @@ -3303,7 +3303,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, add_wait_queue(&port->open_wait, &wait); spin_lock_irqsave(&info->lock, flags); - port->count--; + atomic_dec(&port->count); spin_unlock_irqrestore(&info->lock, flags); port->blocked_open++; @@ -3339,7 +3339,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, remove_wait_queue(&port->open_wait, &wait); if (!tty_hung_up_p(filp)) - port->count++; + atomic_inc(&port->count); port->blocked_open--; if (!retval) diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 08633a8..3d56e14 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -750,7 +750,7 @@ static int open(struct tty_struct *tty, struct file *filp) if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s open(), old ref count = %d\n", - __FILE__,__LINE__,tty->driver->name, info->port.count); + __FILE__,__LINE__,tty->driver->name, atomic_read(&info->port.count)); /* If port is closing, signal caller to try again */ if (info->port.flags & ASYNC_CLOSING){ @@ -769,10 +769,10 @@ static int open(struct tty_struct *tty, struct file *filp) spin_unlock_irqrestore(&info->netlock, flags); goto cleanup; } - info->port.count++; + atomic_inc(&info->port.count); spin_unlock_irqrestore(&info->netlock, flags); - if (info->port.count == 1) { + if (atomic_read(&info->port.count) == 1) { /* 1st open on this device, init hardware */ retval = startup(info); if (retval < 0) @@ -796,8 +796,8 @@ cleanup: if (retval) { if (tty->count == 1) info->port.tty = NULL; /* tty layer will release tty struct */ - if(info->port.count) - info->port.count--; + if(atomic_read(&info->port.count)) + atomic_dec(&info->port.count); } return retval; @@ -815,7 +815,7 @@ static void close(struct tty_struct *tty, struct file *filp) if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s close() entry, count=%d\n", - __FILE__,__LINE__, info->device_name, info->port.count); + __FILE__,__LINE__, info->device_name, atomic_read(&info->port.count)); if (tty_port_close_start(&info->port, tty, filp) == 0) goto cleanup; @@ -834,7 +834,7 @@ static void close(struct tty_struct *tty, struct file *filp) cleanup: if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s close() exit, count=%d\n", __FILE__,__LINE__, - tty->driver->name, info->port.count); + tty->driver->name, atomic_read(&info->port.count)); } /* Called by tty_hangup() when a hangup is signaled. @@ -857,7 +857,7 @@ static void hangup(struct tty_struct *tty) shutdown(info); spin_lock_irqsave(&info->port.lock, flags); - info->port.count = 0; + atomic_set(&info->port.count, 0); info->port.flags &= ~ASYNC_NORMAL_ACTIVE; info->port.tty = NULL; spin_unlock_irqrestore(&info->port.lock, flags); @@ -1565,7 +1565,7 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, unsigned short new_crctype; /* return error if TTY interface open */ - if (info->port.count) + if (atomic_read(&info->port.count)) return -EBUSY; switch (encoding) @@ -1661,7 +1661,7 @@ static int hdlcdev_open(struct net_device *dev) /* arbitrate between network and tty opens */ spin_lock_irqsave(&info->netlock, flags); - if (info->port.count != 0 || info->netcount != 0) { + if (atomic_read(&info->port.count) != 0 || info->netcount != 0) { printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name); spin_unlock_irqrestore(&info->netlock, flags); return -EBUSY; @@ -1747,7 +1747,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name); /* return error if TTY interface open */ - if (info->port.count) + if (atomic_read(&info->port.count)) return -EBUSY; if (cmd != SIOCWANDEV) @@ -2624,7 +2624,7 @@ static irqreturn_t synclinkmp_interrupt(int dummy, void *dev_id) * do not request bottom half processing if the * device is not open in a normal mode. */ - if ( port && (port->port.count || port->netcount) && + if ( port && (atomic_read(&port->port.count) || port->netcount) && port->pending_bh && !port->bh_running && !port->bh_requested ) { if ( debug_level >= DEBUG_LEVEL_ISR ) @@ -3321,10 +3321,10 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s block_til_ready() before block, count=%d\n", - __FILE__,__LINE__, tty->driver->name, port->count ); + __FILE__,__LINE__, tty->driver->name, atomic_read(&port->count)); spin_lock_irqsave(&info->lock, flags); - port->count--; + atomic_dec(&port->count); spin_unlock_irqrestore(&info->lock, flags); port->blocked_open++; @@ -3352,7 +3352,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s block_til_ready() count=%d\n", - __FILE__,__LINE__, tty->driver->name, port->count ); + __FILE__,__LINE__, tty->driver->name, atomic_read(&port->count)); tty_unlock(tty); schedule(); @@ -3362,12 +3362,12 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, set_current_state(TASK_RUNNING); remove_wait_queue(&port->open_wait, &wait); if (!tty_hung_up_p(filp)) - port->count++; + atomic_inc(&port->count); port->blocked_open--; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s block_til_ready() after, count=%d\n", - __FILE__,__LINE__, tty->driver->name, port->count ); + __FILE__,__LINE__, tty->driver->name, atomic_read(&port->count)); if (!retval) port->flags |= ASYNC_NORMAL_ACTIVE; diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 95b330a..43dc301 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -1079,7 +1079,7 @@ EXPORT_SYMBOL(unregister_sysrq_key); static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - if (count) { + if (count && capable(CAP_SYS_ADMIN)) { char c; if (get_user(c, buf)) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index f435977..8b399ef 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -3533,7 +3533,7 @@ EXPORT_SYMBOL(tty_devnum); void tty_default_fops(struct file_operations *fops) { - *fops = tty_fops; + memcpy((void *)fops, &tty_fops, sizeof(tty_fops)); } /* diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 71750cb..8db9583 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -68,7 +68,7 @@ int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc) raw_spin_lock_irqsave(&tty_ldiscs_lock, flags); tty_ldiscs[disc] = new_ldisc; new_ldisc->num = disc; - new_ldisc->refcount = 0; + atomic_set(&new_ldisc->refcount, 0); raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags); return ret; @@ -96,7 +96,7 @@ int tty_unregister_ldisc(int disc) return -EINVAL; raw_spin_lock_irqsave(&tty_ldiscs_lock, flags); - if (tty_ldiscs[disc]->refcount) + if (atomic_read(&tty_ldiscs[disc]->refcount)) ret = -EBUSY; else tty_ldiscs[disc] = NULL; @@ -117,7 +117,7 @@ static struct tty_ldisc_ops *get_ldops(int disc) if (ldops) { ret = ERR_PTR(-EAGAIN); if (try_module_get(ldops->owner)) { - ldops->refcount++; + atomic_inc(&ldops->refcount); ret = ldops; } } @@ -130,7 +130,7 @@ static void put_ldops(struct tty_ldisc_ops *ldops) unsigned long flags; raw_spin_lock_irqsave(&tty_ldiscs_lock, flags); - ldops->refcount--; + atomic_dec(&ldops->refcount); module_put(ldops->owner); raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags); } diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 40b31835..94d92ae 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -236,7 +236,7 @@ void tty_port_hangup(struct tty_port *port) unsigned long flags; spin_lock_irqsave(&port->lock, flags); - port->count = 0; + atomic_set(&port->count, 0); port->flags &= ~ASYNC_NORMAL_ACTIVE; tty = port->tty; if (tty) @@ -398,7 +398,7 @@ int tty_port_block_til_ready(struct tty_port *port, /* The port lock protects the port counts */ spin_lock_irqsave(&port->lock, flags); - port->count--; + atomic_dec(&port->count); port->blocked_open++; spin_unlock_irqrestore(&port->lock, flags); @@ -440,7 +440,7 @@ int tty_port_block_til_ready(struct tty_port *port, we must not mess that up further */ spin_lock_irqsave(&port->lock, flags); if (!tty_hung_up_p(filp)) - port->count++; + atomic_inc(&port->count); port->blocked_open--; if (retval == 0) port->flags |= ASYNC_NORMAL_ACTIVE; @@ -476,19 +476,19 @@ int tty_port_close_start(struct tty_port *port, return 0; spin_lock_irqsave(&port->lock, flags); - if (tty->count == 1 && port->count != 1) { + if (tty->count == 1 && atomic_read(&port->count) != 1) { printk(KERN_WARNING "tty_port_close_start: tty->count = 1 port count = %d.\n", - port->count); - port->count = 1; + atomic_read(&port->count)); + atomic_set(&port->count, 1); } - if (--port->count < 0) { + if (atomic_dec_return(&port->count) < 0) { printk(KERN_WARNING "tty_port_close_start: count = %d\n", - port->count); - port->count = 0; + atomic_read(&port->count)); + atomic_set(&port->count, 0); } - if (port->count) { + if (atomic_read(&port->count)) { spin_unlock_irqrestore(&port->lock, flags); return 0; } @@ -590,7 +590,7 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty, struct file *filp) { spin_lock_irq(&port->lock); - ++port->count; + atomic_inc(&port->count); spin_unlock_irq(&port->lock); tty_port_tty_set(port, tty); diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 6f0336f..5818bc1 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -642,6 +642,16 @@ static void k_spec(struct vc_data *vc, unsigned char value, char up_flag) kbd->kbdmode == VC_OFF) && value != KVAL(K_SAK)) return; /* SAK is allowed even in raw mode */ + +#if defined(CONFIG_GRKERNSEC_PROC) || defined(CONFIG_GRKERNSEC_PROC_MEMMAP) + { + void *func = fn_handler[value]; + if (func == fn_show_state || func == fn_show_ptregs || + func == fn_show_mem) + return; + } +#endif + fn_handler[value](vc); } @@ -1880,9 +1890,6 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) return -EFAULT; - if (!capable(CAP_SYS_TTY_CONFIG)) - perm = 0; - switch (cmd) { case KDGKBENT: /* Ensure another thread doesn't free it under us */ @@ -1897,6 +1904,9 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, spin_unlock_irqrestore(&kbd_event_lock, flags); return put_user(val, &user_kbe->kb_value); case KDSKBENT: + if (!capable(CAP_SYS_TTY_CONFIG)) + perm = 0; + if (!perm) return -EPERM; if (!i && v == K_NOSUCHMAP) { @@ -1987,9 +1997,6 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) int i, j, k; int ret; - if (!capable(CAP_SYS_TTY_CONFIG)) - perm = 0; - kbs = kmalloc(sizeof(*kbs), GFP_KERNEL); if (!kbs) { ret = -ENOMEM; @@ -2023,6 +2030,9 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) kfree(kbs); return ((p && *p) ? -EOVERFLOW : 0); case KDSKBSENT: + if (!capable(CAP_SYS_TTY_CONFIG)) + perm = 0; + if (!perm) { ret = -EPERM; goto reterr; diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 8196581..aa153a5 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -25,6 +25,7 @@ #include #include #include +#include #define UIO_MAX_DEVICES (1U << MINORBITS) @@ -231,7 +232,7 @@ static ssize_t event_show(struct device *dev, struct device_attribute *attr, char *buf) { struct uio_device *idev = dev_get_drvdata(dev); - return sprintf(buf, "%u\n", (unsigned int)atomic_read(&idev->event)); + return sprintf(buf, "%u\n", (unsigned int)atomic_read_unchecked(&idev->event)); } static DEVICE_ATTR_RO(event); @@ -393,7 +394,7 @@ void uio_event_notify(struct uio_info *info) { struct uio_device *idev = info->uio_dev; - atomic_inc(&idev->event); + atomic_inc_unchecked(&idev->event); wake_up_interruptible(&idev->wait); kill_fasync(&idev->async_queue, SIGIO, POLL_IN); } @@ -446,7 +447,7 @@ static int uio_open(struct inode *inode, struct file *filep) } listener->dev = idev; - listener->event_count = atomic_read(&idev->event); + listener->event_count = atomic_read_unchecked(&idev->event); filep->private_data = listener; if (idev->info->open) { @@ -497,7 +498,7 @@ static unsigned int uio_poll(struct file *filep, poll_table *wait) return -EIO; poll_wait(filep, &idev->wait, wait); - if (listener->event_count != atomic_read(&idev->event)) + if (listener->event_count != atomic_read_unchecked(&idev->event)) return POLLIN | POLLRDNORM; return 0; } @@ -522,7 +523,7 @@ static ssize_t uio_read(struct file *filep, char __user *buf, do { set_current_state(TASK_INTERRUPTIBLE); - event_count = atomic_read(&idev->event); + event_count = atomic_read_unchecked(&idev->event); if (event_count != listener->event_count) { if (copy_to_user(buf, &event_count, count)) retval = -EFAULT; @@ -579,9 +580,13 @@ static ssize_t uio_write(struct file *filep, const char __user *buf, static int uio_find_mem_index(struct vm_area_struct *vma) { struct uio_device *idev = vma->vm_private_data; + unsigned long size; if (vma->vm_pgoff < MAX_UIO_MAPS) { - if (idev->info->mem[vma->vm_pgoff].size == 0) + size = idev->info->mem[vma->vm_pgoff].size; + if (size == 0) + return -1; + if (vma->vm_end - vma->vm_start > size) return -1; return (int)vma->vm_pgoff; } @@ -813,7 +818,7 @@ int __uio_register_device(struct module *owner, idev->owner = owner; idev->info = info; init_waitqueue_head(&idev->wait); - atomic_set(&idev->event, 0); + atomic_set_unchecked(&idev->event, 0); ret = uio_get_minor(idev); if (ret) diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 1173f9c..6ded1e9 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -474,7 +474,7 @@ static ssize_t cxacru_sysfs_store_adsl_config(struct device *dev, ret = sscanf(buf + pos, "%x=%x%n", &index, &value, &tmp); if (ret < 2) return -EINVAL; - if (index < 0 || index > 0x7f) + if (index > 0x7f) return -EINVAL; pos += tmp; diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index db322d9..f0f4bc1 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -331,7 +331,7 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char if (printk_ratelimit()) atm_warn(instance, "%s: OAM not supported (vpi %d, vci %d)!\n", __func__, vpi, vci); - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); return; } @@ -358,7 +358,7 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char if (length > ATM_MAX_AAL5_PDU) { atm_rldbg(instance, "%s: bogus length %u (vcc: 0x%p)!\n", __func__, length, vcc); - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); goto out; } @@ -367,14 +367,14 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char if (sarb->len < pdu_length) { atm_rldbg(instance, "%s: bogus pdu_length %u (sarb->len: %u, vcc: 0x%p)!\n", __func__, pdu_length, sarb->len, vcc); - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); goto out; } if (crc32_be(~0, skb_tail_pointer(sarb) - pdu_length, pdu_length) != 0xc704dd7b) { atm_rldbg(instance, "%s: packet failed crc check (vcc: 0x%p)!\n", __func__, vcc); - atomic_inc(&vcc->stats->rx_err); + atomic_inc_unchecked(&vcc->stats->rx_err); goto out; } @@ -387,7 +387,7 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char if (printk_ratelimit()) atm_err(instance, "%s: no memory for skb (length: %u)!\n", __func__, length); - atomic_inc(&vcc->stats->rx_drop); + atomic_inc_unchecked(&vcc->stats->rx_drop); goto out; } @@ -415,7 +415,7 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char vcc->push(vcc, skb); - atomic_inc(&vcc->stats->rx); + atomic_inc_unchecked(&vcc->stats->rx); out: skb_trim(sarb, 0); } @@ -613,7 +613,7 @@ static void usbatm_tx_process(unsigned long data) struct atm_vcc *vcc = UDSL_SKB(skb)->atm.vcc; usbatm_pop(vcc, skb); - atomic_inc(&vcc->stats->tx); + atomic_inc_unchecked(&vcc->stats->tx); skb = skb_dequeue(&instance->sndqueue); } @@ -757,11 +757,11 @@ static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t *pos, char *page if (!left--) return sprintf(page, "AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )\n", - atomic_read(&atm_dev->stats.aal5.tx), - atomic_read(&atm_dev->stats.aal5.tx_err), - atomic_read(&atm_dev->stats.aal5.rx), - atomic_read(&atm_dev->stats.aal5.rx_err), - atomic_read(&atm_dev->stats.aal5.rx_drop)); + atomic_read_unchecked(&atm_dev->stats.aal5.tx), + atomic_read_unchecked(&atm_dev->stats.aal5.tx_err), + atomic_read_unchecked(&atm_dev->stats.aal5.rx), + atomic_read_unchecked(&atm_dev->stats.aal5.rx_err), + atomic_read_unchecked(&atm_dev->stats.aal5.rx_drop)); if (!left--) { if (instance->disconnected) diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index dd9af38..75b53e3 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -95,7 +95,7 @@ struct acm { struct urb *read_urbs[ACM_NR]; struct acm_rb read_buffers[ACM_NR]; int rx_buflimit; - int rx_endpoint; + unsigned int rx_endpoint; spinlock_t read_lock; int write_used; /* number of non-empty write buffers */ int transmitting; diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 2a3bbdf..91d72cf 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -126,7 +126,7 @@ static const char format_endpt[] = * time it gets called. */ static struct device_connect_event { - atomic_t count; + atomic_unchecked_t count; wait_queue_head_t wait; } device_event = { .count = ATOMIC_INIT(1), @@ -164,7 +164,7 @@ static const struct class_info clas_info[] = { void usbfs_conn_disc_event(void) { - atomic_add(2, &device_event.count); + atomic_add_unchecked(2, &device_event.count); wake_up(&device_event.wait); } @@ -652,7 +652,7 @@ static unsigned int usb_device_poll(struct file *file, poll_wait(file, &device_event.wait, wait); - event_count = atomic_read(&device_event.count); + event_count = atomic_read_unchecked(&device_event.count); if (file->f_version != event_count) { file->f_version = event_count; return POLLIN | POLLRDNORM; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 38ae877c..9bf9e7d 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -187,7 +187,7 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, struct usb_dev_state *ps = file->private_data; struct usb_device *dev = ps->dev; ssize_t ret = 0; - unsigned len; + size_t len; loff_t pos; int i; @@ -229,22 +229,22 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, for (i = 0; nbytes && i < dev->descriptor.bNumConfigurations; i++) { struct usb_config_descriptor *config = (struct usb_config_descriptor *)dev->rawdescriptors[i]; - unsigned int length = le16_to_cpu(config->wTotalLength); + size_t length = le16_to_cpu(config->wTotalLength); if (*ppos < pos + length) { /* The descriptor may claim to be longer than it * really is. Here is the actual allocated length. */ - unsigned alloclen = + size_t alloclen = le16_to_cpu(dev->config[i].desc.wTotalLength); - len = length - (*ppos - pos); + len = length + pos - *ppos; if (len > nbytes) len = nbytes; /* Simply don't write (skip over) unallocated parts */ if (alloclen > (*ppos - pos)) { - alloclen -= (*ppos - pos); + alloclen = alloclen + pos - *ppos; if (copy_to_user(buf, dev->rawdescriptors[i] + (*ppos - pos), min(len, alloclen))) { @@ -1502,7 +1502,7 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb } } as->urb->dev = ps->dev; - as->urb->pipe = (uurb->type << 30) | + as->urb->pipe = ((unsigned int)uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 4d64e5c4..e21932a 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1554,7 +1554,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) */ usb_get_urb(urb); atomic_inc(&urb->use_count); - atomic_inc(&urb->dev->urbnum); + atomic_inc_unchecked(&urb->dev->urbnum); usbmon_urb_submit(&hcd->self, urb); /* NOTE requirements on root-hub callers (usbfs and the hub @@ -1581,7 +1581,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) urb->hcpriv = NULL; INIT_LIST_HEAD(&urb->urb_list); atomic_dec(&urb->use_count); - atomic_dec(&urb->dev->urbnum); + atomic_dec_unchecked(&urb->dev->urbnum); if (atomic_read(&urb->reject)) wake_up(&usb_kill_urb_queue); usb_put_urb(urb); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 431839b..8d241f6 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -4659,6 +4660,10 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, goto done; return; } + + if (gr_handle_new_usb()) + goto done; + if (hub_is_superspeed(hub->hdev)) unit_load = 150; else diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index cfc68c1..38f943f 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -244,7 +244,7 @@ static ssize_t urbnum_show(struct device *dev, struct device_attribute *attr, struct usb_device *udev; udev = to_usb_device(dev); - return sprintf(buf, "%d\n", atomic_read(&udev->urbnum)); + return sprintf(buf, "%d\n", atomic_read_unchecked(&udev->urbnum)); } static DEVICE_ATTR_RO(urbnum); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 8d5b2f4..3896940 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -447,7 +447,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, set_dev_node(&dev->dev, dev_to_node(bus->controller)); dev->state = USB_STATE_ATTACHED; dev->lpm_disable_count = 1; - atomic_set(&dev->urbnum, 0); + atomic_set_unchecked(&dev->urbnum, 0); INIT_LIST_HEAD(&dev->ep0.urb_list); dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c index 8cfc319..4868255 100644 --- a/drivers/usb/early/ehci-dbgp.c +++ b/drivers/usb/early/ehci-dbgp.c @@ -98,7 +98,8 @@ static inline u32 dbgp_len_update(u32 x, u32 len) #ifdef CONFIG_KGDB static struct kgdb_io kgdbdbgp_io_ops; -#define dbgp_kgdb_mode (dbg_io_ops == &kgdbdbgp_io_ops) +static struct kgdb_io kgdbdbgp_io_ops_console; +#define dbgp_kgdb_mode (dbg_io_ops == &kgdbdbgp_io_ops || dbg_io_ops == &kgdbdbgp_io_ops_console) #else #define dbgp_kgdb_mode (0) #endif @@ -1043,6 +1044,13 @@ static struct kgdb_io kgdbdbgp_io_ops = { .write_char = kgdbdbgp_write_char, }; +static struct kgdb_io kgdbdbgp_io_ops_console = { + .name = "kgdbdbgp", + .read_char = kgdbdbgp_read_char, + .write_char = kgdbdbgp_write_char, + .is_console = 1 +}; + static int kgdbdbgp_wait_time; static int __init kgdbdbgp_parse_config(char *str) @@ -1058,8 +1066,10 @@ static int __init kgdbdbgp_parse_config(char *str) ptr++; kgdbdbgp_wait_time = simple_strtoul(ptr, &ptr, 10); } - kgdb_register_io_module(&kgdbdbgp_io_ops); - kgdbdbgp_io_ops.is_console = early_dbgp_console.index != -1; + if (early_dbgp_console.index != -1) + kgdb_register_io_module(&kgdbdbgp_io_ops_console); + else + kgdb_register_io_module(&kgdbdbgp_io_ops); return 0; } diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index 7856b33..8b7fe09 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "u_uac1.h" diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 7ee05793..2e31e99 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -732,9 +732,9 @@ static int gs_open(struct tty_struct *tty, struct file *file) spin_lock_irq(&port->port_lock); /* already open? Great. */ - if (port->port.count) { + if (atomic_read(&port->port.count)) { status = 0; - port->port.count++; + atomic_inc(&port->port.count); /* currently opening/closing? wait ... */ } else if (port->openclose) { @@ -793,7 +793,7 @@ static int gs_open(struct tty_struct *tty, struct file *file) tty->driver_data = port; port->port.tty = tty; - port->port.count = 1; + atomic_set(&port->port.count, 1); port->openclose = false; /* if connected, start the I/O stream */ @@ -835,11 +835,11 @@ static void gs_close(struct tty_struct *tty, struct file *file) spin_lock_irq(&port->port_lock); - if (port->port.count != 1) { - if (port->port.count == 0) + if (atomic_read(&port->port.count) != 1) { + if (atomic_read(&port->port.count) == 0) WARN_ON(1); else - --port->port.count; + atomic_dec(&port->port.count); goto exit; } @@ -849,7 +849,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) * and sleep if necessary */ port->openclose = true; - port->port.count = 0; + atomic_set(&port->port.count, 0); gser = port->port_usb; if (gser && gser->disconnect) @@ -1065,7 +1065,7 @@ static int gs_closed(struct gs_port *port) int cond; spin_lock_irq(&port->port_lock); - cond = (port->port.count == 0) && !port->openclose; + cond = (atomic_read(&port->port.count) == 0) && !port->openclose; spin_unlock_irq(&port->port_lock); return cond; } @@ -1208,7 +1208,7 @@ int gserial_connect(struct gserial *gser, u8 port_num) /* if it's already open, start I/O ... and notify the serial * protocol about open/close status (connect/disconnect). */ - if (port->port.count) { + if (atomic_read(&port->port.count)) { pr_debug("gserial_connect: start ttyGS%d\n", port->port_num); gs_start_io(port); if (gser->connect) @@ -1255,7 +1255,7 @@ void gserial_disconnect(struct gserial *gser) port->port_usb = NULL; gser->ioport = NULL; - if (port->port.count > 0 || port->openclose) { + if (atomic_read(&port->port.count) > 0 || port->openclose) { wake_up_interruptible(&port->drain_wait); if (port->port.tty) tty_hangup(port->port.tty); @@ -1271,7 +1271,7 @@ void gserial_disconnect(struct gserial *gser) /* finally, free any unused/unusable I/O buffers */ spin_lock_irqsave(&port->port_lock, flags); - if (port->port.count == 0 && !port->openclose) + if (atomic_read(&port->port.count) == 0 && !port->openclose) gs_buf_free(&port->port_write_buf); gs_free_requests(gser->out, &port->read_pool, NULL); gs_free_requests(gser->out, &port->read_queue, NULL); diff --git a/drivers/usb/gadget/function/u_uac1.c b/drivers/usb/gadget/function/u_uac1.c index c78c841..48fd281 100644 --- a/drivers/usb/gadget/function/u_uac1.c +++ b/drivers/usb/gadget/function/u_uac1.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "u_uac1.h" diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 27af0f0..c1ff952 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -2463,7 +2463,7 @@ static int dummy_setup(struct usb_hcd *hcd) struct dummy *dum; dum = *((void **)dev_get_platdata(hcd->self.controller)); - hcd->self.sg_tablesize = ~0; + hcd->self.sg_tablesize = SG_ALL; if (usb_hcd_is_primary_hcd(hcd)) { dum->hs_hcd = hcd_to_dummy_hcd(hcd); dum->hs_hcd->dum = dum; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index c63d82c..a7e8665 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -564,7 +564,7 @@ static int ehci_init(struct usb_hcd *hcd) /* Accept arbitrarily long scatter-gather lists */ if (!(hcd->driver->flags & HCD_LOCAL_MEM)) - hcd->self.sg_tablesize = ~0; + hcd->self.sg_tablesize = SG_ALL; return 0; } diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 086a711..1caf013 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -773,7 +773,7 @@ static struct urb *request_single_step_set_feature_urb( urb->transfer_flags = URB_DIR_IN; usb_get_urb(urb); atomic_inc(&urb->use_count); - atomic_inc(&urb->dev->urbnum); + atomic_inc_unchecked(&urb->dev->urbnum); urb->setup_dma = dma_map_single( hcd->self.controller, urb->setup_packet, @@ -840,7 +840,7 @@ static int ehset_single_step_set_feature(struct usb_hcd *hcd, int port) urb->status = -EINPROGRESS; usb_get_urb(urb); atomic_inc(&urb->use_count); - atomic_inc(&urb->dev->urbnum); + atomic_inc_unchecked(&urb->dev->urbnum); retval = submit_single_step_set_feature(hcd, urb, 0); if (!retval && !wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) { diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 54f5332..8b8335c 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -44,9 +44,9 @@ static int qtd_fill(struct ehci_hcd *ehci, struct ehci_qtd *qtd, dma_addr_t buf, - size_t len, int token, int maxpacket) + size_t len, u32 token, int maxpacket) { - int i, count; + u32 i, count; u64 addr = buf; /* one buffer entry per 4K ... first might be short or unaligned */ diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index 000ed80..2701154 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -5231,7 +5231,7 @@ static int hcd_fotg210_init(struct usb_hcd *hcd) /* Accept arbitrarily long scatter-gather lists */ if (!(hcd->driver->flags & HCD_LOCAL_MEM)) - hcd->self.sg_tablesize = ~0; + hcd->self.sg_tablesize = SG_ALL; return 0; } diff --git a/drivers/usb/host/fusbh200-hcd.c b/drivers/usb/host/fusbh200-hcd.c index 1fd8718..c7ff47c 100644 --- a/drivers/usb/host/fusbh200-hcd.c +++ b/drivers/usb/host/fusbh200-hcd.c @@ -5156,7 +5156,7 @@ static int hcd_fusbh200_init(struct usb_hcd *hcd) /* Accept arbitrarily long scatter-gather lists */ if (!(hcd->driver->flags & HCD_LOCAL_MEM)) - hcd->self.sg_tablesize = ~0; + hcd->self.sg_tablesize = SG_ALL; return 0; } diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c index 1db0626..2e9f5ea 100644 --- a/drivers/usb/host/hwa-hc.c +++ b/drivers/usb/host/hwa-hc.c @@ -337,7 +337,10 @@ static int __hwahc_op_bwa_set(struct wusbhc *wusbhc, s8 stream_index, struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); struct wahc *wa = &hwahc->wa; struct device *dev = &wa->usb_iface->dev; - u8 mas_le[UWB_NUM_MAS/8]; + u8 *mas_le = kmalloc(UWB_NUM_MAS/8, GFP_KERNEL); + + if (mas_le == NULL) + return -ENOMEM; /* Set the stream index */ result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), @@ -356,10 +359,12 @@ static int __hwahc_op_bwa_set(struct wusbhc *wusbhc, s8 stream_index, WUSB_REQ_SET_WUSB_MAS, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, - mas_le, 32, USB_CTRL_SET_TIMEOUT); + mas_le, UWB_NUM_MAS/8, USB_CTRL_SET_TIMEOUT); if (result < 0) dev_err(dev, "Cannot set WUSB MAS allocation: %d\n", result); out: + kfree(mas_le); + return result; } @@ -812,7 +817,7 @@ static int hwahc_probe(struct usb_interface *usb_iface, goto error_alloc; } usb_hcd->wireless = 1; - usb_hcd->self.sg_tablesize = ~0; + usb_hcd->self.sg_tablesize = SG_ALL; wusbhc = usb_hcd_to_wusbhc(usb_hcd); hwahc = container_of(wusbhc, struct hwahc, wusbhc); hwahc_init(hwahc); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 760cb57..fc7f8ad 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -444,7 +444,7 @@ static int ohci_init (struct ohci_hcd *ohci) struct usb_hcd *hcd = ohci_to_hcd(ohci); /* Accept arbitrarily long scatter-gather lists */ - hcd->self.sg_tablesize = ~0; + hcd->self.sg_tablesize = SG_ALL; if (distrust_firmware) ohci->flags |= OHCI_QUIRK_HUB_POWER; diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h index 672cea3..31a730db 100644 --- a/drivers/usb/host/r8a66597.h +++ b/drivers/usb/host/r8a66597.h @@ -125,7 +125,7 @@ struct r8a66597 { unsigned short interval_map; unsigned char pipe_cnt[R8A66597_MAX_NUM_PIPE]; unsigned char dma_map; - unsigned int max_root_hub; + unsigned char max_root_hub; struct list_head child_device; unsigned long child_connect_map[4]; diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index a7de8e8..e1ef134 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -570,7 +570,7 @@ static int uhci_start(struct usb_hcd *hcd) hcd->uses_new_polling = 1; /* Accept arbitrarily long scatter-gather lists */ if (!(hcd->driver->flags & HCD_LOCAL_MEM)) - hcd->self.sg_tablesize = ~0; + hcd->self.sg_tablesize = SG_ALL; spin_lock_init(&uhci->lock); setup_timer(&uhci->fsbr_timer, uhci_fsbr_timeout, diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index c47d3e4..35bcc1e 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -30,7 +30,7 @@ #define PORT2_SSIC_CONFIG_REG2 0x883c #define PROG_DONE (1 << 30) -#define SSIC_PORT_UNUSED (1 << 31) +#define SSIC_PORT_UNUSED (1U << 31) /* Device for a quirk */ #define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 385f9f5..fe0610e 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4843,7 +4843,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) int retval; /* Accept arbitrarily long scatter-gather lists */ - hcd->self.sg_tablesize = ~0; + hcd->self.sg_tablesize = SG_ALL; /* support to build packet from discontinuous buffers */ hcd->self.no_sg_constraint = 1; diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index a0a3827..d7ec10b 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -84,7 +84,7 @@ struct appledisplay { struct mutex sysfslock; /* concurrent read and write */ }; -static atomic_t count_displays = ATOMIC_INIT(0); +static atomic_unchecked_t count_displays = ATOMIC_INIT(0); static struct workqueue_struct *wq; static void appledisplay_complete(struct urb *urb) @@ -288,7 +288,7 @@ static int appledisplay_probe(struct usb_interface *iface, /* Register backlight device */ snprintf(bl_name, sizeof(bl_name), "appledisplay%d", - atomic_inc_return(&count_displays) - 1); + atomic_inc_return_unchecked(&count_displays) - 1); memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = 0xff; diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 3806e70..55c508b 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -126,7 +126,7 @@ static int usb_console_setup(struct console *co, char *options) info->port = port; - ++port->port.count; + atomic_inc(&port->port.count); if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) { if (serial->type->set_termios) { /* @@ -175,7 +175,7 @@ static int usb_console_setup(struct console *co, char *options) } /* Now that any required fake tty operations are completed restore * the tty port count */ - --port->port.count; + atomic_dec(&port->port.count); /* The console is special in terms of closing the device so * indicate this port is now acting as a system console. */ port->port.console = 1; @@ -188,7 +188,7 @@ static int usb_console_setup(struct console *co, char *options) put_tty: tty_kref_put(tty); reset_open_count: - port->port.count = 0; + atomic_set(&port->port.count, 0); usb_autopm_put_interface(serial->interface); error_get_interface: usb_serial_put(serial); @@ -199,7 +199,7 @@ static int usb_console_setup(struct console *co, char *options) static void usb_console_write(struct console *co, const char *buf, unsigned count) { - static struct usbcons_info *info = &usbcons_info; + struct usbcons_info *info = &usbcons_info; struct usb_serial_port *port = info->port; struct usb_serial *serial; int retval = -ENODEV; diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 5e67f63..2ef08d6 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -689,7 +689,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) if (need_auto_sense) { int temp_result; struct scsi_eh_save ses; - int sense_size = US_SENSE_SIZE; + unsigned int sense_size = US_SENSE_SIZE; struct scsi_sense_hdr sshdr; const u8 *scdd; u8 fm_ili; diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 43576ed..583589d 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -912,7 +912,7 @@ static void usb_stor_scan_dwork(struct work_struct *work) clear_bit(US_FLIDX_SCAN_PENDING, &us->dflags); } -static unsigned int usb_stor_sg_tablesize(struct usb_interface *intf) +static unsigned short usb_stor_sg_tablesize(struct usb_interface *intf) { struct usb_device *usb_dev = interface_to_usbdev(intf); diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index da0ad32..50b5bbe 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -63,7 +63,7 @@ struct us_unusual_dev { __u8 useProtocol; __u8 useTransport; int (*initFunction)(struct us_data *); -}; +} __do_const; /* Dynamic bitflag definitions (us->dflags): used in set_bit() etc. */ diff --git a/drivers/usb/usbip/vhci.h b/drivers/usb/usbip/vhci.h index a863a98..d272795 100644 --- a/drivers/usb/usbip/vhci.h +++ b/drivers/usb/usbip/vhci.h @@ -83,7 +83,7 @@ struct vhci_hcd { unsigned resuming:1; unsigned long re_timeout; - atomic_t seqnum; + atomic_unchecked_t seqnum; /* * NOTE: diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index e9ef1ec..c3a0b04 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -440,7 +440,7 @@ static void vhci_tx_urb(struct urb *urb) spin_lock(&vdev->priv_lock); - priv->seqnum = atomic_inc_return(&the_controller->seqnum); + priv->seqnum = atomic_inc_return_unchecked(&the_controller->seqnum); if (priv->seqnum == 0xffff) dev_info(&urb->dev->dev, "seqnum max\n"); @@ -685,7 +685,7 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) return -ENOMEM; } - unlink->seqnum = atomic_inc_return(&the_controller->seqnum); + unlink->seqnum = atomic_inc_return_unchecked(&the_controller->seqnum); if (unlink->seqnum == 0xffff) pr_info("seqnum max\n"); @@ -889,7 +889,7 @@ static int vhci_start(struct usb_hcd *hcd) vdev->rhport = rhport; } - atomic_set(&vhci->seqnum, 0); + atomic_set_unchecked(&vhci->seqnum, 0); spin_lock_init(&vhci->lock); hcd->power_budget = 0; /* no limit */ diff --git a/drivers/usb/usbip/vhci_rx.c b/drivers/usb/usbip/vhci_rx.c index 00e4a54..d676f85 100644 --- a/drivers/usb/usbip/vhci_rx.c +++ b/drivers/usb/usbip/vhci_rx.c @@ -80,7 +80,7 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev, if (!urb) { pr_err("cannot find a urb of seqnum %u\n", pdu->base.seqnum); pr_info("max seqnum %d\n", - atomic_read(&the_controller->seqnum)); + atomic_read_unchecked(&the_controller->seqnum)); usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); return; } diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c index 211f43f..6c22ae1 100644 --- a/drivers/usb/usbip/vhci_sysfs.c +++ b/drivers/usb/usbip/vhci_sysfs.c @@ -59,7 +59,7 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr, if (vdev->ud.status == VDEV_ST_USED) { out += sprintf(out, "%03u %08x ", vdev->speed, vdev->devid); - out += sprintf(out, "%16p ", vdev->ud.tcp_socket); + out += sprintf(out, "%16pK ", vdev->ud.tcp_socket); out += sprintf(out, "%s", dev_name(&vdev->udev->dev)); } else { diff --git a/drivers/usb/wusbcore/wa-hc.h b/drivers/usb/wusbcore/wa-hc.h index edc7267..9f65ce2 100644 --- a/drivers/usb/wusbcore/wa-hc.h +++ b/drivers/usb/wusbcore/wa-hc.h @@ -240,7 +240,7 @@ struct wahc { spinlock_t xfer_list_lock; struct work_struct xfer_enqueue_work; struct work_struct xfer_error_work; - atomic_t xfer_id_count; + atomic_unchecked_t xfer_id_count; kernel_ulong_t quirks; }; @@ -305,7 +305,7 @@ static inline void wa_init(struct wahc *wa) INIT_WORK(&wa->xfer_enqueue_work, wa_urb_enqueue_run); INIT_WORK(&wa->xfer_error_work, wa_process_errored_transfers_run); wa->dto_in_use = 0; - atomic_set(&wa->xfer_id_count, 1); + atomic_set_unchecked(&wa->xfer_id_count, 1); /* init the buf in URBs */ for (index = 0; index < WA_MAX_BUF_IN_URBS; ++index) usb_init_urb(&(wa->buf_in_urbs[index])); diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c index 69af4fd..da390d7 100644 --- a/drivers/usb/wusbcore/wa-xfer.c +++ b/drivers/usb/wusbcore/wa-xfer.c @@ -314,7 +314,7 @@ static void wa_xfer_completion(struct wa_xfer *xfer) */ static void wa_xfer_id_init(struct wa_xfer *xfer) { - xfer->id = atomic_add_return(1, &xfer->wa->xfer_id_count); + xfer->id = atomic_add_return_unchecked(1, &xfer->wa->xfer_id_count); } /* Return the xfer's ID. */ diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 563c510..1fcc957 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c @@ -517,7 +517,7 @@ static int vfio_group_nb_add_dev(struct vfio_group *group, struct device *dev) return 0; /* TODO Prevent device auto probing */ - WARN("Device %s added to live group %d!\n", dev_name(dev), + WARN(1, "Device %s added to live group %d!\n", dev_name(dev), iommu_group_id(group->iommu_group)); return 0; diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c index 3bb02c6..a01ff38 100644 --- a/drivers/vhost/vringh.c +++ b/drivers/vhost/vringh.c @@ -551,7 +551,7 @@ static inline void __vringh_notify_disable(struct vringh *vrh, static inline int getu16_user(const struct vringh *vrh, u16 *val, const __virtio16 *p) { __virtio16 v = 0; - int rc = get_user(v, (__force __virtio16 __user *)p); + int rc = get_user(v, (__force_user __virtio16 *)p); *val = vringh16_to_cpu(vrh, v); return rc; } @@ -559,12 +559,12 @@ static inline int getu16_user(const struct vringh *vrh, u16 *val, const __virtio static inline int putu16_user(const struct vringh *vrh, __virtio16 *p, u16 val) { __virtio16 v = cpu_to_vringh16(vrh, val); - return put_user(v, (__force __virtio16 __user *)p); + return put_user(v, (__force_user __virtio16 *)p); } static inline int copydesc_user(void *dst, const void *src, size_t len) { - return copy_from_user(dst, (__force void __user *)src, len) ? + return copy_from_user(dst, (void __force_user *)src, len) ? -EFAULT : 0; } @@ -572,19 +572,19 @@ static inline int putused_user(struct vring_used_elem *dst, const struct vring_used_elem *src, unsigned int num) { - return copy_to_user((__force void __user *)dst, src, + return copy_to_user((void __force_user *)dst, src, sizeof(*dst) * num) ? -EFAULT : 0; } static inline int xfer_from_user(void *src, void *dst, size_t len) { - return copy_from_user(dst, (__force void __user *)src, len) ? + return copy_from_user(dst, (void __force_user *)src, len) ? -EFAULT : 0; } static inline int xfer_to_user(void *dst, void *src, size_t len) { - return copy_to_user((__force void __user *)dst, src, len) ? + return copy_to_user((void __force_user *)dst, src, len) ? -EFAULT : 0; } @@ -621,9 +621,9 @@ int vringh_init_user(struct vringh *vrh, u64 features, vrh->last_used_idx = 0; vrh->vring.num = num; /* vring expects kernel addresses, but only used via accessors. */ - vrh->vring.desc = (__force struct vring_desc *)desc; - vrh->vring.avail = (__force struct vring_avail *)avail; - vrh->vring.used = (__force struct vring_used *)used; + vrh->vring.desc = (__force_kernel struct vring_desc *)desc; + vrh->vring.avail = (__force_kernel struct vring_avail *)avail; + vrh->vring.used = (__force_kernel struct vring_used *)used; return 0; } EXPORT_SYMBOL(vringh_init_user); @@ -826,7 +826,7 @@ static inline int getu16_kern(const struct vringh *vrh, static inline int putu16_kern(const struct vringh *vrh, __virtio16 *p, u16 val) { - ACCESS_ONCE(*p) = cpu_to_vringh16(vrh, val); + ACCESS_ONCE_RW(*p) = cpu_to_vringh16(vrh, val); return 0; } diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c index 84a110a..96312c3 100644 --- a/drivers/video/backlight/kb3886_bl.c +++ b/drivers/video/backlight/kb3886_bl.c @@ -78,7 +78,7 @@ static struct kb3886bl_machinfo *bl_machinfo; static unsigned long kb3886bl_flags; #define KB3886BL_SUSPENDED 0x01 -static struct dmi_system_id kb3886bl_device_table[] __initdata = { +static const struct dmi_system_id kb3886bl_device_table[] __initconst = { { .ident = "Sahara Touch-iT", .matches = { diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 92f3949..7bb0e86 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -106,7 +106,7 @@ static int fbcon_softback_size = 32768; static unsigned long softback_buf, softback_curr; static unsigned long softback_in; static unsigned long softback_top, softback_end; -static int softback_lines; +static long softback_lines; /* console mappings */ static int first_fb_vc; static int last_fb_vc = MAX_NR_CONSOLES - 1; diff --git a/drivers/video/fbdev/arcfb.c b/drivers/video/fbdev/arcfb.c index 1b0b233..6f34c2c 100644 --- a/drivers/video/fbdev/arcfb.c +++ b/drivers/video/fbdev/arcfb.c @@ -458,7 +458,7 @@ static ssize_t arcfb_write(struct fb_info *info, const char __user *buf, return -ENOSPC; err = 0; - if ((count + p) > fbmemlength) { + if (count > (fbmemlength - p)) { count = fbmemlength - p; err = -ENOSPC; } diff --git a/drivers/video/fbdev/aty/aty128fb.c b/drivers/video/fbdev/aty/aty128fb.c index c42ce2f..4c8bc59 100644 --- a/drivers/video/fbdev/aty/aty128fb.c +++ b/drivers/video/fbdev/aty/aty128fb.c @@ -145,7 +145,7 @@ enum { }; /* Must match above enum */ -static char * const r128_family[] = { +static const char * const r128_family[] = { "AGP", "PCI", "PRO AGP", diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c index f34ed47..026367f 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) par->accel_flags = var->accel_flags; /* hack */ if (var->accel_flags) { - info->fbops->fb_sync = atyfb_sync; + pax_open_kernel(); + *(void **)&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; + pax_close_kernel(); info->flags |= FBINFO_HWACCEL_DISABLED; } diff --git a/drivers/video/fbdev/aty/mach64_cursor.c b/drivers/video/fbdev/aty/mach64_cursor.c index 2fa0317..4983f2a 100644 --- a/drivers/video/fbdev/aty/mach64_cursor.c +++ b/drivers/video/fbdev/aty/mach64_cursor.c @@ -8,6 +8,7 @@ #include "../core/fb_draw.h" #include +#include #ifdef __sparc__ #include @@ -218,7 +219,9 @@ int aty_init_cursor(struct fb_info *info) info->sprite.buf_align = 16; /* and 64 lines tall. */ info->sprite.flags = FB_PIXMAP_IO; - info->fbops->fb_cursor = atyfb_cursor; + pax_open_kernel(); + *(void **)&info->fbops->fb_cursor = atyfb_cursor; + pax_close_kernel(); return 0; } diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c index 3fc63c2..eec5e49 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) BUG_ON(!fbdefio); mutex_init(&fbdefio->lock); - info->fbops->fb_mmap = fb_deferred_io_mmap; + pax_open_kernel(); + *(void **)&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) page->mapping = NULL; } - info->fbops->fb_mmap = NULL; + *(void **)&info->fbops->fb_mmap = NULL; mutex_destroy(&fbdefio->lock); } EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup); diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 0705d88..0e17c07 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1301,7 +1301,7 @@ static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix, __u32 data; int err; - err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id)); + err = copy_to_user(fix32->id, &fix->id, sizeof(fix32->id)); data = (__u32) (unsigned long) fix->smem_start; err |= put_user(data, &fix32->smem_start); @@ -1435,10 +1435,7 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) return vm_iomap_memory(vma, start, len); } -static int -fb_open(struct inode *inode, struct file *file) -__acquires(&info->lock) -__releases(&info->lock) +static int fb_open(struct inode *inode, struct file *file) { int fbidx = iminor(inode); struct fb_info *info; @@ -1476,10 +1473,7 @@ out: return res; } -static int -fb_release(struct inode *inode, struct file *file) -__acquires(&info->lock) -__releases(&info->lock) +static int fb_release(struct inode *inode, struct file *file) { struct fb_info * const info = file->private_data; diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index e2451bd..ab7ccd1 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -240,7 +240,7 @@ static uint screen_fb_size; static inline int synthvid_send(struct hv_device *hdev, struct synthvid_msg *msg) { - static atomic64_t request_id = ATOMIC64_INIT(0); + static atomic64_unchecked_t request_id = ATOMIC64_INIT(0); int ret; msg->pipe_hdr.type = PIPE_MSG_DATA; @@ -248,7 +248,7 @@ static inline int synthvid_send(struct hv_device *hdev, ret = vmbus_sendpacket(hdev->channel, msg, msg->vid_hdr.size + sizeof(struct pipe_msg_hdr), - atomic64_inc_return(&request_id), + atomic64_inc_return_unchecked(&request_id), VM_PKT_DATA_INBAND, 0); if (ret) diff --git a/drivers/video/fbdev/i810/i810_accel.c b/drivers/video/fbdev/i810/i810_accel.c index 7672d2e..b56437f 100644 --- a/drivers/video/fbdev/i810/i810_accel.c +++ b/drivers/video/fbdev/i810/i810_accel.c @@ -73,6 +73,7 @@ static inline int wait_for_space(struct fb_info *info, u32 space) } } printk("ringbuffer lockup!!!\n"); + printk("head:%u tail:%u iring.size:%u space:%u\n", head, tail, par->iring.size, space); i810_report_error(mmio); par->dev_flags |= LOCKUP; info->pixmap.scan_align = 1; diff --git a/drivers/video/fbdev/matrox/matroxfb_DAC1064.c b/drivers/video/fbdev/matrox/matroxfb_DAC1064.c index a01147f..5d896f8 100644 --- a/drivers/video/fbdev/matrox/matroxfb_DAC1064.c +++ b/drivers/video/fbdev/matrox/matroxfb_DAC1064.c @@ -1088,14 +1088,20 @@ static void MGAG100_restore(struct matrox_fb_info *minfo) #ifdef CONFIG_FB_MATROX_MYSTIQUE struct matrox_switch matrox_mystique = { - MGA1064_preinit, MGA1064_reset, MGA1064_init, MGA1064_restore, + .preinit = MGA1064_preinit, + .reset = MGA1064_reset, + .init = MGA1064_init, + .restore = MGA1064_restore, }; EXPORT_SYMBOL(matrox_mystique); #endif #ifdef CONFIG_FB_MATROX_G struct matrox_switch matrox_G100 = { - MGAG100_preinit, MGAG100_reset, MGAG100_init, MGAG100_restore, + .preinit = MGAG100_preinit, + .reset = MGAG100_reset, + .init = MGAG100_init, + .restore = MGAG100_restore, }; EXPORT_SYMBOL(matrox_G100); #endif diff --git a/drivers/video/fbdev/matrox/matroxfb_Ti3026.c b/drivers/video/fbdev/matrox/matroxfb_Ti3026.c index 195ad7c..09743fc 100644 --- a/drivers/video/fbdev/matrox/matroxfb_Ti3026.c +++ b/drivers/video/fbdev/matrox/matroxfb_Ti3026.c @@ -738,7 +738,10 @@ static int Ti3026_preinit(struct matrox_fb_info *minfo) } struct matrox_switch matrox_millennium = { - Ti3026_preinit, Ti3026_reset, Ti3026_init, Ti3026_restore + .preinit = Ti3026_preinit, + .reset = Ti3026_reset, + .init = Ti3026_init, + .restore = Ti3026_restore }; EXPORT_SYMBOL(matrox_millennium); #endif diff --git a/drivers/video/fbdev/matrox/matroxfb_base.c b/drivers/video/fbdev/matrox/matroxfb_base.c index 11eb094..622ee31 100644 --- a/drivers/video/fbdev/matrox/matroxfb_base.c +++ b/drivers/video/fbdev/matrox/matroxfb_base.c @@ -2176,7 +2176,7 @@ static struct pci_driver matroxfb_driver = { #define RS1056x480 14 /* 132 x 60 text */ #define RSNoxNo 15 /* 10-FF */ -static struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = { +static struct { unsigned int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = { { 640, 400, 48, 16, 39, 8, 96, 2, 70 }, { 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 --- 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) struct mb862xxfb_par *par = info->par; if (info->var.bits_per_pixel == 32) { - info->fbops->fb_fillrect = cfb_fillrect; - 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; + pax_close_kernel(); } else { outreg(disp, GC_L0EM, 3); - info->fbops->fb_fillrect = mb86290fb_fillrect; - 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; + 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 --- 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) info->fix.line_length = (info->var.xres_virtual * info->var.bits_per_pixel) >> 3; if (info->var.accel_flags) { - info->fbops->fb_imageblit = nvidiafb_imageblit; - info->fbops->fb_fillrect = nvidiafb_fillrect; - 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; + pax_close_kernel(); info->pixmap.scan_align = 4; info->flags &= ~FBINFO_HWACCEL_DISABLED; info->flags |= FBINFO_READS_FAST; NVResetGraphics(info); } else { - info->fbops->fb_imageblit = cfb_imageblit; - info->fbops->fb_fillrect = cfb_fillrect; - 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; + pax_close_kernel(); info->pixmap.scan_align = 1; info->flags |= FBINFO_HWACCEL_DISABLED; info->flags &= ~FBINFO_READS_FAST; @@ -1164,8 +1168,11 @@ static int nvidia_set_fbinfo(struct fb_info *info) info->pixmap.size = 8 * 1024; info->pixmap.flags = FB_PIXMAP_SYSTEM; - if (!hwcur) - info->fbops->fb_cursor = NULL; + if (!hwcur) { + pax_open_kernel(); + *(void **)&info->fbops->fb_cursor = NULL; + pax_close_kernel(); + } info->var.accel_flags = (!noaccel); diff --git a/drivers/video/fbdev/omap2/dss/display.c b/drivers/video/fbdev/omap2/dss/display.c index ef5b902..47cf7f5 100644 --- a/drivers/video/fbdev/omap2/dss/display.c +++ b/drivers/video/fbdev/omap2/dss/display.c @@ -161,12 +161,14 @@ int omapdss_register_display(struct omap_dss_device *dssdev) if (dssdev->name == NULL) dssdev->name = dssdev->alias; + pax_open_kernel(); if (drv && drv->get_resolution == NULL) - drv->get_resolution = omapdss_default_get_resolution; + *(void **)&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; if (drv && drv->get_timings == NULL) - drv->get_timings = omapdss_default_get_timings; + *(void **)&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 --- a/drivers/video/fbdev/s1d13xxxfb.c +++ b/drivers/video/fbdev/s1d13xxxfb.c @@ -880,8 +880,10 @@ static int s1d13xxxfb_probe(struct platform_device *pdev) switch(prod_id) { case S1D13506_PROD_ID: /* activate acceleration */ - 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; + pax_close_kernel(); info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN | FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA; break; diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c index 82c0a8c..42499a1 100644 --- a/drivers/video/fbdev/sh_mobile_lcdcfb.c +++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c @@ -439,9 +439,9 @@ static unsigned long lcdc_sys_read_data(void *handle) } static struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { - lcdc_sys_write_index, - lcdc_sys_write_data, - lcdc_sys_read_data, + .write_index = lcdc_sys_write_index, + .write_data = lcdc_sys_write_data, + .read_data = lcdc_sys_read_data, }; static int sh_mobile_lcdc_sginit(struct fb_info *info, diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c index 9279e5f..d5f5276 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) fb_deferred_io_cleanup(info); kfree(info->fbdefio); info->fbdefio = NULL; - info->fbops->fb_mmap = ufx_ops_mmap; + pax_open_kernel(); + *(void **)&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 --- 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, dlfb_urb_completion(urb); error: - atomic_add(bytes_sent, &dev->bytes_sent); - atomic_add(bytes_identical, &dev->bytes_identical); - atomic_add(width*height*2, &dev->bytes_rendered); + atomic_add_unchecked(bytes_sent, &dev->bytes_sent); + atomic_add_unchecked(bytes_identical, &dev->bytes_identical); + atomic_add_unchecked(width*height*2, &dev->bytes_rendered); end_cycles = get_cycles(); - atomic_add(((unsigned int) ((end_cycles - start_cycles) + atomic_add_unchecked(((unsigned int) ((end_cycles - start_cycles) >> 10)), /* Kcycles */ &dev->cpu_kcycles_used); @@ -748,11 +748,11 @@ static void dlfb_dpy_deferred_io(struct fb_info *info, dlfb_urb_completion(urb); error: - atomic_add(bytes_sent, &dev->bytes_sent); - atomic_add(bytes_identical, &dev->bytes_identical); - atomic_add(bytes_rendered, &dev->bytes_rendered); + atomic_add_unchecked(bytes_sent, &dev->bytes_sent); + atomic_add_unchecked(bytes_identical, &dev->bytes_identical); + atomic_add_unchecked(bytes_rendered, &dev->bytes_rendered); end_cycles = get_cycles(); - atomic_add(((unsigned int) ((end_cycles - start_cycles) + atomic_add_unchecked(((unsigned int) ((end_cycles - start_cycles) >> 10)), /* Kcycles */ &dev->cpu_kcycles_used); } @@ -991,7 +991,9 @@ static int dlfb_ops_release(struct fb_info *info, int user) fb_deferred_io_cleanup(info); kfree(info->fbdefio); info->fbdefio = NULL; - info->fbops->fb_mmap = dlfb_ops_mmap; + pax_open_kernel(); + *(void **)&info->fbops->fb_mmap = dlfb_ops_mmap; + pax_close_kernel(); } pr_warn("released /dev/fb%d user=%d count=%d\n", @@ -1373,7 +1375,7 @@ static ssize_t metrics_bytes_rendered_show(struct device *fbdev, struct fb_info *fb_info = dev_get_drvdata(fbdev); struct dlfb_data *dev = fb_info->par; return snprintf(buf, PAGE_SIZE, "%u\n", - atomic_read(&dev->bytes_rendered)); + atomic_read_unchecked(&dev->bytes_rendered)); } static ssize_t metrics_bytes_identical_show(struct device *fbdev, @@ -1381,7 +1383,7 @@ static ssize_t metrics_bytes_identical_show(struct device *fbdev, struct fb_info *fb_info = dev_get_drvdata(fbdev); struct dlfb_data *dev = fb_info->par; return snprintf(buf, PAGE_SIZE, "%u\n", - atomic_read(&dev->bytes_identical)); + atomic_read_unchecked(&dev->bytes_identical)); } static ssize_t metrics_bytes_sent_show(struct device *fbdev, @@ -1389,7 +1391,7 @@ static ssize_t metrics_bytes_sent_show(struct device *fbdev, struct fb_info *fb_info = dev_get_drvdata(fbdev); struct dlfb_data *dev = fb_info->par; return snprintf(buf, PAGE_SIZE, "%u\n", - atomic_read(&dev->bytes_sent)); + atomic_read_unchecked(&dev->bytes_sent)); } static ssize_t metrics_cpu_kcycles_used_show(struct device *fbdev, @@ -1397,7 +1399,7 @@ static ssize_t metrics_cpu_kcycles_used_show(struct device *fbdev, struct fb_info *fb_info = dev_get_drvdata(fbdev); struct dlfb_data *dev = fb_info->par; return snprintf(buf, PAGE_SIZE, "%u\n", - atomic_read(&dev->cpu_kcycles_used)); + atomic_read_unchecked(&dev->cpu_kcycles_used)); } static ssize_t edid_show( @@ -1457,10 +1459,10 @@ static ssize_t metrics_reset_store(struct device *fbdev, struct fb_info *fb_info = dev_get_drvdata(fbdev); struct dlfb_data *dev = fb_info->par; - atomic_set(&dev->bytes_rendered, 0); - atomic_set(&dev->bytes_identical, 0); - atomic_set(&dev->bytes_sent, 0); - atomic_set(&dev->cpu_kcycles_used, 0); + atomic_set_unchecked(&dev->bytes_rendered, 0); + atomic_set_unchecked(&dev->bytes_identical, 0); + atomic_set_unchecked(&dev->bytes_sent, 0); + atomic_set_unchecked(&dev->cpu_kcycles_used, 0); return count; } diff --git a/drivers/video/fbdev/uvesafb.c b/drivers/video/fbdev/uvesafb.c index 178ae93..624b2eb 100644 --- a/drivers/video/fbdev/uvesafb.c +++ b/drivers/video/fbdev/uvesafb.c @@ -19,6 +19,7 @@ #include #include #include +#include #include