1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Data objects whose checksums must move for reasons the raw bytes do not 4 * show. 5 * 6 * checksum_update_object() hashes a data symbol's length and its bytes, and 7 * then walks its relocations: a reference into a string section contributes 8 * the string's *contents*, and any other reference contributes the target 9 * symbol's name and the adjusted addend. So three changes that leave the 10 * object's own bytes identical still have to change its checksum: 11 * 12 * Each variant is selected by a -D on the patched build only, so the original 13 * is always the baseline: 14 * 15 * WHICH_FUNC the function pointer points somewhere else 16 * WHICH_STR the string pointer points at a different literal 17 * STR_CONTENT the string it points at is edited in place 18 * WHICH_SLOT the same array, at a different index: addend only 19 * WHICH_PRIV likewise, but a static, reached through its section symbol 20 * 21 * The last is the interesting one. Nothing in the pointer changes -- same 22 * section, same offset -- so a checksum that hashed only the relocation and 23 * not what it referred to would call the object unchanged, and the patched 24 * kernel would keep the old string. 25 */ 26 27 static const char __modinfo[] 28 __attribute__((section(".modinfo"), used, aligned(1))) = "\0name=vmlinux"; 29 30 int callee_a(int x); 31 int callee_b(int x); 32 int callee_a(int x) { return x + 1; } 33 int callee_b(int x) { return x + 2; } 34 35 /* 36 * String *literals*, not named arrays. The contents-hashing path keys on 37 * SHF_STRINGS, which the compiler sets on the mergeable .rodata.str1.1 a 38 * literal lands in and not on a named char[] given a section of its own. A 39 * fixture using the latter exercises the ordinary name-and-addend path and 40 * reports nothing when the text changes. 41 */ 42 #if defined(PATCHED) && defined(STR_CONTENT) 43 #define MESSAGE "edited" 44 #else 45 #define MESSAGE "original" 46 #endif 47 48 /* A plain data object: only its own bytes decide the checksum. */ 49 #if defined(PATCHED) && defined(PLAIN_VALUE) 50 int plain = 43; 51 #else 52 int plain = 42; 53 #endif 54 55 /* 56 * A .bss object, where length is the only thing there is to hash: the section 57 * has no data, so the bytes are skipped and only sym->len distinguishes this 58 * from an object of another size. An initialised array would not isolate it 59 * -- growing one changes the hashed bytes as well. 60 */ 61 #if defined(PATCHED) && defined(LONGER) 62 char sized[4]; 63 #else 64 char sized[2]; 65 #endif 66 67 /* 68 * A reference into the middle of an array: same target symbol, different 69 * addend. Nothing else in the object changes, so this is the only way to see 70 * whether the addend is hashed at all. 71 */ 72 int slots[4]; 73 74 /* 75 * A file-local array. A reference to a static lands on its section symbol 76 * plus an offset, so the hash has to resolve that back to the underlying 77 * object before it has a name to hash at all -- a different code path from the 78 * global above, and one that silently contributes nothing when it fails. 79 */ 80 static int priv_slots[4]; 81 82 struct desc { 83 int (*fn)(int arg); 84 const char *str; 85 int *slot; 86 int *priv; 87 }; 88 89 const struct desc descriptor = { 90 #if defined(PATCHED) && defined(WHICH_FUNC) 91 .fn = callee_b, 92 #else 93 .fn = callee_a, 94 #endif 95 #if defined(PATCHED) && defined(WHICH_STR) 96 .str = "a different literal", 97 #else 98 .str = MESSAGE, 99 #endif 100 #if defined(PATCHED) && defined(WHICH_SLOT) 101 .slot = &slots[2], 102 #else 103 .slot = &slots[1], 104 #endif 105 #if defined(PATCHED) && defined(WHICH_PRIV) 106 .priv = &priv_slots[3], 107 #else 108 .priv = &priv_slots[1], 109 #endif 110 }; 111 112 int target(int x) 113 { 114 return descriptor.fn(x) + plain + sized[0] + (int)descriptor.str[0] + 115 *descriptor.slot + *descriptor.priv; 116 } 117