aboutsummaryrefslogtreecommitdiff
path: root/sbopkglint.d/20-arch.t.sh
blob: b2a877c7eb2e5fa1bf9932e095353ad609aa3c37 (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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#!/bin/bash

# sbopkglint test, must be sourced by sbopkglint (not run standalone).

# PKG, PRGNAM, VERSION, ARCH are set by sbopkglint. also the current
# directory is the root of the installed package tree.

########################################################################
# for noarch packages, do nothing.
# for everything else, make sure any ELF binaries/libraries match the
# ARCH, and that libs are in the correct directory (lib vs. lib64).
# also, check the required glibc version of each bin/lib, and complain
# if it's newer than the glibc on the system.

# warnings:
# if an i?86 package has any 64-bit ELF objects (libs or bins)
# if an x86_64 package has any 32-bit ELF objects (libs or bins)
# if an i?86 package has lib64 or usr/lib64 at all
# if an x86_64 package has 64-bit libs in lib or usr/lib
# same 32/64 checking for arm (32-bit) and aarch64 (64-bit)

# note: sometimes files in /lib/firmware are ELF, and would cause
# false "wrong directory" warnings, so we exclude that dir from the
# search.

set_glibc_ver() {
	GLIBC_VER="$( /$1/libc.so.6 --version | \
                 grep version | \
                 head -n1 | \
                 sed 's,.* \([0-9]\.[0-9]\+\)\.*$,\1,' )"
	[ "$GLIBC_VER" = "" ] && note "can't get glibc version, disabling glibc check"
}

# compare the highest required version of glibc from a binary against
# the version we have installed. ugly code, sorry.
# one approach would be to run ldd and look for "version `.*' not found",
# but it's better not to run ldd on arbitrary binaries as root...
glibc_check() {
	local ver
	local highver

	[ "$GLIBC_VER" = "" ] && return

	# get the highest required glibc verson from the binary. there *must*
	# be a cleaner way to do this, but I haven't found it yet.
	ver="$( objdump -p "$1" 2>/dev/null | \
	        sed -n '/Version Ref/,$s/GLIBC_[0-9]\./&/p' | \
			  rev | cut -d_ -f1 | rev | sort -V | tail -n 1 )"
	[ "$ver" = "" ] && return  # probably a static binary

	# highver is whichever of (our glibc, binary's highest required glibc)
	# is higher (or, same as our glibc, if they're the same)
	highver="$( ( echo $GLIBC_VER ; echo $ver ) | sort -V | tail -n 1 )"

	#echo "===> ver: $ver   highver: $highver"

	if [ "$highver" != "$GLIBC_VER" ]; then
		echo "$1" >> .badglibc.$$
	fi
}

case "$ARCH" in
	noarch)  ;; # ok, do nothing.
	i?86)    WRONGDIR="lib64"; CPU="80386"   ; set_glibc_ver "lib"   ;;
	x86_64)  WRONGDIR="lib";   CPU="x86-64"  ; set_glibc_ver "lib64" ;;
	aarch64) WRONGDIR="lib";   CPU="aarch64" ; set_glibc_ver "lib64" ;;
	arm)     WRONGDIR="lib64"; CPU="ARM"     ; set_glibc_ver "lib"   ;;
	*) warn "ARCH isn't noarch, i?86, x86_64, arm, or aarch64. don't know how to check binaries." ;;
esac

if [ -n "$WRONGDIR" ]; then
	# 20230701 bkw: special case for /usr/share/qemu, it contains BIOS and such
	# for emulated systems, some of which are ELF binaries.
	# 20241008 bkw: special cases for firmware dirs.
	find * -type f \
		-a \! -path usr/share/qemu/\* \
		-a \! -path usr/share/alsa/firmware/\* \
		-a \! -path lib/firmware/\* \
		-print0 | \
		xargs -0 file -m /etc/file/magic/elf | \
		grep 'ELF.*\(executable\|shared object\)' > .tmp.$$

		while read line; do
			file="$( echo $line | cut -d: -f1 )"
			filetype="$( echo $line | cut -d: -f2 )"
			nomachine="$( echo $line | grep 'no machine' )"

			# 20230630 bkw: don't require nomachine objects to be +x.
			# AFAIK, the only thing that uses them is guile2.2, and it
			# installs them 0644.
			if [ ! "$nomachine" ]; then
				[ ! -x "$file" ] && ls -bld "$file" >> .nonexec.$$
			fi

			case "$file" in
				# 20220414 bkw: only check for libs directly in the dir.
				# this avoids e.g. lib/udev/<executable> and usr/lib/prgnam/plugins/*.so.
				# had to relax this check; it was too strict.
				# 20231216 bkw: don't check opt/ either.
				opt/*|$WRONGDIR/*/*|usr/$WRONGDIR/*/*) continue ;;
				$WRONGDIR/*|usr/$WRONGDIR/*)
					ls -lb "$file" >> .inwrongdir.$$ ;;
				usr/share/*)
					ls -lb "$file" >> .insharedir.$$ ;;
			esac

			# 64-bit packages can contain 2 types of 32-bit binaries:
			# - statically linked.
			# - statified. very few of these exist, and we can't make
			#   them on 15.0 (statifier can't handle modern kernel/glibc
			#   and the author hasn't updated it).
			if [ "$ARCH" = "x86_64" ]; then
				echo "$filetype" | grep -q 'statically linked' && continue
				grep -q DL_RO_DYN_TEMP_CNT "$file" && continue
			fi

			# "no machine" ELF objects are allowed, but since they still come
			# in 64-bit and 32-bit varieties, they must be in the correct
			# directory.
			if ! echo "$filetype" | grep -q -e "$CPU" -e 'no machine'; then
				ls -lb "$file" >> .wrongarch.$$
			fi

			# don't check "no machine" ELF objects for being stripped.
			# our strip command doesn't know how to strip them!
			# also, check for binaries that need too new of a glibc.
			if [ ! "$nomachine" ]; then
				if echo "$filetype" | grep -q "not stripped"; then
					ls -lb "$file" >> .notstripped.$$
				fi
				glibc_check "$file"
			fi
		done < .tmp.$$
		rm -f .tmp.$$
fi

[ -s .inwrongdir.$$ ] && warn "shared lib(s) in wrong dir for ARCH:" && cat .inwrongdir.$$
[ -s .wrongarch.$$ ] && warn "ELF object(s) with wrong arch (should be $CPU):" && cat .wrongarch.$$
[ -s .notstripped.$$ ] && warn "ELF object(s) not stripped:" && cat .notstripped.$$
[ -s .nonexec.$$ ] && warn "ELF binaries/libraries should be executable:" && cat .nonexec.$$
[ -s .badglibc.$$ ] && warn "ELF binaries/libraries with bad glibc version:" && cat .badglibc.$$

if [ "$WRONGDIR" = "lib64" ]; then
	[ -e usr/lib64 ] && warn "32-bit $ARCH package may not contain /usr/lib64"
	[ -e lib64 ] && warn "32-bit $ARCH package may not contain /lib64"
elif [ "$WRONGDIR" = "lib" -a -e usr/lib ]; then
	note "64-bit $ARCH package contains /usr/lib; this may or may not be a problem."
fi

rm -f .inwrongdir.$$ .wrongarch.$$ .notstripped.$$ .nonexec.$$ .badglibc.$$