x86/jump-label: Add safety checks to jump label conversions
authorSteven Rostedt <srostedt@redhat.com>
Thu, 26 Jan 2012 23:38:07 +0000 (18:38 -0500)
committerSteven Rostedt <rostedt@goodmis.org>
Wed, 7 Aug 2013 01:43:20 +0000 (21:43 -0400)
As with all modifying of kernel text, we need to be very paranoid.

When converting the jump label locations to and from nops to jumps
a check has been added to make sure what we are replacing is what we
expect, otherwise we bug.

Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jason Baron <jbaron@redhat.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
arch/x86/kernel/jump_label.c

index ae3d8fb..24cf2b2 100644 (file)
@@ -26,16 +26,40 @@ union jump_code_union {
 
 static void __jump_label_transform(struct jump_entry *entry,
                                   enum jump_label_type type,
-                                  void *(*poker)(void *, const void *, size_t))
+                                  void *(*poker)(void *, const void *, size_t),
+                                  int init)
 {
        union jump_code_union code;
+       const unsigned char *ideal_nop = ideal_nops[NOP_ATOMIC5];
 
        if (type == JUMP_LABEL_ENABLE) {
+               /*
+                * We are enabling this jump label. If it is not a nop
+                * then something must have gone wrong.
+                */
+               BUG_ON(memcmp((void *)entry->code, ideal_nop, 5) != 0);
+
                code.jump = 0xe9;
                code.offset = entry->target -
                                (entry->code + JUMP_LABEL_NOP_SIZE);
-       } else
+       } else {
+               /*
+                * We are disabling this jump label. If it is not what
+                * we think it is, then something must have gone wrong.
+                * If this is the first initialization call, then we
+                * are converting the default nop to the ideal nop.
+                */
+               if (init) {
+                       const unsigned char default_nop[] = { STATIC_KEY_INIT_NOP };
+                       BUG_ON(memcmp((void *)entry->code, default_nop, 5) != 0);
+               } else {
+                       code.jump = 0xe9;
+                       code.offset = entry->target -
+                               (entry->code + JUMP_LABEL_NOP_SIZE);
+                       BUG_ON(memcmp((void *)entry->code, &code, 5) != 0);
+               }
                memcpy(&code, ideal_nops[NOP_ATOMIC5], JUMP_LABEL_NOP_SIZE);
+       }
 
        (*poker)((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE);
 }
@@ -45,7 +69,7 @@ void arch_jump_label_transform(struct jump_entry *entry,
 {
        get_online_cpus();
        mutex_lock(&text_mutex);
-       __jump_label_transform(entry, type, text_poke_smp);
+       __jump_label_transform(entry, type, text_poke_smp, 0);
        mutex_unlock(&text_mutex);
        put_online_cpus();
 }
@@ -76,7 +100,7 @@ __init_or_module void arch_jump_label_transform_static(struct jump_entry *entry,
                        jlstate = JL_STATE_NO_UPDATE;
        }
        if (jlstate == JL_STATE_UPDATE)
-               __jump_label_transform(entry, type, text_poke_early);
+               __jump_label_transform(entry, type, text_poke_early, 1);
 }
 
 #endif