Rahul Sandhu <[email protected]> writes:

> Currently, a manual rebuild using the `@selinux-rebuild` set is needed
> upon update of the POLICY_TYPES variable. This means that portage can't
> track changes to it with `emerge --changed-use`. By making POLICY_TYPES
> the new USE expand, SELINUX_POLICY_TYPES, `--changed-use` will trigger
> a rebuild upon changes to it.
>
> However, make SELINUX_POLICY_TYPES different so that POLICY_TYPES, the
> old variable remains intact for EAPI 7, providing backwards compat with
> EAPI 7. This patch only bumps the eclass however; sec-policy/selinux-*
> and other related ebuilds are to be migrated to EAPI 8 later. This also
> gives us time to put out a news article for this migration.
>
> Naming the new USE expand SELINUX_POLICY_TYPES also makes it inline
> with eclass variables, such as SELINUX_GIT_REPO and SELINUX_GIT_BRANCH.
>
> Also document why we parse IUSE instead of USE, and strip the possible
> leading '+' so that IUSE="+foo" is interpreted as 'foo' and not '+foo'.
>

As discussed on IRC, here's the nits, but please let's fix them once the
first patch is in to not delay things.

> Bug: https://bugs.gentoo.org/951355
> Signed-off-by: Rahul Sandhu <[email protected]>
> ---
>  eclass/selinux-policy-2.eclass          | 204 ++++++++++++++++++------
>  profiles/base/make.defaults             |   2 +-
>  profiles/desc/selinux_policy_types.desc |   9 ++
>  3 files changed, 161 insertions(+), 54 deletions(-)
>  create mode 100644 profiles/desc/selinux_policy_types.desc
>
> v2: rename IUSE variable to SELINUX_POLICY_TYPES, update copyright headers
> v3: fix-up REQUIRED_USE such that at least one policy type is required, pull
>     in the appropriate policy type for the base policy.
>
> diff --git a/eclass/selinux-policy-2.eclass b/eclass/selinux-policy-2.eclass
> index 5ec7ff99ed74..739acc695cf3 100644
> --- a/eclass/selinux-policy-2.eclass
> +++ b/eclass/selinux-policy-2.eclass
> @@ -7,7 +7,7 @@
>  # @ECLASS: selinux-policy-2.eclass
>  # @MAINTAINER:
>  # [email protected]
> -# @SUPPORTED_EAPIS: 7
> +# @SUPPORTED_EAPIS: 7 8
>  # @BLURB: This eclass supports the deployment of the various SELinux modules 
> in sec-policy
>  # @DESCRIPTION:
>  # The selinux-policy-2.eclass supports deployment of the various SELinux 
> modules
> @@ -19,7 +19,7 @@
>  # manageable.
>  
>  case ${EAPI} in
> -     7) ;;
> +     7|8) ;;
>       *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
>  esac
>  
> @@ -55,14 +55,16 @@ _SELINUX_POLICY_2_ECLASS=1
>  # (space-separated) or a bash array.
>  : "${POLICY_FILES:=""}"
>  
> -# @ECLASS_VARIABLE: POLICY_TYPES
> -# @DESCRIPTION:
> -# This variable informs the eclass for which SELinux policies the module 
> should
> -# be built. Currently, Gentoo supports targeted, strict, mcs and mls.
> -# This variable is the same POLICY_TYPES variable that we tell SELinux
> -# users to set in make.conf. Therefore, it is not the module that should
> -# override it, but the user.
> -: "${POLICY_TYPES:="targeted strict mcs mls"}"
> +if [[ ${EAPI} == 7 ]]; then
> +     # @ECLASS_VARIABLE: POLICY_TYPES
> +     # @DESCRIPTION:
> +     # This variable informs the eclass for which SELinux policies the 
> module should
> +     # be built. Currently, Gentoo supports targeted, strict, mcs and mls.
> +     # This variable is the same POLICY_TYPES variable that we tell SELinux
> +     # users to set in make.conf. Therefore, it is not the module that should
> +     # override it, but the user.
> +     : "${POLICY_TYPES:="targeted strict mcs mls"}"
> +fi
>  
>  # @ECLASS_VARIABLE: SELINUX_GIT_REPO
>  # @DESCRIPTION:
> @@ -89,7 +91,13 @@ case ${BASEPOL} in
>                       EGIT_CHECKOUT_DIR="${WORKDIR}/refpolicy";;
>  esac
>  
> -IUSE=""
> +if [[ ${EAPI} == 7 ]]; then
> +     IUSE=""
> +else
> +     # Build all policy types by default
> +     IUSE="+selinux_policy_types_targeted +selinux_policy_types_strict 
> +selinux_policy_types_mcs +selinux_policy_types_mls"
> +     REQUIRED_USE="|| ( selinux_policy_types_targeted 
> selinux_policy_types_strict selinux_policy_types_mcs selinux_policy_types_mls 
> )"
> +fi
>  
>  HOMEPAGE="https://wiki.gentoo.org/wiki/Project:SELinux";
>  if [[ -n ${BASEPOL} ]] && [[ "${BASEPOL}" != "9999" ]]; then
> @@ -114,13 +122,32 @@ 
> PATCHBUNDLE="${DISTDIR}/patchbundle-selinux-base-policy-${BASEPOL}.tar.bz2"
>  # Modules should always depend on at least the first release of the
>  # selinux-base-policy for which they are generated.
>  if [[ -n ${BASEPOL} ]]; then
> +     _BASE_POLICY_VERSION="${BASEPOL}"
> +else
> +     _BASE_POLICY_VERSION="${PV}"
> +fi
> +
> +if [[ ${EAPI} == 7 ]]; then
>       RDEPEND=">=sys-apps/policycoreutils-2.5
> -             >=sec-policy/selinux-base-policy-${BASEPOL}"
> +             >=sec-policy/selinux-base-policy-${_BASE_POLICY_VERSION}"
>  else
>       RDEPEND=">=sys-apps/policycoreutils-2.5
> -             >=sec-policy/selinux-base-policy-${PV}"
> +             selinux_policy_types_targeted? (
> +                     
> >=sec-policy/selinux-base-policy-${_BASE_POLICY_VERSION}[selinux_policy_types_targeted]
> +             )
> +             selinux_policy_types_strict? (
> +                     
> >=sec-policy/selinux-base-policy-${_BASE_POLICY_VERSION}[selinux_policy_types_strict]
> +             )
> +             selinux_policy_types_mcs? (
> +                     
> >=sec-policy/selinux-base-policy-${_BASE_POLICY_VERSION}[selinux_policy_types_mcs]
> +             )
> +             selinux_policy_types_mls? (
> +                     
> >=sec-policy/selinux-base-policy-${_BASE_POLICY_VERSION}[selinux_policy_types_mls]
> +             )"

This could be a loop:

for _poltype in selinux_policy_types_{targeted,strict,mcs,mls} ; do
    RDEPEND+="
        ${_poltype}? (
            
>=sec-policy/selinux-base-policy-${_BASE_POLICY_VERSION}[${_poltype}]
        )
    "
done
unset _poltype

>  fi
>  
> +unset _BASE_POLICY_VERSION
> +
>  DEPEND="${RDEPEND}"
>  BDEPEND="
>       sys-devel/m4
> @@ -197,14 +224,26 @@ selinux-policy-2_src_prepare() {
>               fi
>       done
>  
> -     for i in ${POLICY_TYPES}; do
> -             mkdir "${S}"/${i} || die "Failed to create directory ${S}/${i}"
> -             cp "${S}"/refpolicy/doc/Makefile.example "${S}"/${i}/Makefile \
> -                     || die "Failed to copy Makefile.example to 
> ${S}/${i}/Makefile"
> +     _selinux_prepare_modules() {
> +             mkdir "${S}"/${1} || die "Failed to create directory ${S}/${1}"
> +             cp "${S}"/refpolicy/doc/Makefile.example "${S}"/${1}/Makefile \
> +                     || die "Failed to copy Makefile.example to 
> ${S}/${1}/Makefile"
>  
> -             cp ${modfiles} "${S}"/${i} \
> -                     || die "Failed to copy the module files to ${S}/${i}"
> -     done
> +             cp ${modfiles} "${S}"/${1} \
> +                     || die "Failed to copy the module files to ${S}/${1}"
> +     }
> +
> +     if [[ ${EAPI} == 7 ]]; then
> +             for i in ${POLICY_TYPES}; do
> +                     _selinux_prepare_modules $i
> +             done
> +     else
> +             for i in targeted strict mcs mls; do
> +                     if use selinux_policy_types_${i}; then
> +                             _selinux_prepare_modules $i
> +                     fi
> +             done
> +     fi
>  }
>  
>  # @FUNCTION: selinux-policy-2_src_compile
> @@ -213,16 +252,39 @@ selinux-policy-2_src_prepare() {
>  # this for each SELinux policy mentioned in POLICY_TYPES
>  selinux-policy-2_src_compile() {
>       local makeuse=""
> +     # We use IUSE instead of USE so that other variables set in the ebuild
> +     # environment, such as architecture ones, are not included.
>       for useflag in ${IUSE};
>       do
> +             # Advance past a possible '+' character: that is NOT part of 
> the USE flag,
> +             # but instead indicates whether it is enabled by default.
> +             useflag="${useflag##+}"
> +
> +             # Only additional USE flags defined in our consumers should be 
> added to
> +             # build options: SELINUX_POLICY_TYPES should NOT be passed to 
> the policy
> +             # build system.
> +             [[ "${useflag}" == selinux_policy_types_* ]] && continue
> +
>               use ${useflag} && makeuse="${makeuse} -D use_${useflag}"
>       done
>  
> -     for i in ${POLICY_TYPES}; do
> +     _selinux_compile_modules() {
>               # Support USE flags in builds
>               export M4PARAM="${makeuse}"
> -             emake NAME=$i SHAREDIR="${EPREFIX}"/usr/share/selinux -C 
> "${S}"/${i}
> -     done
> +             emake NAME=$1 SHAREDIR="${EPREFIX}"/usr/share/selinux -C 
> "${S}"/${1}
> +     }
> +
> +     if [[ ${EAPI} == 7 ]]; then
> +             for i in ${POLICY_TYPES}; do
> +                     _selinux_compile_modules $i
> +             done
> +     else
> +             for i in targeted strict mcs mls; do
> +                     if use selinux_policy_types_${i}; then

Check everywhere wrt localise point.

> +                             _selinux_compile_modules $i
> +                     fi
> +             done
> +     fi
>  }
>  
>  # @FUNCTION: selinux-policy-2_src_install
> @@ -232,22 +294,34 @@ selinux-policy-2_src_compile() {
>  selinux-policy-2_src_install() {
>       local BASEDIR="/usr/share/selinux"
>  
> -     for i in ${POLICY_TYPES}; do
> -             for j in ${MODS}; do
> -                     einfo "Installing ${i} ${j} policy package"
> -                     insinto ${BASEDIR}/${i}
> -                     if [[ -f "${S}/${i}/${j}.pp" ]] ; then
> -                       doins "${S}"/${i}/${j}.pp || die "Failed to add 
> ${j}.pp to ${i}"
> -                     elif [[ -f "${S}/${i}/${j}.cil" ]] ; then
> -                       doins "${S}"/${i}/${j}.cil || die "Failed to add 
> ${j}.cil to ${i}"
> +     _selinux_install_modules() {

Always `local`ise variables in functions first, or their value will leak
afterwards.

> +             for i in ${MODS}; do

Make MODS a proper array?

> +                     einfo "Installing ${1} ${i} policy package"
> +                     insinto ${BASEDIR}/${1}
> +                     if [[ -f "${S}/${1}/${i}.pp" ]] ; then
> +                       doins "${S}"/${1}/${i}.pp || die "Failed to add 
> ${i}.pp to ${1}"
> +                     elif [[ -f "${S}/${1}/${i}.cil" ]] ; then
> +                       doins "${S}"/${1}/${i}.cil || die "Failed to add 
> ${i}.cil to ${1}"
>                       fi
>  
> -                     if [[ "${POLICY_FILES[@]}" == *"${j}.if"* ]]; then
> -                             insinto ${BASEDIR}/${i}/include/3rd_party
> -                             doins "${S}"/${i}/${j}.if || die "Failed to add 
> ${j}.if to ${i}"
> +                     if [[ "${POLICY_FILES[@]}" == *"${i}.if"* ]]; then
> +                             insinto ${BASEDIR}/${1}/include/3rd_party
> +                             doins "${S}"/${1}/${i}.if || die "Failed to add 
> ${i}.if to ${1}"

doins || die is redundant (no need for die); it's a helper in the spec
and it is defined to die in modern EAPIs, so the 'die' is unreachable.

If you REALLY want to add a custom error message, you can use nonfatal
but I don't think that is worth it here.

>                       fi
>               done
> -     done
> +     }
> +
> +     if [[ ${EAPI} == 7 ]]; then
> +             for i in ${POLICY_TYPES}; do
> +                     _selinux_install_modules $i
> +             done
> +     else
> +             for i in targeted strict mcs mls; do

May want to just have some array with each of these names (either with
or without the prefix, or one w/ and then another w/ it stripped, dunno)
so you don't have to keep repeating it.

> +                     if use selinux_policy_types_${i}; then
> +                             _selinux_install_modules $i
> +                     fi
> +             done
> +     fi
>  }
>  
>  # @FUNCTION: selinux-policy-2_pkg_postinst
> @@ -264,31 +338,31 @@ selinux-policy-2_pkg_postinst() {
>       # build up the command in the case of multiple modules
>       local COMMAND
>  
> -     for i in ${POLICY_TYPES}; do
> -             if [[ "${i}" == "strict" ]] && [[ "${MODS}" = "unconfined" ]]; 
> then
> +     _selinux_postinst() {
> +             if [[ "${1}" == "strict" ]] && [[ "${MODS}" =

Also, consistently use == or = please. I always use == in bash tests
because When In Bash (as we're already making full use of bashisms).

> "unconfined" ]]; then

You can put these inside the same [[ ]].

>                       einfo "Ignoring loading of unconfined module in strict 
> module store.";
>                       continue;
>               fi
>  
>               einfo "Inserting the following modules into the $i module 
> store: ${MODS}"
>  
> -             cd "${ROOT}/usr/share/selinux/${i}" || die "Could not enter 
> /usr/share/selinux/${i}"
> -             for j in ${MODS} ; do
> -                     if [[ -f "${j}.pp" ]] ; then
> -                             COMMAND="${j}.pp ${COMMAND}"
> -                     elif [[ -f "${j}.cil" ]] ; then
> -                             COMMAND="${j}.cil ${COMMAND}"
> +             cd "${ROOT}/usr/share/selinux/${1}" || die "Could not enter 
> /usr/share/selinux/${1}"
> +             for i in ${MODS} ; do
> +                     if [[ -f "${i}.pp" ]] ; then
> +                             COMMAND="${i}.pp ${COMMAND}"
> +                     elif [[ -f "${i}.cil" ]] ; then
> +                             COMMAND="${i}.cil ${COMMAND}"

If neither are true, what do we want to do? Warn about it? Is doing
nothing OK? Should we add a comment explaining this?

>                       fi
>               done
>  
> -             semodule ${root_opts} -s ${i} -i ${COMMAND}
> +             semodule ${root_opts} -s ${1} -i ${COMMAND}
>               if [[ $? -ne 0 ]]; then
>                       ewarn "SELinux module load failed. Trying full 
> reload...";
>  
> -                     if [[ "${i}" == "targeted" ]]; then
> -                             semodule ${root_opts} -s ${i} -i *.pp
> +                     if [[ "${1}" == "targeted" ]]; then
> +                             semodule ${root_opts} -s ${1} -i *.pp
>                       else
> -                             semodule ${root_opts} -s ${i} -i $(ls *.pp | 
> grep -v unconfined.pp);
> +                             semodule ${root_opts} -s ${1} -i $(ls *.pp | 
> grep -v unconfined.pp);

Parsing output of `ls` is bad practice: https://mywiki.wooledge.org/ParsingLs

>                       fi
>                       if [[ $? -ne 0 ]]; then
>                               ewarn "Failed to reload SELinux policies."
> @@ -302,7 +376,7 @@ selinux-policy-2_pkg_postinst() {
>                               ewarn "action since the new SELinux policies 
> are not loaded until the"
>                               ewarn "command finished successfully."
>                               ewarn ""
> -                             ewarn "To reload, run the following command 
> from within /usr/share/selinux/${i}:"
> +                             ewarn "To reload, run the following command 
> from within /usr/share/selinux/${1}:"
>                               ewarn "  semodule -i *.pp"
>                               ewarn "or"
>                               ewarn "  semodule -i \$(ls *.pp | grep -v 
> unconfined.pp)"
> @@ -314,7 +388,19 @@ selinux-policy-2_pkg_postinst() {
>                       einfo "SELinux modules loaded successfully."
>               fi
>               COMMAND="";
> -     done
> +     }
> +
> +     if [[ ${EAPI} == 7 ]]; then
> +             for i in ${POLICY_TYPES}; do
> +                     _selinux_postinst $i
> +             done
> +     else
> +             for i in targeted strict mcs mls; do
> +                     if use selinux_policy_types_${i}; then
> +                             _selinux_postinst $i
> +                     fi
> +             done
> +     fi
>  
>       # Don't relabel when cross compiling
>       if [[ -z ${ROOT} ]]; then
> @@ -350,16 +436,28 @@ selinux-policy-2_pkg_postrm() {
>                       COMMAND="-r ${i} ${COMMAND}"
>               done
>  
> -             for i in ${POLICY_TYPES}; do
> -                     einfo "Removing the following modules from the $i 
> module store: ${MODS}"
> +             _selinux_postrm() {
> +                     einfo "Removing the following modules from the $1 
> module store: ${MODS}"
>  
> -                     semodule ${root_opts} -s ${i} ${COMMAND}
> +                     semodule ${root_opts} -s ${1} ${COMMAND}
>                       if [[ $? -ne 0 ]]; then
>                               ewarn "SELinux module unload failed.";

ebegin/eend might be nicer for this? I am not sure if it would be too
noisy though (it might run many times, or just a few times, dunno).

>                       else
>                               einfo "SELinux modules unloaded successfully."
>                       fi
> -             done
> +             }
> +
> +             if [[ ${EAPI} == 7 ]]; then
> +                     for i in ${POLICY_TYPES}; do
> +                             _selinux_postrm $i
> +                     done
> +             else
> +                     for i in targeted strict mcs mls; do
> +                             if use selinux_policy_types_${i}; then
> +                                     _selinux_postrm $i
> +                             fi
> +                     done
> +             fi
>       fi
>  }
>  
> diff --git a/profiles/base/make.defaults b/profiles/base/make.defaults
> index 1d272050d375..9934496a96e2 100644
> --- a/profiles/base/make.defaults
> +++ b/profiles/base/make.defaults
> @@ -12,7 +12,7 @@ USE_EXPAND_VALUES_KERNEL="Darwin linux SunOS"
>  
>  # Env vars to expand into USE vars.  Modifying this requires prior
>  # discussion on [email protected].
> -USE_EXPAND="ABI_MIPS ABI_S390 ABI_X86 ADA_TARGET ALSA_CARDS AMDGPU_TARGETS 
> APACHE2_MODULES APACHE2_MPMS CALLIGRA_FEATURES CAMERAS COLLECTD_PLUGINS 
> CPU_FLAGS_ARM CPU_FLAGS_PPC CPU_FLAGS_X86 CURL_SSL CURL_QUIC ELIBC FFTOOLS 
> GPSD_PROTOCOLS GRUB_PLATFORMS GUILE_SINGLE_TARGET GUILE_TARGETS INPUT_DEVICES 
> KERNEL L10N LCD_DEVICES LIBREOFFICE_EXTENSIONS LLVM_SLOT LLVM_TARGETS 
> LUA_SINGLE_TARGET LUA_TARGETS NGINX_MODULES_HTTP NGINX_MODULES_MAIL 
> NGINX_MODULES_STREAM OFFICE_IMPLEMENTATION OPENMPI_FABRICS 
> OPENMPI_OFED_FEATURES OPENMPI_RM PERL_FEATURES PHP_TARGETS POSTGRES_TARGETS 
> PYTHON_SINGLE_TARGET PYTHON_TARGETS QEMU_SOFTMMU_TARGETS QEMU_USER_TARGETS 
> RUBY_TARGETS RUST_SYSROOTS SANE_BACKENDS UWSGI_PLUGINS VIDEO_CARDS 
> VOICEMAIL_STORAGE XTABLES_ADDONS"
> +USE_EXPAND="ABI_MIPS ABI_S390 ABI_X86 ADA_TARGET ALSA_CARDS AMDGPU_TARGETS 
> APACHE2_MODULES APACHE2_MPMS CALLIGRA_FEATURES CAMERAS COLLECTD_PLUGINS 
> CPU_FLAGS_ARM CPU_FLAGS_PPC CPU_FLAGS_X86 CURL_SSL CURL_QUIC ELIBC FFTOOLS 
> GPSD_PROTOCOLS GRUB_PLATFORMS GUILE_SINGLE_TARGET GUILE_TARGETS INPUT_DEVICES 
> KERNEL L10N LCD_DEVICES LIBREOFFICE_EXTENSIONS LLVM_SLOT LLVM_TARGETS 
> LUA_SINGLE_TARGET LUA_TARGETS NGINX_MODULES_HTTP NGINX_MODULES_MAIL 
> NGINX_MODULES_STREAM OFFICE_IMPLEMENTATION OPENMPI_FABRICS 
> OPENMPI_OFED_FEATURES OPENMPI_RM PERL_FEATURES PHP_TARGETS POSTGRES_TARGETS 
> PYTHON_SINGLE_TARGET PYTHON_TARGETS QEMU_SOFTMMU_TARGETS QEMU_USER_TARGETS 
> RUBY_TARGETS RUST_SYSROOTS SANE_BACKENDS UWSGI_PLUGINS VIDEO_CARDS 
> VOICEMAIL_STORAGE XTABLES_ADDONS SELINUX_POLICY_TYPES"
>  
>  # USE_EXPAND variables whose contents are not shown in package manager
>  # output. Changes need discussion on gentoo-dev.
> diff --git a/profiles/desc/selinux_policy_types.desc 
> b/profiles/desc/selinux_policy_types.desc
> new file mode 100644
> index 000000000000..0fe398aeaa89
> --- /dev/null
> +++ b/profiles/desc/selinux_policy_types.desc
> @@ -0,0 +1,9 @@
> +# Copyright 2025 Gentoo Authors
> +# Distributed under the terms of the GNU General Public License v2
> +
> +# This file contains descriptions of SELINUX_POLICY_TYPES USE_EXPAND flags.
> +
> +targeted - Targeted policy
> +strict - Strict policy
> +mcs - Multi-Category Security policy
> +mls - Multi-Level Security policy

Reply via email to