Compare commits
12 Commits
2edc494216
...
cc479760b4
Author | SHA1 | Date |
---|---|---|
Dave Reisner | cc479760b4 | |
Luca Boccassi | 0389f4fa81 | |
Lennart Poettering | 6fe01ced0e | |
Zbigniew Jędrzejewski-Szmek | 75ae672bb2 | |
Zbigniew Jędrzejewski-Szmek | 5c9918aca0 | |
Lennart Poettering | 65804d6aff | |
Elisei Roca | 9e1732924d | |
наб | affa893da0 | |
наб | c2ad8c0978 | |
Frantisek Sumsal | 0116d27a30 | |
Frantisek Sumsal | 305efcaf3c | |
Frantisek Sumsal | eeb8c7accf |
187
.travis.yml
187
.travis.yml
|
@ -1,127 +1,82 @@
|
||||||
sudo: required
|
---
|
||||||
|
# vi: ts=2 sw=2 et:
|
||||||
|
|
||||||
|
language: bash
|
||||||
dist: bionic
|
dist: bionic
|
||||||
services:
|
services:
|
||||||
- docker
|
- docker
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- AUTHOR_EMAIL="$(git log -1 $TRAVIS_COMMIT --pretty=\"%aE\")"
|
- AUTHOR_EMAIL="$(git log -1 $TRAVIS_COMMIT --pretty=\"%aE\")"
|
||||||
- CI_MANAGERS="$TRAVIS_BUILD_DIR/travis-ci/managers"
|
- CI_MANAGERS="$TRAVIS_BUILD_DIR/travis-ci/managers"
|
||||||
- CI_TOOLS="$TRAVIS_BUILD_DIR/travis-ci/tools"
|
- CI_TOOLS="$TRAVIS_BUILD_DIR/travis-ci/tools"
|
||||||
- REPO_ROOT="$TRAVIS_BUILD_DIR"
|
- REPO_ROOT="$TRAVIS_BUILD_DIR"
|
||||||
|
jobs:
|
||||||
|
- DEBIAN_RELEASE=testing PHASE="RUN_GCC"
|
||||||
|
- DEBIAN_RELEASE=testing PHASE="RUN_GCC_ASAN_UBSAN"
|
||||||
|
- DEBIAN_RELEASE=testing PHASE="RUN_CLANG"
|
||||||
|
- DEBIAN_RELEASE=testing PHASE="RUN_CLANG_ASAN_UBSAN"
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- name: Build & test
|
# 'Test' is the default stage (for matrix jobs)
|
||||||
if: type != cron
|
- name: Test
|
||||||
|
if: type != cron
|
||||||
|
|
||||||
# Run Coverity periodically instead of for each commit/PR
|
# Run Coverity periodically instead of for each commit/PR
|
||||||
- name: Coverity
|
- name: Coverity
|
||||||
if: type = cron
|
if: type = cron
|
||||||
|
|
||||||
|
# Matrix job definition - this is run for each combination of env variables
|
||||||
|
# from the env.jobs array above
|
||||||
|
before_install:
|
||||||
|
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
||||||
|
- docker --version
|
||||||
|
install:
|
||||||
|
- $CI_MANAGERS/debian.sh SETUP
|
||||||
|
script:
|
||||||
|
- $CI_MANAGERS/debian.sh $PHASE || travis_terminate 1
|
||||||
|
after_script:
|
||||||
|
- $CI_MANAGERS/debian.sh CLEANUP
|
||||||
|
|
||||||
|
# Inject another (single) job into the matrix for Coverity
|
||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
- stage: Build & test
|
- stage: Coverity
|
||||||
name: Debian Testing
|
language: bash
|
||||||
language: bash
|
env:
|
||||||
env:
|
- FEDORA_RELEASE="latest"
|
||||||
- DEBIAN_RELEASE="testing"
|
- TOOL_BASE="/var/tmp/coverity-scan-analysis"
|
||||||
- CONT_NAME="systemd-debian-$DEBIAN_RELEASE"
|
- DOCKER_RUN="docker run -v $TOOL_BASE:$TOOL_BASE:rw --env-file .cov-env"
|
||||||
- DOCKER_EXEC="docker exec -ti $CONT_NAME"
|
# Coverity env variables
|
||||||
before_install:
|
- PLATFORM="$(uname)"
|
||||||
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
- TOOL_ARCHIVE="/var/tmp/cov-analysis-$PLATFORM.tgz"
|
||||||
- docker --version
|
- SCAN_URL="https://scan.coverity.com"
|
||||||
install:
|
- UPLOAD_URL="https://scan.coverity.com/builds"
|
||||||
- $CI_MANAGERS/debian.sh SETUP
|
- COVERITY_SCAN_PROJECT_NAME="$TRAVIS_REPO_SLUG"
|
||||||
script:
|
- COVERITY_SCAN_NOTIFICATION_EMAIL="${AUTHOR_EMAIL}"
|
||||||
- $CI_MANAGERS/debian.sh RUN || travis_terminate 1
|
- COVERITY_SCAN_BRANCH_PATTERN="$TRAVIS_BRANCH"
|
||||||
after_script:
|
# Encrypted COVERITY_SCAN_TOKEN env variable
|
||||||
- $CI_MANAGERS/debian.sh CLEANUP
|
# Generated using `travis encrypt -r systemd/systemd COVERITY_SCAN_TOKEN=xxxx`
|
||||||
|
- secure: "jKSz+Y1Mv8xMpQHh7g5lzW7E6HQGndFz/vKDJQ1CVShwFoyjV3Zu+MFS3UYKlh1236zL0Z4dvsYFx/b3Hq8nxZWCrWeZs2NdXgy/wh8LZhxwzcGYigp3sIA/cYdP5rDjFJO0MasNkl25/rml8+eZWz+8/xQic98UQHjSco/EOWtssoRcg0J0c4eDM7bGLfIQWE73NNY1Q1UtWjKmx1kekVrM8dPmHXJ9aERka7bmcbJAcKd6vabs6DQ5AfWccUPIn/EsRYqIJTRxJrFYU6XizANZ1a7Vwk/DWHZUEn2msxcZw5BbAMDTMx0TbfrNkKSHMHuvQUCu6KCBAq414i+LgkMfmQ2SWwKiIUsud1kxXX3ZPl9bxDv1HkvVdcniC/EM7lNEEVwm4meOnjuhI2lhOyOjmP3FTSlMHGP7xlK8DS2k9fqL58vn0BaSjwWgd+2+HuL2+nJmxcK1eLGzKqaostFxrk2Xs2vPZkUdV2nWY/asUrcWHml6YlWDn2eP83pfwxHYsMiEHY/rTKvxeVY+iirO/AphoO+eaYu7LvjKZU1Yx5Z4u/SnGWAiCH0yhMis0bWmgi7SCbw+sDd2uya+aoiLIGiB2ChW7hXHXCue/dif6/gLU7b+L8R00pQwnWdvKUPoIJCmZJYCluTeib4jpW+EmARB2+nR8wms2K9FGKM="
|
||||||
|
before_install:
|
||||||
|
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
||||||
|
- docker --version
|
||||||
|
install:
|
||||||
|
# Install Coverity on the host
|
||||||
|
- $CI_TOOLS/get-coverity.sh
|
||||||
|
# Export necessary env variables for Coverity
|
||||||
|
- env | grep -E "TRAVIS|COV|TOOL|URL" > .cov-env
|
||||||
|
# Pull a Docker image and start a new container
|
||||||
|
- $CI_MANAGERS/fedora.sh SETUP
|
||||||
|
script:
|
||||||
|
- set -e
|
||||||
|
# Preconfigure with meson to prevent Coverity from capturing meson metadata
|
||||||
|
- $DOCKER_EXEC meson cov-build -Dman=false
|
||||||
|
# Run Coverity
|
||||||
|
- $DOCKER_EXEC tools/coverity.sh build
|
||||||
|
- $DOCKER_EXEC tools/coverity.sh upload
|
||||||
|
|
||||||
- name: Debian Testing (ASan+UBSan)
|
- set +e
|
||||||
language: bash
|
after_script:
|
||||||
env:
|
- $CI_MANAGERS/fedora.sh CLEANUP
|
||||||
- DEBIAN_RELEASE="testing"
|
|
||||||
- CONT_NAME="systemd-debian-$DEBIAN_RELEASE"
|
|
||||||
- DOCKER_EXEC="docker exec -ti $CONT_NAME"
|
|
||||||
before_install:
|
|
||||||
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
|
||||||
- docker --version
|
|
||||||
install:
|
|
||||||
- $CI_MANAGERS/debian.sh SETUP
|
|
||||||
script:
|
|
||||||
- $CI_MANAGERS/debian.sh RUN_ASAN || travis_terminate 1
|
|
||||||
after_script:
|
|
||||||
- $CI_MANAGERS/debian.sh CLEANUP
|
|
||||||
|
|
||||||
- name: Debian Testing (clang)
|
|
||||||
language: bash
|
|
||||||
env:
|
|
||||||
- DEBIAN_RELEASE="testing"
|
|
||||||
- CONT_NAME="systemd-debian-$DEBIAN_RELEASE"
|
|
||||||
- DOCKER_EXEC="docker exec -ti $CONT_NAME"
|
|
||||||
before_install:
|
|
||||||
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
|
||||||
- docker --version
|
|
||||||
install:
|
|
||||||
- $CI_MANAGERS/debian.sh SETUP
|
|
||||||
script:
|
|
||||||
- $CI_MANAGERS/debian.sh RUN_CLANG || travis-travis_terminate 1
|
|
||||||
after_script:
|
|
||||||
- $CI_MANAGERS/debian.sh CLEANUP
|
|
||||||
|
|
||||||
- name: Debian Testing (clang ASan+UBSan)
|
|
||||||
language: bash
|
|
||||||
env:
|
|
||||||
- DEBIAN_RELEASE="testing"
|
|
||||||
- CONT_NAME="systemd-debian-$DEBIAN_RELEASE"
|
|
||||||
- DOCKER_EXEC="docker exec -ti $CONT_NAME"
|
|
||||||
before_install:
|
|
||||||
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
|
||||||
- docker --version
|
|
||||||
install:
|
|
||||||
- $CI_MANAGERS/debian.sh SETUP
|
|
||||||
script:
|
|
||||||
- $CI_MANAGERS/debian.sh RUN_CLANG_ASAN || travis_terminate 1
|
|
||||||
after_script:
|
|
||||||
- $CI_MANAGERS/debian.sh CLEANUP
|
|
||||||
|
|
||||||
- stage: Coverity
|
|
||||||
language: bash
|
|
||||||
env:
|
|
||||||
- FEDORA_RELEASE="latest"
|
|
||||||
- CONT_NAME="coverity-fedora-$FEDORA_RELEASE"
|
|
||||||
- DOCKER_EXEC="docker exec -ti $CONT_NAME"
|
|
||||||
- TOOL_BASE="/var/tmp/coverity-scan-analysis"
|
|
||||||
- DOCKER_RUN="docker run -v $TOOL_BASE:$TOOL_BASE:rw --env-file .cov-env"
|
|
||||||
# Coverity env variables
|
|
||||||
- PLATFORM="$(uname)"
|
|
||||||
- TOOL_ARCHIVE="/var/tmp/cov-analysis-$PLATFORM.tgz"
|
|
||||||
- SCAN_URL="https://scan.coverity.com"
|
|
||||||
- UPLOAD_URL="https://scan.coverity.com/builds"
|
|
||||||
- COVERITY_SCAN_PROJECT_NAME="$TRAVIS_REPO_SLUG"
|
|
||||||
- COVERITY_SCAN_NOTIFICATION_EMAIL="${AUTHOR_EMAIL}"
|
|
||||||
- COVERITY_SCAN_BRANCH_PATTERN="$TRAVIS_BRANCH"
|
|
||||||
# Encrypted COVERITY_SCAN_TOKEN env variable
|
|
||||||
# Generated using `travis encrypt -r systemd/systemd COVERITY_SCAN_TOKEN=xxxx`
|
|
||||||
- secure: "jKSz+Y1Mv8xMpQHh7g5lzW7E6HQGndFz/vKDJQ1CVShwFoyjV3Zu+MFS3UYKlh1236zL0Z4dvsYFx/b3Hq8nxZWCrWeZs2NdXgy/wh8LZhxwzcGYigp3sIA/cYdP5rDjFJO0MasNkl25/rml8+eZWz+8/xQic98UQHjSco/EOWtssoRcg0J0c4eDM7bGLfIQWE73NNY1Q1UtWjKmx1kekVrM8dPmHXJ9aERka7bmcbJAcKd6vabs6DQ5AfWccUPIn/EsRYqIJTRxJrFYU6XizANZ1a7Vwk/DWHZUEn2msxcZw5BbAMDTMx0TbfrNkKSHMHuvQUCu6KCBAq414i+LgkMfmQ2SWwKiIUsud1kxXX3ZPl9bxDv1HkvVdcniC/EM7lNEEVwm4meOnjuhI2lhOyOjmP3FTSlMHGP7xlK8DS2k9fqL58vn0BaSjwWgd+2+HuL2+nJmxcK1eLGzKqaostFxrk2Xs2vPZkUdV2nWY/asUrcWHml6YlWDn2eP83pfwxHYsMiEHY/rTKvxeVY+iirO/AphoO+eaYu7LvjKZU1Yx5Z4u/SnGWAiCH0yhMis0bWmgi7SCbw+sDd2uya+aoiLIGiB2ChW7hXHXCue/dif6/gLU7b+L8R00pQwnWdvKUPoIJCmZJYCluTeib4jpW+EmARB2+nR8wms2K9FGKM="
|
|
||||||
before_install:
|
|
||||||
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
|
||||||
- docker --version
|
|
||||||
install:
|
|
||||||
# Install Coverity on the host
|
|
||||||
- $CI_TOOLS/get-coverity.sh
|
|
||||||
# Export necessary env variables for Coverity
|
|
||||||
- env | grep -E "TRAVIS|COV|TOOL|URL" > .cov-env
|
|
||||||
# Pull a Docker image and start a new container
|
|
||||||
- $CI_MANAGERS/fedora.sh SETUP
|
|
||||||
script:
|
|
||||||
- set -e
|
|
||||||
# Preconfigure with meson to prevent Coverity from capturing meson metadata
|
|
||||||
- $DOCKER_EXEC meson cov-build -Dman=false
|
|
||||||
# Run Coverity
|
|
||||||
- $DOCKER_EXEC tools/coverity.sh build
|
|
||||||
- $DOCKER_EXEC tools/coverity.sh upload
|
|
||||||
|
|
||||||
- set +e
|
|
||||||
after_script:
|
|
||||||
- $CI_MANAGERS/fedora.sh CLEANUP
|
|
||||||
|
|
|
@ -19,7 +19,8 @@
|
||||||
<xsl:template match="citerefentry[not(@project)]">
|
<xsl:template match="citerefentry[not(@project)]">
|
||||||
<a>
|
<a>
|
||||||
<xsl:attribute name="href">
|
<xsl:attribute name="href">
|
||||||
<xsl:value-of select="refentrytitle"/><xsl:text>.html#</xsl:text>
|
<xsl:value-of select="refentrytitle"/>
|
||||||
|
<xsl:text>.html#</xsl:text>
|
||||||
<xsl:value-of select="refentrytitle/@target"/>
|
<xsl:value-of select="refentrytitle/@target"/>
|
||||||
</xsl:attribute>
|
</xsl:attribute>
|
||||||
<xsl:call-template name="inline.charseq"/>
|
<xsl:call-template name="inline.charseq"/>
|
||||||
|
@ -133,6 +134,15 @@
|
||||||
</a>
|
</a>
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="citerefentry[@project='url']">
|
||||||
|
<a>
|
||||||
|
<xsl:attribute name="href">
|
||||||
|
<xsl:value-of select="refentrytitle/@url"/>
|
||||||
|
</xsl:attribute>
|
||||||
|
<xsl:call-template name="inline.charseq"/>
|
||||||
|
</a>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
- helper template to do conflict resolution between various headings with the same inferred ID attribute/tag from the headerlink template
|
- helper template to do conflict resolution between various headings with the same inferred ID attribute/tag from the headerlink template
|
||||||
- this conflict resolution is necessary to prevent malformed HTML output (multiple ID attributes with the same value)
|
- this conflict resolution is necessary to prevent malformed HTML output (multiple ID attributes with the same value)
|
||||||
|
|
|
@ -51,7 +51,8 @@
|
||||||
<para><filename>systemd-makefs</filename> knows very little about specific file
|
<para><filename>systemd-makefs</filename> knows very little about specific file
|
||||||
systems and swap devices, and after checking that the block device does not already
|
systems and swap devices, and after checking that the block device does not already
|
||||||
contain a file system or other content, it will execute binaries specific to
|
contain a file system or other content, it will execute binaries specific to
|
||||||
each filesystem type (<filename>/sbin/mkfs.<replaceable>type</replaceable></filename>).</para>
|
each filesystem type (<filename>/sbin/mkfs.<replaceable>type</replaceable></filename>
|
||||||
|
or <filename>/sbin/mkswap</filename>).</para>
|
||||||
|
|
||||||
<para><filename>systemd-growfs</filename> knows very little about specific file
|
<para><filename>systemd-growfs</filename> knows very little about specific file
|
||||||
systems and swap devices, and will instruct the kernel to grow the mounted
|
systems and swap devices, and will instruct the kernel to grow the mounted
|
||||||
|
@ -61,8 +62,7 @@
|
||||||
number specific to each file system, so only certain types are supported.
|
number specific to each file system, so only certain types are supported.
|
||||||
Currently:
|
Currently:
|
||||||
<citerefentry project='man-pages'><refentrytitle>ext4</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
<citerefentry project='man-pages'><refentrytitle>ext4</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||||
btrfs (see
|
<citerefentry project='url'><refentrytitle url='https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs(5)'>btrfs</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||||
<citerefentry project='man-pages'><refentrytitle>btrfs-man5</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
|
|
||||||
<citerefentry project='man-pages'><refentrytitle>xfs</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
<citerefentry project='man-pages'><refentrytitle>xfs</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||||
<!-- yes, that's what the man page is called. -->
|
<!-- yes, that's what the man page is called. -->
|
||||||
and dm-crypt partitions (see
|
and dm-crypt partitions (see
|
||||||
|
|
|
@ -145,6 +145,43 @@
|
||||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>RootHash=</varname></term>
|
||||||
|
|
||||||
|
<listitem><para>Takes a data integrity (dm-verity) root hash specified in hexadecimal, or the path to a file
|
||||||
|
containing a root hash in ASCII hexadecimal format. This option enables data integrity checks using dm-verity,
|
||||||
|
if the used image contains the appropriate integrity data (see above) or if <varname>RootVerity=</varname> is used.
|
||||||
|
The specified hash must match the root hash of integrity data, and is usually at least 256 bits (and hence 64
|
||||||
|
formatted hexadecimal characters) long (in case of SHA256 for example). If this option is not specified, but
|
||||||
|
the image file carries the <literal>user.verity.roothash</literal> extended file attribute (see <citerefentry
|
||||||
|
project='man-pages'><refentrytitle>xattr</refentrytitle><manvolnum>7</manvolnum></citerefentry>), then the root
|
||||||
|
hash is read from it, also as formatted hexadecimal characters. If the extended file attribute is not found (or
|
||||||
|
is not supported by the underlying file system), but a file with the <filename>.roothash</filename> suffix is
|
||||||
|
found next to the image file, bearing otherwise the same name (except if the image has the
|
||||||
|
<filename>.raw</filename> suffix, in which case the root hash file must not have it in its name), the root hash
|
||||||
|
is read from it and automatically used, also as formatted hexadecimal characters.</para>
|
||||||
|
|
||||||
|
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>RootVerity=</varname></term>
|
||||||
|
|
||||||
|
<listitem><para>Takes the path to a data integrity (dm-verity) file. This option enables data integrity checks
|
||||||
|
using dm-verity, if <varname>RootImage=</varname> is used and a root-hash is passed and if the used image itself
|
||||||
|
does not contains the integrity data. The integrity data must be matched by the root hash. If this option is not
|
||||||
|
specified, but a file with the <filename>.verity</filename> suffix is found next to the image file, bearing otherwise
|
||||||
|
the same name (except if the image has the <filename>.raw</filename> suffix, in which case the verity data file must
|
||||||
|
not have it in its name), the verity data is read from it and automatically used.</para>
|
||||||
|
|
||||||
|
<para>This option is supported only for disk images that contain a single file system, without an enveloping partition
|
||||||
|
table. Images that contain a GPT partition table should instead include both root file system and matching Verity
|
||||||
|
data in the same image, implementing the
|
||||||
|
[Discoverable Partition Specification](https://systemd.io/DISCOVERABLE_PARTITIONS)</para>
|
||||||
|
|
||||||
|
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>MountAPIVFS=</varname></term>
|
<term><varname>MountAPIVFS=</varname></term>
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,18 @@ static int cached_enforcing = -1;
|
||||||
static struct selabel_handle *label_hnd = NULL;
|
static struct selabel_handle *label_hnd = NULL;
|
||||||
|
|
||||||
#define log_enforcing(...) log_full(mac_selinux_enforcing() ? LOG_ERR : LOG_WARNING, __VA_ARGS__)
|
#define log_enforcing(...) log_full(mac_selinux_enforcing() ? LOG_ERR : LOG_WARNING, __VA_ARGS__)
|
||||||
#define log_enforcing_errno(r, ...) log_full_errno(mac_selinux_enforcing() ? LOG_ERR : LOG_WARNING, r, __VA_ARGS__)
|
|
||||||
|
#define log_enforcing_errno(error, ...) \
|
||||||
|
({ \
|
||||||
|
bool _enforcing = mac_selinux_enforcing(); \
|
||||||
|
int _level = _enforcing ? LOG_ERR : LOG_WARNING; \
|
||||||
|
int _e = (error); \
|
||||||
|
\
|
||||||
|
int _r = (log_get_max_level() >= LOG_PRI(_level)) \
|
||||||
|
? log_internal_realm(_level, _e, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \
|
||||||
|
: -ERRNO_VALUE(_e); \
|
||||||
|
_enforcing ? _r : 0; \
|
||||||
|
})
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool mac_selinux_use(void) {
|
bool mac_selinux_use(void) {
|
||||||
|
@ -59,14 +70,15 @@ bool mac_selinux_enforcing(void) {
|
||||||
#if HAVE_SELINUX
|
#if HAVE_SELINUX
|
||||||
if (_unlikely_(cached_enforcing < 0)) {
|
if (_unlikely_(cached_enforcing < 0)) {
|
||||||
cached_enforcing = security_getenforce();
|
cached_enforcing = security_getenforce();
|
||||||
if (cached_enforcing == -1)
|
if (cached_enforcing < 0) {
|
||||||
log_error_errno(errno, "Failed to get SELinux enforced status, continue in enforcing mode: %m");
|
log_debug_errno(errno, "Failed to get SELinux enforced status, continuing in enforcing mode: %m");
|
||||||
else
|
return true; /* treat failure as enforcing mode */
|
||||||
log_debug("SELinux enforcing state cached to: %s", cached_enforcing ? "enforcing" : "permissive");
|
}
|
||||||
|
|
||||||
|
log_debug("SELinux enforcing state cached to: %s", cached_enforcing ? "enforcing" : "permissive");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* treat failure as enforcing mode */
|
return cached_enforcing > 0;
|
||||||
return (cached_enforcing != 0);
|
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
@ -90,11 +102,11 @@ static int setenforce_callback(int enforcing) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int mac_selinux_init(void) {
|
int mac_selinux_init(void) {
|
||||||
int r = 0;
|
|
||||||
|
|
||||||
#if HAVE_SELINUX
|
#if HAVE_SELINUX
|
||||||
usec_t before_timestamp, after_timestamp;
|
usec_t before_timestamp, after_timestamp;
|
||||||
struct mallinfo before_mallinfo, after_mallinfo;
|
struct mallinfo before_mallinfo, after_mallinfo;
|
||||||
|
char timespan[FORMAT_TIMESPAN_MAX];
|
||||||
|
int l;
|
||||||
|
|
||||||
selinux_set_callback(SELINUX_CB_POLICYLOAD, (union selinux_callback) mac_selinux_reload);
|
selinux_set_callback(SELINUX_CB_POLICYLOAD, (union selinux_callback) mac_selinux_reload);
|
||||||
selinux_set_callback(SELINUX_CB_SETENFORCE, (union selinux_callback) setenforce_callback);
|
selinux_set_callback(SELINUX_CB_SETENFORCE, (union selinux_callback) setenforce_callback);
|
||||||
|
@ -109,25 +121,20 @@ int mac_selinux_init(void) {
|
||||||
before_timestamp = now(CLOCK_MONOTONIC);
|
before_timestamp = now(CLOCK_MONOTONIC);
|
||||||
|
|
||||||
label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
|
label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
|
||||||
if (!label_hnd) {
|
if (!label_hnd)
|
||||||
log_enforcing_errno(errno, "Failed to initialize SELinux context: %m");
|
return log_enforcing_errno(errno, "Failed to initialize SELinux context: %m");
|
||||||
r = mac_selinux_enforcing() ? -errno : 0;
|
|
||||||
} else {
|
|
||||||
char timespan[FORMAT_TIMESPAN_MAX];
|
|
||||||
int l;
|
|
||||||
|
|
||||||
after_timestamp = now(CLOCK_MONOTONIC);
|
after_timestamp = now(CLOCK_MONOTONIC);
|
||||||
after_mallinfo = mallinfo();
|
after_mallinfo = mallinfo();
|
||||||
|
|
||||||
l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
|
l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
|
||||||
|
|
||||||
|
log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
|
||||||
|
format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
|
||||||
|
(l+1023)/1024);
|
||||||
|
|
||||||
log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
|
|
||||||
format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
|
|
||||||
(l+1023)/1024);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
return 0;
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mac_selinux_finish(void) {
|
void mac_selinux_finish(void) {
|
||||||
|
@ -226,9 +233,7 @@ int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFi
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
log_enforcing_errno(r, "Unable to fix SELinux security context of %s (%s): %m", path, inside_path);
|
return log_enforcing_errno(r, "Unable to fix SELinux security context of %s (%s): %m", path, inside_path);
|
||||||
if (mac_selinux_enforcing())
|
|
||||||
return r;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -243,21 +248,17 @@ int mac_selinux_apply(const char *path, const char *label) {
|
||||||
assert(path);
|
assert(path);
|
||||||
assert(label);
|
assert(label);
|
||||||
|
|
||||||
if (setfilecon(path, label) < 0) {
|
if (setfilecon(path, label) < 0)
|
||||||
log_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, path);
|
return log_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, path);
|
||||||
if (mac_selinux_enforcing())
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
|
int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
|
||||||
int r = -EOPNOTSUPP;
|
|
||||||
|
|
||||||
#if HAVE_SELINUX
|
#if HAVE_SELINUX
|
||||||
_cleanup_freecon_ char *mycon = NULL, *fcon = NULL;
|
_cleanup_freecon_ char *mycon = NULL, *fcon = NULL;
|
||||||
security_class_t sclass;
|
security_class_t sclass;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(exe);
|
assert(exe);
|
||||||
assert(label);
|
assert(label);
|
||||||
|
@ -280,36 +281,39 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
|
||||||
r = security_compute_create_raw(mycon, fcon, sclass, label);
|
r = security_compute_create_raw(mycon, fcon, sclass, label);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
#endif
|
|
||||||
|
|
||||||
return r;
|
return 0;
|
||||||
|
#else
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int mac_selinux_get_our_label(char **label) {
|
int mac_selinux_get_our_label(char **label) {
|
||||||
int r = -EOPNOTSUPP;
|
#if HAVE_SELINUX
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(label);
|
assert(label);
|
||||||
|
|
||||||
#if HAVE_SELINUX
|
|
||||||
if (!mac_selinux_use())
|
if (!mac_selinux_use())
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
r = getcon_raw(label);
|
r = getcon_raw(label);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
#endif
|
|
||||||
|
|
||||||
return r;
|
return 0;
|
||||||
|
#else
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label) {
|
int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label) {
|
||||||
int r = -EOPNOTSUPP;
|
|
||||||
|
|
||||||
#if HAVE_SELINUX
|
#if HAVE_SELINUX
|
||||||
_cleanup_freecon_ char *mycon = NULL, *peercon = NULL, *fcon = NULL;
|
_cleanup_freecon_ char *mycon = NULL, *peercon = NULL, *fcon = NULL;
|
||||||
_cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
|
_cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
|
||||||
security_class_t sclass;
|
security_class_t sclass;
|
||||||
const char *range = NULL;
|
const char *range = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(socket_fd >= 0);
|
assert(socket_fd >= 0);
|
||||||
assert(exe);
|
assert(exe);
|
||||||
|
@ -362,9 +366,11 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
|
||||||
r = security_compute_create_raw(mycon, fcon, sclass, label);
|
r = security_compute_create_raw(mycon, fcon, sclass, label);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
#endif
|
|
||||||
|
|
||||||
return r;
|
return 0;
|
||||||
|
#else
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
char* mac_selinux_free(char *label) {
|
char* mac_selinux_free(char *label) {
|
||||||
|
@ -399,26 +405,21 @@ static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode)
|
||||||
if (errno == ENOENT)
|
if (errno == ENOENT)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", abspath);
|
return log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", abspath);
|
||||||
} else {
|
|
||||||
if (setfscreatecon_raw(filecon) >= 0)
|
|
||||||
return 0; /* Success! */
|
|
||||||
|
|
||||||
log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, abspath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mac_selinux_enforcing())
|
if (setfscreatecon_raw(filecon) < 0)
|
||||||
return -errno;
|
return log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, abspath);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode) {
|
int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode) {
|
||||||
int r = 0;
|
|
||||||
|
|
||||||
#if HAVE_SELINUX
|
#if HAVE_SELINUX
|
||||||
_cleanup_free_ char *abspath = NULL;
|
_cleanup_free_ char *abspath = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
|
||||||
assert(path);
|
assert(path);
|
||||||
|
|
||||||
|
@ -440,15 +441,16 @@ int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = selinux_create_file_prepare_abspath(path, mode);
|
return selinux_create_file_prepare_abspath(path, mode);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
|
int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
|
||||||
int r = 0;
|
|
||||||
|
|
||||||
#if HAVE_SELINUX
|
#if HAVE_SELINUX
|
||||||
|
int r;
|
||||||
|
|
||||||
_cleanup_free_ char *abspath = NULL;
|
_cleanup_free_ char *abspath = NULL;
|
||||||
|
|
||||||
assert(path);
|
assert(path);
|
||||||
|
@ -460,9 +462,10 @@ int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = selinux_create_file_prepare_abspath(abspath, mode);
|
return selinux_create_file_prepare_abspath(abspath, mode);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mac_selinux_create_file_clear(void) {
|
void mac_selinux_create_file_clear(void) {
|
||||||
|
@ -480,17 +483,13 @@ void mac_selinux_create_file_clear(void) {
|
||||||
int mac_selinux_create_socket_prepare(const char *label) {
|
int mac_selinux_create_socket_prepare(const char *label) {
|
||||||
|
|
||||||
#if HAVE_SELINUX
|
#if HAVE_SELINUX
|
||||||
|
assert(label);
|
||||||
|
|
||||||
if (!mac_selinux_use())
|
if (!mac_selinux_use())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
assert(label);
|
if (setsockcreatecon(label) < 0)
|
||||||
|
return log_enforcing_errno(errno, "Failed to set SELinux security context %s for sockets: %m", label);
|
||||||
if (setsockcreatecon(label) < 0) {
|
|
||||||
log_enforcing_errno(errno, "Failed to set SELinux security context %s for sockets: %m", label);
|
|
||||||
|
|
||||||
if (mac_selinux_enforcing())
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -561,15 +560,14 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||||
if (errno == ENOENT)
|
if (errno == ENOENT)
|
||||||
goto skipped;
|
goto skipped;
|
||||||
|
|
||||||
log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", path);
|
r = log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", path);
|
||||||
if (mac_selinux_enforcing())
|
if (r < 0)
|
||||||
return -errno;
|
return r;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (setfscreatecon_raw(fcon) < 0) {
|
if (setfscreatecon_raw(fcon) < 0) {
|
||||||
log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", fcon, path);
|
r = log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", fcon, path);
|
||||||
if (mac_selinux_enforcing())
|
if (r < 0)
|
||||||
return -errno;
|
return r;
|
||||||
} else
|
} else
|
||||||
context_changed = true;
|
context_changed = true;
|
||||||
}
|
}
|
||||||
|
@ -577,7 +575,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||||
r = bind(fd, addr, addrlen) < 0 ? -errno : 0;
|
r = bind(fd, addr, addrlen) < 0 ? -errno : 0;
|
||||||
|
|
||||||
if (context_changed)
|
if (context_changed)
|
||||||
setfscreatecon_raw(NULL);
|
(void) setfscreatecon_raw(NULL);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -746,6 +746,25 @@ static int property_get_log_extra_fields(
|
||||||
return sd_bus_message_close_container(reply);
|
return sd_bus_message_close_container(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int property_get_root_hash(
|
||||||
|
sd_bus *bus,
|
||||||
|
const char *path,
|
||||||
|
const char *interface,
|
||||||
|
const char *property,
|
||||||
|
sd_bus_message *reply,
|
||||||
|
void *userdata,
|
||||||
|
sd_bus_error *error) {
|
||||||
|
|
||||||
|
ExecContext *c = userdata;
|
||||||
|
|
||||||
|
assert(bus);
|
||||||
|
assert(c);
|
||||||
|
assert(property);
|
||||||
|
assert(reply);
|
||||||
|
|
||||||
|
return sd_bus_message_append_array(reply, 'y', c->root_hash, c->root_hash_size);
|
||||||
|
}
|
||||||
|
|
||||||
const sd_bus_vtable bus_exec_vtable[] = {
|
const sd_bus_vtable bus_exec_vtable[] = {
|
||||||
SD_BUS_VTABLE_START(0),
|
SD_BUS_VTABLE_START(0),
|
||||||
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
@ -788,6 +807,9 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
||||||
SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("RootImage", "s", NULL, offsetof(ExecContext, root_image), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RootImage", "s", NULL, offsetof(ExecContext, root_image), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
SD_BUS_PROPERTY("RootHash", "ay", property_get_root_hash, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
SD_BUS_PROPERTY("RootHashPath", "s", NULL, offsetof(ExecContext, root_hash_path), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
SD_BUS_PROPERTY("RootVerity", "s", NULL, offsetof(ExecContext, root_verity), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("CoredumpFilter", "t", property_get_coredump_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("CoredumpFilter", "t", property_get_coredump_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
@ -1258,6 +1280,55 @@ int bus_exec_context_set_transient_property(
|
||||||
if (streq(name, "RootImage"))
|
if (streq(name, "RootImage"))
|
||||||
return bus_set_transient_path(u, name, &c->root_image, message, flags, error);
|
return bus_set_transient_path(u, name, &c->root_image, message, flags, error);
|
||||||
|
|
||||||
|
if (streq(name, "RootHash")) {
|
||||||
|
const void *roothash_decoded;
|
||||||
|
size_t roothash_decoded_size;
|
||||||
|
|
||||||
|
r = sd_bus_message_read_array(message, 'y', &roothash_decoded, &roothash_decoded_size);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||||
|
_cleanup_free_ char *encoded = NULL;
|
||||||
|
|
||||||
|
if (roothash_decoded_size == 0) {
|
||||||
|
c->root_hash_path = mfree(c->root_hash_path);
|
||||||
|
c->root_hash = mfree(c->root_hash);
|
||||||
|
c->root_hash_size = 0;
|
||||||
|
|
||||||
|
unit_write_settingf(u, flags, name, "RootHash=");
|
||||||
|
} else {
|
||||||
|
_cleanup_free_ void *p;
|
||||||
|
|
||||||
|
encoded = hexmem(roothash_decoded, roothash_decoded_size);
|
||||||
|
if (!encoded)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
p = memdup(roothash_decoded, roothash_decoded_size);
|
||||||
|
if (!p)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
free_and_replace(c->root_hash, p);
|
||||||
|
c->root_hash_size = roothash_decoded_size;
|
||||||
|
c->root_hash_path = mfree(c->root_hash_path);
|
||||||
|
|
||||||
|
unit_write_settingf(u, flags, name, "RootHash=%s", encoded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streq(name, "RootHashPath")) {
|
||||||
|
c->root_hash_size = 0;
|
||||||
|
c->root_hash = mfree(c->root_hash);
|
||||||
|
|
||||||
|
return bus_set_transient_path(u, "RootHash", &c->root_hash_path, message, flags, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streq(name, "RootVerity"))
|
||||||
|
return bus_set_transient_path(u, name, &c->root_verity, message, flags, error);
|
||||||
|
|
||||||
if (streq(name, "RootDirectory"))
|
if (streq(name, "RootDirectory"))
|
||||||
return bus_set_transient_path(u, name, &c->root_directory, message, flags, error);
|
return bus_set_transient_path(u, name, &c->root_directory, message, flags, error);
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
#include "format-util.h"
|
#include "format-util.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "glob-util.h"
|
#include "glob-util.h"
|
||||||
|
#include "hexdecoct.h"
|
||||||
#include "io-util.h"
|
#include "io-util.h"
|
||||||
#include "ioprio.h"
|
#include "ioprio.h"
|
||||||
#include "label.h"
|
#include "label.h"
|
||||||
|
@ -2666,6 +2667,7 @@ static int apply_mount_namespace(
|
||||||
needs_sandboxing ? context->protect_home : PROTECT_HOME_NO,
|
needs_sandboxing ? context->protect_home : PROTECT_HOME_NO,
|
||||||
needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO,
|
needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO,
|
||||||
context->mount_flags,
|
context->mount_flags,
|
||||||
|
context->root_hash, context->root_hash_size, context->root_hash_path, context->root_verity,
|
||||||
DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK,
|
DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK,
|
||||||
error_path);
|
error_path);
|
||||||
|
|
||||||
|
@ -4195,6 +4197,10 @@ void exec_context_done(ExecContext *c) {
|
||||||
c->working_directory = mfree(c->working_directory);
|
c->working_directory = mfree(c->working_directory);
|
||||||
c->root_directory = mfree(c->root_directory);
|
c->root_directory = mfree(c->root_directory);
|
||||||
c->root_image = mfree(c->root_image);
|
c->root_image = mfree(c->root_image);
|
||||||
|
c->root_hash = mfree(c->root_hash);
|
||||||
|
c->root_hash_size = 0;
|
||||||
|
c->root_hash_path = mfree(c->root_hash_path);
|
||||||
|
c->root_verity = mfree(c->root_verity);
|
||||||
c->tty_path = mfree(c->tty_path);
|
c->tty_path = mfree(c->tty_path);
|
||||||
c->syslog_identifier = mfree(c->syslog_identifier);
|
c->syslog_identifier = mfree(c->syslog_identifier);
|
||||||
c->user = mfree(c->user);
|
c->user = mfree(c->user);
|
||||||
|
@ -4599,6 +4605,19 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
||||||
if (c->root_image)
|
if (c->root_image)
|
||||||
fprintf(f, "%sRootImage: %s\n", prefix, c->root_image);
|
fprintf(f, "%sRootImage: %s\n", prefix, c->root_image);
|
||||||
|
|
||||||
|
if (c->root_hash) {
|
||||||
|
_cleanup_free_ char *encoded = NULL;
|
||||||
|
encoded = hexmem(c->root_hash, c->root_hash_size);
|
||||||
|
if (encoded)
|
||||||
|
fprintf(f, "%sRootHash: %s\n", prefix, encoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->root_hash_path)
|
||||||
|
fprintf(f, "%sRootHash: %s\n", prefix, c->root_hash_path);
|
||||||
|
|
||||||
|
if (c->root_verity)
|
||||||
|
fprintf(f, "%sRootVerity: %s\n", prefix, c->root_verity);
|
||||||
|
|
||||||
STRV_FOREACH(e, c->environment)
|
STRV_FOREACH(e, c->environment)
|
||||||
fprintf(f, "%sEnvironment: %s\n", prefix, *e);
|
fprintf(f, "%sEnvironment: %s\n", prefix, *e);
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,9 @@ struct ExecContext {
|
||||||
char **unset_environment;
|
char **unset_environment;
|
||||||
|
|
||||||
struct rlimit *rlimit[_RLIMIT_MAX];
|
struct rlimit *rlimit[_RLIMIT_MAX];
|
||||||
char *working_directory, *root_directory, *root_image;
|
char *working_directory, *root_directory, *root_image, *root_verity, *root_hash_path;
|
||||||
|
void *root_hash;
|
||||||
|
size_t root_hash_size;
|
||||||
bool working_directory_missing_ok:1;
|
bool working_directory_missing_ok:1;
|
||||||
bool working_directory_home:1;
|
bool working_directory_home:1;
|
||||||
|
|
||||||
|
|
|
@ -387,62 +387,25 @@ JobType job_type_lookup_merge(JobType a, JobType b) {
|
||||||
return job_merging_table[(a - 1) * a / 2 + b];
|
return job_merging_table[(a - 1) * a / 2 + b];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool job_later_link_matters(Job *j, JobType type, unsigned generation) {
|
bool job_type_is_redundant(JobType a, UnitActiveState b) {
|
||||||
JobDependency *l;
|
switch (a) {
|
||||||
|
|
||||||
assert(j);
|
|
||||||
|
|
||||||
j->generation = generation;
|
|
||||||
|
|
||||||
LIST_FOREACH(subject, l, j->subject_list) {
|
|
||||||
UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID;
|
|
||||||
|
|
||||||
/* Have we seen this before? */
|
|
||||||
if (l->object->generation == generation)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
state = unit_active_state(l->object->unit);
|
|
||||||
switch (type) {
|
|
||||||
|
|
||||||
case JOB_START:
|
|
||||||
return IN_SET(state, UNIT_INACTIVE, UNIT_FAILED) ||
|
|
||||||
job_later_link_matters(l->object, type, generation);
|
|
||||||
|
|
||||||
case JOB_STOP:
|
|
||||||
return IN_SET(state, UNIT_ACTIVE, UNIT_RELOADING) ||
|
|
||||||
job_later_link_matters(l->object, type, generation);
|
|
||||||
|
|
||||||
default:
|
|
||||||
assert_not_reached("Invalid job type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool job_is_redundant(Job *j, unsigned generation) {
|
|
||||||
|
|
||||||
assert(j);
|
|
||||||
|
|
||||||
UnitActiveState state = unit_active_state(j->unit);
|
|
||||||
switch (j->type) {
|
|
||||||
|
|
||||||
case JOB_START:
|
case JOB_START:
|
||||||
return IN_SET(state, UNIT_ACTIVE, UNIT_RELOADING) && !job_later_link_matters(j, JOB_START, generation);
|
return IN_SET(b, UNIT_ACTIVE, UNIT_RELOADING);
|
||||||
|
|
||||||
case JOB_STOP:
|
case JOB_STOP:
|
||||||
return IN_SET(state, UNIT_INACTIVE, UNIT_FAILED) && !job_later_link_matters(j, JOB_STOP, generation);
|
return IN_SET(b, UNIT_INACTIVE, UNIT_FAILED);
|
||||||
|
|
||||||
case JOB_VERIFY_ACTIVE:
|
case JOB_VERIFY_ACTIVE:
|
||||||
return IN_SET(state, UNIT_ACTIVE, UNIT_RELOADING);
|
return IN_SET(b, UNIT_ACTIVE, UNIT_RELOADING);
|
||||||
|
|
||||||
case JOB_RELOAD:
|
case JOB_RELOAD:
|
||||||
return
|
return
|
||||||
state == UNIT_RELOADING;
|
b == UNIT_RELOADING;
|
||||||
|
|
||||||
case JOB_RESTART:
|
case JOB_RESTART:
|
||||||
return
|
return
|
||||||
state == UNIT_ACTIVATING;
|
b == UNIT_ACTIVATING;
|
||||||
|
|
||||||
case JOB_NOP:
|
case JOB_NOP:
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -196,8 +196,7 @@ _pure_ static inline bool job_type_is_superset(JobType a, JobType b) {
|
||||||
return a == job_type_lookup_merge(a, b);
|
return a == job_type_lookup_merge(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool job_later_link_matters(Job *j, JobType type, unsigned generation);
|
bool job_type_is_redundant(JobType a, UnitActiveState b) _pure_;
|
||||||
bool job_is_redundant(Job *j, unsigned generation);
|
|
||||||
|
|
||||||
/* Collapses a state-dependent job type into a simpler type by observing
|
/* Collapses a state-dependent job type into a simpler type by observing
|
||||||
* the state of the unit which it is going to be applied to. */
|
* the state of the unit which it is going to be applied to. */
|
||||||
|
|
|
@ -23,6 +23,8 @@ m4_define(`EXEC_CONTEXT_CONFIG_ITEMS',
|
||||||
`$1.WorkingDirectory, config_parse_working_directory, 0, offsetof($1, exec_context)
|
`$1.WorkingDirectory, config_parse_working_directory, 0, offsetof($1, exec_context)
|
||||||
$1.RootDirectory, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_directory)
|
$1.RootDirectory, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_directory)
|
||||||
$1.RootImage, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_image)
|
$1.RootImage, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_image)
|
||||||
|
$1.RootHash, config_parse_exec_root_hash, 0, offsetof($1, exec_context)
|
||||||
|
$1.RootVerity, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_verity)
|
||||||
$1.User, config_parse_user_group_compat, 0, offsetof($1, exec_context.user)
|
$1.User, config_parse_user_group_compat, 0, offsetof($1, exec_context.user)
|
||||||
$1.Group, config_parse_user_group_compat, 0, offsetof($1, exec_context.group)
|
$1.Group, config_parse_user_group_compat, 0, offsetof($1, exec_context.group)
|
||||||
$1.SupplementaryGroups, config_parse_user_group_strv_compat, 0, offsetof($1, exec_context.supplementary_groups)
|
$1.SupplementaryGroups, config_parse_user_group_strv_compat, 0, offsetof($1, exec_context.supplementary_groups)
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "errno-list.h"
|
#include "errno-list.h"
|
||||||
#include "escape.h"
|
#include "escape.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
|
#include "fileio.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "hexdecoct.h"
|
#include "hexdecoct.h"
|
||||||
#include "io-util.h"
|
#include "io-util.h"
|
||||||
|
@ -1413,6 +1414,64 @@ int config_parse_exec_cpu_sched_prio(const char *unit,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int config_parse_exec_root_hash(
|
||||||
|
const char *unit,
|
||||||
|
const char *filename,
|
||||||
|
unsigned line,
|
||||||
|
const char *section,
|
||||||
|
unsigned section_line,
|
||||||
|
const char *lvalue,
|
||||||
|
int ltype,
|
||||||
|
const char *rvalue,
|
||||||
|
void *data,
|
||||||
|
void *userdata) {
|
||||||
|
|
||||||
|
_cleanup_free_ void *roothash_decoded = NULL;
|
||||||
|
ExecContext *c = data;
|
||||||
|
size_t roothash_decoded_size = 0;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(data);
|
||||||
|
assert(filename);
|
||||||
|
assert(line);
|
||||||
|
assert(rvalue);
|
||||||
|
|
||||||
|
if (isempty(rvalue)) {
|
||||||
|
/* Reset if the empty string is assigned */
|
||||||
|
c->root_hash_path = mfree(c->root_hash_path);
|
||||||
|
c->root_hash = mfree(c->root_hash);
|
||||||
|
c->root_hash_size = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path_is_absolute(rvalue)) {
|
||||||
|
/* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
|
||||||
|
_cleanup_free_ char *p = NULL;
|
||||||
|
|
||||||
|
p = strdup(rvalue);
|
||||||
|
if (!p)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
free_and_replace(c->root_hash_path, p);
|
||||||
|
c->root_hash = mfree(c->root_hash);
|
||||||
|
c->root_hash_size = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We have a roothash to decode, eg: RootHash=012345789abcdef */
|
||||||
|
r = unhexmem(rvalue, strlen(rvalue), &roothash_decoded, &roothash_decoded_size);
|
||||||
|
if (r < 0)
|
||||||
|
return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to decode RootHash=, ignoring: %s", rvalue);
|
||||||
|
if (roothash_decoded_size < sizeof(sd_id128_t))
|
||||||
|
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), "RootHash= is too short, ignoring: %s", rvalue);
|
||||||
|
|
||||||
|
free_and_replace(c->root_hash, roothash_decoded);
|
||||||
|
c->root_hash_size = roothash_decoded_size;
|
||||||
|
c->root_hash_path = mfree(c->root_hash_path);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int config_parse_exec_cpu_affinity(const char *unit,
|
int config_parse_exec_cpu_affinity(const char *unit,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
unsigned line,
|
unsigned line,
|
||||||
|
|
|
@ -44,6 +44,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_sched_policy);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_sched_prio);
|
CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_sched_prio);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_affinity);
|
CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_affinity);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_exec_secure_bits);
|
CONFIG_PARSER_PROTOTYPE(config_parse_exec_secure_bits);
|
||||||
|
CONFIG_PARSER_PROTOTYPE(config_parse_exec_root_hash);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_capability_set);
|
CONFIG_PARSER_PROTOTYPE(config_parse_capability_set);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_exec_mount_flags);
|
CONFIG_PARSER_PROTOTYPE(config_parse_exec_mount_flags);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_timer);
|
CONFIG_PARSER_PROTOTYPE(config_parse_timer);
|
||||||
|
|
|
@ -1257,16 +1257,20 @@ int setup_namespace(
|
||||||
ProtectHome protect_home,
|
ProtectHome protect_home,
|
||||||
ProtectSystem protect_system,
|
ProtectSystem protect_system,
|
||||||
unsigned long mount_flags,
|
unsigned long mount_flags,
|
||||||
|
const void *root_hash,
|
||||||
|
size_t root_hash_size,
|
||||||
|
const char *root_hash_path,
|
||||||
|
const char *root_verity,
|
||||||
DissectImageFlags dissect_image_flags,
|
DissectImageFlags dissect_image_flags,
|
||||||
char **error_path) {
|
char **error_path) {
|
||||||
|
|
||||||
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
|
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
|
||||||
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
||||||
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
|
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
|
||||||
_cleanup_free_ void *root_hash = NULL;
|
_cleanup_free_ void *root_hash_decoded = NULL;
|
||||||
_cleanup_free_ char *verity_data = NULL;
|
_cleanup_free_ char *verity_data = NULL;
|
||||||
MountEntry *m = NULL, *mounts = NULL;
|
MountEntry *m = NULL, *mounts = NULL;
|
||||||
size_t n_mounts, root_hash_size = 0;
|
size_t n_mounts;
|
||||||
bool require_prefix = false;
|
bool require_prefix = false;
|
||||||
const char *root;
|
const char *root;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
@ -1295,16 +1299,16 @@ int setup_namespace(
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to create loop device for root image: %m");
|
return log_debug_errno(r, "Failed to create loop device for root image: %m");
|
||||||
|
|
||||||
r = verity_metadata_load(root_image, &root_hash, &root_hash_size, &verity_data);
|
r = verity_metadata_load(root_image, root_hash_path, root_hash ? NULL : &root_hash_decoded, root_hash ? NULL : &root_hash_size, root_verity ? NULL : &verity_data);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to load root hash: %m");
|
return log_debug_errno(r, "Failed to load root hash: %m");
|
||||||
dissect_image_flags |= verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
|
dissect_image_flags |= root_verity || verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
|
||||||
|
|
||||||
r = dissect_image(loop_device->fd, root_hash, root_hash_size, verity_data, dissect_image_flags, &dissected_image);
|
r = dissect_image(loop_device->fd, root_hash ?: root_hash_decoded, root_hash_size, root_verity ?: verity_data, dissect_image_flags, &dissected_image);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to dissect image: %m");
|
return log_debug_errno(r, "Failed to dissect image: %m");
|
||||||
|
|
||||||
r = dissected_image_decrypt(dissected_image, NULL, root_hash, root_hash_size, verity_data, dissect_image_flags, &decrypted_image);
|
r = dissected_image_decrypt(dissected_image, NULL, root_hash ?: root_hash_decoded, root_hash_size, root_verity ?: verity_data, dissect_image_flags, &decrypted_image);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to decrypt dissected image: %m");
|
return log_debug_errno(r, "Failed to decrypt dissected image: %m");
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,10 @@ int setup_namespace(
|
||||||
ProtectHome protect_home,
|
ProtectHome protect_home,
|
||||||
ProtectSystem protect_system,
|
ProtectSystem protect_system,
|
||||||
unsigned long mount_flags,
|
unsigned long mount_flags,
|
||||||
|
const void *root_hash,
|
||||||
|
size_t root_hash_size,
|
||||||
|
const char *root_hash_path,
|
||||||
|
const char *root_verity,
|
||||||
DissectImageFlags dissected_image_flags,
|
DissectImageFlags dissected_image_flags,
|
||||||
char **error_path);
|
char **error_path);
|
||||||
|
|
||||||
|
|
|
@ -279,7 +279,7 @@ static int transaction_merge_jobs(Transaction *tr, sd_bus_error *e) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void transaction_drop_redundant(Transaction *tr, unsigned generation) {
|
static void transaction_drop_redundant(Transaction *tr) {
|
||||||
bool again;
|
bool again;
|
||||||
|
|
||||||
/* Goes through the transaction and removes all jobs of the units whose jobs are all noops. If not
|
/* Goes through the transaction and removes all jobs of the units whose jobs are all noops. If not
|
||||||
|
@ -299,7 +299,7 @@ static void transaction_drop_redundant(Transaction *tr, unsigned generation) {
|
||||||
|
|
||||||
LIST_FOREACH(transaction, k, j)
|
LIST_FOREACH(transaction, k, j)
|
||||||
if (tr->anchor_job == k ||
|
if (tr->anchor_job == k ||
|
||||||
!job_is_redundant(k, generation) ||
|
!job_type_is_redundant(k->type, unit_active_state(k->unit)) ||
|
||||||
(k->unit->job && job_type_is_conflicting(k->type, k->unit->job->type))) {
|
(k->unit->job && job_type_is_conflicting(k->type, k->unit->job->type))) {
|
||||||
keep = true;
|
keep = true;
|
||||||
break;
|
break;
|
||||||
|
@ -735,7 +735,7 @@ int transaction_activate(
|
||||||
transaction_minimize_impact(tr);
|
transaction_minimize_impact(tr);
|
||||||
|
|
||||||
/* Third step: Drop redundant jobs */
|
/* Third step: Drop redundant jobs */
|
||||||
transaction_drop_redundant(tr, generation++);
|
transaction_drop_redundant(tr);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* Fourth step: Let's remove unneeded jobs that might
|
/* Fourth step: Let's remove unneeded jobs that might
|
||||||
|
@ -777,7 +777,7 @@ int transaction_activate(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
|
/* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
|
||||||
transaction_drop_redundant(tr, generation++);
|
transaction_drop_redundant(tr);
|
||||||
|
|
||||||
/* Ninth step: check whether we can actually apply this */
|
/* Ninth step: check whether we can actually apply this */
|
||||||
r = transaction_is_destructive(tr, mode, e);
|
r = transaction_is_destructive(tr, mode, e);
|
||||||
|
|
|
@ -201,7 +201,7 @@ static int run(int argc, char *argv[]) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to set up loopback device: %m");
|
return log_error_errno(r, "Failed to set up loopback device: %m");
|
||||||
|
|
||||||
r = verity_metadata_load(arg_image, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
|
r = verity_metadata_load(arg_image, NULL, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
|
||||||
arg_verity_data ? NULL : &arg_verity_data);
|
arg_verity_data ? NULL : &arg_verity_data);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
|
return log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
|
||||||
|
|
|
@ -619,9 +619,9 @@ int mount_all(const char *dest,
|
||||||
|
|
||||||
#if HAVE_SELINUX
|
#if HAVE_SELINUX
|
||||||
{ "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND,
|
{ "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND,
|
||||||
0 }, /* Bind mount first */
|
MOUNT_MKDIR }, /* Bind mount first (mkdir/chown the mount point in case /sys/ is mounted as minimal skeleton tmpfs) */
|
||||||
{ NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
|
{ NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
|
||||||
0 }, /* Then, make it r/o */
|
0 }, /* Then, make it r/o (don't mkdir/chown the mount point here, the previous entry already did that) */
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5141,7 +5141,7 @@ static int run(int argc, char *argv[]) {
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = verity_metadata_load(arg_image, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
|
r = verity_metadata_load(arg_image, NULL, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
|
||||||
arg_verity_data ? NULL : &arg_verity_data);
|
arg_verity_data ? NULL : &arg_verity_data);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
|
log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "escape.h"
|
#include "escape.h"
|
||||||
#include "exec-util.h"
|
#include "exec-util.h"
|
||||||
#include "exit-status.h"
|
#include "exit-status.h"
|
||||||
|
#include "fileio.h"
|
||||||
#include "hexdecoct.h"
|
#include "hexdecoct.h"
|
||||||
#include "hostname-util.h"
|
#include "hostname-util.h"
|
||||||
#include "in-addr-util.h"
|
#include "in-addr-util.h"
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
#include "nsflags.h"
|
#include "nsflags.h"
|
||||||
#include "numa-util.h"
|
#include "numa-util.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
|
#include "path-util.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
#include "rlimit-util.h"
|
#include "rlimit-util.h"
|
||||||
#include "securebits-util.h"
|
#include "securebits-util.h"
|
||||||
|
@ -849,6 +851,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||||
"ProtectHome",
|
"ProtectHome",
|
||||||
"SELinuxContext",
|
"SELinuxContext",
|
||||||
"RootImage",
|
"RootImage",
|
||||||
|
"RootVerity",
|
||||||
"RuntimeDirectoryPreserve",
|
"RuntimeDirectoryPreserve",
|
||||||
"Personality",
|
"Personality",
|
||||||
"KeyringMode",
|
"KeyringMode",
|
||||||
|
@ -1415,6 +1418,24 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (streq(field, "RootHash")) {
|
||||||
|
_cleanup_free_ void *roothash_decoded = NULL;
|
||||||
|
size_t roothash_decoded_size = 0;
|
||||||
|
|
||||||
|
/* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
|
||||||
|
if (path_is_absolute(eq))
|
||||||
|
return bus_append_string(m, "RootHashPath", eq);
|
||||||
|
|
||||||
|
/* We have a roothash to decode, eg: RootHash=012345789abcdef */
|
||||||
|
r = unhexmem(eq, strlen(eq), &roothash_decoded, &roothash_decoded_size);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
|
||||||
|
if (roothash_decoded_size < sizeof(sd_id128_t))
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short: %m", eq);
|
||||||
|
|
||||||
|
return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1421,7 +1421,7 @@ int decrypted_image_relinquish(DecryptedImage *d) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int verity_metadata_load(const char *image, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data) {
|
int verity_metadata_load(const char *image, const char *root_hash_path, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data) {
|
||||||
_cleanup_free_ char *verity_filename = NULL;
|
_cleanup_free_ char *verity_filename = NULL;
|
||||||
_cleanup_free_ void *roothash_decoded = NULL;
|
_cleanup_free_ void *roothash_decoded = NULL;
|
||||||
size_t roothash_decoded_size = 0;
|
size_t roothash_decoded_size = 0;
|
||||||
|
@ -1465,24 +1465,31 @@ int verity_metadata_load(const char *image, void **ret_roothash, size_t *ret_roo
|
||||||
_cleanup_free_ char *text = NULL;
|
_cleanup_free_ char *text = NULL;
|
||||||
assert(ret_roothash_size);
|
assert(ret_roothash_size);
|
||||||
|
|
||||||
r = getxattr_malloc(image, "user.verity.roothash", &text, true);
|
if (root_hash_path) {
|
||||||
if (r < 0) {
|
/* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
|
||||||
char *fn, *e, *n;
|
r = read_one_line_file(root_hash_path, &text);
|
||||||
|
if (r < 0)
|
||||||
if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT))
|
|
||||||
return r;
|
return r;
|
||||||
|
} else {
|
||||||
|
r = getxattr_malloc(image, "user.verity.roothash", &text, true);
|
||||||
|
if (r < 0) {
|
||||||
|
char *fn, *e, *n;
|
||||||
|
|
||||||
fn = newa(char, strlen(image) + STRLEN(".roothash") + 1);
|
if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT))
|
||||||
n = stpcpy(fn, image);
|
return r;
|
||||||
e = endswith(fn, ".raw");
|
|
||||||
if (e)
|
|
||||||
n = e;
|
|
||||||
|
|
||||||
strcpy(n, ".roothash");
|
fn = newa(char, strlen(image) + STRLEN(".roothash") + 1);
|
||||||
|
n = stpcpy(fn, image);
|
||||||
|
e = endswith(fn, ".raw");
|
||||||
|
if (e)
|
||||||
|
n = e;
|
||||||
|
|
||||||
r = read_one_line_file(fn, &text);
|
strcpy(n, ".roothash");
|
||||||
if (r < 0 && r != -ENOENT)
|
|
||||||
return r;
|
r = read_one_line_file(fn, &text);
|
||||||
|
if (r < 0 && r != -ENOENT)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (text) {
|
if (text) {
|
||||||
|
|
|
@ -100,6 +100,6 @@ int decrypted_image_relinquish(DecryptedImage *d);
|
||||||
const char* partition_designator_to_string(int i) _const_;
|
const char* partition_designator_to_string(int i) _const_;
|
||||||
int partition_designator_from_string(const char *name) _pure_;
|
int partition_designator_from_string(const char *name) _pure_;
|
||||||
|
|
||||||
int verity_metadata_load(const char *image, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data);
|
int verity_metadata_load(const char *image, const char *root_hash_path, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data);
|
||||||
bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator);
|
bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator);
|
||||||
bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator);
|
bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator);
|
||||||
|
|
|
@ -152,6 +152,10 @@ static void test_protect_kernel_logs(void) {
|
||||||
PROTECT_HOME_NO,
|
PROTECT_HOME_NO,
|
||||||
PROTECT_SYSTEM_NO,
|
PROTECT_SYSTEM_NO,
|
||||||
0,
|
0,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
0,
|
0,
|
||||||
NULL);
|
NULL);
|
||||||
assert_se(r == 0);
|
assert_se(r == 0);
|
||||||
|
|
|
@ -76,6 +76,10 @@ int main(int argc, char *argv[]) {
|
||||||
PROTECT_HOME_NO,
|
PROTECT_HOME_NO,
|
||||||
PROTECT_SYSTEM_NO,
|
PROTECT_SYSTEM_NO,
|
||||||
0,
|
0,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
0,
|
0,
|
||||||
NULL);
|
NULL);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
|
|
|
@ -196,6 +196,8 @@ ReusePort=
|
||||||
RootDirectory=
|
RootDirectory=
|
||||||
RootDirectoryStartOnly=
|
RootDirectoryStartOnly=
|
||||||
RootImage=
|
RootImage=
|
||||||
|
RootHash=
|
||||||
|
RootVerity=
|
||||||
RuntimeMaxSec=
|
RuntimeMaxSec=
|
||||||
SELinuxContextFromNet=
|
SELinuxContextFromNet=
|
||||||
SecureBits=
|
SecureBits=
|
||||||
|
|
|
@ -935,7 +935,7 @@ install_config_files() {
|
||||||
inst /etc/login.defs
|
inst /etc/login.defs
|
||||||
inst /etc/group
|
inst /etc/group
|
||||||
inst /etc/shells
|
inst /etc/shells
|
||||||
inst /etc/nsswitch.conf
|
inst_any /etc/nsswitch.conf /usr/etc/nsswitch.conf
|
||||||
inst /etc/pam.conf || :
|
inst /etc/pam.conf || :
|
||||||
inst /etc/os-release
|
inst /etc/os-release
|
||||||
inst /etc/localtime
|
inst /etc/localtime
|
||||||
|
|
|
@ -9,23 +9,25 @@
|
||||||
# export CONT_NAME="my-fancy-container"
|
# export CONT_NAME="my-fancy-container"
|
||||||
# travis-ci/managers/debian.sh SETUP RUN CLEANUP
|
# travis-ci/managers/debian.sh SETUP RUN CLEANUP
|
||||||
|
|
||||||
PHASES=(${@:-SETUP RUN RUN_ASAN CLEANUP})
|
PHASES=(${@:-SETUP RUN RUN_ASAN_UBSAN CLEANUP})
|
||||||
DEBIAN_RELEASE="${DEBIAN_RELEASE:-testing}"
|
DEBIAN_RELEASE="${DEBIAN_RELEASE:-testing}"
|
||||||
CONT_NAME="${CONT_NAME:-debian-$DEBIAN_RELEASE-$RANDOM}"
|
CONT_NAME="${CONT_NAME:-systemd-debian-$DEBIAN_RELEASE}"
|
||||||
DOCKER_EXEC="${DOCKER_EXEC:-docker exec -it $CONT_NAME}"
|
DOCKER_EXEC="${DOCKER_EXEC:-docker exec -it $CONT_NAME}"
|
||||||
DOCKER_RUN="${DOCKER_RUN:-docker run}"
|
DOCKER_RUN="${DOCKER_RUN:-docker run}"
|
||||||
REPO_ROOT="${REPO_ROOT:-$PWD}"
|
REPO_ROOT="${REPO_ROOT:-$PWD}"
|
||||||
ADDITIONAL_DEPS=(python3-libevdev
|
ADDITIONAL_DEPS=(
|
||||||
python3-pyparsing
|
clang
|
||||||
clang
|
fdisk
|
||||||
perl
|
libfdisk-dev
|
||||||
libpwquality-dev
|
libp11-kit-dev
|
||||||
fdisk
|
libpwquality-dev
|
||||||
libfdisk-dev
|
libssl-dev
|
||||||
libp11-kit-dev
|
libzstd-dev
|
||||||
libssl-dev
|
perl
|
||||||
libzstd-dev
|
python3-libevdev
|
||||||
zstd)
|
python3-pyparsing
|
||||||
|
zstd
|
||||||
|
)
|
||||||
|
|
||||||
function info() {
|
function info() {
|
||||||
echo -e "\033[33;1m$1\033[0m"
|
echo -e "\033[33;1m$1\033[0m"
|
||||||
|
@ -54,7 +56,7 @@ for phase in "${PHASES[@]}"; do
|
||||||
$DOCKER_EXEC apt-get -y build-dep systemd
|
$DOCKER_EXEC apt-get -y build-dep systemd
|
||||||
$DOCKER_EXEC apt-get -y install "${ADDITIONAL_DEPS[@]}"
|
$DOCKER_EXEC apt-get -y install "${ADDITIONAL_DEPS[@]}"
|
||||||
;;
|
;;
|
||||||
RUN|RUN_CLANG)
|
RUN|RUN_GCC|RUN_CLANG)
|
||||||
if [[ "$phase" = "RUN_CLANG" ]]; then
|
if [[ "$phase" = "RUN_CLANG" ]]; then
|
||||||
ENV_VARS="-e CC=clang -e CXX=clang++"
|
ENV_VARS="-e CC=clang -e CXX=clang++"
|
||||||
fi
|
fi
|
||||||
|
@ -62,8 +64,8 @@ for phase in "${PHASES[@]}"; do
|
||||||
$DOCKER_EXEC ninja -v -C build
|
$DOCKER_EXEC ninja -v -C build
|
||||||
docker exec -e "TRAVIS=$TRAVIS" -it $CONT_NAME ninja -C build test
|
docker exec -e "TRAVIS=$TRAVIS" -it $CONT_NAME ninja -C build test
|
||||||
;;
|
;;
|
||||||
RUN_ASAN|RUN_CLANG_ASAN)
|
RUN_ASAN_UBSAN|RUN_GCC_ASAN_UBSAN|RUN_CLANG_ASAN_UBSAN)
|
||||||
if [[ "$phase" = "RUN_CLANG_ASAN" ]]; then
|
if [[ "$phase" = "RUN_CLANG_ASAN_UBSAN" ]]; then
|
||||||
ENV_VARS="-e CC=clang -e CXX=clang++"
|
ENV_VARS="-e CC=clang -e CXX=clang++"
|
||||||
# Build fuzzer regression tests only with clang (for now),
|
# Build fuzzer regression tests only with clang (for now),
|
||||||
# see: https://github.com/systemd/systemd/pull/15886#issuecomment-632689604
|
# see: https://github.com/systemd/systemd/pull/15886#issuecomment-632689604
|
||||||
|
|
|
@ -9,38 +9,32 @@
|
||||||
# export CONT_NAME="my-fancy-container"
|
# export CONT_NAME="my-fancy-container"
|
||||||
# travis-ci/managers/fedora.sh SETUP RUN CLEANUP
|
# travis-ci/managers/fedora.sh SETUP RUN CLEANUP
|
||||||
|
|
||||||
PHASES=(${@:-SETUP RUN RUN_ASAN CLEANUP})
|
PHASES=(${@:-SETUP RUN RUN_ASAN_UBSAN CLEANUP})
|
||||||
FEDORA_RELEASE="${FEDORA_RELEASE:-rawhide}"
|
FEDORA_RELEASE="${FEDORA_RELEASE:-rawhide}"
|
||||||
CONT_NAME="${CONT_NAME:-fedora-$FEDORA_RELEASE-$RANDOM}"
|
CONT_NAME="${CONT_NAME:-systemd-fedora-$FEDORA_RELEASE}"
|
||||||
DOCKER_EXEC="${DOCKER_EXEC:-docker exec -it $CONT_NAME}"
|
DOCKER_EXEC="${DOCKER_EXEC:-docker exec -it $CONT_NAME}"
|
||||||
DOCKER_RUN="${DOCKER_RUN:-docker run}"
|
DOCKER_RUN="${DOCKER_RUN:-docker run}"
|
||||||
REPO_ROOT="${REPO_ROOT:-$PWD}"
|
REPO_ROOT="${REPO_ROOT:-$PWD}"
|
||||||
ADDITIONAL_DEPS=(dnf-plugins-core
|
ADDITIONAL_DEPS=(
|
||||||
jq iputils
|
clang
|
||||||
hostname libasan
|
dnf-plugins-core
|
||||||
python3-pyparsing
|
hostname libasan
|
||||||
python3-evdev
|
jq iputils
|
||||||
libubsan
|
libfdisk-devel
|
||||||
clang
|
libpwquality-devel
|
||||||
llvm
|
libubsan
|
||||||
perl
|
llvm
|
||||||
libfdisk-devel
|
openssl-devel
|
||||||
libpwquality-devel
|
p11-kit-devel
|
||||||
openssl-devel
|
perl
|
||||||
p11-kit-devel)
|
python3-evdev
|
||||||
|
python3-pyparsing
|
||||||
|
)
|
||||||
|
|
||||||
info() {
|
info() {
|
||||||
echo -e "\033[33;1m$1\033[0m"
|
echo -e "\033[33;1m$1\033[0m"
|
||||||
}
|
}
|
||||||
|
|
||||||
error() {
|
|
||||||
echo >&2 -e "\033[31;1m$1\033[0m"
|
|
||||||
}
|
|
||||||
|
|
||||||
success() {
|
|
||||||
echo >&2 -e "\033[32;1m$1\033[0m"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Simple wrapper which retries given command up to five times
|
# Simple wrapper which retries given command up to five times
|
||||||
_retry() {
|
_retry() {
|
||||||
local EC=1
|
local EC=1
|
||||||
|
@ -94,8 +88,8 @@ for phase in "${PHASES[@]}"; do
|
||||||
$DOCKER_EXEC ninja -v -C build
|
$DOCKER_EXEC ninja -v -C build
|
||||||
$DOCKER_EXEC ninja -C build test
|
$DOCKER_EXEC ninja -C build test
|
||||||
;;
|
;;
|
||||||
RUN_ASAN|RUN_CLANG_ASAN)
|
RUN_ASAN|RUN_GCC_ASAN_UBSAN|RUN_CLANG_ASAN_UBSAN)
|
||||||
if [[ "$phase" = "RUN_CLANG_ASAN" ]]; then
|
if [[ "$phase" = "RUN_CLANG_ASAN_UBSAN" ]]; then
|
||||||
ENV_VARS="-e CC=clang -e CXX=clang++"
|
ENV_VARS="-e CC=clang -e CXX=clang++"
|
||||||
MESON_ARGS="-Db_lundef=false" # See https://github.com/mesonbuild/meson/issues/764
|
MESON_ARGS="-Db_lundef=false" # See https://github.com/mesonbuild/meson/issues/764
|
||||||
fi
|
fi
|
||||||
|
@ -110,46 +104,6 @@ for phase in "${PHASES[@]}"; do
|
||||||
-t $CONT_NAME \
|
-t $CONT_NAME \
|
||||||
meson test --timeout-multiplier=3 -C ./build/ --print-errorlogs
|
meson test --timeout-multiplier=3 -C ./build/ --print-errorlogs
|
||||||
;;
|
;;
|
||||||
RUN_BUILD_CHECK_GCC|RUN_BUILD_CHECK_CLANG)
|
|
||||||
ARGS=(
|
|
||||||
"--optimization=0"
|
|
||||||
"--optimization=2"
|
|
||||||
"--optimization=3"
|
|
||||||
"--optimization=s"
|
|
||||||
"-Db_lto=true"
|
|
||||||
"-Db_ndebug=true"
|
|
||||||
)
|
|
||||||
|
|
||||||
if [[ "$phase" = "RUN_BUILD_CHECK_CLANG" ]]; then
|
|
||||||
ENV_VARS="-e CC=clang -e CXX=clang++"
|
|
||||||
$DOCKER_EXEC clang --version
|
|
||||||
else
|
|
||||||
$DOCKER_EXEC gcc --version
|
|
||||||
fi
|
|
||||||
|
|
||||||
for args in "${ARGS[@]}"; do
|
|
||||||
SECONDS=0
|
|
||||||
info "Checking build with $args"
|
|
||||||
# Redirect meson/ninja logs into separate files, otherwise we
|
|
||||||
# would trip over Travis' log size limit
|
|
||||||
if ! docker exec $ENV_VARS -it $CONT_NAME meson --werror $args build &> meson.log; then
|
|
||||||
cat meson.log
|
|
||||||
error "meson failed with $args"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! $DOCKER_EXEC ninja -v -C build &> ninja.log; then
|
|
||||||
cat ninja.log
|
|
||||||
error "ninja failed with $args"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
$DOCKER_EXEC rm -fr build
|
|
||||||
rm -f meson.log ninja.log
|
|
||||||
success "Build with $args passed in $SECONDS seconds"
|
|
||||||
done
|
|
||||||
|
|
||||||
;;
|
|
||||||
CLEANUP)
|
CLEANUP)
|
||||||
info "Cleanup phase"
|
info "Cleanup phase"
|
||||||
docker stop $CONT_NAME
|
docker stop $CONT_NAME
|
||||||
|
|
Loading…
Reference in New Issue