summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2016-11-07 16:26:37 -0500
committerSteven Rostedt (VMware) <rostedt@goodmis.org>2019-04-05 09:26:43 -0400
commitb35f549df1d7520d37ba1e6d4a8d4df6bd52d136 (patch)
treeb7e544da953806a2f4d9b2d0aeb167d0baad3955
parented3bb007021b9bddb90afae28a19f08ed8890add (diff)
syscalls: Remove start and number from syscall_get_arguments() args
At Linux Plumbers, Andy Lutomirski approached me and pointed out that the function call syscall_get_arguments() implemented in x86 was horribly written and not optimized for the standard case of passing in 0 and 6 for the starting index and the number of system calls to get. When looking at all the users of this function, I discovered that all instances pass in only 0 and 6 for these arguments. Instead of having this function handle different cases that are never used, simply rewrite it to return the first 6 arguments of a system call. This should help out the performance of tracing system calls by ptrace, ftrace and perf. Link: http://lkml.kernel.org/r/20161107213233.754809394@goodmis.org Cc: Oleg Nesterov <oleg@redhat.com> Cc: Kees Cook <keescook@chromium.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Dominik Brodowski <linux@dominikbrodowski.net> Cc: Dave Martin <dave.martin@arm.com> Cc: "Dmitry V. Levin" <ldv@altlinux.org> Cc: x86@kernel.org Cc: linux-snps-arc@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-c6x-dev@linux-c6x.org Cc: uclinux-h8-devel@lists.sourceforge.jp Cc: linux-hexagon@vger.kernel.org Cc: linux-ia64@vger.kernel.org Cc: linux-mips@vger.kernel.org Cc: nios2-dev@lists.rocketboards.org Cc: openrisc@lists.librecores.org Cc: linux-parisc@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-riscv@lists.infradead.org Cc: linux-s390@vger.kernel.org Cc: linux-sh@vger.kernel.org Cc: sparclinux@vger.kernel.org Cc: linux-um@lists.infradead.org Cc: linux-xtensa@linux-xtensa.org Cc: linux-arch@vger.kernel.org Acked-by: Paul Burton <paul.burton@mips.com> # MIPS parts Acked-by: Max Filippov <jcmvbkbc@gmail.com> # For xtensa changes Acked-by: Will Deacon <will.deacon@arm.com> # For the arm64 bits Reviewed-by: Thomas Gleixner <tglx@linutronix.de> # for x86 Reviewed-by: Dmitry V. Levin <ldv@altlinux.org> Reported-by: Andy Lutomirski <luto@amacapital.net> Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
-rw-r--r--arch/arc/include/asm/syscall.h7
-rw-r--r--arch/arm/include/asm/syscall.h23
-rw-r--r--arch/arm64/include/asm/syscall.h22
-rw-r--r--arch/c6x/include/asm/syscall.h41
-rw-r--r--arch/csky/include/asm/syscall.h14
-rw-r--r--arch/h8300/include/asm/syscall.h34
-rw-r--r--arch/hexagon/include/asm/syscall.h4
-rw-r--r--arch/ia64/include/asm/syscall.h5
-rw-r--r--arch/microblaze/include/asm/syscall.h4
-rw-r--r--arch/mips/include/asm/syscall.h3
-rw-r--r--arch/mips/kernel/ptrace.c2
-rw-r--r--arch/nds32/include/asm/syscall.h33
-rw-r--r--arch/nios2/include/asm/syscall.h42
-rw-r--r--arch/openrisc/include/asm/syscall.h6
-rw-r--r--arch/parisc/include/asm/syscall.h30
-rw-r--r--arch/powerpc/include/asm/syscall.h8
-rw-r--r--arch/riscv/include/asm/syscall.h13
-rw-r--r--arch/s390/include/asm/syscall.h17
-rw-r--r--arch/sh/include/asm/syscall_32.h26
-rw-r--r--arch/sh/include/asm/syscall_64.h4
-rw-r--r--arch/sparc/include/asm/syscall.h4
-rw-r--r--arch/um/include/asm/syscall-generic.h39
-rw-r--r--arch/x86/include/asm/syscall.h73
-rw-r--r--arch/xtensa/include/asm/syscall.h16
-rw-r--r--include/asm-generic/syscall.h11
-rw-r--r--include/trace/events/syscalls.h2
-rw-r--r--kernel/seccomp.c2
-rw-r--r--kernel/trace/trace_syscalls.c4
-rw-r--r--lib/syscall.c2
29 files changed, 113 insertions, 378 deletions
diff --git a/arch/arc/include/asm/syscall.h b/arch/arc/include/asm/syscall.h
index 29de09804306..c7a4201ed62b 100644
--- a/arch/arc/include/asm/syscall.h
+++ b/arch/arc/include/asm/syscall.h
@@ -55,12 +55,11 @@ syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
55 */ 55 */
56static inline void 56static inline void
57syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, 57syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
58 unsigned int i, unsigned int n, unsigned long *args) 58 unsigned long *args)
59{ 59{
60 unsigned long *inside_ptregs = &(regs->r0); 60 unsigned long *inside_ptregs = &(regs->r0);
61 inside_ptregs -= i; 61 unsigned int n = 6;
62 62 unsigned int i = 0;
63 BUG_ON((i + n) > 6);
64 63
65 while (n--) { 64 while (n--) {
66 args[i++] = (*inside_ptregs); 65 args[i++] = (*inside_ptregs);
diff --git a/arch/arm/include/asm/syscall.h b/arch/arm/include/asm/syscall.h
index 06dea6bce293..db969a2972ae 100644
--- a/arch/arm/include/asm/syscall.h
+++ b/arch/arm/include/asm/syscall.h
@@ -55,29 +55,12 @@ static inline void syscall_set_return_value(struct task_struct *task,
55 55
56static inline void syscall_get_arguments(struct task_struct *task, 56static inline void syscall_get_arguments(struct task_struct *task,
57 struct pt_regs *regs, 57 struct pt_regs *regs,
58 unsigned int i, unsigned int n,
59 unsigned long *args) 58 unsigned long *args)
60{ 59{
61 if (n == 0) 60 args[0] = regs->ARM_ORIG_r0;
62 return; 61 args++;
63
64 if (i + n > SYSCALL_MAX_ARGS) {
65 unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i;
66 unsigned int n_bad = n + i - SYSCALL_MAX_ARGS;
67 pr_warn("%s called with max args %d, handling only %d\n",
68 __func__, i + n, SYSCALL_MAX_ARGS);
69 memset(args_bad, 0, n_bad * sizeof(args[0]));
70 n = SYSCALL_MAX_ARGS - i;
71 }
72
73 if (i == 0) {
74 args[0] = regs->ARM_ORIG_r0;
75 args++;
76 i++;
77 n--;
78 }
79 62
80 memcpy(args, &regs->ARM_r0 + i, n * sizeof(args[0])); 63 memcpy(args, &regs->ARM_r0 + 1, 5 * sizeof(args[0]));
81} 64}
82 65
83static inline void syscall_set_arguments(struct task_struct *task, 66static inline void syscall_set_arguments(struct task_struct *task,
diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index ad8be16a39c9..55b2dab21023 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -65,28 +65,12 @@ static inline void syscall_set_return_value(struct task_struct *task,
65 65
66static inline void syscall_get_arguments(struct task_struct *task, 66static inline void syscall_get_arguments(struct task_struct *task,
67 struct pt_regs *regs, 67 struct pt_regs *regs,
68 unsigned int i, unsigned int n,
69 unsigned long *args) 68 unsigned long *args)
70{ 69{
71 if (n == 0) 70 args[0] = regs->orig_x0;
72 return; 71 args++;
73
74 if (i + n > SYSCALL_MAX_ARGS) {
75 unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i;
76 unsigned int n_bad = n + i - SYSCALL_MAX_ARGS;
77 pr_warning("%s called with max args %d, handling only %d\n",
78 __func__, i + n, SYSCALL_MAX_ARGS);
79 memset(args_bad, 0, n_bad * sizeof(args[0]));
80 }
81
82 if (i == 0) {
83 args[0] = regs->orig_x0;
84 args++;
85 i++;
86 n--;
87 }
88 72
89 memcpy(args, &regs->regs[i], n * sizeof(args[0])); 73 memcpy(args, &regs->regs[1], 5 * sizeof(args[0]));
90} 74}
91 75
92static inline void syscall_set_arguments(struct task_struct *task, 76static inline void syscall_set_arguments(struct task_struct *task,
diff --git a/arch/c6x/include/asm/syscall.h b/arch/c6x/include/asm/syscall.h
index ae2be315ee9c..06db3251926b 100644
--- a/arch/c6x/include/asm/syscall.h
+++ b/arch/c6x/include/asm/syscall.h
@@ -46,40 +46,15 @@ static inline void syscall_set_return_value(struct task_struct *task,
46} 46}
47 47
48static inline void syscall_get_arguments(struct task_struct *task, 48static inline void syscall_get_arguments(struct task_struct *task,
49 struct pt_regs *regs, unsigned int i, 49 struct pt_regs *regs,
50 unsigned int n, unsigned long *args) 50 unsigned long *args)
51{ 51{
52 switch (i) { 52 *args++ = regs->a4;
53 case 0: 53 *args++ = regs->b4;
54 if (!n--) 54 *args++ = regs->a6;
55 break; 55 *args++ = regs->b6;
56 *args++ = regs->a4; 56 *args++ = regs->a8;
57 case 1: 57 *args = regs->b8;
58 if (!n--)
59 break;
60 *args++ = regs->b4;
61 case 2:
62 if (!n--)
63 break;
64 *args++ = regs->a6;
65 case 3:
66 if (!n--)
67 break;
68 *args++ = regs->b6;
69 case 4:
70 if (!n--)
71 break;
72 *args++ = regs->a8;
73 case 5:
74 if (!n--)
75 break;
76 *args++ = regs->b8;
77 case 6:
78 if (!n--)
79 break;
80 default:
81 BUG();
82 }
83} 58}
84 59
85static inline void syscall_set_arguments(struct task_struct *task, 60static inline void syscall_set_arguments(struct task_struct *task,
diff --git a/arch/csky/include/asm/syscall.h b/arch/csky/include/asm/syscall.h
index 9a9cd81e66c1..c691fe92edc6 100644
--- a/arch/csky/include/asm/syscall.h
+++ b/arch/csky/include/asm/syscall.h
@@ -43,17 +43,11 @@ syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
43 43
44static inline void 44static inline void
45syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, 45syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
46 unsigned int i, unsigned int n, unsigned long *args) 46 unsigned long *args)
47{ 47{
48 BUG_ON(i + n > 6); 48 args[0] = regs->orig_a0;
49 if (i == 0) { 49 args++;
50 args[0] = regs->orig_a0; 50 memcpy(args, &regs->a1, 5 * sizeof(args[0]));
51 args++;
52 n--;
53 } else {
54 i--;
55 }
56 memcpy(args, &regs->a1 + i, n * sizeof(args[0]));
57} 51}
58 52
59static inline void 53static inline void
diff --git a/arch/h8300/include/asm/syscall.h b/arch/h8300/include/asm/syscall.h
index 924990401237..ddd483c6ca95 100644
--- a/arch/h8300/include/asm/syscall.h
+++ b/arch/h8300/include/asm/syscall.h
@@ -17,34 +17,14 @@ syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
17 17
18static inline void 18static inline void
19syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, 19syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
20 unsigned int i, unsigned int n, unsigned long *args) 20 unsigned long *args)
21{ 21{
22 BUG_ON(i + n > 6); 22 *args++ = regs->er1;
23 23 *args++ = regs->er2;
24 while (n > 0) { 24 *args++ = regs->er3;
25 switch (i) { 25 *args++ = regs->er4;
26 case 0: 26 *args++ = regs->er5;
27 *args++ = regs->er1; 27 *args = regs->er6;
28 break;
29 case 1:
30 *args++ = regs->er2;
31 break;
32 case 2:
33 *args++ = regs->er3;
34 break;
35 case 3:
36 *args++ = regs->er4;
37 break;
38 case 4:
39 *args++ = regs->er5;
40 break;
41 case 5:
42 *args++ = regs->er6;
43 break;
44 }
45 i++;
46 n--;
47 }
48} 28}
49 29
50 30
diff --git a/arch/hexagon/include/asm/syscall.h b/arch/hexagon/include/asm/syscall.h
index 4af9c7b6f13a..ae3a1e24fabd 100644
--- a/arch/hexagon/include/asm/syscall.h
+++ b/arch/hexagon/include/asm/syscall.h
@@ -37,10 +37,8 @@ static inline long syscall_get_nr(struct task_struct *task,
37 37
38static inline void syscall_get_arguments(struct task_struct *task, 38static inline void syscall_get_arguments(struct task_struct *task,
39 struct pt_regs *regs, 39 struct pt_regs *regs,
40 unsigned int i, unsigned int n,
41 unsigned long *args) 40 unsigned long *args)
42{ 41{
43 BUG_ON(i + n > 6); 42 memcpy(args, &(&regs->r00)[0], 6 * sizeof(args[0]));
44 memcpy(args, &(&regs->r00)[i], n * sizeof(args[0]));
45} 43}
46#endif 44#endif
diff --git a/arch/ia64/include/asm/syscall.h b/arch/ia64/include/asm/syscall.h
index 1d0b875fec44..8204c1ff70ce 100644
--- a/arch/ia64/include/asm/syscall.h
+++ b/arch/ia64/include/asm/syscall.h
@@ -63,12 +63,9 @@ extern void ia64_syscall_get_set_arguments(struct task_struct *task,
63 unsigned long *args, int rw); 63 unsigned long *args, int rw);
64static inline void syscall_get_arguments(struct task_struct *task, 64static inline void syscall_get_arguments(struct task_struct *task,
65 struct pt_regs *regs, 65 struct pt_regs *regs,
66 unsigned int i, unsigned int n,
67 unsigned long *args) 66 unsigned long *args)
68{ 67{
69 BUG_ON(i + n > 6); 68 ia64_syscall_get_set_arguments(task, regs, 0, 6, args, 0);
70
71 ia64_syscall_get_set_arguments(task, regs, i, n, args, 0);
72} 69}
73 70
74static inline void syscall_set_arguments(struct task_struct *task, 71static inline void syscall_set_arguments(struct task_struct *task,
diff --git a/arch/microblaze/include/asm/syscall.h b/arch/microblaze/include/asm/syscall.h
index 220decd605a4..4b23e44e5c3c 100644
--- a/arch/microblaze/include/asm/syscall.h
+++ b/arch/microblaze/include/asm/syscall.h
@@ -82,9 +82,11 @@ static inline void microblaze_set_syscall_arg(struct pt_regs *regs,
82 82
83static inline void syscall_get_arguments(struct task_struct *task, 83static inline void syscall_get_arguments(struct task_struct *task,
84 struct pt_regs *regs, 84 struct pt_regs *regs,
85 unsigned int i, unsigned int n,
86 unsigned long *args) 85 unsigned long *args)
87{ 86{
87 unsigned int i = 0;
88 unsigned int n = 6;
89
88 while (n--) 90 while (n--)
89 *args++ = microblaze_get_syscall_arg(regs, i++); 91 *args++ = microblaze_get_syscall_arg(regs, i++);
90} 92}
diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h
index 6cf8ffb5367e..a2b4748655df 100644
--- a/arch/mips/include/asm/syscall.h
+++ b/arch/mips/include/asm/syscall.h
@@ -116,9 +116,10 @@ static inline void syscall_set_return_value(struct task_struct *task,
116 116
117static inline void syscall_get_arguments(struct task_struct *task, 117static inline void syscall_get_arguments(struct task_struct *task,
118 struct pt_regs *regs, 118 struct pt_regs *regs,
119 unsigned int i, unsigned int n,
120 unsigned long *args) 119 unsigned long *args)
121{ 120{
121 unsigned int i = 0;
122 unsigned int n = 6;
122 int ret; 123 int ret;
123 124
124 /* O32 ABI syscall() */ 125 /* O32 ABI syscall() */
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 0057c910bc2f..3a62f80958e1 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -1419,7 +1419,7 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall)
1419 1419
1420 sd.nr = syscall; 1420 sd.nr = syscall;
1421 sd.arch = syscall_get_arch(); 1421 sd.arch = syscall_get_arch();
1422 syscall_get_arguments(current, regs, 0, 6, args); 1422 syscall_get_arguments(current, regs, args);
1423 for (i = 0; i < 6; i++) 1423 for (i = 0; i < 6; i++)
1424 sd.args[i] = args[i]; 1424 sd.args[i] = args[i];
1425 sd.instruction_pointer = KSTK_EIP(current); 1425 sd.instruction_pointer = KSTK_EIP(current);
diff --git a/arch/nds32/include/asm/syscall.h b/arch/nds32/include/asm/syscall.h
index f7e5e86765fe..89a6ec8731d8 100644
--- a/arch/nds32/include/asm/syscall.h
+++ b/arch/nds32/include/asm/syscall.h
@@ -108,42 +108,21 @@ void syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
108 * syscall_get_arguments - extract system call parameter values 108 * syscall_get_arguments - extract system call parameter values
109 * @task: task of interest, must be blocked 109 * @task: task of interest, must be blocked
110 * @regs: task_pt_regs() of @task 110 * @regs: task_pt_regs() of @task
111 * @i: argument index [0,5]
112 * @n: number of arguments; n+i must be [1,6].
113 * @args: array filled with argument values 111 * @args: array filled with argument values
114 * 112 *
115 * Fetches @n arguments to the system call starting with the @i'th argument 113 * Fetches 6 arguments to the system call (from 0 through 5). The first
116 * (from 0 through 5). Argument @i is stored in @args[0], and so on. 114 * argument is stored in @args[0], and so on.
117 * An arch inline version is probably optimal when @i and @n are constants.
118 * 115 *
119 * It's only valid to call this when @task is stopped for tracing on 116 * It's only valid to call this when @task is stopped for tracing on
120 * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT. 117 * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
121 * It's invalid to call this with @i + @n > 6; we only support system calls
122 * taking up to 6 arguments.
123 */ 118 */
124#define SYSCALL_MAX_ARGS 6 119#define SYSCALL_MAX_ARGS 6
125void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, 120void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
126 unsigned int i, unsigned int n, unsigned long *args) 121 unsigned long *args)
127{ 122{
128 if (n == 0) 123 args[0] = regs->orig_r0;
129 return; 124 args++;
130 if (i + n > SYSCALL_MAX_ARGS) { 125 memcpy(args, &regs->uregs[0] + 1, 5 * sizeof(args[0]));
131 unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i;
132 unsigned int n_bad = n + i - SYSCALL_MAX_ARGS;
133 pr_warning("%s called with max args %d, handling only %d\n",
134 __func__, i + n, SYSCALL_MAX_ARGS);
135 memset(args_bad, 0, n_bad * sizeof(args[0]));
136 memset(args_bad, 0, n_bad * sizeof(args[0]));
137 }
138
139 if (i == 0) {
140 args[0] = regs->orig_r0;
141 args++;
142 i++;
143 n--;
144 }
145
146 memcpy(args, &regs->uregs[0] + i, n * sizeof(args[0]));
147} 126}
148 127
149/** 128/**
diff --git a/arch/nios2/include/asm/syscall.h b/arch/nios2/include/asm/syscall.h
index 9de220854c4a..792bd449d839 100644
--- a/arch/nios2/include/asm/syscall.h
+++ b/arch/nios2/include/asm/syscall.h
@@ -58,42 +58,14 @@ static inline void syscall_set_return_value(struct task_struct *task,
58} 58}
59 59
60static inline void syscall_get_arguments(struct task_struct *task, 60static inline void syscall_get_arguments(struct task_struct *task,
61 struct pt_regs *regs, unsigned int i, unsigned int n, 61 struct pt_regs *regs, unsigned long *args)
62 unsigned long *args)
63{ 62{
64 BUG_ON(i + n > 6); 63 *args++ = regs->r4;
65 64 *args++ = regs->r5;
66 switch (i) { 65 *args++ = regs->r6;
67 case 0: 66 *args++ = regs->r7;
68 if (!n--) 67 *args++ = regs->r8;
69 break; 68 *args = regs->r9;
70 *args++ = regs->r4;
71 case 1:
72 if (!n--)
73 break;
74 *args++ = regs->r5;
75 case 2:
76 if (!n--)
77 break;
78 *args++ = regs->r6;
79 case 3:
80 if (!n--)
81 break;
82 *args++ = regs->r7;
83 case 4:
84 if (!n--)
85 break;
86 *args++ = regs->r8;
87 case 5:
88 if (!n--)
89 break;
90 *args++ = regs->r9;
91 case 6:
92 if (!n--)
93 break;
94 default:
95 BUG();
96 }
97} 69}
98 70
99static inline void syscall_set_arguments(struct task_struct *task, 71static inline void syscall_set_arguments(struct task_struct *task,
diff --git a/arch/openrisc/include/asm/syscall.h b/arch/openrisc/include/asm/syscall.h
index 2db9f1cf0694..72607860cd55 100644
--- a/arch/openrisc/include/asm/syscall.h
+++ b/arch/openrisc/include/asm/syscall.h
@@ -56,11 +56,9 @@ syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
56 56
57static inline void 57static inline void
58syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, 58syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
59 unsigned int i, unsigned int n, unsigned long *args) 59 unsigned long *args)
60{ 60{
61 BUG_ON(i + n > 6); 61 memcpy(args, &regs->gpr[3], 6 * sizeof(args[0]));
62
63 memcpy(args, &regs->gpr[3 + i], n * sizeof(args[0]));
64} 62}
65 63
66static inline void 64static inline void
diff --git a/arch/parisc/include/asm/syscall.h b/arch/parisc/include/asm/syscall.h
index 8bff1a58c97f..62a6d477fae0 100644
--- a/arch/parisc/include/asm/syscall.h
+++ b/arch/parisc/include/asm/syscall.h
@@ -18,29 +18,15 @@ static inline long syscall_get_nr(struct task_struct *tsk,
18} 18}
19 19
20static inline void syscall_get_arguments(struct task_struct *tsk, 20static inline void syscall_get_arguments(struct task_struct *tsk,
21 struct pt_regs *regs, unsigned int i, 21 struct pt_regs *regs,
22 unsigned int n, unsigned long *args) 22 unsigned long *args)
23{ 23{
24 BUG_ON(i); 24 args[5] = regs->gr[21];
25 25 args[4] = regs->gr[22];
26 switch (n) { 26 args[3] = regs->gr[23];
27 case 6: 27 args[2] = regs->gr[24];
28 args[5] = regs->gr[21]; 28 args[1] = regs->gr[25];
29 case 5: 29 args[0] = regs->gr[26];
30 args[4] = regs->gr[22];
31 case 4:
32 args[3] = regs->gr[23];
33 case 3:
34 args[2] = regs->gr[24];
35 case 2:
36 args[1] = regs->gr[25];
37 case 1:
38 args[0] = regs->gr[26];
39 case 0:
40 break;
41 default:
42 BUG();
43 }
44} 30}
45 31
46static inline long syscall_get_return_value(struct task_struct *task, 32static inline long syscall_get_return_value(struct task_struct *task,
diff --git a/arch/powerpc/include/asm/syscall.h b/arch/powerpc/include/asm/syscall.h
index 1a0e7a8b1c81..5c9b9dc82b7e 100644
--- a/arch/powerpc/include/asm/syscall.h
+++ b/arch/powerpc/include/asm/syscall.h
@@ -65,22 +65,20 @@ static inline void syscall_set_return_value(struct task_struct *task,
65 65
66static inline void syscall_get_arguments(struct task_struct *task, 66static inline void syscall_get_arguments(struct task_struct *task,
67 struct pt_regs *regs, 67 struct pt_regs *regs,
68 unsigned int i, unsigned int n,
69 unsigned long *args) 68 unsigned long *args)
70{ 69{
71 unsigned long val, mask = -1UL; 70 unsigned long val, mask = -1UL;
72 71 unsigned int n = 6;
73 BUG_ON(i + n > 6);
74 72
75#ifdef CONFIG_COMPAT 73#ifdef CONFIG_COMPAT
76 if (test_tsk_thread_flag(task, TIF_32BIT)) 74 if (test_tsk_thread_flag(task, TIF_32BIT))
77 mask = 0xffffffff; 75 mask = 0xffffffff;
78#endif 76#endif
79 while (n--) { 77 while (n--) {
80 if (n == 0 && i == 0) 78 if (n == 0)
81 val = regs->orig_gpr3; 79 val = regs->orig_gpr3;
82 else 80 else
83 val = regs->gpr[3 + i + n]; 81 val = regs->gpr[3 + n];
84 82
85 args[n] = val & mask; 83 args[n] = val & mask;
86 } 84 }
diff --git a/arch/riscv/include/asm/syscall.h b/arch/riscv/include/asm/syscall.h
index 6ea9e1804233..6adca1804be1 100644
--- a/arch/riscv/include/asm/syscall.h
+++ b/arch/riscv/include/asm/syscall.h
@@ -72,18 +72,11 @@ static inline void syscall_set_return_value(struct task_struct *task,
72 72
73static inline void syscall_get_arguments(struct task_struct *task, 73static inline void syscall_get_arguments(struct task_struct *task,
74 struct pt_regs *regs, 74 struct pt_regs *regs,
75 unsigned int i, unsigned int n,
76 unsigned long *args) 75 unsigned long *args)
77{ 76{
78 BUG_ON(i + n > 6); 77 args[0] = regs->orig_a0;
79 if (i == 0) { 78 args++;
80 args[0] = regs->orig_a0; 79 memcpy(args, &regs->a1, 5 * sizeof(args[0]));
81 args++;
82 n--;
83 } else {
84 i--;
85 }
86 memcpy(args, &regs->a1 + i, n * sizeof(args[0]));
87} 80}
88 81
89static inline void syscall_set_arguments(struct task_struct *task, 82static inline void syscall_set_arguments(struct task_struct *task,
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h
index 96f9a9151fde..ee0b1f6aa36d 100644
--- a/arch/s390/include/asm/syscall.h
+++ b/arch/s390/include/asm/syscall.h
@@ -56,27 +56,20 @@ static inline void syscall_set_return_value(struct task_struct *task,
56 56
57static inline void syscall_get_arguments(struct task_struct *task, 57static inline void syscall_get_arguments(struct task_struct *task,
58 struct pt_regs *regs, 58 struct pt_regs *regs,
59 unsigned int i, unsigned int n,
60 unsigned long *args) 59 unsigned long *args)
61{ 60{
62 unsigned long mask = -1UL; 61 unsigned long mask = -1UL;
62 unsigned int n = 6;
63 63
64 /*
65 * No arguments for this syscall, there's nothing to do.
66 */
67 if (!n)
68 return;
69
70 BUG_ON(i + n > 6);
71#ifdef CONFIG_COMPAT 64#ifdef CONFIG_COMPAT
72 if (test_tsk_thread_flag(task, TIF_31BIT)) 65 if (test_tsk_thread_flag(task, TIF_31BIT))
73 mask = 0xffffffff; 66 mask = 0xffffffff;
74#endif 67#endif
75 while (n-- > 0) 68 while (n-- > 0)
76 if (i + n > 0) 69 if (n > 0)
77 args[n] = regs->gprs[2 + i + n] & mask; 70 args[n] = regs->gprs[2 + n] & mask;
78 if (i == 0) 71
79 args[0] = regs->orig_gpr2 & mask; 72 args[0] = regs->orig_gpr2 & mask;
80} 73}
81 74
82static inline void syscall_set_arguments(struct task_struct *task, 75static inline void syscall_set_arguments(struct task_struct *task,
diff --git a/arch/sh/include/asm/syscall_32.h b/arch/sh/include/asm/syscall_32.h
index 6e118799831c..2bf1199a0595 100644
--- a/arch/sh/include/asm/syscall_32.h
+++ b/arch/sh/include/asm/syscall_32.h
@@ -48,30 +48,16 @@ static inline void syscall_set_return_value(struct task_struct *task,
48 48
49static inline void syscall_get_arguments(struct task_struct *task, 49static inline void syscall_get_arguments(struct task_struct *task,
50 struct pt_regs *regs, 50 struct pt_regs *regs,
51 unsigned int i, unsigned int n,
52 unsigned long *args) 51 unsigned long *args)
53{ 52{
54 /*
55 * Do this simply for now. If we need to start supporting
56 * fetching arguments from arbitrary indices, this will need some
57 * extra logic. Presently there are no in-tree users that depend
58 * on this behaviour.
59 */
60 BUG_ON(i);
61 53
62 /* Argument pattern is: R4, R5, R6, R7, R0, R1 */ 54 /* Argument pattern is: R4, R5, R6, R7, R0, R1 */
63 switch (n) { 55 args[5] = regs->regs[1];
64 case 6: args[5] = regs->regs[1]; 56 args[4] = regs->regs[0];
65 case 5: args[4] = regs->regs[0]; 57 args[3] = regs->regs[7];
66 case 4: args[3] = regs->regs[7]; 58 args[2] = regs->regs[6];
67 case 3: args[2] = regs->regs[6]; 59 args[1] = regs->regs[5];
68 case 2: args[1] = regs->regs[5]; 60 args[0] = regs->regs[4];
69 case 1: args[0] = regs->regs[4];
70 case 0:
71 break;
72 default:
73 BUG();
74 }
75} 61}
76 62
77static inline void syscall_set_arguments(struct task_struct *task, 63static inline void syscall_set_arguments(struct task_struct *task,
diff --git a/arch/sh/include/asm/syscall_64.h b/arch/sh/include/asm/syscall_64.h
index 43882580c7f9..4e8f6460c703 100644
--- a/arch/sh/include/asm/syscall_64.h
+++ b/arch/sh/include/asm/syscall_64.h
@@ -47,11 +47,9 @@ static inline void syscall_set_return_value(struct task_struct *task,
47 47
48static inline void syscall_get_arguments(struct task_struct *task, 48static inline void syscall_get_arguments(struct task_struct *task,
49 struct pt_regs *regs, 49 struct pt_regs *regs,
50 unsigned int i, unsigned int n,
51 unsigned long *args) 50 unsigned long *args)
52{ 51{
53 BUG_ON(i + n > 6); 52 memcpy(args, &regs->regs[2], 6 * sizeof(args[0]));
54 memcpy(args, &regs->regs[2 + i], n * sizeof(args[0]));
55} 53}
56 54
57static inline void syscall_set_arguments(struct task_struct *task, 55static inline void syscall_set_arguments(struct task_struct *task,
diff --git a/arch/sparc/include/asm/syscall.h b/arch/sparc/include/asm/syscall.h
index 053989e3f6a6..872dfee852d6 100644
--- a/arch/sparc/include/asm/syscall.h
+++ b/arch/sparc/include/asm/syscall.h
@@ -96,11 +96,11 @@ static inline void syscall_set_return_value(struct task_struct *task,
96 96
97static inline void syscall_get_arguments(struct task_struct *task, 97static inline void syscall_get_arguments(struct task_struct *task,
98 struct pt_regs *regs, 98 struct pt_regs *regs,
99 unsigned int i, unsigned int n,
100 unsigned long *args) 99 unsigned long *args)
101{ 100{
102 int zero_extend = 0; 101 int zero_extend = 0;
103 unsigned int j; 102 unsigned int j;
103 unsigned int n = 6;
104 104
105#ifdef CONFIG_SPARC64 105#ifdef CONFIG_SPARC64
106 if (test_tsk_thread_flag(task, TIF_32BIT)) 106 if (test_tsk_thread_flag(task, TIF_32BIT))
@@ -108,7 +108,7 @@ static inline void syscall_get_arguments(struct task_struct *task,
108#endif 108#endif
109 109
110 for (j = 0; j < n; j++) { 110 for (j = 0; j < n; j++) {
111 unsigned long val = regs->u_regs[UREG_I0 + i + j]; 111 unsigned long val = regs->u_regs[UREG_I0 + j];
112 112
113 if (zero_extend) 113 if (zero_extend)
114 args[j] = (u32) val; 114 args[j] = (u32) val;
diff --git a/arch/um/include/asm/syscall-generic.h b/arch/um/include/asm/syscall-generic.h
index 9fb9cf8cd39a..25d00acd1322 100644
--- a/arch/um/include/asm/syscall-generic.h
+++ b/arch/um/include/asm/syscall-generic.h
@@ -53,43 +53,16 @@ static inline void syscall_set_return_value(struct task_struct *task,
53 53
54static inline void syscall_get_arguments(struct task_struct *task, 54static inline void syscall_get_arguments(struct task_struct *task,
55 struct pt_regs *regs, 55 struct pt_regs *regs,
56 unsigned int i, unsigned int n,
57 unsigned long *args) 56 unsigned long *args)
58{ 57{
59 const struct uml_pt_regs *r = &regs->regs; 58 const struct uml_pt_regs *r = &regs->regs;
60 59
61 switch (i) { 60 *args++ = UPT_SYSCALL_ARG1(r);
62 case 0: 61 *args++ = UPT_SYSCALL_ARG2(r);
63 if (!n--) 62 *args++ = UPT_SYSCALL_ARG3(r);
64 break; 63 *args++ = UPT_SYSCALL_ARG4(r);
65 *args++ = UPT_SYSCALL_ARG1(r); 64 *args++ = UPT_SYSCALL_ARG5(r);
66 case 1: 65 *args = UPT_SYSCALL_ARG6(r);
67 if (!n--)
68 break;
69 *args++ = UPT_SYSCALL_ARG2(r);
70 case 2:
71 if (!n--)
72 break;
73 *args++ = UPT_SYSCALL_ARG3(r);
74 case 3:
75 if (!n--)
76 break;
77 *args++ = UPT_SYSCALL_ARG4(r);
78 case 4:
79 if (!n--)
80 break;
81 *args++ = UPT_SYSCALL_ARG5(r);
82 case 5:
83 if (!n--)
84 break;
85 *args++ = UPT_SYSCALL_ARG6(r);
86 case 6:
87 if (!n--)
88 break;
89 default:
90 BUG();
91 break;
92 }
93} 66}
94 67
95static inline void syscall_set_arguments(struct task_struct *task, 68static inline void syscall_set_arguments(struct task_struct *task,
diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h
index d653139857af..8dbb5c379450 100644
--- a/arch/x86/include/asm/syscall.h
+++ b/arch/x86/include/asm/syscall.h
@@ -91,11 +91,9 @@ static inline void syscall_set_return_value(struct task_struct *task,
91 91
92static inline void syscall_get_arguments(struct task_struct *task, 92static inline void syscall_get_arguments(struct task_struct *task,
93 struct pt_regs *regs, 93 struct pt_regs *regs,
94 unsigned int i, unsigned int n,
95 unsigned long *args) 94 unsigned long *args)
96{ 95{
97 BUG_ON(i + n > 6); 96 memcpy(args, &regs->bx, 6 * sizeof(args[0]));
98 memcpy(args, &regs->bx + i, n * sizeof(args[0]));
99} 97}
100 98
101static inline void syscall_set_arguments(struct task_struct *task, 99static inline void syscall_set_arguments(struct task_struct *task,
@@ -116,63 +114,26 @@ static inline int syscall_get_arch(void)
116 114
117static inline void syscall_get_arguments(struct task_struct *task, 115static inline void syscall_get_arguments(struct task_struct *task,
118 struct pt_regs *regs, 116 struct pt_regs *regs,
119 unsigned int i, unsigned int n,
120 unsigned long *args) 117 unsigned long *args)
121{ 118{
122# ifdef CONFIG_IA32_EMULATION 119# ifdef CONFIG_IA32_EMULATION
123 if (task->thread_info.status & TS_COMPAT) 120 if (task->thread_info.status & TS_COMPAT) {
124 switch (i) { 121 *args++ = regs->bx;
125 case 0: 122 *args++ = regs->cx;
126 if (!n--) break; 123 *args++ = regs->dx;
127 *args++ = regs->bx; 124 *args++ = regs->si;
128 case 1: 125 *args++ = regs->di;
129 if (!n--) break; 126 *args = regs->bp;
130 *args++ = regs->cx; 127 } else
131 case 2:
132 if (!n--) break;
133 *args++ = regs->dx;
134 case 3:
135 if (!n--) break;
136 *args++ = regs->si;
137 case 4:
138 if (!n--) break;
139 *args++ = regs->di;
140 case 5:
141 if (!n--) break;
142 *args++ = regs->bp;
143 case 6:
144 if (!n--) break;
145 default:
146 BUG();
147 break;
148 }
149 else
150# endif 128# endif
151 switch (i) { 129 {
152 case 0: 130 *args++ = regs->di;
153 if (!n--) break; 131 *args++ = regs->si;
154 *args++ = regs->di; 132 *args++ = regs->dx;
155 case 1: 133 *args++ = regs->r10;
156 if (!n--) break; 134 *args++ = regs->r8;
157 *args++ = regs->si; 135 *args = regs->r9;
158 case 2: 136 }
159 if (!n--) break;
160 *args++ = regs->dx;
161 case 3:
162 if (!n--) break;
163 *args++ = regs->r10;
164 case 4:
165 if (!n--) break;
166 *args++ = regs->r8;
167 case 5:
168 if (!n--) break;
169 *args++ = regs->r9;
170 case 6:
171 if (!n--) break;
172 default:
173 BUG();
174 break;
175 }
176} 137}
177 138
178static inline void syscall_set_arguments(struct task_struct *task, 139static inline void syscall_set_arguments(struct task_struct *task,
diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h
index a168bf81c7f4..1504ce9a233a 100644
--- a/arch/xtensa/include/asm/syscall.h
+++ b/arch/xtensa/include/asm/syscall.h
@@ -59,23 +59,13 @@ static inline void syscall_set_return_value(struct task_struct *task,
59 59
60static inline void syscall_get_arguments(struct task_struct *task, 60static inline void syscall_get_arguments(struct task_struct *task,
61 struct pt_regs *regs, 61 struct pt_regs *regs,
62 unsigned int i, unsigned int n,
63 unsigned long *args) 62 unsigned long *args)
64{ 63{
65 static const unsigned int reg[] = XTENSA_SYSCALL_ARGUMENT_REGS; 64 static const unsigned int reg[] = XTENSA_SYSCALL_ARGUMENT_REGS;
66 unsigned int j; 65 unsigned int i;
67
68 if (n == 0)
69 return;
70
71 WARN_ON_ONCE(i + n > SYSCALL_MAX_ARGS);
72 66
73 for (j = 0; j < n; ++j) { 67 for (i = 0; i < 6; ++i)
74 if (i + j < SYSCALL_MAX_ARGS) 68 args[i] = regs->areg[reg[i]];
75 args[j] = regs->areg[reg[i + j]];
76 else
77 args[j] = 0;
78 }
79} 69}
80 70
81static inline void syscall_set_arguments(struct task_struct *task, 71static inline void syscall_set_arguments(struct task_struct *task,
diff --git a/include/asm-generic/syscall.h b/include/asm-generic/syscall.h
index 0c938a4354f6..269e9412ef42 100644
--- a/include/asm-generic/syscall.h
+++ b/include/asm-generic/syscall.h
@@ -105,21 +105,16 @@ void syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
105 * syscall_get_arguments - extract system call parameter values 105 * syscall_get_arguments - extract system call parameter values
106 * @task: task of interest, must be blocked 106 * @task: task of interest, must be blocked
107 * @regs: task_pt_regs() of @task 107 * @regs: task_pt_regs() of @task
108 * @i: argument index [0,5]
109 * @n: number of arguments; n+i must be [1,6].
110 * @args: array filled with argument values 108 * @args: array filled with argument values
111 * 109 *
112 * Fetches @n arguments to the system call starting with the @i'th argument 110 * Fetches 6 arguments to the system call. First argument is stored in
113 * (from 0 through 5). Argument @i is stored in @args[0], and so on. 111* @args[0], and so on.
114 * An arch inline version is probably optimal when @i and @n are constants.
115 * 112 *
116 * It's only valid to call this when @task is stopped for tracing on 113 * It's only valid to call this when @task is stopped for tracing on
117 * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT. 114 * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
118 * It's invalid to call this with @i + @n > 6; we only support system calls
119 * taking up to 6 arguments.
120 */ 115 */
121void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, 116void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
122 unsigned int i, unsigned int n, unsigned long *args); 117 unsigned long *args);
123 118
124/** 119/**
125 * syscall_set_arguments - change system call parameter value 120 * syscall_set_arguments - change system call parameter value
diff --git a/include/trace/events/syscalls.h b/include/trace/events/syscalls.h
index 44a3259ed4a5..b6e0cbc2c71f 100644
--- a/include/trace/events/syscalls.h
+++ b/include/trace/events/syscalls.h
@@ -28,7 +28,7 @@ TRACE_EVENT_FN(sys_enter,
28 28
29 TP_fast_assign( 29 TP_fast_assign(
30 __entry->id = id; 30 __entry->id = id;
31 syscall_get_arguments(current, regs, 0, 6, __entry->args); 31 syscall_get_arguments(current, regs, __entry->args);
32 ), 32 ),
33 33
34 TP_printk("NR %ld (%lx, %lx, %lx, %lx, %lx, %lx)", 34 TP_printk("NR %ld (%lx, %lx, %lx, %lx, %lx, %lx)",
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 54a0347ca812..df27e499956a 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -149,7 +149,7 @@ static void populate_seccomp_data(struct seccomp_data *sd)
149 149
150 sd->nr = syscall_get_nr(task, regs); 150 sd->nr = syscall_get_nr(task, regs);
151 sd->arch = syscall_get_arch(); 151 sd->arch = syscall_get_arch();
152 syscall_get_arguments(task, regs, 0, 6, args); 152 syscall_get_arguments(task, regs, args);
153 sd->args[0] = args[0]; 153 sd->args[0] = args[0];
154 sd->args[1] = args[1]; 154 sd->args[1] = args[1];
155 sd->args[2] = args[2]; 155 sd->args[2] = args[2];
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index e9f5bbbad6d9..fa8fbff736d6 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -348,7 +348,7 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id)
348 348
349 entry = ring_buffer_event_data(event); 349 entry = ring_buffer_event_data(event);
350 entry->nr = syscall_nr; 350 entry->nr = syscall_nr;
351 syscall_get_arguments(current, regs, 0, 6, args); 351 syscall_get_arguments(current, regs, args);
352 memcpy(entry->args, args, sizeof(unsigned long) * sys_data->nb_args); 352 memcpy(entry->args, args, sizeof(unsigned long) * sys_data->nb_args);
353 353
354 event_trigger_unlock_commit(trace_file, buffer, event, entry, 354 event_trigger_unlock_commit(trace_file, buffer, event, entry,
@@ -616,7 +616,7 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
616 return; 616 return;
617 617
618 rec->nr = syscall_nr; 618 rec->nr = syscall_nr;
619 syscall_get_arguments(current, regs, 0, 6, args); 619 syscall_get_arguments(current, regs, args);
620 memcpy(&rec->args, args, sizeof(unsigned long) * sys_data->nb_args); 620 memcpy(&rec->args, args, sizeof(unsigned long) * sys_data->nb_args);
621 621
622 if ((valid_prog_array && 622 if ((valid_prog_array &&
diff --git a/lib/syscall.c b/lib/syscall.c
index e8467e17b9a2..fb328e7ccb08 100644
--- a/lib/syscall.c
+++ b/lib/syscall.c
@@ -27,7 +27,7 @@ static int collect_syscall(struct task_struct *target, struct syscall_info *info
27 27
28 info->data.nr = syscall_get_nr(target, regs); 28 info->data.nr = syscall_get_nr(target, regs);
29 if (info->data.nr != -1L) 29 if (info->data.nr != -1L)
30 syscall_get_arguments(target, regs, 0, 6, 30 syscall_get_arguments(target, regs,
31 (unsigned long *)&info->data.args[0]); 31 (unsigned long *)&info->data.args[0]);
32 32
33 put_task_stack(target); 33 put_task_stack(target);