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