xref: /linux/tools/objtool/tests/generic/fixtures/checksum_data.c (revision 5b6dca02b3e2254d2fd5706d76d7ab4610a67296)
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