diff options
32 files changed, 247 insertions, 722 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 | */ |
| 56 | static inline void | 56 | static inline void |
| 57 | syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, | 57 | syscall_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..080ce70cab12 100644 --- a/arch/arm/include/asm/syscall.h +++ b/arch/arm/include/asm/syscall.h | |||
| @@ -55,53 +55,22 @@ static inline void syscall_set_return_value(struct task_struct *task, | |||
| 55 | 55 | ||
| 56 | static inline void syscall_get_arguments(struct task_struct *task, | 56 | static 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 | 62 | ||
| 64 | if (i + n > SYSCALL_MAX_ARGS) { | 63 | memcpy(args, ®s->ARM_r0 + 1, 5 * sizeof(args[0])); |
| 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 | |||
| 80 | memcpy(args, ®s->ARM_r0 + i, n * sizeof(args[0])); | ||
| 81 | } | 64 | } |
| 82 | 65 | ||
| 83 | static inline void syscall_set_arguments(struct task_struct *task, | 66 | static inline void syscall_set_arguments(struct task_struct *task, |
| 84 | struct pt_regs *regs, | 67 | struct pt_regs *regs, |
| 85 | unsigned int i, unsigned int n, | ||
| 86 | const unsigned long *args) | 68 | const unsigned long *args) |
| 87 | { | 69 | { |
| 88 | if (n == 0) | 70 | regs->ARM_ORIG_r0 = args[0]; |
| 89 | return; | 71 | args++; |
| 90 | 72 | ||
| 91 | if (i + n > SYSCALL_MAX_ARGS) { | 73 | memcpy(®s->ARM_r0 + 1, args, 5 * sizeof(args[0])); |
| 92 | pr_warn("%s called with max args %d, handling only %d\n", | ||
| 93 | __func__, i + n, SYSCALL_MAX_ARGS); | ||
| 94 | n = SYSCALL_MAX_ARGS - i; | ||
| 95 | } | ||
| 96 | |||
| 97 | if (i == 0) { | ||
| 98 | regs->ARM_ORIG_r0 = args[0]; | ||
| 99 | args++; | ||
| 100 | i++; | ||
| 101 | n--; | ||
| 102 | } | ||
| 103 | |||
| 104 | memcpy(®s->ARM_r0 + i, args, n * sizeof(args[0])); | ||
| 105 | } | 74 | } |
| 106 | 75 | ||
| 107 | static inline int syscall_get_arch(void) | 76 | static inline int syscall_get_arch(void) |
diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h index ad8be16a39c9..a179df3674a1 100644 --- a/arch/arm64/include/asm/syscall.h +++ b/arch/arm64/include/asm/syscall.h | |||
| @@ -65,52 +65,22 @@ static inline void syscall_set_return_value(struct task_struct *task, | |||
| 65 | 65 | ||
| 66 | static inline void syscall_get_arguments(struct task_struct *task, | 66 | static 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 | 72 | ||
| 74 | if (i + n > SYSCALL_MAX_ARGS) { | 73 | memcpy(args, ®s->regs[1], 5 * sizeof(args[0])); |
| 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 | |||
| 89 | memcpy(args, ®s->regs[i], n * sizeof(args[0])); | ||
| 90 | } | 74 | } |
| 91 | 75 | ||
| 92 | static inline void syscall_set_arguments(struct task_struct *task, | 76 | static inline void syscall_set_arguments(struct task_struct *task, |
| 93 | struct pt_regs *regs, | 77 | struct pt_regs *regs, |
| 94 | unsigned int i, unsigned int n, | ||
| 95 | const unsigned long *args) | 78 | const unsigned long *args) |
| 96 | { | 79 | { |
| 97 | if (n == 0) | 80 | regs->orig_x0 = args[0]; |
| 98 | return; | 81 | args++; |
| 99 | 82 | ||
| 100 | if (i + n > SYSCALL_MAX_ARGS) { | 83 | memcpy(®s->regs[1], args, 5 * sizeof(args[0])); |
| 101 | pr_warning("%s called with max args %d, handling only %d\n", | ||
| 102 | __func__, i + n, SYSCALL_MAX_ARGS); | ||
| 103 | n = SYSCALL_MAX_ARGS - i; | ||
| 104 | } | ||
| 105 | |||
| 106 | if (i == 0) { | ||
| 107 | regs->orig_x0 = args[0]; | ||
| 108 | args++; | ||
| 109 | i++; | ||
| 110 | n--; | ||
| 111 | } | ||
| 112 | |||
| 113 | memcpy(®s->regs[i], args, n * sizeof(args[0])); | ||
| 114 | } | 84 | } |
| 115 | 85 | ||
| 116 | /* | 86 | /* |
diff --git a/arch/c6x/include/asm/syscall.h b/arch/c6x/include/asm/syscall.h index ae2be315ee9c..15ba8599858e 100644 --- a/arch/c6x/include/asm/syscall.h +++ b/arch/c6x/include/asm/syscall.h | |||
| @@ -46,78 +46,27 @@ static inline void syscall_set_return_value(struct task_struct *task, | |||
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | static inline void syscall_get_arguments(struct task_struct *task, | 48 | static 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 | ||
| 85 | static inline void syscall_set_arguments(struct task_struct *task, | 60 | static inline void syscall_set_arguments(struct task_struct *task, |
| 86 | struct pt_regs *regs, | 61 | struct pt_regs *regs, |
| 87 | unsigned int i, unsigned int n, | ||
| 88 | const unsigned long *args) | 62 | const unsigned long *args) |
| 89 | { | 63 | { |
| 90 | switch (i) { | 64 | regs->a4 = *args++; |
| 91 | case 0: | 65 | regs->b4 = *args++; |
| 92 | if (!n--) | 66 | regs->a6 = *args++; |
| 93 | break; | 67 | regs->b6 = *args++; |
| 94 | regs->a4 = *args++; | 68 | regs->a8 = *args++; |
| 95 | case 1: | 69 | regs->a9 = *args; |
| 96 | if (!n--) | ||
| 97 | break; | ||
| 98 | regs->b4 = *args++; | ||
| 99 | case 2: | ||
| 100 | if (!n--) | ||
| 101 | break; | ||
| 102 | regs->a6 = *args++; | ||
| 103 | case 3: | ||
| 104 | if (!n--) | ||
| 105 | break; | ||
| 106 | regs->b6 = *args++; | ||
| 107 | case 4: | ||
| 108 | if (!n--) | ||
| 109 | break; | ||
| 110 | regs->a8 = *args++; | ||
| 111 | case 5: | ||
| 112 | if (!n--) | ||
| 113 | break; | ||
| 114 | regs->a9 = *args++; | ||
| 115 | case 6: | ||
| 116 | if (!n) | ||
| 117 | break; | ||
| 118 | default: | ||
| 119 | BUG(); | ||
| 120 | } | ||
| 121 | } | 70 | } |
| 122 | 71 | ||
| 123 | #endif /* __ASM_C6X_SYSCALLS_H */ | 72 | #endif /* __ASM_C6X_SYSCALLS_H */ |
diff --git a/arch/csky/include/asm/syscall.h b/arch/csky/include/asm/syscall.h index d637445737b7..bda0a446c63e 100644 --- a/arch/csky/include/asm/syscall.h +++ b/arch/csky/include/asm/syscall.h | |||
| @@ -43,30 +43,20 @@ syscall_set_return_value(struct task_struct *task, struct pt_regs *regs, | |||
| 43 | 43 | ||
| 44 | static inline void | 44 | static inline void |
| 45 | syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, | 45 | syscall_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, ®s->a1, 5 * sizeof(args[0])); |
| 51 | args++; | ||
| 52 | i++; | ||
| 53 | n--; | ||
| 54 | } | ||
| 55 | memcpy(args, ®s->a1 + i * sizeof(regs->a1), n * sizeof(args[0])); | ||
| 56 | } | 51 | } |
| 57 | 52 | ||
| 58 | static inline void | 53 | static inline void |
| 59 | syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, | 54 | syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, |
| 60 | unsigned int i, unsigned int n, const unsigned long *args) | 55 | const unsigned long *args) |
| 61 | { | 56 | { |
| 62 | BUG_ON(i + n > 6); | 57 | regs->orig_a0 = args[0]; |
| 63 | if (i == 0) { | 58 | args++; |
| 64 | regs->orig_a0 = args[0]; | 59 | memcpy(®s->a1, args, 5 * sizeof(regs->a1)); |
| 65 | args++; | ||
| 66 | i++; | ||
| 67 | n--; | ||
| 68 | } | ||
| 69 | memcpy(®s->a1 + i * sizeof(regs->a1), args, n * sizeof(regs->a0)); | ||
| 70 | } | 60 | } |
| 71 | 61 | ||
| 72 | static inline int | 62 | static inline int |
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 | ||
| 18 | static inline void | 18 | static inline void |
| 19 | syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, | 19 | syscall_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 | ||
| 38 | static inline void syscall_get_arguments(struct task_struct *task, | 38 | static 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, &(®s->r00)[0], 6 * sizeof(args[0])); |
| 44 | memcpy(args, &(®s->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..0d9e7fab4a79 100644 --- a/arch/ia64/include/asm/syscall.h +++ b/arch/ia64/include/asm/syscall.h | |||
| @@ -59,26 +59,19 @@ static inline void syscall_set_return_value(struct task_struct *task, | |||
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | extern void ia64_syscall_get_set_arguments(struct task_struct *task, | 61 | extern void ia64_syscall_get_set_arguments(struct task_struct *task, |
| 62 | struct pt_regs *regs, unsigned int i, unsigned int n, | 62 | struct pt_regs *regs, unsigned long *args, int rw); |
| 63 | unsigned long *args, int rw); | ||
| 64 | static inline void syscall_get_arguments(struct task_struct *task, | 63 | static inline void syscall_get_arguments(struct task_struct *task, |
| 65 | struct pt_regs *regs, | 64 | struct pt_regs *regs, |
| 66 | unsigned int i, unsigned int n, | ||
| 67 | unsigned long *args) | 65 | unsigned long *args) |
| 68 | { | 66 | { |
| 69 | BUG_ON(i + n > 6); | 67 | ia64_syscall_get_set_arguments(task, regs, args, 0); |
| 70 | |||
| 71 | ia64_syscall_get_set_arguments(task, regs, i, n, args, 0); | ||
| 72 | } | 68 | } |
| 73 | 69 | ||
| 74 | static inline void syscall_set_arguments(struct task_struct *task, | 70 | static inline void syscall_set_arguments(struct task_struct *task, |
| 75 | struct pt_regs *regs, | 71 | struct pt_regs *regs, |
| 76 | unsigned int i, unsigned int n, | ||
| 77 | unsigned long *args) | 72 | unsigned long *args) |
| 78 | { | 73 | { |
| 79 | BUG_ON(i + n > 6); | 74 | ia64_syscall_get_set_arguments(task, regs, args, 1); |
| 80 | |||
| 81 | ia64_syscall_get_set_arguments(task, regs, i, n, args, 1); | ||
| 82 | } | 75 | } |
| 83 | 76 | ||
| 84 | static inline int syscall_get_arch(void) | 77 | static inline int syscall_get_arch(void) |
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 6d50ede0ed69..bf9c24d9ce84 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c | |||
| @@ -2179,12 +2179,11 @@ static void syscall_get_set_args_cb(struct unw_frame_info *info, void *data) | |||
| 2179 | } | 2179 | } |
| 2180 | 2180 | ||
| 2181 | void ia64_syscall_get_set_arguments(struct task_struct *task, | 2181 | void ia64_syscall_get_set_arguments(struct task_struct *task, |
| 2182 | struct pt_regs *regs, unsigned int i, unsigned int n, | 2182 | struct pt_regs *regs, unsigned long *args, int rw) |
| 2183 | unsigned long *args, int rw) | ||
| 2184 | { | 2183 | { |
| 2185 | struct syscall_get_set_args data = { | 2184 | struct syscall_get_set_args data = { |
| 2186 | .i = i, | 2185 | .i = 0, |
| 2187 | .n = n, | 2186 | .n = 6, |
| 2188 | .args = args, | 2187 | .args = args, |
| 2189 | .regs = regs, | 2188 | .regs = regs, |
| 2190 | .rw = rw, | 2189 | .rw = rw, |
diff --git a/arch/microblaze/include/asm/syscall.h b/arch/microblaze/include/asm/syscall.h index 220decd605a4..833d3a53dab3 100644 --- a/arch/microblaze/include/asm/syscall.h +++ b/arch/microblaze/include/asm/syscall.h | |||
| @@ -82,18 +82,22 @@ static inline void microblaze_set_syscall_arg(struct pt_regs *regs, | |||
| 82 | 82 | ||
| 83 | static inline void syscall_get_arguments(struct task_struct *task, | 83 | static 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 | } |
| 91 | 93 | ||
| 92 | static inline void syscall_set_arguments(struct task_struct *task, | 94 | static inline void syscall_set_arguments(struct task_struct *task, |
| 93 | struct pt_regs *regs, | 95 | struct pt_regs *regs, |
| 94 | unsigned int i, unsigned int n, | ||
| 95 | const unsigned long *args) | 96 | const unsigned long *args) |
| 96 | { | 97 | { |
| 98 | unsigned int i = 0; | ||
| 99 | unsigned int n = 6; | ||
| 100 | |||
| 97 | while (n--) | 101 | while (n--) |
| 98 | microblaze_set_syscall_arg(regs, i++, *args++); | 102 | microblaze_set_syscall_arg(regs, i++, *args++); |
| 99 | } | 103 | } |
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 | ||
| 117 | static inline void syscall_get_arguments(struct task_struct *task, | 117 | static 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..671ebd357496 100644 --- a/arch/nds32/include/asm/syscall.h +++ b/arch/nds32/include/asm/syscall.h | |||
| @@ -108,81 +108,41 @@ 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 |
| 125 | void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, | 120 | void 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, ®s->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, ®s->uregs[0] + i, n * sizeof(args[0])); | ||
| 147 | } | 126 | } |
| 148 | 127 | ||
| 149 | /** | 128 | /** |
| 150 | * syscall_set_arguments - change system call parameter value | 129 | * syscall_set_arguments - change system call parameter value |
| 151 | * @task: task of interest, must be in system call entry tracing | 130 | * @task: task of interest, must be in system call entry tracing |
| 152 | * @regs: task_pt_regs() of @task | 131 | * @regs: task_pt_regs() of @task |
| 153 | * @i: argument index [0,5] | ||
| 154 | * @n: number of arguments; n+i must be [1,6]. | ||
| 155 | * @args: array of argument values to store | 132 | * @args: array of argument values to store |
| 156 | * | 133 | * |
| 157 | * Changes @n arguments to the system call starting with the @i'th argument. | 134 | * Changes 6 arguments to the system call. The first argument gets value |
| 158 | * Argument @i gets value @args[0], and so on. | 135 | * @args[0], and so on. |
| 159 | * An arch inline version is probably optimal when @i and @n are constants. | ||
| 160 | * | 136 | * |
| 161 | * It's only valid to call this when @task is stopped for tracing on | 137 | * It's only valid to call this when @task is stopped for tracing on |
| 162 | * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT. | 138 | * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT. |
| 163 | * It's invalid to call this with @i + @n > 6; we only support system calls | ||
| 164 | * taking up to 6 arguments. | ||
| 165 | */ | 139 | */ |
| 166 | void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, | 140 | void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, |
| 167 | unsigned int i, unsigned int n, | ||
| 168 | const unsigned long *args) | 141 | const unsigned long *args) |
| 169 | { | 142 | { |
| 170 | if (n == 0) | 143 | regs->orig_r0 = args[0]; |
| 171 | return; | 144 | args++; |
| 172 | |||
| 173 | if (i + n > SYSCALL_MAX_ARGS) { | ||
| 174 | pr_warn("%s called with max args %d, handling only %d\n", | ||
| 175 | __func__, i + n, SYSCALL_MAX_ARGS); | ||
| 176 | n = SYSCALL_MAX_ARGS - i; | ||
| 177 | } | ||
| 178 | |||
| 179 | if (i == 0) { | ||
| 180 | regs->orig_r0 = args[0]; | ||
| 181 | args++; | ||
| 182 | i++; | ||
| 183 | n--; | ||
| 184 | } | ||
| 185 | 145 | ||
| 186 | memcpy(®s->uregs[0] + i, args, n * sizeof(args[0])); | 146 | memcpy(®s->uregs[0] + 1, args, 5 * sizeof(args[0])); |
| 187 | } | 147 | } |
| 188 | #endif /* _ASM_NDS32_SYSCALL_H */ | 148 | #endif /* _ASM_NDS32_SYSCALL_H */ |
diff --git a/arch/nios2/include/asm/syscall.h b/arch/nios2/include/asm/syscall.h index 9de220854c4a..d7624ed06efb 100644 --- a/arch/nios2/include/asm/syscall.h +++ b/arch/nios2/include/asm/syscall.h | |||
| @@ -58,81 +58,25 @@ static inline void syscall_set_return_value(struct task_struct *task, | |||
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | static inline void syscall_get_arguments(struct task_struct *task, | 60 | static 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 | ||
| 99 | static inline void syscall_set_arguments(struct task_struct *task, | 71 | static inline void syscall_set_arguments(struct task_struct *task, |
| 100 | struct pt_regs *regs, unsigned int i, unsigned int n, | 72 | struct pt_regs *regs, const unsigned long *args) |
| 101 | const unsigned long *args) | ||
| 102 | { | 73 | { |
| 103 | BUG_ON(i + n > 6); | 74 | regs->r4 = *args++; |
| 104 | 75 | regs->r5 = *args++; | |
| 105 | switch (i) { | 76 | regs->r6 = *args++; |
| 106 | case 0: | 77 | regs->r7 = *args++; |
| 107 | if (!n--) | 78 | regs->r8 = *args++; |
| 108 | break; | 79 | regs->r9 = *args; |
| 109 | regs->r4 = *args++; | ||
| 110 | case 1: | ||
| 111 | if (!n--) | ||
| 112 | break; | ||
| 113 | regs->r5 = *args++; | ||
| 114 | case 2: | ||
| 115 | if (!n--) | ||
| 116 | break; | ||
| 117 | regs->r6 = *args++; | ||
| 118 | case 3: | ||
| 119 | if (!n--) | ||
| 120 | break; | ||
| 121 | regs->r7 = *args++; | ||
| 122 | case 4: | ||
| 123 | if (!n--) | ||
| 124 | break; | ||
| 125 | regs->r8 = *args++; | ||
| 126 | case 5: | ||
| 127 | if (!n--) | ||
| 128 | break; | ||
| 129 | regs->r9 = *args++; | ||
| 130 | case 6: | ||
| 131 | if (!n) | ||
| 132 | break; | ||
| 133 | default: | ||
| 134 | BUG(); | ||
| 135 | } | ||
| 136 | } | 80 | } |
| 137 | 81 | ||
| 138 | #endif | 82 | #endif |
diff --git a/arch/openrisc/include/asm/syscall.h b/arch/openrisc/include/asm/syscall.h index 2db9f1cf0694..b4ff07c1baed 100644 --- a/arch/openrisc/include/asm/syscall.h +++ b/arch/openrisc/include/asm/syscall.h | |||
| @@ -56,20 +56,16 @@ syscall_set_return_value(struct task_struct *task, struct pt_regs *regs, | |||
| 56 | 56 | ||
| 57 | static inline void | 57 | static inline void |
| 58 | syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, | 58 | syscall_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, ®s->gpr[3], 6 * sizeof(args[0])); |
| 62 | |||
| 63 | memcpy(args, ®s->gpr[3 + i], n * sizeof(args[0])); | ||
| 64 | } | 62 | } |
| 65 | 63 | ||
| 66 | static inline void | 64 | static inline void |
| 67 | syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, | 65 | syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, |
| 68 | unsigned int i, unsigned int n, const unsigned long *args) | 66 | const unsigned long *args) |
| 69 | { | 67 | { |
| 70 | BUG_ON(i + n > 6); | 68 | memcpy(®s->gpr[3], args, 6 * sizeof(args[0])); |
| 71 | |||
| 72 | memcpy(®s->gpr[3 + i], args, n * sizeof(args[0])); | ||
| 73 | } | 69 | } |
| 74 | 70 | ||
| 75 | static inline int syscall_get_arch(void) | 71 | static inline int syscall_get_arch(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 | ||
| 20 | static inline void syscall_get_arguments(struct task_struct *tsk, | 20 | static 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 | ||
| 46 | static inline long syscall_get_return_value(struct task_struct *task, | 32 | static 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..1243045bad2d 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 | ||
| 66 | static inline void syscall_get_arguments(struct task_struct *task, | 66 | static 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 | } |
| @@ -88,15 +86,12 @@ static inline void syscall_get_arguments(struct task_struct *task, | |||
| 88 | 86 | ||
| 89 | static inline void syscall_set_arguments(struct task_struct *task, | 87 | static inline void syscall_set_arguments(struct task_struct *task, |
| 90 | struct pt_regs *regs, | 88 | struct pt_regs *regs, |
| 91 | unsigned int i, unsigned int n, | ||
| 92 | const unsigned long *args) | 89 | const unsigned long *args) |
| 93 | { | 90 | { |
| 94 | BUG_ON(i + n > 6); | 91 | memcpy(®s->gpr[3], args, 6 * sizeof(args[0])); |
| 95 | memcpy(®s->gpr[3 + i], args, n * sizeof(args[0])); | ||
| 96 | 92 | ||
| 97 | /* Also copy the first argument into orig_gpr3 */ | 93 | /* Also copy the first argument into orig_gpr3 */ |
| 98 | if (i == 0 && n > 0) | 94 | regs->orig_gpr3 = args[0]; |
| 99 | regs->orig_gpr3 = args[0]; | ||
| 100 | } | 95 | } |
| 101 | 96 | ||
| 102 | static inline int syscall_get_arch(void) | 97 | static inline int syscall_get_arch(void) |
diff --git a/arch/riscv/include/asm/syscall.h b/arch/riscv/include/asm/syscall.h index bba3da6ef157..a3d5273ded7c 100644 --- a/arch/riscv/include/asm/syscall.h +++ b/arch/riscv/include/asm/syscall.h | |||
| @@ -72,32 +72,20 @@ static inline void syscall_set_return_value(struct task_struct *task, | |||
| 72 | 72 | ||
| 73 | static inline void syscall_get_arguments(struct task_struct *task, | 73 | static 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, ®s->a1, 5 * sizeof(args[0])); |
| 81 | args++; | ||
| 82 | i++; | ||
| 83 | n--; | ||
| 84 | } | ||
| 85 | memcpy(args, ®s->a1 + i * sizeof(regs->a1), n * sizeof(args[0])); | ||
| 86 | } | 80 | } |
| 87 | 81 | ||
| 88 | static inline void syscall_set_arguments(struct task_struct *task, | 82 | static inline void syscall_set_arguments(struct task_struct *task, |
| 89 | struct pt_regs *regs, | 83 | struct pt_regs *regs, |
| 90 | unsigned int i, unsigned int n, | ||
| 91 | const unsigned long *args) | 84 | const unsigned long *args) |
| 92 | { | 85 | { |
| 93 | BUG_ON(i + n > 6); | 86 | regs->orig_a0 = args[0]; |
| 94 | if (i == 0) { | 87 | args++; |
| 95 | regs->orig_a0 = args[0]; | 88 | memcpy(®s->a1, args, 5 * sizeof(regs->a1)); |
| 96 | args++; | ||
| 97 | i++; | ||
| 98 | n--; | ||
| 99 | } | ||
| 100 | memcpy(®s->a1 + i * sizeof(regs->a1), args, n * sizeof(regs->a0)); | ||
| 101 | } | 89 | } |
| 102 | 90 | ||
| 103 | static inline int syscall_get_arch(void) | 91 | static inline int syscall_get_arch(void) |
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h index 96f9a9151fde..59c3e91f2cdb 100644 --- a/arch/s390/include/asm/syscall.h +++ b/arch/s390/include/asm/syscall.h | |||
| @@ -56,40 +56,32 @@ static inline void syscall_set_return_value(struct task_struct *task, | |||
| 56 | 56 | ||
| 57 | static inline void syscall_get_arguments(struct task_struct *task, | 57 | static 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 | ||
| 82 | static inline void syscall_set_arguments(struct task_struct *task, | 75 | static inline void syscall_set_arguments(struct task_struct *task, |
| 83 | struct pt_regs *regs, | 76 | struct pt_regs *regs, |
| 84 | unsigned int i, unsigned int n, | ||
| 85 | const unsigned long *args) | 77 | const unsigned long *args) |
| 86 | { | 78 | { |
| 87 | BUG_ON(i + n > 6); | 79 | unsigned int n = 6; |
| 80 | |||
| 88 | while (n-- > 0) | 81 | while (n-- > 0) |
| 89 | if (i + n > 0) | 82 | if (n > 0) |
| 90 | regs->gprs[2 + i + n] = args[n]; | 83 | regs->gprs[2 + n] = args[n]; |
| 91 | if (i == 0) | 84 | regs->orig_gpr2 = args[0]; |
| 92 | regs->orig_gpr2 = args[0]; | ||
| 93 | } | 85 | } |
| 94 | 86 | ||
| 95 | static inline int syscall_get_arch(void) | 87 | static inline int syscall_get_arch(void) |
diff --git a/arch/sh/include/asm/syscall_32.h b/arch/sh/include/asm/syscall_32.h index 6e118799831c..8c9d7e5e5dcc 100644 --- a/arch/sh/include/asm/syscall_32.h +++ b/arch/sh/include/asm/syscall_32.h | |||
| @@ -48,51 +48,28 @@ static inline void syscall_set_return_value(struct task_struct *task, | |||
| 48 | 48 | ||
| 49 | static inline void syscall_get_arguments(struct task_struct *task, | 49 | static 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 | ||
| 77 | static inline void syscall_set_arguments(struct task_struct *task, | 63 | static inline void syscall_set_arguments(struct task_struct *task, |
| 78 | struct pt_regs *regs, | 64 | struct pt_regs *regs, |
| 79 | unsigned int i, unsigned int n, | ||
| 80 | const unsigned long *args) | 65 | const unsigned long *args) |
| 81 | { | 66 | { |
| 82 | /* Same note as above applies */ | 67 | regs->regs[1] = args[5]; |
| 83 | BUG_ON(i); | 68 | regs->regs[0] = args[4]; |
| 84 | 69 | regs->regs[7] = args[3]; | |
| 85 | switch (n) { | 70 | regs->regs[6] = args[2]; |
| 86 | case 6: regs->regs[1] = args[5]; | 71 | regs->regs[5] = args[1]; |
| 87 | case 5: regs->regs[0] = args[4]; | 72 | regs->regs[4] = args[0]; |
| 88 | case 4: regs->regs[7] = args[3]; | ||
| 89 | case 3: regs->regs[6] = args[2]; | ||
| 90 | case 2: regs->regs[5] = args[1]; | ||
| 91 | case 1: regs->regs[4] = args[0]; | ||
| 92 | break; | ||
| 93 | default: | ||
| 94 | BUG(); | ||
| 95 | } | ||
| 96 | } | 73 | } |
| 97 | 74 | ||
| 98 | static inline int syscall_get_arch(void) | 75 | static inline int syscall_get_arch(void) |
diff --git a/arch/sh/include/asm/syscall_64.h b/arch/sh/include/asm/syscall_64.h index 43882580c7f9..22fad97da066 100644 --- a/arch/sh/include/asm/syscall_64.h +++ b/arch/sh/include/asm/syscall_64.h | |||
| @@ -47,20 +47,16 @@ static inline void syscall_set_return_value(struct task_struct *task, | |||
| 47 | 47 | ||
| 48 | static inline void syscall_get_arguments(struct task_struct *task, | 48 | static 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, ®s->regs[2], 6 * sizeof(args[0])); |
| 54 | memcpy(args, ®s->regs[2 + i], n * sizeof(args[0])); | ||
| 55 | } | 53 | } |
| 56 | 54 | ||
| 57 | static inline void syscall_set_arguments(struct task_struct *task, | 55 | static inline void syscall_set_arguments(struct task_struct *task, |
| 58 | struct pt_regs *regs, | 56 | struct pt_regs *regs, |
| 59 | unsigned int i, unsigned int n, | ||
| 60 | const unsigned long *args) | 57 | const unsigned long *args) |
| 61 | { | 58 | { |
| 62 | BUG_ON(i + n > 6); | 59 | memcpy(®s->regs[2], args, 6 * sizeof(args[0])); |
| 63 | memcpy(®s->regs[2 + i], args, n * sizeof(args[0])); | ||
| 64 | } | 60 | } |
| 65 | 61 | ||
| 66 | static inline int syscall_get_arch(void) | 62 | static inline int syscall_get_arch(void) |
diff --git a/arch/sparc/include/asm/syscall.h b/arch/sparc/include/asm/syscall.h index 053989e3f6a6..4d075434e816 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 | ||
| 97 | static inline void syscall_get_arguments(struct task_struct *task, | 97 | static 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; |
| @@ -119,13 +119,12 @@ static inline void syscall_get_arguments(struct task_struct *task, | |||
| 119 | 119 | ||
| 120 | static inline void syscall_set_arguments(struct task_struct *task, | 120 | static inline void syscall_set_arguments(struct task_struct *task, |
| 121 | struct pt_regs *regs, | 121 | struct pt_regs *regs, |
| 122 | unsigned int i, unsigned int n, | ||
| 123 | const unsigned long *args) | 122 | const unsigned long *args) |
| 124 | { | 123 | { |
| 125 | unsigned int j; | 124 | unsigned int i; |
| 126 | 125 | ||
| 127 | for (j = 0; j < n; j++) | 126 | for (i = 0; i < 6; i++) |
| 128 | regs->u_regs[UREG_I0 + i + j] = args[j]; | 127 | regs->u_regs[UREG_I0 + i] = args[i]; |
| 129 | } | 128 | } |
| 130 | 129 | ||
| 131 | static inline int syscall_get_arch(void) | 130 | static inline int syscall_get_arch(void) |
diff --git a/arch/um/include/asm/syscall-generic.h b/arch/um/include/asm/syscall-generic.h index 9fb9cf8cd39a..98e50c50c12e 100644 --- a/arch/um/include/asm/syscall-generic.h +++ b/arch/um/include/asm/syscall-generic.h | |||
| @@ -53,84 +53,30 @@ static inline void syscall_set_return_value(struct task_struct *task, | |||
| 53 | 53 | ||
| 54 | static inline void syscall_get_arguments(struct task_struct *task, | 54 | static 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 = ®s->regs; | 58 | const struct uml_pt_regs *r = ®s->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 | ||
| 95 | static inline void syscall_set_arguments(struct task_struct *task, | 68 | static inline void syscall_set_arguments(struct task_struct *task, |
| 96 | struct pt_regs *regs, | 69 | struct pt_regs *regs, |
| 97 | unsigned int i, unsigned int n, | ||
| 98 | const unsigned long *args) | 70 | const unsigned long *args) |
| 99 | { | 71 | { |
| 100 | struct uml_pt_regs *r = ®s->regs; | 72 | struct uml_pt_regs *r = ®s->regs; |
| 101 | 73 | ||
| 102 | switch (i) { | 74 | UPT_SYSCALL_ARG1(r) = *args++; |
| 103 | case 0: | 75 | UPT_SYSCALL_ARG2(r) = *args++; |
| 104 | if (!n--) | 76 | UPT_SYSCALL_ARG3(r) = *args++; |
| 105 | break; | 77 | UPT_SYSCALL_ARG4(r) = *args++; |
| 106 | UPT_SYSCALL_ARG1(r) = *args++; | 78 | UPT_SYSCALL_ARG5(r) = *args++; |
| 107 | case 1: | 79 | UPT_SYSCALL_ARG6(r) = *args; |
| 108 | if (!n--) | ||
| 109 | break; | ||
| 110 | UPT_SYSCALL_ARG2(r) = *args++; | ||
| 111 | case 2: | ||
| 112 | if (!n--) | ||
| 113 | break; | ||
| 114 | UPT_SYSCALL_ARG3(r) = *args++; | ||
| 115 | case 3: | ||
| 116 | if (!n--) | ||
| 117 | break; | ||
| 118 | UPT_SYSCALL_ARG4(r) = *args++; | ||
| 119 | case 4: | ||
| 120 | if (!n--) | ||
| 121 | break; | ||
| 122 | UPT_SYSCALL_ARG5(r) = *args++; | ||
| 123 | case 5: | ||
| 124 | if (!n--) | ||
| 125 | break; | ||
| 126 | UPT_SYSCALL_ARG6(r) = *args++; | ||
| 127 | case 6: | ||
| 128 | if (!n--) | ||
| 129 | break; | ||
| 130 | default: | ||
| 131 | BUG(); | ||
| 132 | break; | ||
| 133 | } | ||
| 134 | } | 80 | } |
| 135 | 81 | ||
| 136 | /* See arch/x86/um/asm/syscall.h for syscall_get_arch() definition. */ | 82 | /* See arch/x86/um/asm/syscall.h for syscall_get_arch() definition. */ |
diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h index d653139857af..4c305471ec33 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 | ||
| 92 | static inline void syscall_get_arguments(struct task_struct *task, | 92 | static 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, ®s->bx, 6 * sizeof(args[0])); |
| 98 | memcpy(args, ®s->bx + i, n * sizeof(args[0])); | ||
| 99 | } | 97 | } |
| 100 | 98 | ||
| 101 | static inline void syscall_set_arguments(struct task_struct *task, | 99 | static inline void syscall_set_arguments(struct task_struct *task, |
| @@ -116,124 +114,50 @@ static inline int syscall_get_arch(void) | |||
| 116 | 114 | ||
| 117 | static inline void syscall_get_arguments(struct task_struct *task, | 115 | static 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 | ||
| 178 | static inline void syscall_set_arguments(struct task_struct *task, | 139 | static inline void syscall_set_arguments(struct task_struct *task, |
| 179 | struct pt_regs *regs, | 140 | struct pt_regs *regs, |
| 180 | unsigned int i, unsigned int n, | ||
| 181 | const unsigned long *args) | 141 | const unsigned long *args) |
| 182 | { | 142 | { |
| 183 | # ifdef CONFIG_IA32_EMULATION | 143 | # ifdef CONFIG_IA32_EMULATION |
| 184 | if (task->thread_info.status & TS_COMPAT) | 144 | if (task->thread_info.status & TS_COMPAT) { |
| 185 | switch (i) { | 145 | regs->bx = *args++; |
| 186 | case 0: | 146 | regs->cx = *args++; |
| 187 | if (!n--) break; | 147 | regs->dx = *args++; |
| 188 | regs->bx = *args++; | 148 | regs->si = *args++; |
| 189 | case 1: | 149 | regs->di = *args++; |
| 190 | if (!n--) break; | 150 | regs->bp = *args; |
| 191 | regs->cx = *args++; | 151 | } else |
| 192 | case 2: | ||
| 193 | if (!n--) break; | ||
| 194 | regs->dx = *args++; | ||
| 195 | case 3: | ||
| 196 | if (!n--) break; | ||
| 197 | regs->si = *args++; | ||
| 198 | case 4: | ||
| 199 | if (!n--) break; | ||
| 200 | regs->di = *args++; | ||
| 201 | case 5: | ||
| 202 | if (!n--) break; | ||
| 203 | regs->bp = *args++; | ||
| 204 | case 6: | ||
| 205 | if (!n--) break; | ||
| 206 | default: | ||
| 207 | BUG(); | ||
| 208 | break; | ||
| 209 | } | ||
| 210 | else | ||
| 211 | # endif | 152 | # endif |
| 212 | switch (i) { | 153 | { |
| 213 | case 0: | 154 | regs->di = *args++; |
| 214 | if (!n--) break; | 155 | regs->si = *args++; |
| 215 | regs->di = *args++; | 156 | regs->dx = *args++; |
| 216 | case 1: | 157 | regs->r10 = *args++; |
| 217 | if (!n--) break; | 158 | regs->r8 = *args++; |
| 218 | regs->si = *args++; | 159 | regs->r9 = *args; |
| 219 | case 2: | 160 | } |
| 220 | if (!n--) break; | ||
| 221 | regs->dx = *args++; | ||
| 222 | case 3: | ||
| 223 | if (!n--) break; | ||
| 224 | regs->r10 = *args++; | ||
| 225 | case 4: | ||
| 226 | if (!n--) break; | ||
| 227 | regs->r8 = *args++; | ||
| 228 | case 5: | ||
| 229 | if (!n--) break; | ||
| 230 | regs->r9 = *args++; | ||
| 231 | case 6: | ||
| 232 | if (!n--) break; | ||
| 233 | default: | ||
| 234 | BUG(); | ||
| 235 | break; | ||
| 236 | } | ||
| 237 | } | 161 | } |
| 238 | 162 | ||
| 239 | static inline int syscall_get_arch(void) | 163 | static inline int syscall_get_arch(void) |
diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h index a168bf81c7f4..91dc06d58060 100644 --- a/arch/xtensa/include/asm/syscall.h +++ b/arch/xtensa/include/asm/syscall.h | |||
| @@ -59,45 +59,24 @@ static inline void syscall_set_return_value(struct task_struct *task, | |||
| 59 | 59 | ||
| 60 | static inline void syscall_get_arguments(struct task_struct *task, | 60 | static 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 | 66 | ||
| 68 | if (n == 0) | 67 | for (i = 0; i < 6; ++i) |
| 69 | return; | 68 | args[i] = regs->areg[reg[i]]; |
| 70 | |||
| 71 | WARN_ON_ONCE(i + n > SYSCALL_MAX_ARGS); | ||
| 72 | |||
| 73 | for (j = 0; j < n; ++j) { | ||
| 74 | if (i + j < SYSCALL_MAX_ARGS) | ||
| 75 | args[j] = regs->areg[reg[i + j]]; | ||
| 76 | else | ||
| 77 | args[j] = 0; | ||
| 78 | } | ||
| 79 | } | 69 | } |
| 80 | 70 | ||
| 81 | static inline void syscall_set_arguments(struct task_struct *task, | 71 | static inline void syscall_set_arguments(struct task_struct *task, |
| 82 | struct pt_regs *regs, | 72 | struct pt_regs *regs, |
| 83 | unsigned int i, unsigned int n, | ||
| 84 | const unsigned long *args) | 73 | const unsigned long *args) |
| 85 | { | 74 | { |
| 86 | static const unsigned int reg[] = XTENSA_SYSCALL_ARGUMENT_REGS; | 75 | static const unsigned int reg[] = XTENSA_SYSCALL_ARGUMENT_REGS; |
| 87 | unsigned int j; | 76 | unsigned int i; |
| 88 | |||
| 89 | if (n == 0) | ||
| 90 | return; | ||
| 91 | |||
| 92 | if (WARN_ON_ONCE(i + n > SYSCALL_MAX_ARGS)) { | ||
| 93 | if (i < SYSCALL_MAX_ARGS) | ||
| 94 | n = SYSCALL_MAX_ARGS - i; | ||
| 95 | else | ||
| 96 | return; | ||
| 97 | } | ||
| 98 | 77 | ||
| 99 | for (j = 0; j < n; ++j) | 78 | for (i = 0; i < 6; ++i) |
| 100 | regs->areg[reg[i + j]] = args[j]; | 79 | regs->areg[reg[i]] = args[i]; |
| 101 | } | 80 | } |
| 102 | 81 | ||
| 103 | asmlinkage long xtensa_rt_sigreturn(struct pt_regs*); | 82 | asmlinkage long xtensa_rt_sigreturn(struct pt_regs*); |
diff --git a/fs/proc/base.c b/fs/proc/base.c index ddef482f1334..6a803a0b75df 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
| @@ -616,24 +616,25 @@ static int proc_pid_limits(struct seq_file *m, struct pid_namespace *ns, | |||
| 616 | static int proc_pid_syscall(struct seq_file *m, struct pid_namespace *ns, | 616 | static int proc_pid_syscall(struct seq_file *m, struct pid_namespace *ns, |
| 617 | struct pid *pid, struct task_struct *task) | 617 | struct pid *pid, struct task_struct *task) |
| 618 | { | 618 | { |
| 619 | long nr; | 619 | struct syscall_info info; |
| 620 | unsigned long args[6], sp, pc; | 620 | u64 *args = &info.data.args[0]; |
| 621 | int res; | 621 | int res; |
| 622 | 622 | ||
| 623 | res = lock_trace(task); | 623 | res = lock_trace(task); |
| 624 | if (res) | 624 | if (res) |
| 625 | return res; | 625 | return res; |
| 626 | 626 | ||
| 627 | if (task_current_syscall(task, &nr, args, 6, &sp, &pc)) | 627 | if (task_current_syscall(task, &info)) |
| 628 | seq_puts(m, "running\n"); | 628 | seq_puts(m, "running\n"); |
| 629 | else if (nr < 0) | 629 | else if (info.data.nr < 0) |
| 630 | seq_printf(m, "%ld 0x%lx 0x%lx\n", nr, sp, pc); | 630 | seq_printf(m, "%d 0x%llx 0x%llx\n", |
| 631 | info.data.nr, info.sp, info.data.instruction_pointer); | ||
| 631 | else | 632 | else |
| 632 | seq_printf(m, | 633 | seq_printf(m, |
| 633 | "%ld 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", | 634 | "%d 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx\n", |
| 634 | nr, | 635 | info.data.nr, |
| 635 | args[0], args[1], args[2], args[3], args[4], args[5], | 636 | args[0], args[1], args[2], args[3], args[4], args[5], |
| 636 | sp, pc); | 637 | info.sp, info.data.instruction_pointer); |
| 637 | unlock_trace(task); | 638 | unlock_trace(task); |
| 638 | 639 | ||
| 639 | return 0; | 640 | return 0; |
diff --git a/include/asm-generic/syscall.h b/include/asm-generic/syscall.h index 0c938a4354f6..b88239e9efe4 100644 --- a/include/asm-generic/syscall.h +++ b/include/asm-generic/syscall.h | |||
| @@ -105,41 +105,30 @@ 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 | */ |
| 121 | void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, | 116 | void 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 |
| 126 | * @task: task of interest, must be in system call entry tracing | 121 | * @task: task of interest, must be in system call entry tracing |
| 127 | * @regs: task_pt_regs() of @task | 122 | * @regs: task_pt_regs() of @task |
| 128 | * @i: argument index [0,5] | ||
| 129 | * @n: number of arguments; n+i must be [1,6]. | ||
| 130 | * @args: array of argument values to store | 123 | * @args: array of argument values to store |
| 131 | * | 124 | * |
| 132 | * Changes @n arguments to the system call starting with the @i'th argument. | 125 | * Changes 6 arguments to the system call. |
| 133 | * Argument @i gets value @args[0], and so on. | 126 | * The first argument gets value @args[0], and so on. |
| 134 | * An arch inline version is probably optimal when @i and @n are constants. | ||
| 135 | * | 127 | * |
| 136 | * It's only valid to call this when @task is stopped for tracing on | 128 | * It's only valid to call this when @task is stopped for tracing on |
| 137 | * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT. | 129 | * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT. |
| 138 | * It's invalid to call this with @i + @n > 6; we only support system calls | ||
| 139 | * taking up to 6 arguments. | ||
| 140 | */ | 130 | */ |
| 141 | void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, | 131 | void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, |
| 142 | unsigned int i, unsigned int n, | ||
| 143 | const unsigned long *args); | 132 | const unsigned long *args); |
| 144 | 133 | ||
| 145 | /** | 134 | /** |
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index edb9b040c94c..d5084ebd9f03 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h | |||
| @@ -9,6 +9,13 @@ | |||
| 9 | #include <linux/bug.h> /* For BUG_ON. */ | 9 | #include <linux/bug.h> /* For BUG_ON. */ |
| 10 | #include <linux/pid_namespace.h> /* For task_active_pid_ns. */ | 10 | #include <linux/pid_namespace.h> /* For task_active_pid_ns. */ |
| 11 | #include <uapi/linux/ptrace.h> | 11 | #include <uapi/linux/ptrace.h> |
| 12 | #include <linux/seccomp.h> | ||
| 13 | |||
| 14 | /* Add sp to seccomp_data, as seccomp is user API, we don't want to modify it */ | ||
| 15 | struct syscall_info { | ||
| 16 | __u64 sp; | ||
| 17 | struct seccomp_data data; | ||
| 18 | }; | ||
| 12 | 19 | ||
| 13 | extern int ptrace_access_vm(struct task_struct *tsk, unsigned long addr, | 20 | extern int ptrace_access_vm(struct task_struct *tsk, unsigned long addr, |
| 14 | void *buf, int len, unsigned int gup_flags); | 21 | void *buf, int len, unsigned int gup_flags); |
| @@ -407,9 +414,7 @@ static inline void user_single_step_report(struct pt_regs *regs) | |||
| 407 | #define current_user_stack_pointer() user_stack_pointer(current_pt_regs()) | 414 | #define current_user_stack_pointer() user_stack_pointer(current_pt_regs()) |
| 408 | #endif | 415 | #endif |
| 409 | 416 | ||
| 410 | extern int task_current_syscall(struct task_struct *target, long *callno, | 417 | extern int task_current_syscall(struct task_struct *target, struct syscall_info *info); |
| 411 | unsigned long args[6], unsigned int maxargs, | ||
| 412 | unsigned long *sp, unsigned long *pc); | ||
| 413 | 418 | ||
| 414 | extern void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact); | 419 | extern void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact); |
| 415 | #endif | 420 | #endif |
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 f93a56d2db27..fa8fbff736d6 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
| @@ -314,6 +314,7 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id) | |||
| 314 | struct ring_buffer_event *event; | 314 | struct ring_buffer_event *event; |
| 315 | struct ring_buffer *buffer; | 315 | struct ring_buffer *buffer; |
| 316 | unsigned long irq_flags; | 316 | unsigned long irq_flags; |
| 317 | unsigned long args[6]; | ||
| 317 | int pc; | 318 | int pc; |
| 318 | int syscall_nr; | 319 | int syscall_nr; |
| 319 | int size; | 320 | int size; |
| @@ -347,7 +348,8 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id) | |||
| 347 | 348 | ||
| 348 | entry = ring_buffer_event_data(event); | 349 | entry = ring_buffer_event_data(event); |
| 349 | entry->nr = syscall_nr; | 350 | entry->nr = syscall_nr; |
| 350 | syscall_get_arguments(current, regs, 0, sys_data->nb_args, entry->args); | 351 | syscall_get_arguments(current, regs, args); |
| 352 | memcpy(entry->args, args, sizeof(unsigned long) * sys_data->nb_args); | ||
| 351 | 353 | ||
| 352 | event_trigger_unlock_commit(trace_file, buffer, event, entry, | 354 | event_trigger_unlock_commit(trace_file, buffer, event, entry, |
| 353 | irq_flags, pc); | 355 | irq_flags, pc); |
| @@ -583,6 +585,7 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id) | |||
| 583 | struct syscall_metadata *sys_data; | 585 | struct syscall_metadata *sys_data; |
| 584 | struct syscall_trace_enter *rec; | 586 | struct syscall_trace_enter *rec; |
| 585 | struct hlist_head *head; | 587 | struct hlist_head *head; |
| 588 | unsigned long args[6]; | ||
| 586 | bool valid_prog_array; | 589 | bool valid_prog_array; |
| 587 | int syscall_nr; | 590 | int syscall_nr; |
| 588 | int rctx; | 591 | int rctx; |
| @@ -613,8 +616,8 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id) | |||
| 613 | return; | 616 | return; |
| 614 | 617 | ||
| 615 | rec->nr = syscall_nr; | 618 | rec->nr = syscall_nr; |
| 616 | syscall_get_arguments(current, regs, 0, sys_data->nb_args, | 619 | syscall_get_arguments(current, regs, args); |
| 617 | (unsigned long *)&rec->args); | 620 | memcpy(&rec->args, args, sizeof(unsigned long) * sys_data->nb_args); |
| 618 | 621 | ||
| 619 | if ((valid_prog_array && | 622 | if ((valid_prog_array && |
| 620 | !perf_call_bpf_enter(sys_data->enter_event, regs, sys_data, rec)) || | 623 | !perf_call_bpf_enter(sys_data->enter_event, regs, sys_data, rec)) || |
diff --git a/lib/syscall.c b/lib/syscall.c index 1a7077f20eae..fb328e7ccb08 100644 --- a/lib/syscall.c +++ b/lib/syscall.c | |||
| @@ -5,16 +5,14 @@ | |||
| 5 | #include <linux/export.h> | 5 | #include <linux/export.h> |
| 6 | #include <asm/syscall.h> | 6 | #include <asm/syscall.h> |
| 7 | 7 | ||
| 8 | static int collect_syscall(struct task_struct *target, long *callno, | 8 | static int collect_syscall(struct task_struct *target, struct syscall_info *info) |
| 9 | unsigned long args[6], unsigned int maxargs, | ||
| 10 | unsigned long *sp, unsigned long *pc) | ||
| 11 | { | 9 | { |
| 12 | struct pt_regs *regs; | 10 | struct pt_regs *regs; |
| 13 | 11 | ||
| 14 | if (!try_get_task_stack(target)) { | 12 | if (!try_get_task_stack(target)) { |
| 15 | /* Task has no stack, so the task isn't in a syscall. */ | 13 | /* Task has no stack, so the task isn't in a syscall. */ |
| 16 | *sp = *pc = 0; | 14 | memset(info, 0, sizeof(*info)); |
| 17 | *callno = -1; | 15 | info->data.nr = -1; |
| 18 | return 0; | 16 | return 0; |
| 19 | } | 17 | } |
| 20 | 18 | ||
| @@ -24,12 +22,13 @@ static int collect_syscall(struct task_struct *target, long *callno, | |||
| 24 | return -EAGAIN; | 22 | return -EAGAIN; |
| 25 | } | 23 | } |
| 26 | 24 | ||
| 27 | *sp = user_stack_pointer(regs); | 25 | info->sp = user_stack_pointer(regs); |
| 28 | *pc = instruction_pointer(regs); | 26 | info->data.instruction_pointer = instruction_pointer(regs); |
| 29 | 27 | ||
| 30 | *callno = syscall_get_nr(target, regs); | 28 | info->data.nr = syscall_get_nr(target, regs); |
| 31 | if (*callno != -1L && maxargs > 0) | 29 | if (info->data.nr != -1L) |
| 32 | syscall_get_arguments(target, regs, 0, maxargs, args); | 30 | syscall_get_arguments(target, regs, |
| 31 | (unsigned long *)&info->data.args[0]); | ||
| 33 | 32 | ||
| 34 | put_task_stack(target); | 33 | put_task_stack(target); |
| 35 | return 0; | 34 | return 0; |
| @@ -38,41 +37,35 @@ static int collect_syscall(struct task_struct *target, long *callno, | |||
| 38 | /** | 37 | /** |
| 39 | * task_current_syscall - Discover what a blocked task is doing. | 38 | * task_current_syscall - Discover what a blocked task is doing. |
| 40 | * @target: thread to examine | 39 | * @target: thread to examine |
| 41 | * @callno: filled with system call number or -1 | 40 | * @info: structure with the following fields: |
| 42 | * @args: filled with @maxargs system call arguments | 41 | * .sp - filled with user stack pointer |
| 43 | * @maxargs: number of elements in @args to fill | 42 | * .data.nr - filled with system call number or -1 |
| 44 | * @sp: filled with user stack pointer | 43 | * .data.args - filled with @maxargs system call arguments |
| 45 | * @pc: filled with user PC | 44 | * .data.instruction_pointer - filled with user PC |
| 46 | * | 45 | * |
| 47 | * If @target is blocked in a system call, returns zero with *@callno | 46 | * If @target is blocked in a system call, returns zero with @info.data.nr |
| 48 | * set to the the call's number and @args filled in with its arguments. | 47 | * set to the the call's number and @info.data.args filled in with its |
| 49 | * Registers not used for system call arguments may not be available and | 48 | * arguments. Registers not used for system call arguments may not be available |
| 50 | * it is not kosher to use &struct user_regset calls while the system | 49 | * and it is not kosher to use &struct user_regset calls while the system |
| 51 | * call is still in progress. Note we may get this result if @target | 50 | * call is still in progress. Note we may get this result if @target |
| 52 | * has finished its system call but not yet returned to user mode, such | 51 | * has finished its system call but not yet returned to user mode, such |
| 53 | * as when it's stopped for signal handling or syscall exit tracing. | 52 | * as when it's stopped for signal handling or syscall exit tracing. |
| 54 | * | 53 | * |
| 55 | * If @target is blocked in the kernel during a fault or exception, | 54 | * If @target is blocked in the kernel during a fault or exception, |
| 56 | * returns zero with *@callno set to -1 and does not fill in @args. | 55 | * returns zero with *@info.data.nr set to -1 and does not fill in |
| 57 | * If so, it's now safe to examine @target using &struct user_regset | 56 | * @info.data.args. If so, it's now safe to examine @target using |
| 58 | * get() calls as long as we're sure @target won't return to user mode. | 57 | * &struct user_regset get() calls as long as we're sure @target won't return |
| 58 | * to user mode. | ||
| 59 | * | 59 | * |
| 60 | * Returns -%EAGAIN if @target does not remain blocked. | 60 | * Returns -%EAGAIN if @target does not remain blocked. |
| 61 | * | ||
| 62 | * Returns -%EINVAL if @maxargs is too large (maximum is six). | ||
| 63 | */ | 61 | */ |
| 64 | int task_current_syscall(struct task_struct *target, long *callno, | 62 | int task_current_syscall(struct task_struct *target, struct syscall_info *info) |
| 65 | unsigned long args[6], unsigned int maxargs, | ||
| 66 | unsigned long *sp, unsigned long *pc) | ||
| 67 | { | 63 | { |
| 68 | long state; | 64 | long state; |
| 69 | unsigned long ncsw; | 65 | unsigned long ncsw; |
| 70 | 66 | ||
| 71 | if (unlikely(maxargs > 6)) | ||
| 72 | return -EINVAL; | ||
| 73 | |||
| 74 | if (target == current) | 67 | if (target == current) |
| 75 | return collect_syscall(target, callno, args, maxargs, sp, pc); | 68 | return collect_syscall(target, info); |
| 76 | 69 | ||
| 77 | state = target->state; | 70 | state = target->state; |
| 78 | if (unlikely(!state)) | 71 | if (unlikely(!state)) |
| @@ -80,7 +73,7 @@ int task_current_syscall(struct task_struct *target, long *callno, | |||
| 80 | 73 | ||
| 81 | ncsw = wait_task_inactive(target, state); | 74 | ncsw = wait_task_inactive(target, state); |
| 82 | if (unlikely(!ncsw) || | 75 | if (unlikely(!ncsw) || |
| 83 | unlikely(collect_syscall(target, callno, args, maxargs, sp, pc)) || | 76 | unlikely(collect_syscall(target, info)) || |
| 84 | unlikely(wait_task_inactive(target, state) != ncsw)) | 77 | unlikely(wait_task_inactive(target, state) != ncsw)) |
| 85 | return -EAGAIN; | 78 | return -EAGAIN; |
| 86 | 79 | ||
