From f80b0c904da93b9ad7db2fd9823dd701932df779 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Fri, 21 Dec 2012 12:25:44 +0530 Subject: [PATCH 1/8] Ensure that kernel_init_freeable() is not inlined into non __init code Commit d6b2123802d "make sure that we always have a return path from kernel_execve()" reshuffled kernel_init()/init_post() to ensure that kernel_execve() has a caller to return to. It removed __init annotation for kernel_init() and introduced/calls a new routine kernel_init_freeable(). Latter however is inlined by any reasonable compiler (ARC gcc 4.4 in this case), causing slight code bloat. This patch forces kernel_init_freeable() as noinline reducing the .text bloat-o-meter vmlinux vmlinux_new add/remove: 1/0 grow/shrink: 0/1 up/down: 374/-334 (40) function old new delta kernel_init_freeable - 374 +374 (.init.text) kernel_init 628 294 -334 (.text) Signed-off-by: Al Viro --- init/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/init/main.c b/init/main.c index 85d69dffe864..92d728a32d51 100644 --- a/init/main.c +++ b/init/main.c @@ -802,7 +802,7 @@ static int run_init_process(const char *init_filename) (const char __user *const __user *)envp_init); } -static void __init kernel_init_freeable(void); +static noinline void __init kernel_init_freeable(void); static int __ref kernel_init(void *unused) { @@ -845,7 +845,7 @@ static int __ref kernel_init(void *unused) "See Linux Documentation/init.txt for guidance."); } -static void __init kernel_init_freeable(void) +static noinline void __init kernel_init_freeable(void) { /* * Wait until kthreadd is all set-up. From f13a3664e4d1de8adc1fc82b981ba4699a731fa1 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Mon, 24 Dec 2012 10:51:36 +0530 Subject: [PATCH 2/8] CONFIG_GENERIC_SIGALTSTACK build breakage with asm-generic/syscalls.h Saner transition plan for GENERIC_SIGALTSTACK conversion - instead of adding #define sys_sigaltstack sys_sigaltstack in asm/syscalls.h of architecture if it's pulls asm-generic/syscalls.h, only to have those defines removed once all architectures are converted, make the declaration in said asm-generic/syscalls.h conditional on the lack of GENERIC_SIGALTSTACK. Less messy in intermediate stages that way... Signed-off-by: Vineet Gupta Acked-by: Al Viro Cc: james.hogan@imgtec.com Cc: arnd@arndb.de Cc: torvalds@linux-foundation.org Cc: linux-kernel@vger.kernel.org Cc: linux-arch@vger.kernel.org Signed-off-by: Al Viro --- include/asm-generic/syscalls.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/asm-generic/syscalls.h b/include/asm-generic/syscalls.h index 58f466ff00d3..1db51b8524e9 100644 --- a/include/asm-generic/syscalls.h +++ b/include/asm-generic/syscalls.h @@ -21,10 +21,12 @@ asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long fd, off_t pgoff); #endif +#ifndef CONFIG_GENERIC_SIGALTSTACK #ifndef sys_sigaltstack asmlinkage long sys_sigaltstack(const stack_t __user *, stack_t __user *, struct pt_regs *); #endif +#endif #ifndef sys_rt_sigreturn asmlinkage long sys_rt_sigreturn(struct pt_regs *regs); From 90228fc110303549aa1d4d86083bf585df8624c3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 23 Dec 2012 03:33:38 -0500 Subject: [PATCH 3/8] switch compat_sys_sigaltstack() to COMPAT_SYSCALL_DEFINE Makes sigaltstack conversion easier to split into per-architecture parts. Signed-off-by: Al Viro --- kernel/signal.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/signal.c b/kernel/signal.c index 7aaa51d8e5b8..00b4a6d4449d 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -3119,8 +3119,9 @@ int __save_altstack(stack_t __user *uss, unsigned long sp) #ifdef CONFIG_COMPAT #ifdef CONFIG_GENERIC_SIGALTSTACK -asmlinkage long compat_sys_sigaltstack(const compat_stack_t __user *uss_ptr, - compat_stack_t __user *uoss_ptr) +COMPAT_SYSCALL_DEFINE2(sigaltstack, + const compat_stack_t __user *, uss_ptr, + compat_stack_t __user *, uoss_ptr) { stack_t uss, uoss; int ret; From 8d9807b109497ca41d363dc7b6ff2bb6c0d52524 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 23 Dec 2012 14:56:40 -0500 Subject: [PATCH 4/8] switch compat_sys_wait4() and compat_sys_waitid() to COMPAT_SYSCALL_DEFINE Strictly speaking, ppc64 needs it for C ABI compliance. Realistically I would be very surprised if e.g. passing 0xffffffff as 'options' argument to waitid() from 32bit task would cause problems, but yes, it puts us into undefined behaviour territory. ppc64 expects int argument to be passed in 64bit register with bits 31..63 containing the same value. SYSCALL_DEFINE on ppc provides a wrapper that normalizes the value passed from userland; so does COMPAT_SYSCALL_DEFINE. Plain declaration of compat_sys_something() with an int argument obviously doesn't. Again, for wait4 and waitid I would be extremely surprised if gcc started to produce code depending on that value having been properly sign-extended - the argument(s) in question end up passed blindly to sys_wait4 and sys_waitid resp. and normalization for native syscalls takes care of their use there. Still, better to use COMPAT_SYSCALL_DEFINE here than worry about nasal daemons... Signed-off-by: Al Viro --- kernel/compat.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/kernel/compat.c b/kernel/compat.c index f6150e92dfc9..0770ac57c62b 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -535,9 +535,11 @@ asmlinkage long compat_sys_getrusage(int who, struct compat_rusage __user *ru) return 0; } -asmlinkage long -compat_sys_wait4(compat_pid_t pid, compat_uint_t __user *stat_addr, int options, - struct compat_rusage __user *ru) +COMPAT_SYSCALL_DEFINE4(wait4, + compat_pid_t, pid, + compat_uint_t __user *, stat_addr, + int, options, + struct compat_rusage __user *, ru) { if (!ru) { return sys_wait4(pid, stat_addr, options, NULL); @@ -564,9 +566,10 @@ compat_sys_wait4(compat_pid_t pid, compat_uint_t __user *stat_addr, int options, } } -asmlinkage long compat_sys_waitid(int which, compat_pid_t pid, - struct compat_siginfo __user *uinfo, int options, - struct compat_rusage __user *uru) +COMPAT_SYSCALL_DEFINE5(waitid, + int, which, compat_pid_t, pid, + struct compat_siginfo __user *, uinfo, int, options, + struct compat_rusage __user *, uru) { siginfo_t info; struct rusage ru; From a566c288826ad4502e43b59570214f18173d7744 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 23 Dec 2012 23:14:49 -0500 Subject: [PATCH 5/8] x32: fix waitid() It needs 64bit rusage and 32bit siginfo. glibc never calls it with non-NULL rusage pointer, or we would've seen breakage already... Signed-off-by: Al Viro --- kernel/compat.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel/compat.c b/kernel/compat.c index 0770ac57c62b..e5cc33c7122c 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -587,7 +587,11 @@ COMPAT_SYSCALL_DEFINE5(waitid, return ret; if (uru) { - ret = put_compat_rusage(&ru, uru); + /* sys_waitid() overwrites everything in ru */ + if (COMPAT_USE_64BIT_TIME) + ret = copy_to_user(uru, &ru, sizeof(ru)); + else + ret = put_compat_rusage(&ru, uru); if (ret) return ret; } From b2ddedcd21f44a5873ee3d6ff6118a2318e01e18 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 24 Dec 2012 12:31:00 -0500 Subject: [PATCH 6/8] x32: fix sigtimedwait It needs 64bit timespec. As it is, we end up truncating the timeout to whole seconds; usually it doesn't matter, but for having all sub-second timeouts truncated to one jiffy is visibly wrong. Signed-off-by: Al Viro --- kernel/compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/compat.c b/kernel/compat.c index e5cc33c7122c..36700e9e2be9 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -1001,7 +1001,7 @@ compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese, sigset_from_compat(&s, &s32); if (uts) { - if (get_compat_timespec(&t, uts)) + if (compat_get_timespec(&t, uts)) return -EFAULT; } From 43b16820249396aea7eb57c747106e211e54bed5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 19 Jan 2013 13:29:54 -0500 Subject: [PATCH 7/8] make sure that /linuxrc has std{in,out,err} Signed-off-by: Al Viro --- init/do_mounts_initrd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c index 5e4ded51788e..f9acf71b9810 100644 --- a/init/do_mounts_initrd.c +++ b/init/do_mounts_initrd.c @@ -36,6 +36,10 @@ __setup("noinitrd", no_initrd); static int init_linuxrc(struct subprocess_info *info, struct cred *new) { sys_unshare(CLONE_FS | CLONE_FILES); + /* stdin/stdout/stderr for /linuxrc */ + sys_open("/dev/console", O_RDWR, 0); + sys_dup(0); + sys_dup(0); /* move initrd over / and chdir/chroot in initrd root */ sys_chdir("/root"); sys_mount(".", "/", NULL, MS_MOVE, NULL); From b1e0318b8cd4bdbb0fbc48967b0350483ad9bd69 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 19 Jan 2013 22:13:34 -0500 Subject: [PATCH 8/8] sys_clone() needs asmlinkage_protect Cc: stable@vger.kernel.org Signed-off-by: Al Viro --- kernel/fork.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/fork.c b/kernel/fork.c index a31b823b3c2d..e05cff2429b5 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1660,8 +1660,10 @@ SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp, int, tls_val) #endif { - return do_fork(clone_flags, newsp, 0, - parent_tidptr, child_tidptr); + long ret = do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr); + asmlinkage_protect(5, ret, clone_flags, newsp, + parent_tidptr, child_tidptr, tls_val); + return ret; } #endif