瀏覽代碼

Reduced the number of SUID binaries via POSIX.1e capabilities

Added check for security.* and user.* extended attributes-
capable filesystem to "mkroot", in order to enable replacing
some SUID bits with POSIX.1e capabilities.

Enabled security.* extended attributes in the kernel, and
removed PT_PAX support in anticipation for migration to
XATTR_PAX (which is fine since current image has no PaX
exceptions).

Moved SUID bits cleanup from "mkimage" into "src" phase.
Added capabilities / xattrs / ACL checks to "chk-live-tree".

Unified "src" and "image" phases.

Moved "copy" tree creation and pruning into "mkimage".
XA-capable "rsync" is not required in the build environment
anymore.

Removed /usr/portage/distfiles sharing with build environment,
simplifying possible change of DISTDIR and other defaults in
the future in Gentoo. This also enables better testing of
fresh builds (all packages are redownloaded).

Added Secure Boot CA certificate to the git tree.
Maxim Kammerer 12 年之前
父節點
當前提交
50cd9e6eb8

+ 4 - 10
build

@@ -30,28 +30,22 @@ sinfo "Downloading and extracting stage3 and portage snapshots"
 ${SRC}/mkroot ${LIVECD} $2
 
 # If "fresh" parameter is passed, rebuilds system from scratch
-sinfo "Installing packages"
+sinfo "Installing packages and configuring system"
 ${SRC}/enter ${LIVECD} -c "./setup $2"
 
 # Reverse emerge rewriting /etc files during full build
-sinfo "Restoring configuration files"
-${SRC}/enter ${LIVECD} -c true
-
 # Destructive operations are done on ${LIVECD}/copy
-sinfo "Synchronizing to a temporary copy"
-${SRC}/mkroot ${LIVECD} copy
+sinfo "Restoring configuration and copying the live tree"
+${SRC}/enter ${LIVECD} -c "./mkimage copy"
 
 # Cleans up ${LIVECD}/copy from inside
 sinfo "Uninstalling development packages"
 ${SRC}/enter ${LIVECD} copy -c ./setup-copy
 
 # Cleans up ${LIVECD}/copy from outside
-sinfo "Pruning the temporary copy"
-${SRC}/mkroot ${LIVECD} clean
-
 # Builds "liberte" dir in ${LIVECD}/dist to deploy
 sinfo "Mastering deployment directory"
-${SRC}/enter ${LIVECD} image -c ./mkimage
+${SRC}/enter ${LIVECD} -c ./mkimage
 
 # OK to copy "liberte" dir and run setup.sh
 sinfo "Done: ZIP archive in ${LIVECD}/dist"

二進制
conf/certs/Liberte-SecureBoot-CA.der


+ 1 - 0
doc/changelog.txt

@@ -4,6 +4,7 @@
   * Better support for QEMU mouse virtualization
   * Xorg server 1.13
   * Firewire SBP-2 module is blacklisted to prevent Firewire RAM access
+  * Reduced the number of SUID binaries via POSIX.1e capabilities
 
   * Replaced htpdate with tlsdate for time synchronization
   * Added "gentoo=obfs" boot parameter for obfsproxy Tor bridges

+ 13 - 29
enter

@@ -7,7 +7,7 @@ sinfo() {
 
 # Must have root directory as an argument
 if [ -z "$1" ]; then
-    echo "$0 <livecd root> [copy|image] [-c shell command...]"
+    echo "$0 <livecd root> [copy] [-c 'shell command']"
     exit 1
 fi
 
@@ -39,10 +39,6 @@ if [ "$2" = copy ]; then
     PHASE=$2
     LIVECD=$1/${PHASE}
     shift 2
-elif [ "$2" = image ]; then
-    PHASE=$2
-    LIVECD=$1/src
-    shift 2
 else
     PHASE=src
     LIVECD=$1/${PHASE}
@@ -109,6 +105,7 @@ environment="${environment} PHASE=${PHASE}"
 setarch=`which setarch`
 chroot=`which chroot`
 tty=`tty`
+mounted=
 
 
 sinfo "Mounting system directories"
@@ -125,22 +122,17 @@ for mp in /proc /dev/null /dev/random /dev/urandom /dev/tty /dev/ptmx /dev/pts $
         fi
     fi
     mount -B ${mp} ${LIVECD}${mp}
+    mounted="${LIVECD}${mp} ${mounted}"
 done
 mount -rB -o remount ${LIVECD}/proc
 
-if [ ${PHASE} = copy  -a  -d ${LIVECD}/usr/portage ]; then
-    mount -B ${LIVECD}/../src/usr/portage ${LIVECD}/usr/portage
-    mount -rB -o remount ${LIVECD}/usr/portage
-fi
-
-if [ -d /usr/portage/distfiles  -a  -d ${LIVECD}/usr/portage/distfiles ]; then
-    mount -B /usr/portage/distfiles ${LIVECD}/usr/portage/distfiles
-fi
-
-if [ ${PHASE} = image ]; then
-    mkdir -p ${LIVECD}/../dist
+if   [ ${PHASE} = src ]; then
+    mkdir -p -m 755 ${LIVECD}/../copy ${LIVECD}/../dist
     mount -B ${LIVECD}/../copy ${LIVECD}/mnt/live
     mount -B ${LIVECD}/../dist ${LIVECD}/mnt/boot
+elif [ ${PHASE} = copy  -a  -d ${LIVECD}/usr/portage ]; then
+    mount -B ${LIVECD}/../src/usr/portage ${LIVECD}/usr/portage
+    mount -rB -o remount ${LIVECD}/usr/portage
 fi
 
 
@@ -160,22 +152,14 @@ fi
 # Unnecessary with unshare -m, but stale processes might hold the mounts
 sinfo "Unmounting system directories"
 
-if [ ${PHASE} = image ]; then
-    umount ${LIVECD}/mnt/live
-    umount ${LIVECD}/mnt/boot
-fi
-
-if [ -d /usr/portage/distfiles  -a  -d ${LIVECD}/usr/portage/distfiles ]; then
-    umount ${LIVECD}/usr/portage/distfiles
-fi
-
-if [ -d ${LIVECD}/usr/portage  -a  ${PHASE} = copy ]; then
+if   [ ${PHASE} = src ]; then
+    umount ${LIVECD}/mnt/live ${LIVECD}/mnt/boot
+elif [ ${PHASE} = copy  -a  -d ${LIVECD}/usr/portage ]; then
     umount ${LIVECD}/usr/portage
 fi
 
-for mp in ${tty} /dev/pts /dev/ptmx /dev/tty /dev/urandom /dev/random /dev/null /proc; do
-    umount -l ${LIVECD}${mp}
-done
+umount -l ${mounted}
+
 # Condition is false for empty ${tty} and for block-device ${tty} (i.e., unmount failed)
 if [ -f ${LIVECD}${tty} ]; then
     rm ${LIVECD}${tty}

+ 100 - 114
mkroot

@@ -9,8 +9,8 @@ sinfo() {
 
 
 # Must have root directory as an argument
-if [ -z "$1"  -o  \( -n "$2" -a "$2" != fresh -a "$2" != copy -a "$2" != clean \) ]; then
-    echo "$0 <livecd root> [fresh|copy|clean]"
+if [ -z "$1"  -o  \( -n "$2" -a "$2" != fresh \) ]; then
+    echo "$0 <livecd root> [fresh]"
     exit 1
 fi
 
@@ -29,147 +29,133 @@ gpg_wwwserver='https://zimmermann.mayfirst.org/pks/lookup?op=get&search=0x${fpr}
 gpg_keys=`sed '/^#/d; /^$/d; s/ //g' ${FROM}/conf/pubkeys`
 
 
-# Copying and pruning
-if [ "$2" = copy ]; then
-    sinfo "Copying ${LIVECD}/src to ${LIVECD}/copy"
-    rsync -aHAXS -x -i --delete-excluded               \
-        --include-from=${FROM}/conf/rootfs.includes    \
-        --exclude-from=${FROM}/conf/rootfs-cp.excludes \
-        ${LIVECD}/src/ ${LIVECD}/copy | head -n 20
-
-    sinfo "Done."
-    exit
-elif [ "$2" = clean ]; then
-    sinfo "Pruning ${LIVECD}/copy"
-    rsync -aHAXS -x -i --delete-excluded               \
-        --include-from=${FROM}/conf/rootfs.includes    \
-        --exclude-from=${FROM}/conf/rootfs.excludes    \
-        --exclude-from=${FROM}/conf/rootfs-cp.excludes \
-        ${LIVECD}/copy/ ${LIVECD}/copy | head
-
-    sinfo "Done."
+if [ "$2" != fresh  -a  -d ${LIVECD}/src ]; then
+    sinfo "Skipping overwrite of ${LIVECD}/src (use \"fresh\")"
     exit
 fi
 
 
 # Extract stage3 + portage snapshot to fresh directory
-if [ "$2" = fresh  -o  ! -d ${LIVECD}/src ]; then
-    # Download stage3 + portage snapshot
-    mkdir -p ${LIVECD}/mirror/stage3 ${LIVECD}/mirror/portage ${LIVECD}/mirror/keys
-    mkdir -p -m 700 ${LIVECD}/mirror/gnupg
-
-    # latest-stage3.txt contains YYYYMMDD/stage3-i686-YYYYMMDD.tar.bz2
-    sinfo "Fetching latest-stage3.txt"
-    wget -N -nv -P ${LIVECD}/mirror/stage3 ${stage3base}/latest-stage3.txt
-    stage3=`grep stage3-i686 ${LIVECD}/mirror/stage3/latest-stage3.txt`
-    stage3file=`basename ${stage3}`
-
-    # If a new stage3 is available, remove old mirrors
-    if [ ! -e ${LIVECD}/mirror/stage3/${stage3file} ]; then
-        rm -f ${LIVECD}/mirror/stage3/stage3-i686-*.tar.bz2*
-    fi
+# Download stage3 + portage snapshot
+mkdir -p ${LIVECD}/mirror/stage3 ${LIVECD}/mirror/portage ${LIVECD}/mirror/keys
+mkdir -p -m 700 ${LIVECD}/mirror/gnupg
+
+sinfo "Testing security labels and user xattrs support"
+touch ${LIVECD}/mirror/fs-test
+if ! setcap cap_net_raw+i  ${LIVECD}/mirror/fs-test || \
+   ! setfattr -n user.test ${LIVECD}/mirror/fs-test; then
+    echo "Filesystem does not support extended attributes."
+    echo "Try ext4 with EXT4_FS_SECURITY and -o user_xattr"
+    exit 1
+fi
+rm ${LIVECD}/mirror/fs-test
 
 
-    sinfo "Downloading ${stage3file}"
-    wget -c -nv -P ${LIVECD}/mirror/stage3 ${stage3base}/${stage3}.DIGESTS.asc \
-        ${stage3base}/${stage3}.CONTENTS ${stage3base}/${stage3}
+# latest-stage3.txt contains YYYYMMDD/stage3-i686-YYYYMMDD.tar.bz2
+sinfo "Fetching latest-stage3.txt"
+wget -N -nv -P ${LIVECD}/mirror/stage3 ${stage3base}/latest-stage3.txt
+stage3=`grep stage3-i686 ${LIVECD}/mirror/stage3/latest-stage3.txt`
+stage3file=`basename ${stage3}`
 
-    sinfo "Downloading portage-latest.tar.bz2"
-    wget -N -nv -P ${LIVECD}/mirror/portage ${portage}.gpgsig ${portage}
+# If a new stage3 is available, remove old mirrors
+if [ ! -e ${LIVECD}/mirror/stage3/${stage3file} ]; then
+    rm -f ${LIVECD}/mirror/stage3/stage3-i686-*.tar.bz2*
+fi
 
 
-    sinfo "Fetching PGP public keys and verifying fingerprints"
-    cp ${FROM}/conf/certs/mfpl.crt ${LIVECD}/mirror/keys
+sinfo "Downloading ${stage3file}"
+wget -c -nv -P ${LIVECD}/mirror/stage3 ${stage3base}/${stage3}.DIGESTS.asc \
+    ${stage3base}/${stage3}.CONTENTS ${stage3base}/${stage3}
 
-    for key in ${gpg_keys}; do
-        org=`echo ${key} | cut -d: -f1`
-        fpr=`echo ${key} | cut -d: -f2`
-        keyid=`echo -n ${fpr} | tail -c -8`
+sinfo "Downloading portage-latest.tar.bz2"
+wget -N -nv -P ${LIVECD}/mirror/portage ${portage}.gpgsig ${portage}
 
-        if [ ! -e ${LIVECD}/mirror/keys/${org}-${keyid}.asc ]; then
-            if ! eval wget -nv --retry-connrefused                         \
-                           --ca-certificate=${LIVECD}/mirror/keys/mfpl.crt \
-                           -O ${LIVECD}/mirror/keys/${org}-${keyid}.asc \"${gpg_wwwserver}\"; then
-                echo "Warning: Failed to fetch ${org}-${keyid}.asc, copying from cache"
-                cp ${FROM}/conf/certs/${org}-${keyid}.asc ${LIVECD}/mirror/keys
-            fi
-        fi
 
-        if type gpg 1>/dev/null 2>&1; then
-            gpg -q --homedir ${LIVECD}/mirror/gnupg --no-default-keyring \
-                --keyring ${org}.gpg --import ${LIVECD}/mirror/keys/${org}-${keyid}.asc
-
-            fpr2=`gpg -q --homedir ${LIVECD}/mirror/gnupg --keyring ${org}.gpg \
-                      --fingerprint --with-colons 0x${fpr} | sed -n '/^fpr:/p' | cut -d: -f10`
-            if [ ${fpr} != "${fpr2}" ]; then
-                echo "Fingerprint mismatch: [${fpr}] != [${fpr2}]"
-                exit 1
-            fi
-        else
-            sinfo "*** No GnuPG, skipping fingerprint verification: ${org}-${keyid}"
-        fi
-    done
+sinfo "Fetching PGP public keys and verifying fingerprints"
+cp ${FROM}/conf/certs/mfpl.crt ${LIVECD}/mirror/keys
 
+for key in ${gpg_keys}; do
+    org=`echo ${key} | cut -d: -f1`
+    fpr=`echo ${key} | cut -d: -f2`
+    keyid=`echo -n ${fpr} | tail -c -8`
+
+    if [ ! -e ${LIVECD}/mirror/keys/${org}-${keyid}.asc ]; then
+        if ! eval wget -nv --retry-connrefused                         \
+                       --ca-certificate=${LIVECD}/mirror/keys/mfpl.crt \
+                       -O ${LIVECD}/mirror/keys/${org}-${keyid}.asc \"${gpg_wwwserver}\"; then
+            echo "Warning: Failed to fetch ${org}-${keyid}.asc, copying from cache"
+            cp ${FROM}/conf/certs/${org}-${keyid}.asc ${LIVECD}/mirror/keys
+        fi
+    fi
 
     if type gpg 1>/dev/null 2>&1; then
-        sinfo "Verifying keyrings"
-        for keyring in `echo "${gpg_keys}" | cut -d: -f1 | sort -u`; do
-            keyids=`gpg -q -k --homedir ${LIVECD}/mirror/gnupg --keyring ${keyring}.gpg \
-                        --fingerprint --with-colons | sed -n '/^fpr:/p' | cut -d: -f10 | sort`
-            expids=`echo "${gpg_keys}" | sed -n "/^${keyring}:/p" | cut -d: -f2 | sort`
-
-            if [ "${keyids}" != "${expids}" ]; then
-                echo "Unexpected public keys in keyring ${keyring}.gpg"
-                exit 1
-            fi
-        done
-
-
-        sinfo "Verifying stage3 and portage PGP signatures"
-        gpg -q --homedir ${LIVECD}/mirror/gnupg --trust-model always --keyring gentoo.gpg \
-            --verify ${LIVECD}/mirror/stage3/${stage3file}.DIGESTS.asc
-        gpg -q --homedir ${LIVECD}/mirror/gnupg --trust-model always --keyring gentoo.gpg \
-            --verify ${LIVECD}/mirror/portage/portage-latest.tar.bz2.gpgsig \
-                     ${LIVECD}/mirror/portage/portage-latest.tar.bz2
+        gpg -q --homedir ${LIVECD}/mirror/gnupg --no-default-keyring \
+            --keyring ${org}.gpg --import ${LIVECD}/mirror/keys/${org}-${keyid}.asc
+
+        fpr2=`gpg -q --homedir ${LIVECD}/mirror/gnupg --keyring ${org}.gpg \
+                  --fingerprint --with-colons 0x${fpr} | sed -n '/^fpr:/p' | cut -d: -f10`
+        if [ ${fpr} != "${fpr2}" ]; then
+            echo "Fingerprint mismatch: [${fpr}] != [${fpr2}]"
+            exit 1
+        fi
     else
-        sinfo "*** No GnuPG, skipping stage3, portage and HKPS CA certificate verification"
+        sinfo "*** No GnuPG, skipping fingerprint verification: ${org}-${keyid}"
     fi
+done
 
 
-    sinfo "Verifying stage3 SHA512 digests"
-    sed -i '6,7d; 10,11d' ${LIVECD}/mirror/stage3/${stage3file}.DIGESTS.asc
-    (cd ${LIVECD}/mirror/stage3; sha512sum -c ${stage3file}.DIGESTS.asc)
-
-
-    if tar --version | grep -q '(GNU tar)'; then
-        sinfo "Verifying stage3 files list"
-        LC_ALL=C tar --utc -tjvf ${LIVECD}/mirror/stage3/${stage3file} > ${LIVECD}/mirror/stage3/${stage3file}.CONTENTS.actual
-        cmp -s ${LIVECD}/mirror/stage3/${stage3file}.CONTENTS \
-               ${LIVECD}/mirror/stage3/${stage3file}.CONTENTS.actual
-        rm     ${LIVECD}/mirror/stage3/${stage3file}.CONTENTS.actual
-    else
-        sinfo "*** No GNU tar, skipping stage3 files list verification"
-    fi
+if type gpg 1>/dev/null 2>&1; then
+    sinfo "Verifying keyrings"
+    for keyring in `echo "${gpg_keys}" | cut -d: -f1 | sort -u`; do
+        keyids=`gpg -q -k --homedir ${LIVECD}/mirror/gnupg --keyring ${keyring}.gpg \
+                    --fingerprint --with-colons | sed -n '/^fpr:/p' | cut -d: -f10 | sort`
+        expids=`echo "${gpg_keys}" | sed -n "/^${keyring}:/p" | cut -d: -f2 | sort`
 
+        if [ "${keyids}" != "${expids}" ]; then
+            echo "Unexpected public keys in keyring ${keyring}.gpg"
+            exit 1
+        fi
+    done
 
-	sinfo "Removing ${LIVECD}/src"
-    rm -rf --one-file-system ${LIVECD}/src
-    mkdir -m 755 ${LIVECD}/src
 
+    sinfo "Verifying stage3 and portage PGP signatures"
+    gpg -q --homedir ${LIVECD}/mirror/gnupg --trust-model always --keyring gentoo.gpg \
+        --verify ${LIVECD}/mirror/stage3/${stage3file}.DIGESTS.asc
+    gpg -q --homedir ${LIVECD}/mirror/gnupg --trust-model always --keyring gentoo.gpg \
+        --verify ${LIVECD}/mirror/portage/portage-latest.tar.bz2.gpgsig \
+                 ${LIVECD}/mirror/portage/portage-latest.tar.bz2
+else
+    sinfo "*** No GnuPG, skipping stage3, portage and HKPS CA certificate verification"
+fi
 
-    sinfo "Extracting stage3 to ${LIVECD}/src"
-    tar -xpSjf ${LIVECD}/mirror/stage3/${stage3file} -C ${LIVECD}/src --exclude './dev/*'
 
+sinfo "Verifying stage3 SHA512 digests"
+sed -i '6,7d; 10,11d' ${LIVECD}/mirror/stage3/${stage3file}.DIGESTS.asc
+(cd ${LIVECD}/mirror/stage3; sha512sum -c ${stage3file}.DIGESTS.asc)
 
-    sinfo "Extracting portage to ${LIVECD}/src/usr"
-    tar -xpSjf ${LIVECD}/mirror/portage/portage-latest.tar.bz2 -C ${LIVECD}/src/usr
 
-    uidgid=`grep '^portage:' ${LIVECD}/src/etc/passwd | cut -d: -f3,4`
-    mkdir -m 2775   ${LIVECD}/src/usr/portage/distfiles
-    chown ${uidgid} ${LIVECD}/src/usr/portage/distfiles
+if tar --version | grep -q '(GNU tar)'; then
+    sinfo "Verifying stage3 files list"
+    LC_ALL=C tar --utc -tjvf ${LIVECD}/mirror/stage3/${stage3file} > ${LIVECD}/mirror/stage3/${stage3file}.CONTENTS.actual
+    cmp -s ${LIVECD}/mirror/stage3/${stage3file}.CONTENTS \
+           ${LIVECD}/mirror/stage3/${stage3file}.CONTENTS.actual
+    rm     ${LIVECD}/mirror/stage3/${stage3file}.CONTENTS.actual
 else
-    sinfo "Skipping overwrite of ${LIVECD}/src (use \"fresh\")"
+    sinfo "*** No GNU tar, skipping stage3 files list verification"
 fi
 
 
+	sinfo "Removing ${LIVECD}/src"
+rm -rf --one-file-system ${LIVECD}/src
+mkdir -m 755 ${LIVECD}/src
+
+
+sinfo "Extracting stage3 to ${LIVECD}/src"
+tar -xpSjf ${LIVECD}/mirror/stage3/${stage3file} -C ${LIVECD}/src --exclude './dev/*'
+
+
+sinfo "Extracting portage to ${LIVECD}/src/usr"
+tar -xpSjf ${LIVECD}/mirror/portage/portage-latest.tar.bz2 -C ${LIVECD}/src/usr
+
+
 sinfo "Done."

+ 1 - 0
src/etc/portage/package.use

@@ -71,6 +71,7 @@ media-libs/freetype             -bzip2
 x11-libs/libXfont               -bzip2
 dev-libs/libxml2                -lzma
 sys-apps/busybox                -pam
+sys-apps/gradm                  -pam
 net-misc/openvpn                -pam
 sys-apps/grep                   -pcre
 dev-lang/tcl                    -threads

+ 1 - 1
src/etc/portage/profile/package.provided

@@ -1,5 +1,5 @@
 # virtual/mta (sudo, gnupg, procmail)
-mail-mta/ssmtp-0
+mail-mta/nullmailer-0
 
 # virtual/mailx (smartmontools)
 mail-client/mailx-0

+ 2 - 2
src/root/config/linux-3.4.7-hardened.config

@@ -3581,7 +3581,7 @@ CONFIG_EXT4_FS=m
 CONFIG_EXT4_USE_FOR_EXT23=y
 CONFIG_EXT4_FS_XATTR=y
 CONFIG_EXT4_FS_POSIX_ACL=y
-# CONFIG_EXT4_FS_SECURITY is not set
+CONFIG_EXT4_FS_SECURITY=y
 # CONFIG_EXT4_DEBUG is not set
 CONFIG_JBD2=m
 CONFIG_FS_MBCACHE=m
@@ -3861,7 +3861,7 @@ CONFIG_PAX=y
 #
 # CONFIG_PAX_SOFTMODE is not set
 # CONFIG_PAX_EI_PAX is not set
-CONFIG_PAX_PT_PAX_FLAGS=y
+# CONFIG_PAX_PT_PAX_FLAGS is not set
 CONFIG_PAX_XATTR_PAX_FLAGS=y
 # CONFIG_PAX_NO_ACL_FLAGS is not set
 CONFIG_PAX_HAVE_ACL_FLAGS=y

+ 5 - 1
conf/rootfs-cp.excludes → src/root/config/rootfs-cp.excludes

@@ -2,7 +2,11 @@
 # Patterns should not disturb unmerges
 # (aggregates with exclusions for copy -> clean)
 
-# Bind-mount /usr/portage and /usr/portage/distfiles
+# Bind-mounts (see "enter" script)
+/dev/**
+/proc/**
+/mnt/boot/**
+/mnt/live/**
 /usr/portage/**
 
 # Sources

+ 1 - 0
conf/rootfs.excludes → src/root/config/rootfs.excludes

@@ -209,3 +209,4 @@
 /usr/sbin/fix_libtool_files.sh
 /usr/share/gcc-data/fixlafiles.awk
 /usr/bin/c[89]9
+/usr/bin/sudoedit

+ 0 - 1
src/root/config/rootfs.ignore

@@ -1,3 +1,2 @@
 boot
-dev
 tmp/transient

+ 0 - 0
conf/rootfs.includes → src/root/config/rootfs.includes


+ 10 - 0
src/root/config/rootfs.nosuid

@@ -2,12 +2,18 @@
 /bin/passwd
 /usr/bin/gpasswd
 
+# Switching groups is unnecessary
+/usr/bin/newgrp
+
 # Administrative dbs entries editing is unnecessary
 /usr/bin/chfn
 /usr/bin/chsh
 /usr/bin/chage
 /usr/bin/expiry
 
+# Inter-user tty messages are unnecessary
+/usr/bin/write
+
 # pt_chown is not used with devpts
 /usr/lib/misc/glibc/pt_chown
 
@@ -31,3 +37,7 @@
 /usr/bin/cdda2wav
 /usr/bin/readcd
 /usr/sbin/rscsi
+
+# POSIX.1e capabilities
+/sbin/unix_chkpwd cap_dac_read_search+ep
+/bin/ping         cap_net_raw+ep

+ 0 - 1
src/root/config/rootfs.pseudo

@@ -1 +0,0 @@
-dev d 755 0 0

+ 7 - 2
src/root/helpers/chk-live-tree

@@ -72,13 +72,18 @@ sinfo "Logs:"
 find . -name '*.log*' -o -type f \( -path './var/run/*' -o -path './var/log/*' \)
 
 
-sinfo "SUID/SGID:"
+sinfo "SUID / SGID / capabilities / xattrs / ACLs:"
 find . -type f -perm /u+s      -printf '%M %u %g\t/%P\n'
 find . -type f -perm /g+s,o+w  -printf '%M %u %g\t/%P\n'
 find . -type d -perm /a+st,o+w -printf '%M %u %g\t/%P\n'
 
+getcap -r . | sed 's/^\.//'
+getfattr -dhR -m- . | sed -r '/^(security\.capability|system\.posix_acl_access)=/d' \
+    | sed -nr '/^# file: /{ s/^# file: (.*)/\/\1:\t/; h; b }; /^./H; /^$/{x; s/\n/ /gp}'
+getfacl -psR .
 
-sinfo "STACK/TEXTRELs/PaX markings:"
+
+sinfo "STACK / TEXTRELs / PaX markings:"
 find . -type f \( -name '*.so*' -o -perm /111 \) ! -path './usr/lib/paxtest/*' -print0 \
     | xargs -0 scanelf -qtex
 

+ 40 - 26
src/root/mkimage

@@ -10,16 +10,12 @@ sinfo() {
 
 # Variables
 helpdir=${HOME}/helpers
-nosuid=${HOME}/config/rootfs.nosuid
 
 live=/mnt/live
-cdroot=/mnt/boot/cdroot
-distroot=/mnt/boot
+rootfspfx=${HOME}/config/rootfs
 
-distname=liberte-${LVERSION}
-zipfile=${distroot}/${distname}.zip
-isofile=${distroot}/${distname}.iso
-isobsfile=${distroot}/${distname}-bootstrap.iso
+cdroot=/mnt/boot/cdroot
+imagepfx=/mnt/boot/liberte-${LVERSION}
 
 efilabel=LIBERTE_EFI
 efiboot=${cdroot}/boot/efiboot.img
@@ -28,8 +24,6 @@ efisbpfx=/usr/local/addons/secureboot/Liberte-SecureBoot
 ziimage=${cdroot}/liberte/boot/kernel-x86.zi
 sqimage=${cdroot}/liberte/boot/root-x86.sfs
 sqsort=${live}/tmp/transient/pkg/squashfs.sort
-sqpseudo=${HOME}/config/rootfs.pseudo
-sqignore=${HOME}/config/rootfs.ignore
 
 sysver=`syslinux -v 2>&1 | cut -d' ' -f2`
 
@@ -40,8 +34,25 @@ mibsize() {
 }
 
 
-sinfo "Removing unnecessary SUID bits"
-chmod a-s `sed -n "s:^/:${live}&:p" ${nosuid}`
+if [ "$1" = copy ]; then
+    # Relies on 755 mode of .../{copy,/dist}
+    # (copied over to .../copy/mnt/{live,boot})
+    sinfo "Creating temporary copy"
+    rsync -aHAXS -x -i --delete-excluded        \
+        --include-from=${rootfspfx}.includes    \
+        --exclude-from=${rootfspfx}-cp.excludes \
+        / ${live} | head
+    sinfo "Done."
+    exit
+fi
+
+
+sinfo "Pruning the temporary copy"
+rsync -aHAXS -x -i --delete-excluded        \
+    --include-from=${rootfspfx}.includes    \
+    --exclude-from=${rootfspfx}.excludes    \
+    --exclude-from=${rootfspfx}-cp.excludes \
+    ${live}/ ${live} | head
 
 
 # Check the live tree
@@ -81,9 +92,12 @@ find ${cdroot} \( -name '*.txt' -o -name '*.bat' -o -name '*.cfg' \) \
 # (chmod due to GRKERNSEC_HIDESYM)
 sinfo "Creating SquashFS image"
 
-mksquashfs ${live} ${sqimage} -noappend -no-progress -no-exports \
-    -always-use-fragments -no-xattrs -comp xz -Xbcj x86          \
-    -pf ${sqpseudo} -sort ${sqsort} -ef ${sqignore}
+# NOTE: POSIX ACLs are not supported by SquashFS
+#       Non-PaX user xattrs are not supported by tmpfs
+mksquashfs ${live} ${sqimage}                \
+    -noappend -no-progress -no-exports       \
+    -always-use-fragments -comp xz -Xbcj x86 \
+    -sort ${sqsort} -ef ${rootfspfx}.ignore
 chmod go= ${sqimage}
 
 
@@ -119,10 +133,10 @@ done
 
 # UEFI Spec 2.3.1 Err. A, Sec. 12.3.3: "UEFI implementations may allow
 # the use of conforming FAT partitions which do not use the ESP GUID."
-sinfo "Building binary distribution ${zipfile##*/}"
-rm -f ${zipfile}
-(cd ${cdroot}; zip -r9 -q ${zipfile} EFI liberte)
-unzip -qt ${zipfile}
+sinfo "Building binary distribution ${imagepfx##*/}.zip"
+rm -f ${imagepfx}.zip
+(cd ${cdroot}; zip -r9 -q ${imagepfx}.zip EFI liberte)
+unzip -qt ${imagepfx}.zip
 
 
 # Add two extra 4K blocks (may need adjustment)
@@ -139,7 +153,7 @@ MTOOLS_SKIP_CHECK=1 mcopy -i ${efiboot} -smQ ${cdroot}/EFI ::
 # Hide root directories on Windows, and reset volume information
 # Allow '-' in filenames, since ISOLINUX doesn't support RockRidge/Joliet
 # (translation equivalent to mount's map=normal is still performed)
-sinfo "Creating ISO image ${isofile##*/}"
+sinfo "Creating ISO image ${imagepfx##*/}.iso"
 
 mkdir ${cdroot}/boot/syslinux
 cp -p ${cdroot}/liberte/boot/syslinux/syslinux.cfg \
@@ -153,18 +167,18 @@ set -- -quiet -iso-level 2 -relaxed-filenames -R -no-pad \
        -eltorito-alt-boot -no-emul-boot                  \
        -eltorito-platform efi -b boot/efiboot.img        \
        -hidden boot -hidden liberte -m EFI
-mkisofs "$@" -o ${isofile} ${cdroot}
-isovfy ${isofile}
+mkisofs "$@" -o ${imagepfx}.iso ${cdroot}
+isovfy ${imagepfx}.iso
 
 
-sinfo "Creating ISO image ${isobsfile##*/}"
-mkisofs "$@" -m ${sqimage##*/} -o ${isobsfile} ${cdroot}
-isovfy ${isobsfile}
+sinfo "Creating ISO image ${imagepfx##*/}-bootstrap.iso"
+mkisofs "$@" -m ${sqimage##*/} -o ${imagepfx}-bootstrap.iso ${cdroot}
+isovfy ${imagepfx}-bootstrap.iso
 
 
 echo "Disk usage: `du -s --apparent-size -B 1M ${cdroot} | cut -f1` MiB"
-echo "ZIP size:   `mibsize ${zipfile}` MiB"
-echo "ISO size:   `mibsize ${isofile}` MiB"
+echo "ZIP size:   `mibsize ${imagepfx}.zip` MiB"
+echo "ISO size:   `mibsize ${imagepfx}.iso` MiB"
 
 
 sinfo "Done."

+ 10 - 0
src/root/setup

@@ -408,6 +408,7 @@ install -d -g uucp -m 775 /run/lock
 
 
 # (lastlog is not sparse on overlayfs, wtmp has no growth limit)
+# /var/run/utmp is created in bootmisc (which is disabled)
 sinfo "Disabling non-rotating logs"
 ln -sf /dev/null /var/log/ConsoleKit/history
 ln -sf /dev/null /var/log/lastlog
@@ -455,6 +456,15 @@ useradd -c nscd    -d /dev/null -s /sbin/nologin -r nscd || [ $? = 9 ]
 useradd -c slay    -d /dev/null -s /sbin/nologin -r slay || [ $? = 9 ]
 
 
+sinfo "Minimizing SUID bits in favor of POSIX.1e capabilities"
+sed -n '/^\//p' ${HOME}/config/rootfs.nosuid | while read file caps; do
+    chmod a-s "${file}"
+    if [ -n "${caps}" ]; then
+        setcap "${caps}" "${file}"
+    fi
+done
+
+
 sinfo "Initializing a secondary PGP keyring"
 sudo -n -u anon gpg -q --homedir /home/anon/persist/security/pgp --no-default-keyring \
     --keyring liberte.gpg --import /usr/local/addons/keys/liberte-*.asc