| // SPDX-License-Identifier: GPL-2.0 | |
| /* | |
| * Static branch in a patched function. The jump table entry is written out by | |
| * hand, mirroring JUMP_TABLE_ENTRY(), so the fixture builds without kernel | |
| * headers. The key is an STT_OBJECT; anything else is ignored by | |
| * validate_special_section_klp_reloc(). | |
| * | |
| * MODNAME selects whether the key is taken to belong to vmlinux or a module. | |
| * | |
| * NEW_KEY puts the whole static branch behind PATCHED, so the patch introduces | |
| * one where the original had none -- a different question from patching code | |
| * that already has a key, because the __jump_table entry itself is new. | |
| * | |
| * KEY_NAME renames the key. Two names are special to | |
| * validate_special_section_klp_reloc(): a __tracepoint_* key and the | |
| * __UNIQUE_ID_ddebug_* one pr_debug() generates are both unsupported in a | |
| * module, but are disabled with a warning rather than rejected, because the | |
| * kernel is full of them and refusing outright would make ordinary functions | |
| * unpatchable. | |
| * | |
| * STATIC_KEY makes the key file-local. That changes the shape of the | |
| * relocation rather than the meaning of the code: a reference to a static lands | |
| * on the section symbol plus an addend, so the key has to be resolved from the | |
| * section before it can be recognised as a key at all. | |
| */ | |
| #ifndef MODNAME | |
| #define MODNAME "vmlinux" | |
| #endif | |
| #ifndef KEY_NAME | |
| #define KEY_NAME klp_test_key | |
| #endif | |
| static const char __modinfo[] | |
| __attribute__((section(".modinfo"), used, aligned(1))) = "\0name=" MODNAME; | |
| #ifdef STATIC_KEY | |
| static long KEY_NAME; | |
| #else | |
| long KEY_NAME; | |
| #endif | |
| int target(int x) | |
| { | |
| int r = x; | |
| #if defined(NEW_KEY) && !defined(PATCHED) | |
| /* The original has no static branch at all. */ | |
| return r + 1; | |
| #else | |
| asm goto( | |
| "1: nop\n\t" | |
| ".pushsection __jump_table, \"aw\"\n\t" | |
| ".balign 8\n\t" | |
| "912:\n\t" | |
| ".pushsection .discard.annotate_data, \"M\", @progbits, 8\n\t" | |
| ".long 912b - ., 1\n\t" | |
| ".popsection\n\t" | |
| ".long 1b - ., %l[l_yes] - .\n\t" | |
| ".quad %c0 - .\n\t" | |
| ".popsection\n\t" | |
| : : "i" (&KEY_NAME) : : l_yes); | |
| r += 1; | |
| goto out; | |
| l_yes: | |
| r += 2; | |
| out: | |
| #endif | |
| #ifdef PATCHED | |
| return r + 100; | |
| #else | |
| return r; | |
| #endif | |
| } |