^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * jump label x86 support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2009 Jason Baron <jbaron@redhat.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/jump_label.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/memory.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/jhash.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/kprobes.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/alternative.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/text-patching.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) static void bug_at(const void *ip, int line)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * The location is not an op that we were expecting.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * Something went wrong. Crash the box, as something could be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * corrupting the kernel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) pr_crit("jump_label: Fatal kernel bug, unexpected op at %pS [%p] (%5ph) %d\n", ip, ip, ip, line);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) BUG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static const void *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) __jump_label_set_jump_code(struct jump_entry *entry, enum jump_label_type type, int init)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) const unsigned char default_nop[] = { STATIC_KEY_INIT_NOP };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) const unsigned char *ideal_nop = ideal_nops[NOP_ATOMIC5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) const void *expect, *code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) const void *addr, *dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) int line;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) addr = (void *)jump_entry_code(entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) dest = (void *)jump_entry_target(entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) code = text_gen_insn(JMP32_INSN_OPCODE, addr, dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) if (init) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) expect = default_nop; line = __LINE__;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) } else if (type == JUMP_LABEL_JMP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) expect = ideal_nop; line = __LINE__;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) expect = code; line = __LINE__;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (memcmp(addr, expect, JUMP_LABEL_NOP_SIZE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) bug_at(addr, line);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (type == JUMP_LABEL_NOP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) code = ideal_nop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static inline void __jump_label_transform(struct jump_entry *entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) enum jump_label_type type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) int init)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) const void *opcode = __jump_label_set_jump_code(entry, type, init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * As long as only a single processor is running and the code is still
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * not marked as RO, text_poke_early() can be used; Checking that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * system_state is SYSTEM_BOOTING guarantees it. It will be set to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * SYSTEM_SCHEDULING before other cores are awaken and before the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * code is write-protected.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * At the time the change is being done, just ignore whether we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * are doing nop -> jump or jump -> nop transition, and assume
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * always nop being the 'currently valid' instruction
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (init || system_state == SYSTEM_BOOTING) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) text_poke_early((void *)jump_entry_code(entry), opcode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) JUMP_LABEL_NOP_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) text_poke_bp((void *)jump_entry_code(entry), opcode, JUMP_LABEL_NOP_SIZE, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static void __ref jump_label_transform(struct jump_entry *entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) enum jump_label_type type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) int init)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) mutex_lock(&text_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) __jump_label_transform(entry, type, init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) mutex_unlock(&text_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) void arch_jump_label_transform(struct jump_entry *entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) enum jump_label_type type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) jump_label_transform(entry, type, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) bool arch_jump_label_transform_queue(struct jump_entry *entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) enum jump_label_type type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) const void *opcode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (system_state == SYSTEM_BOOTING) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * Fallback to the non-batching mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) arch_jump_label_transform(entry, type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) mutex_lock(&text_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) opcode = __jump_label_set_jump_code(entry, type, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) text_poke_queue((void *)jump_entry_code(entry),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) opcode, JUMP_LABEL_NOP_SIZE, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) mutex_unlock(&text_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) void arch_jump_label_transform_apply(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) mutex_lock(&text_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) text_poke_finish();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) mutex_unlock(&text_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) JL_STATE_START,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) JL_STATE_NO_UPDATE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) JL_STATE_UPDATE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) } jlstate __initdata_or_module = JL_STATE_START;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) __init_or_module void arch_jump_label_transform_static(struct jump_entry *entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) enum jump_label_type type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * This function is called at boot up and when modules are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * first loaded. Check if the default nop, the one that is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * inserted at compile time, is the ideal nop. If it is, then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * we do not need to update the nop, and we can leave it as is.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * If it is not, then we need to update the nop to the ideal nop.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (jlstate == JL_STATE_START) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) const unsigned char default_nop[] = { STATIC_KEY_INIT_NOP };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) const unsigned char *ideal_nop = ideal_nops[NOP_ATOMIC5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (memcmp(ideal_nop, default_nop, 5) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) jlstate = JL_STATE_UPDATE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) jlstate = JL_STATE_NO_UPDATE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (jlstate == JL_STATE_UPDATE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) jump_label_transform(entry, type, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }