blob: 5ae759e719eb80a166c4ae289714bcf23cbfa509 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# A function's checksum must not depend on where the function sits.
#
# A jump or call without a relocation encodes its target as an offset from the
# instruction. Hashing those bytes makes the checksum change whenever anything
# ahead of the function changes size -- so an unrelated edit elsewhere in the
# file reports this function as changed too, and the patch grows to include it
# and everything it references. Nothing fails; the livepatch is just larger and
# riskier than the patch it came from.
#
# Here the "patch" moves target() away from callee() and changes nothing else:
# both are aligned to 64 in the patched build, which shifts them apart without
# touching a byte of either. See the fixture for why it is done that way.
. "$(dirname "$0")/../lib.sh"
setup
# -fno-function-sections, or each function is at offset 0 of its own section
# and target() never moves.
build_pair checksum_position.c -fno-function-sections
assert_input_symbol target
# The fixture is only meaningful if the displacement target's calls encode
# actually changed, and that is the distance to callee() -- not target's own
# offset. A compiler which shifted the two by the same amount would move
# target and leave the distance alone, and then the bytes are identical and
# the checksum matches for the uninteresting reason. Ask about the distance.
sym_off() # $1 object, $2 symbol
{
in_symbols "$1" | awk -v n="$2" '$NF == n { print $2; exit }'
}
orig_t="$(sym_off orig.o target)"; orig_c="$(sym_off orig.o callee)"
new_t="$(sym_off patched.o target)"; new_c="$(sym_off patched.o callee)"
[ -n "$orig_t" ] && [ -n "$orig_c" ] && [ -n "$new_t" ] && [ -n "$new_c" ] ||
fail "target or callee missing from one of the objects"
orig_gap=$(( 16#$orig_t - 16#$orig_c ))
new_gap=$(( 16#$new_t - 16#$new_c ))
[ "$orig_gap" != "$new_gap" ] ||
probe_skip "this compiler kept target() and callee() the same distance" \
"apart; the call displacement did not change"
assert_checksum_matches target
pass "checksum unchanged when the function only moves"
|