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);
callee_a(int x)32 int callee_a(int x) { return x + 1; }
callee_b(int x)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
target(int x)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