[RFC PATCH 11/11] prctl: Refactor PR_{SET,GET}_UNALIGN to reduce boilerplate

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The PR_SET_UNALIGN and PR_GET_UNALIGN prctl() calls are implemented
by five architectures today, but there is some irregularity and
duplication in the way they are implemented.

This patch moves the common put_user() operation to common code,
since the user pointer type is the same in all cases.

Because this is hardly hot-path code, there is no strong reason to
inline the arch backends for these operations, so this patch also
pushes them down into the arch trees as proper C functions, and
regularises the style of the backends somewhat.

Signed-off-by: Dave Martin <Dave.Martin@xxxxxxx>
Cc: Kees Cook <keescook@xxxxxxxxxxxx>
Cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
Cc: Ingo Molnar <mingo@xxxxxxxxxx>
Cc: Richard Henderson <rth@xxxxxxxxxxx>
Cc: Ivan Kokshaysky <ink@xxxxxxxxxxxxxxxxxxxx>
Cc: Matt Turner <mattst88@xxxxxxxxx>
Cc: Tony Luck <tony.luck@xxxxxxxxx>
Cc: Fenghua Yu <fenghua.yu@xxxxxxxxx>
Cc: Benjamin Herrenschmidt <benh@xxxxxxxxxxxxxxxxxxx>
Cc: Paul Mackerras <paulus@xxxxxxxxx>
Cc: Michael Ellerman <mpe@xxxxxxxxxxxxxx>
Cc: Yoshinori Sato <ysato@xxxxxxxxxxxxxxxxxxxx>
Cc: Rich Felker <dalias@xxxxxxxx>
---
 arch/Kconfig                         |  3 +++
 arch/alpha/Kconfig                   |  1 +
 arch/alpha/include/asm/thread_info.h | 23 -----------------------
 arch/alpha/kernel/Makefile           |  2 +-
 arch/alpha/kernel/sys.c              | 36 ++++++++++++++++++++++++++++++++++++
 arch/ia64/Kconfig                    |  1 +
 arch/ia64/include/asm/processor.h    | 12 ------------
 arch/ia64/kernel/sys_ia64.c          | 15 +++++++++++++++
 arch/parisc/Kconfig                  |  1 +
 arch/parisc/include/asm/processor.h  | 14 --------------
 arch/parisc/kernel/sys_parisc.c      | 15 +++++++++++++++
 arch/powerpc/Kconfig                 |  1 +
 arch/powerpc/include/asm/processor.h |  6 ------
 arch/powerpc/kernel/process.c        |  6 +++---
 arch/sh/Kconfig                      |  1 +
 arch/sh/include/asm/processor.h      |  7 -------
 arch/sh/mm/alignment.c               |  8 ++++----
 include/linux/prctl.h                |  8 ++++++++
 kernel/sys.c                         | 20 ++++++++++----------
 19 files changed, 100 insertions(+), 80 deletions(-)
 create mode 100644 arch/alpha/kernel/sys.c

diff --git a/arch/Kconfig b/arch/Kconfig
index b34b3e8..a9195ffc 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -972,4 +972,7 @@ config REFCOUNT_FULL
 config HAVE_PRCTL_ARCH
 	bool
 
+config HAVE_ARCH_PR_SET_GET_UNALIGN
+	bool
+
 source "kernel/gcov/Kconfig"
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index b202288..afb9aaa 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -23,6 +23,7 @@ config ALPHA
 	select GENERIC_STRNCPY_FROM_USER
 	select GENERIC_STRNLEN_USER
 	select HAVE_ARCH_AUDITSYSCALL
+	select HAVE_ARCH_PR_SET_GET_UNALIGN
 	select HAVE_MOD_ARCH_SPECIFIC
 	select MODULES_USE_ELF_RELA
 	select ODD_RT_SIGACTION
diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h
index 403b3c8..7ba2099 100644
--- a/arch/alpha/include/asm/thread_info.h
+++ b/arch/alpha/include/asm/thread_info.h
@@ -85,28 +85,5 @@ register struct thread_info *__current_thread_info __asm__("$8");
 #define TS_UAC_NOFIX		0x0002	/* ! flags as they match          */
 #define TS_UAC_SIGBUS		0x0004	/* ! userspace part of 'osf_sysinfo' */
 
-#define SET_UNALIGN_CTL(value)	({					\
-	__u32 status = current_thread_info()->status & ~UAC_BITMASK;	\
-	if (value & PR_UNALIGN_NOPRINT)					\
-		status |= TS_UAC_NOPRINT;				\
-	if (value & PR_UNALIGN_SIGBUS)					\
-		status |= TS_UAC_SIGBUS;				\
-	if (value & 4)	/* alpha-specific */				\
-		status |= TS_UAC_NOFIX;					\
-	current_thread_info()->status = status;				\
-	0; })
-
-#define GET_UNALIGN_CTL(value)	({					\
-	__u32 status = current_thread_info()->status & ~UAC_BITMASK;	\
-	__u32 res = 0;							\
-	if (status & TS_UAC_NOPRINT)					\
-		res |= PR_UNALIGN_NOPRINT;				\
-	if (status & TS_UAC_SIGBUS)					\
-		res |= PR_UNALIGN_SIGBUS;				\
-	if (status & TS_UAC_NOFIX)					\
-		res |= 4;						\
-	put_user(res, (int __user *)(value));				\
-	})
-
 #endif /* __KERNEL__ */
 #endif /* _ALPHA_THREAD_INFO_H */
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
index 5a74581..e4b5294 100644
--- a/arch/alpha/kernel/Makefile
+++ b/arch/alpha/kernel/Makefile
@@ -9,7 +9,7 @@ ccflags-y	:= -Wno-sign-compare
 
 obj-y    := entry.o traps.o process.o osf_sys.o irq.o \
 	    irq_alpha.o signal.o setup.o ptrace.o time.o \
-	    systbls.o err_common.o io.o bugs.o
+	    systbls.o err_common.o io.o bugs.o sys.o
 
 obj-$(CONFIG_VGA_HOSE)	+= console.o
 obj-$(CONFIG_SMP)	+= smp.o
diff --git a/arch/alpha/kernel/sys.c b/arch/alpha/kernel/sys.c
new file mode 100644
index 0000000..3dc454f
--- /dev/null
+++ b/arch/alpha/kernel/sys.c
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/prctl.h>
+#include <linux/thread_info.h>
+#include <linux/uaccess.h>
+
+int arch_set_unalign_ctl(unsigned int val)
+{
+	__u32 status = current_thread_info()->status & ~UAC_BITMASK;
+
+	if (val & PR_UNALIGN_NOPRINT)
+		status |= TS_UAC_NOPRINT;
+	if (val & PR_UNALIGN_SIGBUS)
+		status |= TS_UAC_SIGBUS;
+	if (val & 4)	/* alpha-specific */
+		status |= TS_UAC_NOFIX;
+
+	current_thread_info()->status = status;
+
+	return 0;
+}
+
+int arch_get_unalign_ctl(void)
+{
+	__u32 status = current_thread_info()->status & ~UAC_BITMASK;
+	int res = 0;
+
+	if (status & TS_UAC_NOPRINT)
+		res |= PR_UNALIGN_NOPRINT;
+	if (status & TS_UAC_SIGBUS)
+		res |= PR_UNALIGN_SIGBUS;
+	if (status & TS_UAC_NOFIX)
+		res |= 4;
+
+	return res;
+}
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index a673dd7..ab62a57 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -55,6 +55,7 @@ config IA64
 	select ARCH_USE_CMPXCHG_LOCKREF
 	select HAVE_ARCH_AUDITSYSCALL
 	select HAVE_PRCTL_ARCH
+	select HAVE_ARCH_PR_SET_GET_UNALIGN
 	default y
 	help
 	  The Itanium Processor Family is Intel's 64-bit successor to
diff --git a/arch/ia64/include/asm/processor.h b/arch/ia64/include/asm/processor.h
index 8d5184f..49f4ef9 100644
--- a/arch/ia64/include/asm/processor.h
+++ b/arch/ia64/include/asm/processor.h
@@ -247,18 +247,6 @@ typedef struct {
 	unsigned long seg;
 } mm_segment_t;
 
-#define SET_UNALIGN_CTL(value)								\
-({												\
-	current->thread.flags = ((current->thread.flags & ~IA64_THREAD_UAC_MASK)			\
-				| (((value) << IA64_THREAD_UAC_SHIFT) & IA64_THREAD_UAC_MASK));	\
-	0;											\
-})
-#define GET_UNALIGN_CTL(addr)								\
-({												\
-	put_user((current->thread.flags & IA64_THREAD_UAC_MASK) >> IA64_THREAD_UAC_SHIFT,	\
-		 (int __user *) (addr));							\
-})
-
 struct thread_struct {
 	__u32 flags;			/* various thread flags (see IA64_THREAD_*) */
 	/* writing on_ustack is performance-critical, so it's worth spending 8 bits on it... */
diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c
index d996585..2c2fd65 100644
--- a/arch/ia64/kernel/sys_ia64.c
+++ b/arch/ia64/kernel/sys_ia64.c
@@ -206,3 +206,18 @@ int prctl_arch(int option, unsigned long arg2, unsigned long arg3,
 		return -EINVAL;
 	}
 }
+
+int arch_set_unalign_ctl(unsigned int val)
+{
+	current->thread.flags &= ~IA64_THREAD_UAC_MASK;
+	current->thread.flags |= (val << IA64_THREAD_UAC_SHIFT) &
+		IA64_THREAD_UAC_MASK;
+
+	return 0;
+}
+
+int arch_get_unalign_ctl(void)
+{
+	return (current->thread.flags & IA64_THREAD_UAC_MASK) >>
+		IA64_THREAD_UAC_SHIFT;
+}
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index fc5a574..a2f0f0a 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -44,6 +44,7 @@ config PARISC
 	select HAVE_DEBUG_STACKOVERFLOW
 	select HAVE_ARCH_AUDITSYSCALL
 	select HAVE_ARCH_HASH
+	select HAVE_ARCH_PR_SET_GET_UNALIGN
 	select HAVE_ARCH_SECCOMP_FILTER
 	select HAVE_ARCH_TRACEHOOK
 	select GENERIC_SCHED_CLOCK
diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h
index b59720f..dbea6e9 100644
--- a/arch/parisc/include/asm/processor.h
+++ b/arch/parisc/include/asm/processor.h
@@ -139,20 +139,6 @@ struct thread_struct {
 #define PARISC_UAC_SHIFT	0
 #define PARISC_UAC_MASK		(PARISC_UAC_NOPRINT|PARISC_UAC_SIGBUS)
 
-#define SET_UNALIGN_CTL(value)                                            \
-        ({                                                                \
-        current->thread.flags = ((current->thread.flags & ~PARISC_UAC_MASK) \
-                                | (((value) << PARISC_UAC_SHIFT) &        \
-                                   PARISC_UAC_MASK));                     \
-        0;                                                                \
-        })
-
-#define GET_UNALIGN_CTL(addr)                                             \
-        ({                                                                \
-        put_user((current->thread.flags & PARISC_UAC_MASK)                \
-                 >> PARISC_UAC_SHIFT, (int __user *) (addr));             \
-        })
-
 #define INIT_THREAD { \
 	.regs = {	.gr	= { 0, }, \
 			.fr	= { 0, }, \
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
index 43b308c..e3a7f29 100644
--- a/arch/parisc/kernel/sys_parisc.c
+++ b/arch/parisc/kernel/sys_parisc.c
@@ -30,6 +30,7 @@
 #include <linux/linkage.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
+#include <linux/prctl.h>
 #include <linux/sched/signal.h>
 #include <linux/sched/mm.h>
 #include <linux/shm.h>
@@ -37,6 +38,7 @@
 #include <linux/utsname.h>
 #include <linux/personality.h>
 #include <linux/random.h>
+#include <asm/processor.h>
 
 /* we construct an artificial offset for the mapping based on the physical
  * address of the kernel mapping variable */
@@ -391,3 +393,16 @@ long parisc_personality(unsigned long personality)
 
 	return err;
 }
+
+int arch_set_unalign_ctl(unsigned int val)
+{
+	current->thread.flags &= ~PARISC_UAC_MASK;
+	current->thread.flags |= (val << PARISC_UAC_SHIFT) & PARISC_UAC_MASK;
+
+	return 0;
+}
+
+int arch_get_unalign_ctl(void)
+{
+	return (current->thread.flags & PARISC_UAC_MASK) >> PARISC_UAC_SHIFT;
+}
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index b94323e..68c31fb 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -181,6 +181,7 @@ config PPC
 	select HAVE_ARCH_KGDB
 	select HAVE_ARCH_MMAP_RND_BITS
 	select HAVE_ARCH_MMAP_RND_COMPAT_BITS	if COMPAT
+	select HAVE_ARCH_PR_SET_GET_UNALIGN
 	select HAVE_ARCH_SECCOMP_FILTER
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_CBPF_JIT			if !PPC64
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index b8d9306..8bac2f6 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -413,12 +413,6 @@ extern int set_fpexc_mode(unsigned int val);
 extern int get_endian(unsigned long adr);
 extern int set_endian(unsigned int val);
 
-#define GET_UNALIGN_CTL(adr)	get_unalign_ctl((adr))
-#define SET_UNALIGN_CTL(val)	set_unalign_ctl((val))
-
-extern int get_unalign_ctl(unsigned long adr);
-extern int set_unalign_ctl(unsigned int val);
-
 extern void load_fp_state(struct thread_fp_state *fp);
 extern void store_fp_state(struct thread_fp_state *fp);
 extern void load_vr_state(struct thread_vr_state *vr);
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 17708b7..a623373 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -2020,15 +2020,15 @@ int get_endian(unsigned long adr)
 	return put_user(val, (unsigned int __user *)adr);
 }
 
-int set_unalign_ctl(unsigned int val)
+int arch_set_unalign_ctl(unsigned int val)
 {
 	current->thread.align_ctl = val;
 	return 0;
 }
 
-int get_unalign_ctl(unsigned long adr)
+int arch_get_unalign_ctl(void)
 {
-	return put_user(current->thread.align_ctl, (unsigned int __user *)adr);
+	return current->thread.align_ctl;
 }
 
 static inline int valid_irq_stack(unsigned long sp, struct task_struct *p,
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 97fe293..f9631bf 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -48,6 +48,7 @@ config SUPERH
 	select OLD_SIGSUSPEND
 	select OLD_SIGACTION
 	select HAVE_ARCH_AUDITSYSCALL
+	select HAVE_ARCH_PR_SET_GET_UNALIGN
 	select HAVE_FUTEX_CMPXCHG if FUTEX
 	select HAVE_NMI
 	help
diff --git a/arch/sh/include/asm/processor.h b/arch/sh/include/asm/processor.h
index ce3d9f6..ff4d332 100644
--- a/arch/sh/include/asm/processor.h
+++ b/arch/sh/include/asm/processor.h
@@ -116,13 +116,6 @@ extern unsigned int xstate_size;
 extern void free_thread_xstate(struct task_struct *);
 extern struct kmem_cache *task_xstate_cachep;
 
-/* arch/sh/mm/alignment.c */
-extern int get_unalign_ctl(unsigned long addr);
-extern int set_unalign_ctl(unsigned int val);
-
-#define GET_UNALIGN_CTL(addr)	get_unalign_ctl((addr))
-#define SET_UNALIGN_CTL(val)	set_unalign_ctl((val))
-
 /* arch/sh/mm/init.c */
 extern unsigned int mem_init_done;
 
diff --git a/arch/sh/mm/alignment.c b/arch/sh/mm/alignment.c
index bad2a31..63fc963 100644
--- a/arch/sh/mm/alignment.c
+++ b/arch/sh/mm/alignment.c
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/seq_file.h>
+#include <linux/prctl.h>
 #include <linux/proc_fs.h>
 #include <linux/uaccess.h>
 #include <linux/ratelimit.h>
@@ -80,13 +81,12 @@ unsigned int unaligned_user_action(void)
 	return action;
 }
 
-int get_unalign_ctl(unsigned long addr)
+int arch_get_unalign_ctl(void)
 {
-	return put_user(current->thread.flags & SH_THREAD_UAC_MASK,
-			(unsigned int __user *)addr);
+	return current->thread.flags & SH_THREAD_UAC_MASK;
 }
 
-int set_unalign_ctl(unsigned int val)
+int arch_set_unalign_ctl(unsigned int val)
 {
 	current->thread.flags = (current->thread.flags & ~SH_THREAD_UAC_MASK) |
 				(val & SH_THREAD_UAC_MASK);
diff --git a/include/linux/prctl.h b/include/linux/prctl.h
index 5ce3713..abc803e 100644
--- a/include/linux/prctl.h
+++ b/include/linux/prctl.h
@@ -16,4 +16,12 @@ static inline int prctl_arch(int option, unsigned long arg2,
 }
 #endif
 
+#ifdef CONFIG_HAVE_ARCH_PR_SET_GET_UNALIGN
+extern int arch_set_unalign_ctl(unsigned int val);
+extern int arch_get_unalign_ctl(void);
+#else
+static inline int arch_set_unalign_ctl(unsigned int val) { return -EINVAL; }
+static inline int arch_get_unalign_ctl(void) { return -EINVAL; }
+#endif
+
 #endif /* ! _LINUX_PRCTL_H */
diff --git a/kernel/sys.c b/kernel/sys.c
index 47cf999..562ffbe 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -71,13 +71,6 @@
 
 #include "uid16.h"
 
-#ifndef SET_UNALIGN_CTL
-# define SET_UNALIGN_CTL(a)	(-EINVAL)
-#endif
-#ifndef GET_UNALIGN_CTL
-# define GET_UNALIGN_CTL(a)	(-EINVAL)
-#endif
-
 /*
  * this is where the system-wide overflow UID and GID are defined, for
  * architectures that now have 32-bit UID/GID but didn't in the past
@@ -2235,10 +2228,17 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
 		break;
 
 	case PR_SET_UNALIGN:
-		error = SET_UNALIGN_CTL(arg2);
+		error = arch_set_unalign_ctl(arg2);
 		break;
-	case PR_GET_UNALIGN:
-		error = GET_UNALIGN_CTL(arg2);
+	case PR_GET_UNALIGN: {
+		int res;
+
+		res = arch_get_unalign_ctl();
+		if (res >= 0)
+			error = put_user(res, (int __user *)arg2);
+		else
+			error = res;
+		}
 		break;
 	case PR_GET_TIMING:
 		error = PR_TIMING_STATISTICAL;
-- 
2.1.4




[Index of Archives]     [Linux Kernel]     [Kernel Newbies]     [x86 Platform Driver]     [Netdev]     [Linux Wireless]     [Netfilter]     [Bugtraq]     [Linux Filesystems]     [Yosemite Discussion]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]

  Powered by Linux