commit: 2e05f723a71309bb372c3ec424efa31d6541e97f
Author: Rahul Sandhu <nvraxn <AT> gmail <DOT> com>
AuthorDate: Thu Jan 8 02:23:23 2026 +0000
Commit: Eli Schwartz <eschwartz <AT> gentoo <DOT> org>
CommitDate: Thu Jan 8 03:04:11 2026 +0000
URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=2e05f723
selinux-policy-2.eclass: fix-up call to qdepends, make PKGSET an array
The call to qdepends before was completely and utterly wrong. Taking
the net-vpn/tor package as an example:
rsandhu@carbon ~ $ CATEGORY="sec-policy" PN="selinux-tor" /usr/bin/qdepends
-Cq -r -Q "${CATEGORY}/${PN}" | grep -v "sec-policy/selinux-"
rsandhu@carbon ~ $
Which returns no results. It also doesn't operate only on installed
packages, which is important to do; we can't relabel packages that
aren't merged onto the filesystem.
Removing the trailing grep, we can see why this is the case:
rsandhu@carbon ~ $ CATEGORY="sec-policy" PN="selinux-tor" /usr/bin/qdepends
-Cq -r -Q "${CATEGORY}/${PN}"
net-vpn/tor-0.4.8.21: sec-policy/selinux-tor
rsandhu@carbon ~ $
Not only does it return an invalid version string (not prefixed with an
equals character), it also tacks on a colon followed by the name of the
package we requested a lookup for as well!
This is completely incorrect. Not only does it result in nothing being
matched, because of the otherwise valid grep we add on to the end, it
also doesn't make sense to tack on the version string; it makes a lot
more sense to instead add on the slot number, as that's a correct way
to check for multiple versions of a packaged installed simultaneously,
which is only possible with slotting.
Hence, pass:
- an additional -q flag to, per the man page, suppress the matching
atom:
> When given two or more times, suppresses the matching atom for -Q
- the -F flag along with a format string such that we get an actually
valid and sensible output that we can pass directly to rlpkg.
- the -i flag to search installed packages only.
rsandhu@carbon ~ $ CATEGORY="sec-policy" PN="selinux-tor" /usr/bin/qdepends
-CiqqrF '%[CATEGORY]%[PN]%[SLOT]' -Q "${CATEGORY}/${PN}" | grep -v
'sec-policy/selinux-'
net-vpn/tor:0
rsandhu@carbon ~ $
This can be passed directly to rlpkg, which per the help:
> Packages can be specified with a portage package specification, for example,
> "policycoreutils" or ">=sys-apps/policycoreutils-1.30".
Also, the success of qdepends or equery is not checked at all! Luckily,
this isn't a huge issue for qdepends; qdepends only prints to stderr on
failure — which is not captured without a redirect to stdout by $() —,
so crisis is averted there: PKGSET is empty as a result and due to the
check that follows, it is in effect a no-op.
In the case of equery however, the results are much more dire. Unlike
qdepends, equery writes to _both_ stderr AND stdout on failure:
rsandhu@carbon ~ $ equery depends -some -invalid -options 2>/dev/null
Usage: depends [options] pkgspec
options
-h, --help display this help message
-a, --all-packages include dependencies that are not installed (slow)
-D, --indirect search both direct and indirect dependencies
-F, --format=TMPL specify a custom output format
--depth=N limit indirect dependency tree to specified depth
Hence, this garbage is passed as an argument _directly_ to rlpkg. Given
that it's passed as an argument, it _should_ have been fine in the best
case senario, but we can't guarentee that. Regardless, this is not at
all robust.
To avoid all of the above, actually check the return value, by adding a
control flow path for the unhappy case, for both equery and qdepends,
printing a nice message with ewarn to the user in the failure case, and
if neither qdepends or equery was found (hence making it impossible for
us to calculate the reverse dependency tree and relabel package files).
If either qdepends or equery fails, don't bother trying the other. If
one fails, it's highly unlikely the other succeeds, and doing as such
would complicate the control flow significantly for little tangible
benefit.
In all cases where we are unable to calculate the reverse dependency
tree, either because of failure or missing tooling to do so, simply
warn instead of erroring. For one, neither qdepends or equery are part
of @system. As well as this, there are valid cases where relabelling
may fail, such as in the conversion process from a normal system to an
SELinux system detailed in our wiki[1], which instructs users to emerge
policy packages[2] _before_ booting a kernel with SELinux enabled and
then later relabelling manually[3]:
> Before proceeding to the next section, perform a reboot.
The entire section of code is also not compliant with tree policy! It
relies on portage-specific behaviour, and hence is not compliant with
PMS. As it has already been committed and removing it would result in
significant breakage for users performing policy updates where said
update introduces new labels, just do damage control for now by fixing
it to behaviour properly. However, as this is not at all ideal, add a
comment noting that it should be removed as soon as possible.
[1] https://wiki.gentoo.org/wiki/SELinux/Installation
[2]
https://wiki.gentoo.org/wiki/SELinux/Installation#Installing_policies_and_utilities.2C_part_two
[3] https://wiki.gentoo.org/wiki/SELinux/Installation#Relabel
Signed-off-by: Rahul Sandhu <nvraxn <AT> gmail.com>
Signed-off-by: Eli Schwartz <eschwartz <AT> gentoo.org>
eclass/selinux-policy-2.eclass | 39 +++++++++++++++++++++++++++++++--------
1 file changed, 31 insertions(+), 8 deletions(-)
diff --git a/eclass/selinux-policy-2.eclass b/eclass/selinux-policy-2.eclass
index 5275507e86bd..96bf57746f68 100644
--- a/eclass/selinux-policy-2.eclass
+++ b/eclass/selinux-policy-2.eclass
@@ -387,16 +387,39 @@ selinux-policy-2_pkg_postinst() {
# Don't relabel when cross compiling
if [[ -z ${ROOT} ]]; then
- # Relabel depending packages
- local PKGSET=""
- if [[ -x /usr/bin/qdepends ]]; then
- PKGSET=$(/usr/bin/qdepends -Cq -r -Q ${CATEGORY}/${PN}
| grep -v "sec-policy/selinux-")
- elif [[ -x /usr/bin/equery ]]; then
- PKGSET=$(/usr/bin/equery -Cq depends ${CATEGORY}/${PN}
| grep -v "sec-policy/selinux-")
+ # Relabel depending packages. This entire section is a hack,
and a violation of tree policy;
+ # it relies on PM specific functionality (qdepends and equery,
which are portage specific) and
+ # hence is not PMS compliant. This should be remove and
replaced with a more robust, PMS-compliant
+ # implementation as soon as possible.
+ local PKGSET=()
+ local out
+ local status
+ local cmd
+
+ if command -v qdepends &>/dev/null; then
+ out=$(qdepends -CiqqrF '%[CATEGORY]%[PN]%[SLOT]' -Q
"${CATEGORY}/${PN}")
+ status=$?
+ cmd='qdepends'
+ elif command -v equery &>/dev/null; then
+ out=$(equery -Cq depends "${CATEGORY}/${PN}")
+ status=$?
+ cmd='equery'
+ else
+ ewarn "Unable to calculate reverse dependencies for
policy: both qdepends and equery were not found."
+ ewarn "Skipping package file relabelling..."
+ return
fi
- if [[ -n "${PKGSET}" ]]; then
- rlpkg ${PKGSET}
+
+ if [[ "${status}" -ne 0 ]]; then
+ ewarn "Failed to calculate reverse dependencies for
policy: ${cmd} returned ${status}."
+ ewarn "Skipping package file relabelling..."
+ return
fi
+
+ # Policy packages may pull in other policy packages, filter
those out.
+ readarray -t PKGSET <<<"$(echo "${out}" | grep -v
'sec-policy/selinux-')"
+
+ [[ "${#PKGSET[@]}" -ne 0 ]] && rlpkg "${PKGSET[@]}"
fi
}