diff options
author | Denys Vlasenko <dvlasenk@redhat.com> | 2015-02-26 17:40:27 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-03-04 16:50:49 -0500 |
commit | 76f5df43cab5e765c0bd42289103e8f625813ae1 (patch) | |
tree | f83868c1222fe87789a149bd66ae726f919a9f3d /arch/x86/include | |
parent | 6e1327bd2b20ccb387fcddc0caa605cb253cc458 (diff) |
x86/asm/entry/64: Always allocate a complete "struct pt_regs" on the kernel stack
The 64-bit entry code was using six stack slots less by not
saving/restoring registers which are callee-preserved according
to the C ABI, and was not allocating space for them.
Only when syscalls needed a complete "struct pt_regs" was
the complete area allocated and filled in.
As an additional twist, on interrupt entry a "slightly less
truncated pt_regs" trick is used, to make nested interrupt
stacks easier to unwind.
This proved to be a source of significant obfuscation and subtle
bugs. For example, 'stub_fork' had to pop the return address,
extend the struct, save registers, and push return address back.
Ugly. 'ia32_ptregs_common' pops return address and "returns" via
jmp insn, throwing a wrench into CPU return stack cache.
This patch changes the code to always allocate a complete
"struct pt_regs" on the kernel stack. The saving of registers
is still done lazily.
"Partial pt_regs" trick on interrupt stack is retained.
Macros which manipulate "struct pt_regs" on stack are reworked:
- ALLOC_PT_GPREGS_ON_STACK allocates the structure.
- SAVE_C_REGS saves to it those registers which are clobbered
by C code.
- SAVE_EXTRA_REGS saves to it all other registers.
- Corresponding RESTORE_* and REMOVE_PT_GPREGS_FROM_STACK macros
reverse it.
'ia32_ptregs_common', 'stub_fork' and friends lost their ugly dance
with the return pointer.
LOAD_ARGS32 in ia32entry.S now uses symbolic stack offsets
instead of magic numbers.
'error_entry' and 'save_paranoid' now use SAVE_C_REGS +
SAVE_EXTRA_REGS instead of having it open-coded yet again.
Patch was run-tested: 64-bit executables, 32-bit executables,
strace works.
Timing tests did not show measurable difference in 32-bit
and 64-bit syscalls.
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
Cc: Alexei Starovoitov <ast@plumgrid.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Will Drewry <wad@chromium.org>
Link: http://lkml.kernel.org/r/1423778052-21038-2-git-send-email-dvlasenk@redhat.com
Link: http://lkml.kernel.org/r/b89763d354aa23e670b9bdf3a40ae320320a7c2e.1424989793.git.luto@amacapital.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/include')
-rw-r--r-- | arch/x86/include/asm/calling.h | 222 | ||||
-rw-r--r-- | arch/x86/include/asm/irqflags.h | 4 | ||||
-rw-r--r-- | arch/x86/include/uapi/asm/ptrace-abi.h | 1 |
3 files changed, 110 insertions, 117 deletions
diff --git a/arch/x86/include/asm/calling.h b/arch/x86/include/asm/calling.h index 3c711f2ab236..38356476b131 100644 --- a/arch/x86/include/asm/calling.h +++ b/arch/x86/include/asm/calling.h | |||
@@ -55,143 +55,137 @@ For 32-bit we have the following conventions - kernel is built with | |||
55 | * for assembly code: | 55 | * for assembly code: |
56 | */ | 56 | */ |
57 | 57 | ||
58 | #define R15 0 | 58 | /* The layout forms the "struct pt_regs" on the stack: */ |
59 | #define R14 8 | 59 | /* |
60 | #define R13 16 | 60 | * C ABI says these regs are callee-preserved. They aren't saved on kernel entry |
61 | #define R12 24 | 61 | * unless syscall needs a complete, fully filled "struct pt_regs". |
62 | #define RBP 32 | 62 | */ |
63 | #define RBX 40 | 63 | #define R15 0*8 |
64 | 64 | #define R14 1*8 | |
65 | /* arguments: interrupts/non tracing syscalls only save up to here: */ | 65 | #define R13 2*8 |
66 | #define R11 48 | 66 | #define R12 3*8 |
67 | #define R10 56 | 67 | #define RBP 4*8 |
68 | #define R9 64 | 68 | #define RBX 5*8 |
69 | #define R8 72 | 69 | /* These regs are callee-clobbered. Always saved on kernel entry. */ |
70 | #define RAX 80 | 70 | #define R11 6*8 |
71 | #define RCX 88 | 71 | #define R10 7*8 |
72 | #define RDX 96 | 72 | #define R9 8*8 |
73 | #define RSI 104 | 73 | #define R8 9*8 |
74 | #define RDI 112 | 74 | #define RAX 10*8 |
75 | #define ORIG_RAX 120 /* + error_code */ | 75 | #define RCX 11*8 |
76 | /* end of arguments */ | 76 | #define RDX 12*8 |
77 | 77 | #define RSI 13*8 | |
78 | /* cpu exception frame or undefined in case of fast syscall: */ | 78 | #define RDI 14*8 |
79 | #define RIP 128 | 79 | /* |
80 | #define CS 136 | 80 | * On syscall entry, this is syscall#. On CPU exception, this is error code. |
81 | #define EFLAGS 144 | 81 | * On hw interrupt, it's IRQ number: |
82 | #define RSP 152 | 82 | */ |
83 | #define SS 160 | 83 | #define ORIG_RAX 15*8 |
84 | 84 | /* Return frame for iretq */ | |
85 | #define ARGOFFSET R11 | 85 | #define RIP 16*8 |
86 | 86 | #define CS 17*8 | |
87 | .macro SAVE_ARGS addskip=0, save_rcx=1, save_r891011=1, rax_enosys=0 | 87 | #define EFLAGS 18*8 |
88 | subq $9*8+\addskip, %rsp | 88 | #define RSP 19*8 |
89 | CFI_ADJUST_CFA_OFFSET 9*8+\addskip | 89 | #define SS 20*8 |
90 | movq_cfi rdi, 8*8 | 90 | |
91 | movq_cfi rsi, 7*8 | 91 | #define ARGOFFSET 0 |
92 | movq_cfi rdx, 6*8 | 92 | |
93 | 93 | .macro ALLOC_PT_GPREGS_ON_STACK addskip=0 | |
94 | .if \save_rcx | 94 | subq $15*8+\addskip, %rsp |
95 | movq_cfi rcx, 5*8 | 95 | CFI_ADJUST_CFA_OFFSET 15*8+\addskip |
96 | .endif | 96 | .endm |
97 | 97 | ||
98 | .if \rax_enosys | 98 | .macro SAVE_C_REGS_HELPER offset=0 rax=1 rcx=1 r8plus=1 |
99 | movq $-ENOSYS, 4*8(%rsp) | 99 | .if \r8plus |
100 | .else | 100 | movq_cfi r11, 6*8+\offset |
101 | movq_cfi rax, 4*8 | 101 | movq_cfi r10, 7*8+\offset |
102 | movq_cfi r9, 8*8+\offset | ||
103 | movq_cfi r8, 9*8+\offset | ||
102 | .endif | 104 | .endif |
103 | 105 | .if \rax | |
104 | .if \save_r891011 | 106 | movq_cfi rax, 10*8+\offset |
105 | movq_cfi r8, 3*8 | 107 | .endif |
106 | movq_cfi r9, 2*8 | 108 | .if \rcx |
107 | movq_cfi r10, 1*8 | 109 | movq_cfi rcx, 11*8+\offset |
108 | movq_cfi r11, 0*8 | ||
109 | .endif | 110 | .endif |
111 | movq_cfi rdx, 12*8+\offset | ||
112 | movq_cfi rsi, 13*8+\offset | ||
113 | movq_cfi rdi, 14*8+\offset | ||
114 | .endm | ||
115 | .macro SAVE_C_REGS offset=0 | ||
116 | SAVE_C_REGS_HELPER \offset, 1, 1, 1 | ||
117 | .endm | ||
118 | .macro SAVE_C_REGS_EXCEPT_RAX_RCX offset=0 | ||
119 | SAVE_C_REGS_HELPER \offset, 0, 0, 1 | ||
120 | .endm | ||
121 | .macro SAVE_C_REGS_EXCEPT_R891011 | ||
122 | SAVE_C_REGS_HELPER 0, 1, 1, 0 | ||
123 | .endm | ||
124 | .macro SAVE_C_REGS_EXCEPT_RCX_R891011 | ||
125 | SAVE_C_REGS_HELPER 0, 1, 0, 0 | ||
126 | .endm | ||
110 | 127 | ||
128 | .macro SAVE_EXTRA_REGS offset=0 | ||
129 | movq_cfi r15, 0*8+\offset | ||
130 | movq_cfi r14, 1*8+\offset | ||
131 | movq_cfi r13, 2*8+\offset | ||
132 | movq_cfi r12, 3*8+\offset | ||
133 | movq_cfi rbp, 4*8+\offset | ||
134 | movq_cfi rbx, 5*8+\offset | ||
135 | .endm | ||
136 | .macro SAVE_EXTRA_REGS_RBP offset=0 | ||
137 | movq_cfi rbp, 4*8+\offset | ||
111 | .endm | 138 | .endm |
112 | 139 | ||
113 | #define ARG_SKIP (9*8) | 140 | .macro RESTORE_EXTRA_REGS offset=0 |
141 | movq_cfi_restore 0*8+\offset, r15 | ||
142 | movq_cfi_restore 1*8+\offset, r14 | ||
143 | movq_cfi_restore 2*8+\offset, r13 | ||
144 | movq_cfi_restore 3*8+\offset, r12 | ||
145 | movq_cfi_restore 4*8+\offset, rbp | ||
146 | movq_cfi_restore 5*8+\offset, rbx | ||
147 | .endm | ||
114 | 148 | ||
115 | .macro RESTORE_ARGS rstor_rax=1, addskip=0, rstor_rcx=1, rstor_r11=1, \ | 149 | .macro RESTORE_C_REGS_HELPER rstor_rax=1, rstor_rcx=1, rstor_r11=1, rstor_r8910=1, rstor_rdx=1 |
116 | rstor_r8910=1, rstor_rdx=1 | ||
117 | .if \rstor_r11 | 150 | .if \rstor_r11 |
118 | movq_cfi_restore 0*8, r11 | 151 | movq_cfi_restore 6*8, r11 |
119 | .endif | 152 | .endif |
120 | |||
121 | .if \rstor_r8910 | 153 | .if \rstor_r8910 |
122 | movq_cfi_restore 1*8, r10 | 154 | movq_cfi_restore 7*8, r10 |
123 | movq_cfi_restore 2*8, r9 | 155 | movq_cfi_restore 8*8, r9 |
124 | movq_cfi_restore 3*8, r8 | 156 | movq_cfi_restore 9*8, r8 |
125 | .endif | 157 | .endif |
126 | |||
127 | .if \rstor_rax | 158 | .if \rstor_rax |
128 | movq_cfi_restore 4*8, rax | 159 | movq_cfi_restore 10*8, rax |
129 | .endif | 160 | .endif |
130 | |||
131 | .if \rstor_rcx | 161 | .if \rstor_rcx |
132 | movq_cfi_restore 5*8, rcx | 162 | movq_cfi_restore 11*8, rcx |
133 | .endif | 163 | .endif |
134 | |||
135 | .if \rstor_rdx | 164 | .if \rstor_rdx |
136 | movq_cfi_restore 6*8, rdx | 165 | movq_cfi_restore 12*8, rdx |
137 | .endif | ||
138 | |||
139 | movq_cfi_restore 7*8, rsi | ||
140 | movq_cfi_restore 8*8, rdi | ||
141 | |||
142 | .if ARG_SKIP+\addskip > 0 | ||
143 | addq $ARG_SKIP+\addskip, %rsp | ||
144 | CFI_ADJUST_CFA_OFFSET -(ARG_SKIP+\addskip) | ||
145 | .endif | 166 | .endif |
167 | movq_cfi_restore 13*8, rsi | ||
168 | movq_cfi_restore 14*8, rdi | ||
146 | .endm | 169 | .endm |
147 | 170 | .macro RESTORE_C_REGS | |
148 | .macro LOAD_ARGS offset, skiprax=0 | 171 | RESTORE_C_REGS_HELPER 1,1,1,1,1 |
149 | movq \offset(%rsp), %r11 | ||
150 | movq \offset+8(%rsp), %r10 | ||
151 | movq \offset+16(%rsp), %r9 | ||
152 | movq \offset+24(%rsp), %r8 | ||
153 | movq \offset+40(%rsp), %rcx | ||
154 | movq \offset+48(%rsp), %rdx | ||
155 | movq \offset+56(%rsp), %rsi | ||
156 | movq \offset+64(%rsp), %rdi | ||
157 | .if \skiprax | ||
158 | .else | ||
159 | movq \offset+72(%rsp), %rax | ||
160 | .endif | ||
161 | .endm | 172 | .endm |
162 | 173 | .macro RESTORE_C_REGS_EXCEPT_RAX | |
163 | #define REST_SKIP (6*8) | 174 | RESTORE_C_REGS_HELPER 0,1,1,1,1 |
164 | |||
165 | .macro SAVE_REST | ||
166 | subq $REST_SKIP, %rsp | ||
167 | CFI_ADJUST_CFA_OFFSET REST_SKIP | ||
168 | movq_cfi rbx, 5*8 | ||
169 | movq_cfi rbp, 4*8 | ||
170 | movq_cfi r12, 3*8 | ||
171 | movq_cfi r13, 2*8 | ||
172 | movq_cfi r14, 1*8 | ||
173 | movq_cfi r15, 0*8 | ||
174 | .endm | 175 | .endm |
175 | 176 | .macro RESTORE_C_REGS_EXCEPT_RCX | |
176 | .macro RESTORE_REST | 177 | RESTORE_C_REGS_HELPER 1,0,1,1,1 |
177 | movq_cfi_restore 0*8, r15 | ||
178 | movq_cfi_restore 1*8, r14 | ||
179 | movq_cfi_restore 2*8, r13 | ||
180 | movq_cfi_restore 3*8, r12 | ||
181 | movq_cfi_restore 4*8, rbp | ||
182 | movq_cfi_restore 5*8, rbx | ||
183 | addq $REST_SKIP, %rsp | ||
184 | CFI_ADJUST_CFA_OFFSET -(REST_SKIP) | ||
185 | .endm | 178 | .endm |
186 | 179 | .macro RESTORE_RSI_RDI | |
187 | .macro SAVE_ALL | 180 | RESTORE_C_REGS_HELPER 0,0,0,0,0 |
188 | SAVE_ARGS | 181 | .endm |
189 | SAVE_REST | 182 | .macro RESTORE_RSI_RDI_RDX |
183 | RESTORE_C_REGS_HELPER 0,0,0,0,1 | ||
190 | .endm | 184 | .endm |
191 | 185 | ||
192 | .macro RESTORE_ALL addskip=0 | 186 | .macro REMOVE_PT_GPREGS_FROM_STACK addskip=0 |
193 | RESTORE_REST | 187 | addq $15*8+\addskip, %rsp |
194 | RESTORE_ARGS 1, \addskip | 188 | CFI_ADJUST_CFA_OFFSET -(15*8+\addskip) |
195 | .endm | 189 | .endm |
196 | 190 | ||
197 | .macro icebp | 191 | .macro icebp |
diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h index 0a8b519226b8..021bee9b86b6 100644 --- a/arch/x86/include/asm/irqflags.h +++ b/arch/x86/include/asm/irqflags.h | |||
@@ -171,9 +171,9 @@ static inline int arch_irqs_disabled(void) | |||
171 | #define ARCH_LOCKDEP_SYS_EXIT_IRQ \ | 171 | #define ARCH_LOCKDEP_SYS_EXIT_IRQ \ |
172 | TRACE_IRQS_ON; \ | 172 | TRACE_IRQS_ON; \ |
173 | sti; \ | 173 | sti; \ |
174 | SAVE_REST; \ | 174 | SAVE_EXTRA_REGS; \ |
175 | LOCKDEP_SYS_EXIT; \ | 175 | LOCKDEP_SYS_EXIT; \ |
176 | RESTORE_REST; \ | 176 | RESTORE_EXTRA_REGS; \ |
177 | cli; \ | 177 | cli; \ |
178 | TRACE_IRQS_OFF; | 178 | TRACE_IRQS_OFF; |
179 | 179 | ||
diff --git a/arch/x86/include/uapi/asm/ptrace-abi.h b/arch/x86/include/uapi/asm/ptrace-abi.h index 7b0a55a88851..ad115bf779f3 100644 --- a/arch/x86/include/uapi/asm/ptrace-abi.h +++ b/arch/x86/include/uapi/asm/ptrace-abi.h | |||
@@ -49,7 +49,6 @@ | |||
49 | #define EFLAGS 144 | 49 | #define EFLAGS 144 |
50 | #define RSP 152 | 50 | #define RSP 152 |
51 | #define SS 160 | 51 | #define SS 160 |
52 | #define ARGOFFSET R11 | ||
53 | #endif /* __ASSEMBLY__ */ | 52 | #endif /* __ASSEMBLY__ */ |
54 | 53 | ||
55 | /* top of stack page */ | 54 | /* top of stack page */ |