Skip to content

Commit 1adce1b

Browse files
committed
Merge tag 'x86_alternatives_for_v6.3_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 asm alternatives updates from Borislav Petkov: - Teach the static_call patching infrastructure to handle conditional tall calls properly which can be static calls too - Add proper struct alt_instr.flags which controls different aspects of insn patching behavior * tag 'x86_alternatives_for_v6.3_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/static_call: Add support for Jcc tail-calls x86/alternatives: Teach text_poke_bp() to patch Jcc.d32 instructions x86/alternatives: Introduce int3_emulate_jcc() x86/alternatives: Add alt_instr.flags
2 parents d9de5ce + 923510c commit 1adce1b

File tree

6 files changed

+218
-115
lines changed

6 files changed

+218
-115
lines changed

arch/x86/include/asm/alternative.h

Lines changed: 76 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
#include <linux/stringify.h>
77
#include <asm/asm.h>
88

9-
#define ALTINSTR_FLAG_INV (1 << 15)
10-
#define ALT_NOT(feat) ((feat) | ALTINSTR_FLAG_INV)
9+
#define ALT_FLAGS_SHIFT 16
10+
11+
#define ALT_FLAG_NOT BIT(0)
12+
#define ALT_NOT(feature) ((ALT_FLAG_NOT << ALT_FLAGS_SHIFT) | (feature))
1113

1214
#ifndef __ASSEMBLY__
1315

@@ -59,10 +61,27 @@
5961
".long 999b - .\n\t" \
6062
".popsection\n\t"
6163

64+
/*
65+
* The patching flags are part of the upper bits of the @ft_flags parameter when
66+
* specifying them. The split is currently like this:
67+
*
68+
* [31... flags ...16][15... CPUID feature bit ...0]
69+
*
70+
* but since this is all hidden in the macros argument being split, those fields can be
71+
* extended in the future to fit in a u64 or however the need arises.
72+
*/
6273
struct alt_instr {
6374
s32 instr_offset; /* original instruction */
6475
s32 repl_offset; /* offset to replacement instruction */
65-
u16 cpuid; /* cpuid bit set for replacement */
76+
77+
union {
78+
struct {
79+
u32 cpuid: 16; /* CPUID bit set for replacement */
80+
u32 flags: 16; /* patching control flags */
81+
};
82+
u32 ft_flags;
83+
};
84+
6685
u8 instrlen; /* length of original instruction */
6786
u8 replacementlen; /* length of new instruction */
6887
} __packed;
@@ -182,10 +201,10 @@ static inline int alternatives_text_reserved(void *start, void *end)
182201
" - (" alt_slen ")), 0x90\n" \
183202
alt_end_marker ":\n"
184203

185-
#define ALTINSTR_ENTRY(feature, num) \
204+
#define ALTINSTR_ENTRY(ft_flags, num) \
186205
" .long 661b - .\n" /* label */ \
187206
" .long " b_replacement(num)"f - .\n" /* new instruction */ \
188-
" .word " __stringify(feature) "\n" /* feature bit */ \
207+
" .4byte " __stringify(ft_flags) "\n" /* feature + flags */ \
189208
" .byte " alt_total_slen "\n" /* source len */ \
190209
" .byte " alt_rlen(num) "\n" /* replacement len */
191210

@@ -194,42 +213,43 @@ static inline int alternatives_text_reserved(void *start, void *end)
194213
b_replacement(num)":\n\t" newinstr "\n" e_replacement(num) ":\n"
195214

196215
/* alternative assembly primitive: */
197-
#define ALTERNATIVE(oldinstr, newinstr, feature) \
216+
#define ALTERNATIVE(oldinstr, newinstr, ft_flags) \
198217
OLDINSTR(oldinstr, 1) \
199218
".pushsection .altinstructions,\"a\"\n" \
200-
ALTINSTR_ENTRY(feature, 1) \
219+
ALTINSTR_ENTRY(ft_flags, 1) \
201220
".popsection\n" \
202221
".pushsection .altinstr_replacement, \"ax\"\n" \
203222
ALTINSTR_REPLACEMENT(newinstr, 1) \
204223
".popsection\n"
205224

206-
#define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\
225+
#define ALTERNATIVE_2(oldinstr, newinstr1, ft_flags1, newinstr2, ft_flags2) \
207226
OLDINSTR_2(oldinstr, 1, 2) \
208227
".pushsection .altinstructions,\"a\"\n" \
209-
ALTINSTR_ENTRY(feature1, 1) \
210-
ALTINSTR_ENTRY(feature2, 2) \
228+
ALTINSTR_ENTRY(ft_flags1, 1) \
229+
ALTINSTR_ENTRY(ft_flags2, 2) \
211230
".popsection\n" \
212231
".pushsection .altinstr_replacement, \"ax\"\n" \
213232
ALTINSTR_REPLACEMENT(newinstr1, 1) \
214233
ALTINSTR_REPLACEMENT(newinstr2, 2) \
215234
".popsection\n"
216235

217236
/* If @feature is set, patch in @newinstr_yes, otherwise @newinstr_no. */
218-
#define ALTERNATIVE_TERNARY(oldinstr, feature, newinstr_yes, newinstr_no) \
237+
#define ALTERNATIVE_TERNARY(oldinstr, ft_flags, newinstr_yes, newinstr_no) \
219238
ALTERNATIVE_2(oldinstr, newinstr_no, X86_FEATURE_ALWAYS, \
220-
newinstr_yes, feature)
221-
222-
#define ALTERNATIVE_3(oldinsn, newinsn1, feat1, newinsn2, feat2, newinsn3, feat3) \
223-
OLDINSTR_3(oldinsn, 1, 2, 3) \
224-
".pushsection .altinstructions,\"a\"\n" \
225-
ALTINSTR_ENTRY(feat1, 1) \
226-
ALTINSTR_ENTRY(feat2, 2) \
227-
ALTINSTR_ENTRY(feat3, 3) \
228-
".popsection\n" \
229-
".pushsection .altinstr_replacement, \"ax\"\n" \
230-
ALTINSTR_REPLACEMENT(newinsn1, 1) \
231-
ALTINSTR_REPLACEMENT(newinsn2, 2) \
232-
ALTINSTR_REPLACEMENT(newinsn3, 3) \
239+
newinstr_yes, ft_flags)
240+
241+
#define ALTERNATIVE_3(oldinsn, newinsn1, ft_flags1, newinsn2, ft_flags2, \
242+
newinsn3, ft_flags3) \
243+
OLDINSTR_3(oldinsn, 1, 2, 3) \
244+
".pushsection .altinstructions,\"a\"\n" \
245+
ALTINSTR_ENTRY(ft_flags1, 1) \
246+
ALTINSTR_ENTRY(ft_flags2, 2) \
247+
ALTINSTR_ENTRY(ft_flags3, 3) \
248+
".popsection\n" \
249+
".pushsection .altinstr_replacement, \"ax\"\n" \
250+
ALTINSTR_REPLACEMENT(newinsn1, 1) \
251+
ALTINSTR_REPLACEMENT(newinsn2, 2) \
252+
ALTINSTR_REPLACEMENT(newinsn3, 3) \
233253
".popsection\n"
234254

235255
/*
@@ -244,14 +264,14 @@ static inline int alternatives_text_reserved(void *start, void *end)
244264
* For non barrier like inlines please define new variants
245265
* without volatile and memory clobber.
246266
*/
247-
#define alternative(oldinstr, newinstr, feature) \
248-
asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, feature) : : : "memory")
267+
#define alternative(oldinstr, newinstr, ft_flags) \
268+
asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, ft_flags) : : : "memory")
249269

250-
#define alternative_2(oldinstr, newinstr1, feature1, newinstr2, feature2) \
251-
asm_inline volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2) ::: "memory")
270+
#define alternative_2(oldinstr, newinstr1, ft_flags1, newinstr2, ft_flags2) \
271+
asm_inline volatile(ALTERNATIVE_2(oldinstr, newinstr1, ft_flags1, newinstr2, ft_flags2) ::: "memory")
252272

253-
#define alternative_ternary(oldinstr, feature, newinstr_yes, newinstr_no) \
254-
asm_inline volatile(ALTERNATIVE_TERNARY(oldinstr, feature, newinstr_yes, newinstr_no) ::: "memory")
273+
#define alternative_ternary(oldinstr, ft_flags, newinstr_yes, newinstr_no) \
274+
asm_inline volatile(ALTERNATIVE_TERNARY(oldinstr, ft_flags, newinstr_yes, newinstr_no) ::: "memory")
255275

256276
/*
257277
* Alternative inline assembly with input.
@@ -261,8 +281,8 @@ static inline int alternatives_text_reserved(void *start, void *end)
261281
* Argument numbers start with 1.
262282
* Leaving an unused argument 0 to keep API compatibility.
263283
*/
264-
#define alternative_input(oldinstr, newinstr, feature, input...) \
265-
asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, feature) \
284+
#define alternative_input(oldinstr, newinstr, ft_flags, input...) \
285+
asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, ft_flags) \
266286
: : "i" (0), ## input)
267287

268288
/*
@@ -273,20 +293,20 @@ static inline int alternatives_text_reserved(void *start, void *end)
273293
* Otherwise, if CPU has feature1, newinstr1 is used.
274294
* Otherwise, oldinstr is used.
275295
*/
276-
#define alternative_input_2(oldinstr, newinstr1, feature1, newinstr2, \
277-
feature2, input...) \
278-
asm_inline volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1, \
279-
newinstr2, feature2) \
296+
#define alternative_input_2(oldinstr, newinstr1, ft_flags1, newinstr2, \
297+
ft_flags2, input...) \
298+
asm_inline volatile(ALTERNATIVE_2(oldinstr, newinstr1, ft_flags1, \
299+
newinstr2, ft_flags2) \
280300
: : "i" (0), ## input)
281301

282302
/* Like alternative_input, but with a single output argument */
283-
#define alternative_io(oldinstr, newinstr, feature, output, input...) \
284-
asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, feature) \
303+
#define alternative_io(oldinstr, newinstr, ft_flags, output, input...) \
304+
asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, ft_flags) \
285305
: output : "i" (0), ## input)
286306

287307
/* Like alternative_io, but for replacing a direct call with another one. */
288-
#define alternative_call(oldfunc, newfunc, feature, output, input...) \
289-
asm_inline volatile (ALTERNATIVE("call %P[old]", "call %P[new]", feature) \
308+
#define alternative_call(oldfunc, newfunc, ft_flags, output, input...) \
309+
asm_inline volatile (ALTERNATIVE("call %P[old]", "call %P[new]", ft_flags) \
290310
: output : [old] "i" (oldfunc), [new] "i" (newfunc), ## input)
291311

292312
/*
@@ -295,10 +315,10 @@ static inline int alternatives_text_reserved(void *start, void *end)
295315
* Otherwise, if CPU has feature1, function1 is used.
296316
* Otherwise, old function is used.
297317
*/
298-
#define alternative_call_2(oldfunc, newfunc1, feature1, newfunc2, feature2, \
318+
#define alternative_call_2(oldfunc, newfunc1, ft_flags1, newfunc2, ft_flags2, \
299319
output, input...) \
300-
asm_inline volatile (ALTERNATIVE_2("call %P[old]", "call %P[new1]", feature1,\
301-
"call %P[new2]", feature2) \
320+
asm_inline volatile (ALTERNATIVE_2("call %P[old]", "call %P[new1]", ft_flags1,\
321+
"call %P[new2]", ft_flags2) \
302322
: output, ASM_CALL_CONSTRAINT \
303323
: [old] "i" (oldfunc), [new1] "i" (newfunc1), \
304324
[new2] "i" (newfunc2), ## input)
@@ -347,10 +367,10 @@ static inline int alternatives_text_reserved(void *start, void *end)
347367
* enough information for the alternatives patching code to patch an
348368
* instruction. See apply_alternatives().
349369
*/
350-
.macro altinstruction_entry orig alt feature orig_len alt_len
370+
.macro altinstr_entry orig alt ft_flags orig_len alt_len
351371
.long \orig - .
352372
.long \alt - .
353-
.word \feature
373+
.4byte \ft_flags
354374
.byte \orig_len
355375
.byte \alt_len
356376
.endm
@@ -361,15 +381,15 @@ static inline int alternatives_text_reserved(void *start, void *end)
361381
* @newinstr. ".skip" directive takes care of proper instruction padding
362382
* in case @newinstr is longer than @oldinstr.
363383
*/
364-
.macro ALTERNATIVE oldinstr, newinstr, feature
384+
.macro ALTERNATIVE oldinstr, newinstr, ft_flags
365385
140:
366386
\oldinstr
367387
141:
368388
.skip -(((144f-143f)-(141b-140b)) > 0) * ((144f-143f)-(141b-140b)),0x90
369389
142:
370390

371391
.pushsection .altinstructions,"a"
372-
altinstruction_entry 140b,143f,\feature,142b-140b,144f-143f
392+
altinstr_entry 140b,143f,\ft_flags,142b-140b,144f-143f
373393
.popsection
374394

375395
.pushsection .altinstr_replacement,"ax"
@@ -399,7 +419,7 @@ static inline int alternatives_text_reserved(void *start, void *end)
399419
* has @feature1, it replaces @oldinstr with @newinstr1. If CPU has
400420
* @feature2, it replaces @oldinstr with @feature2.
401421
*/
402-
.macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2
422+
.macro ALTERNATIVE_2 oldinstr, newinstr1, ft_flags1, newinstr2, ft_flags2
403423
140:
404424
\oldinstr
405425
141:
@@ -408,8 +428,8 @@ static inline int alternatives_text_reserved(void *start, void *end)
408428
142:
409429

410430
.pushsection .altinstructions,"a"
411-
altinstruction_entry 140b,143f,\feature1,142b-140b,144f-143f
412-
altinstruction_entry 140b,144f,\feature2,142b-140b,145f-144f
431+
altinstr_entry 140b,143f,\ft_flags1,142b-140b,144f-143f
432+
altinstr_entry 140b,144f,\ft_flags2,142b-140b,145f-144f
413433
.popsection
414434

415435
.pushsection .altinstr_replacement,"ax"
@@ -421,7 +441,7 @@ static inline int alternatives_text_reserved(void *start, void *end)
421441
.popsection
422442
.endm
423443

424-
.macro ALTERNATIVE_3 oldinstr, newinstr1, feature1, newinstr2, feature2, newinstr3, feature3
444+
.macro ALTERNATIVE_3 oldinstr, newinstr1, ft_flags1, newinstr2, ft_flags2, newinstr3, ft_flags3
425445
140:
426446
\oldinstr
427447
141:
@@ -430,9 +450,9 @@ static inline int alternatives_text_reserved(void *start, void *end)
430450
142:
431451

432452
.pushsection .altinstructions,"a"
433-
altinstruction_entry 140b,143f,\feature1,142b-140b,144f-143f
434-
altinstruction_entry 140b,144f,\feature2,142b-140b,145f-144f
435-
altinstruction_entry 140b,145f,\feature3,142b-140b,146f-145f
453+
altinstr_entry 140b,143f,\ft_flags1,142b-140b,144f-143f
454+
altinstr_entry 140b,144f,\ft_flags2,142b-140b,145f-144f
455+
altinstr_entry 140b,145f,\ft_flags3,142b-140b,146f-145f
436456
.popsection
437457

438458
.pushsection .altinstr_replacement,"ax"
@@ -447,9 +467,9 @@ static inline int alternatives_text_reserved(void *start, void *end)
447467
.endm
448468

449469
/* If @feature is set, patch in @newinstr_yes, otherwise @newinstr_no. */
450-
#define ALTERNATIVE_TERNARY(oldinstr, feature, newinstr_yes, newinstr_no) \
470+
#define ALTERNATIVE_TERNARY(oldinstr, ft_flags, newinstr_yes, newinstr_no) \
451471
ALTERNATIVE_2 oldinstr, newinstr_no, X86_FEATURE_ALWAYS, \
452-
newinstr_yes, feature
472+
newinstr_yes, ft_flags
453473

454474
#endif /* __ASSEMBLY__ */
455475

arch/x86/include/asm/text-patching.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,37 @@ void int3_emulate_ret(struct pt_regs *regs)
184184
unsigned long ip = int3_emulate_pop(regs);
185185
int3_emulate_jmp(regs, ip);
186186
}
187+
188+
static __always_inline
189+
void int3_emulate_jcc(struct pt_regs *regs, u8 cc, unsigned long ip, unsigned long disp)
190+
{
191+
static const unsigned long jcc_mask[6] = {
192+
[0] = X86_EFLAGS_OF,
193+
[1] = X86_EFLAGS_CF,
194+
[2] = X86_EFLAGS_ZF,
195+
[3] = X86_EFLAGS_CF | X86_EFLAGS_ZF,
196+
[4] = X86_EFLAGS_SF,
197+
[5] = X86_EFLAGS_PF,
198+
};
199+
200+
bool invert = cc & 1;
201+
bool match;
202+
203+
if (cc < 0xc) {
204+
match = regs->flags & jcc_mask[cc >> 1];
205+
} else {
206+
match = ((regs->flags & X86_EFLAGS_SF) >> X86_EFLAGS_SF_BIT) ^
207+
((regs->flags & X86_EFLAGS_OF) >> X86_EFLAGS_OF_BIT);
208+
if (cc >= 0xe)
209+
match = match || (regs->flags & X86_EFLAGS_ZF);
210+
}
211+
212+
if ((match && !invert) || (!match && invert))
213+
ip += disp;
214+
215+
int3_emulate_jmp(regs, ip);
216+
}
217+
187218
#endif /* !CONFIG_UML_X86 */
188219

189220
#endif /* _ASM_X86_TEXT_PATCHING_H */

0 commit comments

Comments
 (0)