abuild: Scan for binaries with extra setcap(8) capabilities

Similar to suid binaries, abuild will now error out if the package
includes binaries with setcap(8) capabilities but doesn't have `setcap`
in `$options`. This eases identifying package which ship binaries
with extra capabilities.

Furthermore, if these binaries are executable by others a warning is
emitted. This warning could be changed to an error in the future.
The recommendation is to make such binaries only executable by owner
and group, thereby requiring the system administrator to explicitly
add users to a specific group in order to give them accesses to these
capabilities.

See: https://gitlab.alpinelinux.org/alpine/tsc/-/issues/45

Discussion: This change requires abuild to depend on the `libcap`
package for the `getcap` binary. It does not seem to be possible
at the moment to use scanelf(1) to identify these binaries.
This commit is contained in:
Sören Tempel 2022-07-03 14:30:15 +02:00
parent 8d6fb8b45f
commit 4a2a0337d0
4 changed files with 76 additions and 1 deletions

View File

@ -278,6 +278,12 @@ file.
to use capabilities or process separation instead of set-uid
where available.
*setcap*
Specifies that binaries in the package may be installed
with extra setcap(8) capabilities. If this option is enabled,
it is highly recommended to only make these binaries executable
by root and users of a specific group, not by others.
*textrels*
Specifies that the package's binaries are known to contain
relocations against text segments. By default, abuild(1)

View File

@ -865,6 +865,20 @@ postcheck() {
e=1
fi
fi
# test capabilities on executables
# see: https://gitlab.alpinelinux.org/alpine/tsc/-/issues/45
getcap -r "$dir" | (local r=true; while read -r line; do
local filename="${line% *}"
if ! options_has "setcap"; then
error "Found binary with extra capabilities: $filename"
r=false
fi
local execothers="$(find "$filename" -perm -o+x)"
if [ -n "$execothers" ]; then
warning "Found setcap binary executable by others: $filename"
fi
done; $r) || e=1
# test for textrels
if ! options_has "textrels"; then

View File

@ -39,7 +39,9 @@ init_tests \
abuild_cleanoldpkg \
abuild_path_with_spaces \
abuild_pyc_warn \
abuild_pyc
abuild_pyc \
abuild_setcap_binary \
abuild_setcap_binary_with_option
export ABUILD_SHAREDIR=$(atf_get_srcdir)/..
export ABUILD_CONF=/dev/null
@ -922,3 +924,23 @@ abuild_pyc_body() {
atf_check -o match:"foo=1.0-r0" -o match:"pyc" \
grep install_if pkg/.control.foo-pyc/.PKGINFO
}
abuild_setcap_binary_body() {
init_keys
cp -ra "$testrepo"/setcap .
cd setcap
atf_check -s exit:1 \
-e match:"Found binary with extra capabilities" \
-e match:"Found setcap binary executable by others" \
abuild all
}
abuild_setcap_binary_with_option_body() {
init_keys
cp -ra "$testrepo"/setcap .
cd setcap
options=setcap atf_check -s exit:0 \
-e not-match:"Found binary with extra capabilities" \
-e match:"Found setcap binary executable by others" \
abuild all
}

View File

@ -0,0 +1,33 @@
# Maintainer: Natanael Copa <ncopa@alpinelinux.org>
# test package
pkgname=setcap
pkgver="1.0"
pkgrel=0
pkgdesc="Dummy test package that has an setcap binary but no setcap option"
url="https://gitlab.alpinelinux.org/alpine/aports"
arch="noarch"
license="MIT"
source=""
prepare() {
mkdir -p "$builddir"
}
build() {
true
}
check() {
true
}
package() {
mkdir -p "$pkgdir/usr/bin"
cat >"$pkgdir/usr/bin/foo" <<EOF
#!/bin/sh
EOF
chmod +x "$pkgdir/usr/bin/foo"
setcap cap_net_bind_service=+ep "$pkgdir/usr/bin/foo"
}