diff options
132 files changed, 1357 insertions, 1083 deletions
diff --git a/.github/workflows/ubuntu-build-check.sh b/.github/workflows/ubuntu-build-check.sh index fb7c71ecb8..75fc36fffb 100755 --- a/.github/workflows/ubuntu-build-check.sh +++ b/.github/workflows/ubuntu-build-check.sh @@ -102,7 +102,7 @@ for args in "${ARGS[@]}"; do SECONDS=0 info "Checking build with $args" - if ! AR="$AR" CC="$CC" CXX="$CXX" meson -Dtests=unsafe -Dslow-tests=true --werror $args build; then + if ! AR="$AR" CC="$CC" CXX="$CXX" CFLAGS="-Werror" CXXFLAGS="-Werror" meson -Dtests=unsafe -Dslow-tests=true --werror $args build; then fatal "meson failed with $args" fi diff --git a/.travis.yml b/.travis.yml index d933ccce06..a72e81552f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,127 +1,82 @@ -sudo: required +--- +# vi: ts=2 sw=2 et: + +language: bash dist: bionic services: - - docker + - docker env: - global: - - AUTHOR_EMAIL="$(git log -1 $TRAVIS_COMMIT --pretty=\"%aE\")" - - CI_MANAGERS="$TRAVIS_BUILD_DIR/travis-ci/managers" - - CI_TOOLS="$TRAVIS_BUILD_DIR/travis-ci/tools" - - REPO_ROOT="$TRAVIS_BUILD_DIR" + global: + - AUTHOR_EMAIL="$(git log -1 $TRAVIS_COMMIT --pretty=\"%aE\")" + - CI_MANAGERS="$TRAVIS_BUILD_DIR/travis-ci/managers" + - CI_TOOLS="$TRAVIS_BUILD_DIR/travis-ci/tools" + - 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: - - name: Build & test - if: type != cron + # 'Test' is the default stage (for matrix jobs) + - name: Test + if: type != cron # Run Coverity periodically instead of for each commit/PR - - name: Coverity - if: type = cron - -jobs: - include: - - stage: Build & test - name: Debian Testing - 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 || travis_terminate 1 - after_script: - - $CI_MANAGERS/debian.sh CLEANUP + - name: Coverity + if: type = cron - - name: Debian Testing (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_ASAN || travis_terminate 1 - after_script: - - $CI_MANAGERS/debian.sh CLEANUP +# 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 - - 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 +# Inject another (single) job into the matrix for Coverity +jobs: + include: + - stage: Coverity + language: bash + env: + - FEDORA_RELEASE="latest" + - 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 + - set +e + after_script: + - $CI_MANAGERS/fedora.sh CLEANUP @@ -87,6 +87,12 @@ CHANGES WITH 246 in spe: used, the DNS-over-TLS certificate is validated to match the specified hostname. + * systemd-resolved may be configured to forward single-label DNS names. + This is not standard-conformant, but may make sense in setups where + public DNS servers are not used. + + * systemd-resolved's DNS-over-TLS support gained SNI validation. + * The fs.suid_dumpable sysctl is set to 2 / "suidsafe". This allows systemd-coredump to save core files for suid processes. When saving the core file, systemd-coredump will use the effective uid and gid of @@ -538,8 +544,6 @@ CHANGES WITH 245: * systemd-sysusers gained support for creating users with the primary group named differently than the user. - * systemd-resolved's DNS-over-TLS support gained SNI validation. - * systemd-growfs (i.e. the x-systemd.growfs mount option in /etc/fstab) gained support for growing XFS partitions. Previously it supported only ext4 and btrfs partitions. diff --git a/docs/RANDOM_SEEDS.md b/docs/RANDOM_SEEDS.md index d3b68e967a..c1735b1ac9 100644 --- a/docs/RANDOM_SEEDS.md +++ b/docs/RANDOM_SEEDS.md @@ -118,7 +118,7 @@ requires random numbers as well, including for the following uses: * systemd maintains various hash tables internally. In order to harden them against [collision - attacks](https://rt.perl.org/Public/Bug/Display.html?CSRF_Token=165691af9ddaa95f653402f1b68de728) + attacks](https://www.cs.auckland.ac.nz/~mcw/Teaching/refs/misc/denial-of-service.pdf) they are seeded with random numbers. * At various places systemd needs random bytes for temporary file name diff --git a/hwdb.d/60-autosuspend.hwdb b/hwdb.d/60-autosuspend.hwdb new file mode 100644 index 0000000000..0de49afa6c --- /dev/null +++ b/hwdb.d/60-autosuspend.hwdb @@ -0,0 +1,44 @@ +# This file is part of systemd. +# +# The lookup keys are $MODALIAS strings, see udev's hwdb builtin. +# +# Match string formats: +# <subsystem>:<modalias> +# +# pci:v<vendor>d<device> +# usb:v<vendor>p<product> +# +# To add local entries, create a new file +# /etc/udev/hwdb.d/61-autosuspend-local.hwdb +# and add your rules there. To load the new rules execute (as root): +# systemd-hwdb update +# udevadm trigger /dev/… +# +# If your changes are generally applicable, preferably send them as a pull +# request to +# https://github.com/systemd/systemd +# or create a bug report on https://github.com/systemd/systemd/issues and +# include your new rules, a description of the device, and the output of +# udevadm info +# the device. +# +# Allowed properties are: +# ID_AUTOSUSPEND=1 + +# +# Sort by brand, model + +######################################### +# Alcor +######################################### + +# AU9540 Smartcard Reader +usb:v058Fp9540* + ID_AUTOSUSPEND=1 + +######################################### +# Wacom +######################################### + +usb:v056Ap51A0* + ID_AUTOSUSPEND=1 diff --git a/hwdb.d/70-mouse.hwdb b/hwdb.d/70-mouse.hwdb index ef5a473e87..63ef1fba12 100644 --- a/hwdb.d/70-mouse.hwdb +++ b/hwdb.d/70-mouse.hwdb @@ -349,6 +349,8 @@ mouse:usb:v046dpc068:name:Logitech G500: mouse:usb:v046dpc332:name:Logitech Gaming Mouse G502: # Logitech G502 HERO SE mouse:usb:v046dpc08b:name:Logitech G502 HERO SE: +# Logitech G502 Hero +mouse:usb:v046dpc08b:name:Logitech G502 HERO Gaming Mouse: MOUSE_DPI=1200@1000 *2400@1000 3200@1000 6400@1000 # Logitech G700 Laser Mouse (Wired) diff --git a/hwdb.d/meson.build b/hwdb.d/meson.build index 4df6dabf89..5c77387a26 100644 --- a/hwdb.d/meson.build +++ b/hwdb.d/meson.build @@ -1,6 +1,9 @@ # SPDX-License-Identifier: LGPL-2.1+ -hwdb_files = files(''' +# Those files right now are not supported by the grammar. Also, +# they are very long but quite repetitive and the parser is not very fast. +# So we don't "test" them. +hwdb_files_notest = files(''' 20-pci-vendor-model.hwdb 20-pci-classes.hwdb 20-usb-vendor-model.hwdb @@ -12,6 +15,10 @@ hwdb_files = files(''' 20-OUI.hwdb 20-net-ifname.hwdb 20-vmbus-class.hwdb +'''.split()) + +hwdb_files_test = files(''' + 60-autosuspend.hwdb 60-evdev.hwdb 60-input-id.hwdb 60-keyboard.hwdb @@ -23,7 +30,16 @@ hwdb_files = files(''' '''.split()) if conf.get('ENABLE_HWDB') == 1 - install_data(hwdb_files, + auto_suspend_rules = custom_target( + '60-autosuspend-chromiumos.hwdb', + output : '60-autosuspend-chromiumos.hwdb', + command : make_autosuspend_rules_py, + capture : true, + install : true, + install_dir: udevhwdbdir) + + install_data(hwdb_files_notest, + hwdb_files_test, install_dir : udevhwdbdir) meson.add_install_script('sh', '-c', @@ -32,15 +48,15 @@ if conf.get('ENABLE_HWDB') == 1 meson.add_install_script('sh', '-c', 'test -n "$DESTDIR" || @0@/systemd-hwdb update' .format(rootbindir)) -endif - -############################################################ -parse_hwdb_py = find_program('parse_hwdb.py') -if want_tests != 'false' - test('parse-hwdb', - parse_hwdb_py, - timeout : 90) + if want_tests != 'false' + parse_hwdb_py = find_program('parse_hwdb.py') + test('parse-hwdb', + parse_hwdb_py, + args : [hwdb_files_test, + auto_suspend_rules], + timeout : 90) + endif endif ############################################################ diff --git a/hwdb.d/parse_hwdb.py b/hwdb.d/parse_hwdb.py index abef56728f..8e1b5fdafa 100755 --- a/hwdb.d/parse_hwdb.py +++ b/hwdb.d/parse_hwdb.py @@ -59,6 +59,7 @@ REAL = Combine((INTEGER + Optional('.' + Optional(INTEGER))) ^ ('.' + INTEGER)) SIGNED_REAL = Combine(Optional(Word('-+')) + REAL) UDEV_TAG = Word(string.ascii_uppercase, alphanums + '_') +# Those patterns are used in type-specific matches TYPES = {'mouse': ('usb', 'bluetooth', 'ps2', '*'), 'evdev': ('name', 'atkbd', 'input'), 'id-input': ('modalias'), @@ -68,13 +69,27 @@ TYPES = {'mouse': ('usb', 'bluetooth', 'ps2', '*'), 'sensor': ('modalias', ), } +# Patterns that are used to set general properties on a device +GENERAL_MATCHES = {'acpi', + 'bluetooth', + 'usb', + 'pci', + 'sdio', + 'vmbus', + 'OUI', + } + @lru_cache() def hwdb_grammar(): ParserElement.setDefaultWhitespaceChars('') prefix = Or(category + ':' + Or(conn) + ':' for category, conn in TYPES.items()) - matchline = Combine(prefix + Word(printables + ' ' + '®')) + EOL + + matchline_typed = Combine(prefix + Word(printables + ' ' + '®')) + matchline_general = Combine(Or(GENERAL_MATCHES) + ':' + Word(printables)) + matchline = (matchline_typed | matchline_general) + EOL + propertyline = (White(' ', exact=1).suppress() + Combine(UDEV_TAG - '=' - Word(alphanums + '_=:@*.!-;, "') - Optional(pythonStyleComment)) + EOL) @@ -102,6 +117,7 @@ def property_grammar(): ('MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL', INTEGER), ('MOUSE_WHEEL_CLICK_COUNT', INTEGER), ('MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL', INTEGER), + ('ID_AUTOSUSPEND', Literal('1')), ('ID_INPUT', Literal('1')), ('ID_INPUT_ACCELEROMETER', Literal('1')), ('ID_INPUT_JOYSTICK', Literal('1')), diff --git a/man/custom-html.xsl b/man/custom-html.xsl index 7eebfdb5a1..57a9cc97d2 100644 --- a/man/custom-html.xsl +++ b/man/custom-html.xsl @@ -19,7 +19,8 @@ <xsl:template match="citerefentry[not(@project)]"> <a> <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:attribute> <xsl:call-template name="inline.charseq"/> @@ -133,6 +134,15 @@ </a> </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 - this conflict resolution is necessary to prevent malformed HTML output (multiple ID attributes with the same value) diff --git a/man/homectl.xml b/man/homectl.xml index 14877a0cde..3a4c6e5f5b 100644 --- a/man/homectl.xml +++ b/man/homectl.xml @@ -268,7 +268,8 @@ independently, for example with <citerefentry project='man-pages'><refentrytitle>groupadd</refentrytitle><manvolnum>8</manvolnum></citerefentry>. If non-existent groups that are listed there are ignored. This option may be used more than once, in - which case all specified group lists are combined.</para></listitem> + which case all specified group lists are combined. If the user is currently a member of a group + which is not listed, the user will be removed from the group.</para></listitem> </varlistentry> <varlistentry> diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml index 9be41baaa5..0e9b90c1cd 100644 --- a/man/resolved.conf.xml +++ b/man/resolved.conf.xml @@ -67,20 +67,28 @@ <varlistentry> <term><varname>Domains=</varname></term> - <listitem><para>A space-separated list of domains. These domains are used as search suffixes when resolving - single-label hostnames (domain names which contain no dot), in order to qualify them into fully-qualified - domain names (FQDNs). Search domains are strictly processed in the order they are specified, until the name - with the suffix appended is found. For compatibility reasons, if this setting is not specified, the search - domains listed in <filename>/etc/resolv.conf</filename> are used instead, if that file exists and any domains - are configured in it. This setting defaults to the empty list.</para> - - <para>Specified domain names may optionally be prefixed with <literal>~</literal>. In this case they do not - define a search path, but preferably direct DNS queries for the indicated domains to the DNS servers configured - with the system <varname>DNS=</varname> setting (see above), in case additional, suitable per-link DNS servers - are known. If no per-link DNS servers are known using the <literal>~</literal> syntax has no effect. Use the - construct <literal>~.</literal> (which is composed of <literal>~</literal> to indicate a routing domain and - <literal>.</literal> to indicate the DNS root domain that is the implied suffix of all DNS domains) to use the - system DNS server defined with <varname>DNS=</varname> preferably for all domains.</para></listitem> + <listitem><para>A space-separated list of domains optionally prefixed with <literal>~</literal>, + used for two distinct purposes described below. Defaults to the empty list.</para> + + <para>Any domains <emphasis>not</emphasis> prefixed with <literal>~</literal> are used as search + suffixes when resolving single-label hostnames (domain names which contain no dot), in order to + qualify them into fully-qualified domain names (FQDNs). These "search domains" are strictly processed + in the order they are specified in, until the name with the suffix appended is found. For + compatibility reasons, if this setting is not specified, the search domains listed in + <filename>/etc/resolv.conf</filename> with the <varname>search</varname> keyword are used instead, if + that file exists and any domains are configured in it.</para> + + <para>The domains prefixed with <literal>~</literal> are called "routing domains". All domains listed + here (both search domains and routing domains after removing the <literal>~</literal> prefix) define + a search path that preferably directs DNS queries to this inteface. This search path has an effect + only when suitable per-link DNS servers are known. Such servers may be defined through the + <varname>DNS=</varname> setting (see above) and dynamically at run time, for example from DHCP + leases. If no per-link DNS servers are known, routing domains have no effect.</para> + + <para>Use the construct <literal>~.</literal> (which is composed from <literal>~</literal> to + indicate a routing domain and <literal>.</literal> to indicate the DNS root domain that is the + implied suffix of all DNS domains) to use the DNS servers defined for this link preferably for all + domains.</para></listitem> </varlistentry> <varlistentry> @@ -258,11 +266,28 @@ <varlistentry> <term><varname>ReadEtcHosts=</varname></term> - <listitem><para>Takes a boolean argument. If <literal>yes</literal> (the default), the DNS stub resolver will read - <filename>/etc/hosts</filename>, and try to resolve hosts or address by using the entries in the file before - sending query to DNS servers.</para></listitem> + <listitem><para>Takes a boolean argument. If <literal>yes</literal> (the default), + <command>systemd-resolved</command> will read <filename>/etc/hosts</filename>, and try to resolve + hosts or address by using the entries in the file before sending query to DNS servers. + </para></listitem> </varlistentry> + <varlistentry> + <term><varname>ResolveUnicastSingleLabel=</varname></term> + <listitem><para>Takes a boolean argument. When false (the default), + <command>systemd-resolved</command> will not resolve A and AAAA queries for single-label names over + classic DNS. Note that such names may still be resolved if search domains are specified (see + <varname>Domains=</varname> above), or using other mechanisms, in particular via LLMNR or from + <filename>/etc/hosts</filename>. When true, queries for single-label names will be forwarded to + global DNS servers even if no search domains are defined. + </para> + + <para>This option is provided for compatibility with configurations where <emphasis>public DNS + servers are not used</emphasis>. Forwarding single-label names to servers not under your control is + not standard-conformant, see <ulink + url="https://www.iab.org/documents/correspondence-reports-documents/2013-2/iab-statement-dotless-domains-considered-harmful/">IAB + Statement</ulink>, and may create a privacy and security risk.</para></listitem> + </varlistentry> </variablelist> </refsect1> diff --git a/man/systemd-makefs@.service.xml b/man/systemd-makefs@.service.xml index d07d90315a..9aa058588e 100644 --- a/man/systemd-makefs@.service.xml +++ b/man/systemd-makefs@.service.xml @@ -51,7 +51,8 @@ <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 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 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. Currently: <citerefentry project='man-pages'><refentrytitle>ext4</refentrytitle><manvolnum>5</manvolnum></citerefentry>, - btrfs (see - <citerefentry project='man-pages'><refentrytitle>btrfs-man5</refentrytitle><manvolnum>5</manvolnum></citerefentry>), + <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>xfs</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <!-- yes, that's what the man page is called. --> and dm-crypt partitions (see diff --git a/man/systemd-modules-load.service.xml b/man/systemd-modules-load.service.xml index ca9edef367..e960609c6c 100644 --- a/man/systemd-modules-load.service.xml +++ b/man/systemd-modules-load.service.xml @@ -29,14 +29,15 @@ <refsect1> <title>Description</title> - <para><filename>systemd-modules-load.service</filename> is an - early boot service that loads kernel modules based on static - configuration.</para> + <para><filename>systemd-modules-load.service</filename> is an early boot service that loads kernel + modules. It reads static configuration from files in <filename>/usr</filename> and + <filename>/etc</filename>, but also runtime configuration from <filename>/run</filename> and the kernel + command line (see below).</para> <para>See - <citerefentry><refentrytitle>modules-load.d</refentrytitle><manvolnum>5</manvolnum></citerefentry> - for information about the configuration of this service.</para> - + <citerefentry><refentrytitle>modules-load.d</refentrytitle><manvolnum>5</manvolnum></citerefentry> for + information about the configuration format of this service and paths where configuration files can be + created.</para> </refsect1> <refsect1> diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml index 6e1ee9f4a5..914607e3f8 100644 --- a/man/systemd-resolved.service.xml +++ b/man/systemd-resolved.service.xml @@ -135,14 +135,16 @@ IPv6.</para></listitem> <listitem><para>Resolution of address records (A and AAAA) via unicast DNS (i.e. not LLMNR or - MulticastDNS) for non-synthesized single-label names is only allowed for non-top-level domains. This - means that such records can only be resolved when search domains are defined. For any interface which - defines search domains, such look-ups are routed to that interface, suffixed with each of the search - domains defined on that interface in turn. When global search domains are defined, such look-ups are - routed to all interfaces, suffixed by each of the global search domains in turn. The details of which - servers are queried and how the final reply is chosen are described below. Note that this means that - address queries for single-label names are never sent out to remote DNS servers, and if no search - domains are defined, resolution will fail.</para></listitem> + MulticastDNS) for non-synthesized single-label names is allowed for non-top-level domains. This means + that such records can be resolved when search domains are defined. For any interface which defines + search domains, such look-ups are routed to that interface, suffixed with each of the search domains + defined on that interface in turn. When global search domains are defined, such look-ups are routed to + all interfaces, suffixed by each of the global search domains in turn. Additionally, lookup of + single-label names via unicast DNS may be enabled with the + <varname>ResolveUnicastSingleLabel=yes</varname> setting. The details of which servers are queried and + how the final reply is chosen are described below. Note that this means that address queries for + single-label names are never sent out to remote DNS servers by default, and if no search domains are + defined, resolution will fail.</para></listitem> <listitem><para>Other multi-label names are routed to all local interfaces that have a DNS server configured, plus the globally configured DNS servers if there are any. Note that by default, lookups for diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index f5db55511f..aa8a3f75bc 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -146,6 +146,43 @@ </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> <term><varname>MountAPIVFS=</varname></term> <listitem><para>Takes a boolean argument. If on, a private mount namespace for the unit's processes is created diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index 6d3568576c..aa368732fb 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -670,8 +670,8 @@ </varlistentry> <varlistentry> - <term><varname>IPIngressFilterPath=<replaceable>BPF_FS_PROGRAMM_PATH</replaceable></varname></term> - <term><varname>IPEgressFilterPath=<replaceable>BPF_FS_PROGRAMM_PATH</replaceable></varname></term> + <term><varname>IPIngressFilterPath=<replaceable>BPF_FS_PROGRAM_PATH</replaceable></varname></term> + <term><varname>IPEgressFilterPath=<replaceable>BPF_FS_PROGRAM_PATH</replaceable></varname></term> <listitem> <para>Add custom network traffic filters implemented as BPF programs, applying to all IP packets diff --git a/meson.build b/meson.build index 4a679449ce..8f1d1b5897 100644 --- a/meson.build +++ b/meson.build @@ -1660,7 +1660,7 @@ test_dlopen = executable( build_by_default : want_tests != 'false') foreach tuple : [['myhostname', 'ENABLE_NSS_MYHOSTNAME'], - ['systemd', 'ENABLE_NSS_SYSTEMD', 'src/nss-systemd/userdb-glue.c src/nss-systemd/userdb-glue.h'], + ['systemd', 'ENABLE_NSS_SYSTEMD', 'src/nss-systemd/userdb-glue.c src/nss-systemd/userdb-glue.h src/nss-systemd/nss-systemd.h'], ['mymachines', 'ENABLE_NSS_MYMACHINES'], ['resolve', 'ENABLE_NSS_RESOLVE']] diff --git a/rules.d/50-udev-default.rules.in b/rules.d/50-udev-default.rules.in index 50747a1988..cef78f9d68 100644 --- a/rules.d/50-udev-default.rules.in +++ b/rules.d/50-udev-default.rules.in @@ -10,8 +10,9 @@ SUBSYSTEM=="virtio-ports", KERNEL=="vport*", ATTR{name}=="?*", SYMLINK+="virtio- SUBSYSTEM=="rtc", ATTR{hctosys}=="1", SYMLINK+="rtc" SUBSYSTEM=="rtc", KERNEL=="rtc0", SYMLINK+="rtc", OPTIONS+="link_priority=-100" -SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb" +SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb", GOTO="default_hwdb_imported" ENV{MODALIAS}!="", IMPORT{builtin}="hwdb --subsystem=$env{SUBSYSTEM}" +LABEL="default_hwdb_imported" ACTION!="add", GOTO="default_end" diff --git a/rules.d/60-autosuspend.rules b/rules.d/60-autosuspend.rules new file mode 100644 index 0000000000..1f9ebef631 --- /dev/null +++ b/rules.d/60-autosuspend.rules @@ -0,0 +1,14 @@ +# do not edit this file, it will be overwritten on update + +ACTION!="add", GOTO="autosuspend_end" + +# I2C rules +SUBSYSTEM=="i2c", ATTR{name}=="cyapa", \ + ATTR{power/control}="on", GOTO="autosuspend_end" + +# Enable autosuspend if hwdb says so. Here we are relying on +# the hwdb import done earlier based on MODALIAS. +ENV{ID_AUTOSUSPEND}=="1", TEST=="power/control", \ + ATTR{power/control}="auto" + +LABEL="autosuspend_end" diff --git a/rules.d/60-serial.rules b/rules.d/60-serial.rules index f303e27fd5..b1626650b7 100644 --- a/rules.d/60-serial.rules +++ b/rules.d/60-serial.rules @@ -4,8 +4,9 @@ ACTION=="remove", GOTO="serial_end" SUBSYSTEM!="tty", GOTO="serial_end" SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}" -SUBSYSTEMS=="pci", IMPORT{builtin}="hwdb --subsystem=pci" -SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb" +# We already ran the hwdb builtin for devices with MODALIAS in 50-default.rules. +# Let's cover the remaining case here, where we walk up the tree to find a node with $MODALIAS. +ENV{MODALIAS}=="", SUBSYSTEMS=="pci", IMPORT{builtin}="hwdb --subsystem=pci" # /dev/serial/by-path/, /dev/serial/by-id/ for USB devices KERNEL!="ttyUSB[0-9]*|ttyACM[0-9]*", GOTO="serial_end" diff --git a/rules.d/61-autosuspend-manual.rules b/rules.d/61-autosuspend-manual.rules deleted file mode 100644 index 2b973af960..0000000000 --- a/rules.d/61-autosuspend-manual.rules +++ /dev/null @@ -1,19 +0,0 @@ -# This udev rule is for any devices that should enter automatic suspend -# but are not already included in generated rules from Chromium OS via -# tools/make-autosuspend-rules.py -# - -ACTION!="add", GOTO="autosuspend_manual_end" -SUBSYSTEM!="usb", GOTO="autosuspend_manual_end" - -SUBSYSTEM=="usb", GOTO="autosuspend_manual_usb" - -# USB rules -LABEL="autosuspend_manual_usb" -GOTO="autosuspend_manual_end" - -# Enable autosuspend -LABEL="autosuspend_manual_enable" -TEST=="power/control", ATTR{power/control}="auto", GOTO="autosuspend_manual_end" - -LABEL="autosuspend_manual_end" diff --git a/rules.d/meson.build b/rules.d/meson.build index 13d1d330cf..ca4445d774 100644 --- a/rules.d/meson.build +++ b/rules.d/meson.build @@ -1,6 +1,7 @@ # SPDX-License-Identifier: LGPL-2.1+ rules = files(''' + 60-autosuspend.rules 60-block.rules 60-cdrom_id.rules 60-drm.rules @@ -14,7 +15,6 @@ rules = files(''' 60-persistent-v4l.rules 60-sensor.rules 60-serial.rules - 61-autosuspend-manual.rules 70-joystick.rules 70-mouse.rules 70-touchpad.rules @@ -45,11 +45,3 @@ foreach file : rules_in install_dir : udevrulesdir) all_rules += gen endforeach - -auto_suspend_rules = custom_target( - '60-autosuspend-chromiumos.rules', - output : '60-autosuspend-chromiumos.rules', - command : make_autosuspend_rules_py, - capture : true, - install : true, - install_dir: [udevrulesdir]) diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index faf50d2ac3..a8bd993cbe 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -2376,9 +2376,7 @@ static int run(int argc, char *argv[]) { setlocale(LC_ALL, ""); setlocale(LC_NUMERIC, "C"); /* we want to format/parse floats in C style */ - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/basic/dlfcn-util.h b/src/basic/dlfcn-util.h new file mode 100644 index 0000000000..d254afb68b --- /dev/null +++ b/src/basic/dlfcn-util.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include <dlfcn.h> + +#include "macro.h" + +DEFINE_TRIVIAL_CLEANUP_FUNC(void*, dlclose); diff --git a/src/basic/log.c b/src/basic/log.c index ca024d970e..c6fe203808 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -7,6 +7,7 @@ #include <stdarg.h> #include <stddef.h> #include <sys/signalfd.h> +#include <sys/stat.h> #include <sys/time.h> #include <sys/uio.h> #include <sys/un.h> @@ -219,6 +220,32 @@ fail: return r; } +static bool stderr_is_journal(void) { + _cleanup_free_ char *w = NULL; + const char *e; + uint64_t dev, ino; + struct stat st; + + e = getenv("JOURNAL_STREAM"); + if (!e) + return false; + + if (extract_first_word(&e, &w, ":", EXTRACT_DONT_COALESCE_SEPARATORS) <= 0) + return false; + if (!e) + return false; + + if (safe_atou64(w, &dev) < 0) + return false; + if (safe_atou64(e, &ino) < 0) + return false; + + if (fstat(STDERR_FILENO, &st) < 0) + return false; + + return st.st_dev == dev && st.st_ino == ino; +} + int log_open(void) { int r; @@ -238,9 +265,7 @@ int log_open(void) { return 0; } - if (log_target != LOG_TARGET_AUTO || - getpid_cached() == 1 || - isatty(STDERR_FILENO) <= 0) { + if (log_target != LOG_TARGET_AUTO || getpid_cached() == 1 || stderr_is_journal()) { if (!prohibit_ipc && IN_SET(log_target, LOG_TARGET_AUTO, @@ -1121,16 +1146,20 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat } void log_parse_environment_realm(LogRealm realm) { - /* Do not call from library code. */ - - const char *e; - if (getpid_cached() == 1 || get_ctty_devnr(0, NULL) < 0) /* Only try to read the command line in daemons. We assume that anything that has a * controlling tty is user stuff. For PID1 we do a special check in case it hasn't * closed the console yet. */ (void) proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX); + log_parse_environment_cli_realm(realm); +} + +void log_parse_environment_cli_realm(LogRealm realm) { + /* Do not call from library code. */ + + const char *e; + e = getenv("SYSTEMD_LOG_TARGET"); if (e && log_set_target_from_string(e) < 0) log_warning("Failed to parse log target '%s'. Ignoring.", e); @@ -1405,3 +1434,11 @@ void log_setup_service(void) { log_parse_environment(); (void) log_open(); } + +void log_setup_cli(void) { + /* Sets up logging the way it is most appropriate for running a program as a CLI utility. */ + + log_show_color(true); + log_parse_environment_cli(); + (void) log_open(); +} diff --git a/src/basic/log.h b/src/basic/log.h index 2c1b00fb88..15807d3029 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -84,8 +84,11 @@ void log_close(void); void log_forget_fds(void); void log_parse_environment_realm(LogRealm realm); +void log_parse_environment_cli_realm(LogRealm realm); #define log_parse_environment() \ log_parse_environment_realm(LOG_REALM) +#define log_parse_environment_cli() \ + log_parse_environment_cli_realm(LOG_REALM) int log_dispatch_internal( int level, @@ -341,3 +344,4 @@ int log_syntax_invalid_utf8_internal( #define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG) void log_setup_service(void); +void log_setup_cli(void); diff --git a/src/basic/memory-util.h b/src/basic/memory-util.h index a6a2ccdbc2..4f596cffb7 100644 --- a/src/basic/memory-util.h +++ b/src/basic/memory-util.h @@ -13,6 +13,7 @@ size_t page_size(void) _pure_; #define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) #define PAGE_ALIGN_DOWN(l) ((l) & ~(page_size() - 1)) +#define PAGE_OFFSET(l) ((l) & (page_size() - 1)) /* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */ static inline void memcpy_safe(void *dst, const void *src, size_t n) { diff --git a/src/basic/meson.build b/src/basic/meson.build index 5bb49ef401..90924d6cb8 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -39,6 +39,7 @@ basic_sources = files(''' device-nodes.h dirent-util.c dirent-util.h + dlfcn-util.h efivars.c efivars.h env-file.c @@ -328,7 +329,8 @@ libbasic = static_library( threads, libcap, libselinux, - libm], + libm, + libdl], c_args : ['-fvisibility=default'], install : false) diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index 33ff427ae7..80bd65b155 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -39,7 +39,18 @@ static int cached_enforcing = -1; static struct selabel_handle *label_hnd = NULL; #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 bool mac_selinux_use(void) { @@ -59,14 +70,15 @@ bool mac_selinux_enforcing(void) { #if HAVE_SELINUX if (_unlikely_(cached_enforcing < 0)) { cached_enforcing = security_getenforce(); - if (cached_enforcing == -1) - log_error_errno(errno, "Failed to get SELinux enforced status, continue in enforcing mode: %m"); - else - log_debug("SELinux enforcing state cached to: %s", cached_enforcing ? "enforcing" : "permissive"); + if (cached_enforcing < 0) { + log_debug_errno(errno, "Failed to get SELinux enforced status, continuing in enforcing mode: %m"); + return true; /* treat failure as enforcing mode */ + } + + 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 return false; #endif @@ -90,11 +102,11 @@ static int setenforce_callback(int enforcing) { #endif int mac_selinux_init(void) { - int r = 0; - #if HAVE_SELINUX usec_t before_timestamp, after_timestamp; 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_SETENFORCE, (union selinux_callback) setenforce_callback); @@ -109,25 +121,20 @@ int mac_selinux_init(void) { before_timestamp = now(CLOCK_MONOTONIC); label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); - if (!label_hnd) { - log_enforcing_errno(errno, "Failed to initialize SELinux context: %m"); - r = mac_selinux_enforcing() ? -errno : 0; - } else { - char timespan[FORMAT_TIMESPAN_MAX]; - int l; + if (!label_hnd) + return log_enforcing_errno(errno, "Failed to initialize SELinux labeling handle: %m"); - after_timestamp = now(CLOCK_MONOTONIC); - after_mallinfo = mallinfo(); + after_timestamp = now(CLOCK_MONOTONIC); + 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); - } -#endif + 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); - return r; +#endif + return 0; } void mac_selinux_finish(void) { @@ -226,9 +233,7 @@ int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFi return 0; fail: - log_enforcing_errno(r, "Unable to fix SELinux security context of %s (%s): %m", path, inside_path); - if (mac_selinux_enforcing()) - return r; + return log_enforcing_errno(r, "Unable to fix SELinux security context of %s (%s): %m", path, inside_path); #endif return 0; @@ -243,21 +248,17 @@ int mac_selinux_apply(const char *path, const char *label) { assert(path); assert(label); - if (setfilecon(path, label) < 0) { - log_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, path); - if (mac_selinux_enforcing()) - return -errno; - } + if (setfilecon(path, label) < 0) + return log_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, path); #endif return 0; } int mac_selinux_get_create_label_from_exe(const char *exe, char **label) { - int r = -EOPNOTSUPP; - #if HAVE_SELINUX _cleanup_freecon_ char *mycon = NULL, *fcon = NULL; security_class_t sclass; + int r; assert(exe); 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); if (r < 0) return -errno; -#endif - return r; + return 0; +#else + return -EOPNOTSUPP; +#endif } int mac_selinux_get_our_label(char **label) { - int r = -EOPNOTSUPP; +#if HAVE_SELINUX + int r; assert(label); -#if HAVE_SELINUX if (!mac_selinux_use()) return -EOPNOTSUPP; r = getcon_raw(label); if (r < 0) 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 r = -EOPNOTSUPP; - #if HAVE_SELINUX _cleanup_freecon_ char *mycon = NULL, *peercon = NULL, *fcon = NULL; _cleanup_context_free_ context_t pcon = NULL, bcon = NULL; security_class_t sclass; const char *range = NULL; + int r; assert(socket_fd >= 0); assert(exe); @@ -362,21 +366,19 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char * r = security_compute_create_raw(mycon, fcon, sclass, label); if (r < 0) return -errno; -#endif - return r; + return 0; +#else + return -EOPNOTSUPP; +#endif } char* mac_selinux_free(char *label) { #if HAVE_SELINUX - if (!label) - return NULL; - - if (!mac_selinux_use()) - return NULL; - freecon(label); +#else + assert(!label); #endif return NULL; @@ -399,26 +401,21 @@ static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode) if (errno == ENOENT) return 0; - 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); + return log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", abspath); } - if (mac_selinux_enforcing()) - return -errno; + if (setfscreatecon_raw(filecon) < 0) + return log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, abspath); return 0; } #endif int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode) { - int r = 0; - #if HAVE_SELINUX _cleanup_free_ char *abspath = NULL; + int r; + assert(path); @@ -440,15 +437,16 @@ int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode) return -ENOMEM; } - r = selinux_create_file_prepare_abspath(path, mode); + return selinux_create_file_prepare_abspath(path, mode); +#else + return 0; #endif - return r; } int mac_selinux_create_file_prepare(const char *path, mode_t mode) { - int r = 0; - #if HAVE_SELINUX + int r; + _cleanup_free_ char *abspath = NULL; assert(path); @@ -460,9 +458,10 @@ int mac_selinux_create_file_prepare(const char *path, mode_t mode) { if (r < 0) return r; - r = selinux_create_file_prepare_abspath(abspath, mode); + return selinux_create_file_prepare_abspath(abspath, mode); +#else + return 0; #endif - return r; } void mac_selinux_create_file_clear(void) { @@ -480,17 +479,13 @@ void mac_selinux_create_file_clear(void) { int mac_selinux_create_socket_prepare(const char *label) { #if HAVE_SELINUX - if (!mac_selinux_use()) - return 0; - assert(label); - if (setsockcreatecon(label) < 0) { - log_enforcing_errno(errno, "Failed to set SELinux security context %s for sockets: %m", label); + if (!mac_selinux_use()) + return 0; - if (mac_selinux_enforcing()) - return -errno; - } + if (setsockcreatecon(label) < 0) + return log_enforcing_errno(errno, "Failed to set SELinux security context %s for sockets: %m", label); #endif return 0; @@ -561,15 +556,14 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { if (errno == ENOENT) goto skipped; - log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", path); - if (mac_selinux_enforcing()) - return -errno; - + r = log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", path); + if (r < 0) + return r; } else { if (setfscreatecon_raw(fcon) < 0) { - log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", fcon, path); - if (mac_selinux_enforcing()) - return -errno; + r = log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", fcon, path); + if (r < 0) + return r; } else context_changed = true; } @@ -577,7 +571,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { r = bind(fd, addr, addrlen) < 0 ? -errno : 0; if (context_changed) - setfscreatecon_raw(NULL); + (void) setfscreatecon_raw(NULL); return r; diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c index 8e000ee119..3ab90de63e 100644 --- a/src/busctl/busctl.c +++ b/src/busctl/busctl.c @@ -2598,9 +2598,7 @@ static int busctl_main(int argc, char *argv[]) { static int run(int argc, char *argv[]) { int r; - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c index b55d7299ca..939a391e21 100644 --- a/src/cgls/cgls.c +++ b/src/cgls/cgls.c @@ -164,9 +164,7 @@ static void show_cg_info(const char *controller, const char *path) { static int run(int argc, char *argv[]) { int r, output_flags; - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index de25aaae5d..e6c09d1b38 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -908,9 +908,7 @@ static int run(int argc, char *argv[]) { CGroupMask mask; int r; - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 8587a712e2..080f6fb1ae 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -707,112 +707,14 @@ static int bus_cgroup_set_boolean( return 1; \ } -#define BUS_DEFINE_SET_CGROUP_PROTECTION(function, mask, scale) \ - static int bus_cgroup_set_##function( \ - Unit *u, \ - const char *name, \ - uint64_t *p, \ - bool *s, \ - sd_bus_message *message, \ - UnitWriteFlags flags, \ - sd_bus_error *error) { \ - \ - uint64_t v = CGROUP_LIMIT_MIN; \ - bool nonempty = true; \ - char type; \ - int r; \ - \ - assert(p); \ - assert(s); \ - \ - r = sd_bus_message_peek_type(message, &type, NULL); \ - if (r < 0) \ - return r; \ - if (type == SD_BUS_TYPE_BOOLEAN) { \ - r = sd_bus_message_read(message, "b", &nonempty); \ - if (r < 0) \ - return r; \ - /* Bool is used to denote empty value only */ \ - if (nonempty) \ - return -EINVAL; \ - } else if (type != SD_BUS_TYPE_UINT64) { \ - return -EINVAL; \ - } else { \ - r = sd_bus_message_read(message, "t", &v); \ - if (r < 0) \ - return r; \ - } \ - \ - if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \ - *p = v; \ - unit_invalidate_cgroup(u, mask); \ - if (!nonempty) { \ - *s = false; \ - unit_write_settingf(u, flags, name, \ - "%s=", name); \ - } else if (v == CGROUP_LIMIT_MAX) { \ - *s = true; \ - unit_write_settingf(u, flags, name, \ - "%s=infinity", name); \ - } else { \ - *s = true; \ - unit_write_settingf(u, flags, name, \ - "%s=%" PRIu64, name, v); \ - } \ - } \ - \ - return 1; \ - } \ - static int bus_cgroup_set_##function##_scale( \ - Unit *u, \ - const char *name, \ - uint64_t *p, \ - bool *s, \ - sd_bus_message *message, \ - UnitWriteFlags flags, \ - sd_bus_error *error) { \ - \ - uint64_t v; \ - uint32_t raw; \ - int r; \ - \ - assert(p); \ - assert(s); \ - \ - r = sd_bus_message_read(message, "u", &raw); \ - if (r < 0) \ - return r; \ - \ - v = scale(raw, UINT32_MAX); \ - if (v >= UINT64_MAX) \ - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, \ - "Value specified in %s is out of range", name); \ - \ - if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \ - *p = v; \ - unit_invalidate_cgroup(u, mask); \ - \ - /* Prepare to chop off suffix */ \ - assert_se(endswith(name, "Scale")); \ - \ - uint32_t scaled = DIV_ROUND_UP((uint64_t) raw * 1000, (uint64_t) UINT32_MAX); \ - unit_write_settingf(u, flags, name, "%.*s=%" PRIu32 ".%" PRIu32 "%%", \ - (int)(strlen(name) - strlen("Scale")), name, \ - scaled / 10, scaled % 10); \ - } \ - \ - *s = true; \ - return 1; \ - } - DISABLE_WARNING_TYPE_LIMITS; BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_weight, CGROUP_MASK_CPU, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID); BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_shares, CGROUP_MASK_CPU, CGROUP_CPU_SHARES_IS_OK, CGROUP_CPU_SHARES_INVALID); BUS_DEFINE_SET_CGROUP_WEIGHT(io_weight, CGROUP_MASK_IO, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID); BUS_DEFINE_SET_CGROUP_WEIGHT(blockio_weight, CGROUP_MASK_BLKIO, CGROUP_BLKIO_WEIGHT_IS_OK, CGROUP_BLKIO_WEIGHT_INVALID); BUS_DEFINE_SET_CGROUP_LIMIT(memory, CGROUP_MASK_MEMORY, physical_memory_scale, 1); +BUS_DEFINE_SET_CGROUP_LIMIT(memory_protection, CGROUP_MASK_MEMORY, physical_memory_scale, 0); BUS_DEFINE_SET_CGROUP_LIMIT(swap, CGROUP_MASK_MEMORY, physical_memory_scale, 0); -BUS_DEFINE_SET_CGROUP_PROTECTION(memory_protection, CGROUP_MASK_MEMORY, physical_memory_scale); REENABLE_WARNING; static int bus_cgroup_set_tasks_max( @@ -938,17 +840,33 @@ int bus_cgroup_set_property( if (streq(name, "MemoryAccounting")) return bus_cgroup_set_boolean(u, name, &c->memory_accounting, CGROUP_MASK_MEMORY, message, flags, error); - if (streq(name, "MemoryMin")) - return bus_cgroup_set_memory_protection(u, name, &c->memory_min, &c->memory_min_set, message, flags, error); + if (streq(name, "MemoryMin")) { + r = bus_cgroup_set_memory_protection(u, name, &c->memory_min, message, flags, error); + if (r > 0) + c->memory_min_set = true; + return r; + } - if (streq(name, "MemoryLow")) - return bus_cgroup_set_memory_protection(u, name, &c->memory_low, &c->memory_low_set, message, flags, error); + if (streq(name, "MemoryLow")) { + r = bus_cgroup_set_memory_protection(u, name, &c->memory_low, message, flags, error); + if (r > 0) + c->memory_low_set = true; + return r; + } - if (streq(name, "DefaultMemoryMin")) - return bus_cgroup_set_memory_protection(u, name, &c->default_memory_min, &c->default_memory_min_set, message, flags, error); + if (streq(name, "DefaultMemoryMin")) { + r = bus_cgroup_set_memory_protection(u, name, &c->default_memory_min, message, flags, error); + if (r > 0) + c->default_memory_min_set = true; + return r; + } - if (streq(name, "DefaultMemoryLow")) - return bus_cgroup_set_memory_protection(u, name, &c->default_memory_low, &c->default_memory_low_set, message, flags, error); + if (streq(name, "DefaultMemoryLow")) { + r = bus_cgroup_set_memory_protection(u, name, &c->default_memory_low, message, flags, error); + if (r > 0) + c->default_memory_low_set = true; + return r; + } if (streq(name, "MemoryHigh")) return bus_cgroup_set_memory(u, name, &c->memory_high, message, flags, error); @@ -962,17 +880,33 @@ int bus_cgroup_set_property( if (streq(name, "MemoryLimit")) return bus_cgroup_set_memory(u, name, &c->memory_limit, message, flags, error); - if (streq(name, "MemoryMinScale")) - return bus_cgroup_set_memory_protection_scale(u, name, &c->memory_min, &c->memory_min_set, message, flags, error); + if (streq(name, "MemoryMinScale")) { + r = bus_cgroup_set_memory_protection_scale(u, name, &c->memory_min, message, flags, error); + if (r > 0) + c->memory_min_set = true; + return r; + } - if (streq(name, "MemoryLowScale")) - return bus_cgroup_set_memory_protection_scale(u, name, &c->memory_low, &c->memory_low_set, message, flags, error); + if (streq(name, "MemoryLowScale")) { + r = bus_cgroup_set_memory_protection_scale(u, name, &c->memory_low, message, flags, error); + if (r > 0) + c->memory_low_set = true; + return r; + } - if (streq(name, "DefaultMemoryMinScale")) - return bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_min, &c->default_memory_min_set, message, flags, error); + if (streq(name, "DefaultMemoryMinScale")) { + r = bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_min, message, flags, error); + if (r > 0) + c->default_memory_min_set = true; + return r; + } - if (streq(name, "DefaultMemoryLowScale")) - return bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_low, &c->default_memory_low_set, message, flags, error); + if (streq(name, "DefaultMemoryLowScale")) { + r = bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_low, message, flags, error); + if (r > 0) + c->default_memory_low_set = true; + return r; + } if (streq(name, "MemoryHighScale")) return bus_cgroup_set_memory_scale(u, name, &c->memory_high, message, flags, error); diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 5b217c059d..68ce395c56 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -746,6 +746,25 @@ static int property_get_log_extra_fields( 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[] = { SD_BUS_VTABLE_START(0), 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("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("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("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), @@ -1258,6 +1280,55 @@ int bus_exec_context_set_transient_property( if (streq(name, "RootImage")) 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")) return bus_set_transient_path(u, name, &c->root_directory, message, flags, error); diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 2a3c8e776a..5cb06867cb 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -234,14 +234,12 @@ static int property_get_show_status( sd_bus_error *error) { Manager *m = userdata; - int b; + assert(m); assert(bus); assert(reply); - assert(m); - b = IN_SET(m->show_status, SHOW_STATUS_TEMPORARY, SHOW_STATUS_YES); - return sd_bus_message_append_basic(reply, 'b', &b); + return sd_bus_message_append(reply, "b", manager_get_show_status_on(m)); } static int property_get_runtime_watchdog( @@ -311,7 +309,7 @@ static int property_set_watchdog(Manager *m, WatchdogType type, sd_bus_message * if (r < 0) return r; - return manager_set_watchdog_overridden(m, type, timeout); + return manager_override_watchdog(m, type, timeout); } static int property_set_runtime_watchdog( @@ -2452,6 +2450,30 @@ static int method_abandon_scope(sd_bus_message *message, void *userdata, sd_bus_ return bus_scope_method_abandon(message, u, error); } +static int method_set_show_status(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + ShowStatus mode = _SHOW_STATUS_INVALID; + const char *t; + int r; + + assert(m); + assert(message); + + r = sd_bus_message_read(message, "s", &t); + if (r < 0) + return r; + + if (!isempty(t)) { + mode = show_status_from_string(t); + if (mode < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid show status '%s'", t); + } + + manager_override_show_status(m, mode, "bus"); + + return sd_bus_reply_method_return(message, NULL); +} + const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_VTABLE_START(0), @@ -2786,6 +2808,12 @@ const sd_bus_vtable bus_manager_vtable[] = { NULL, method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("SetShowStatus", + "s", + SD_BUS_PARAM(mode), + NULL,, + method_set_show_status, + SD_BUS_VTABLE_CAPABILITY(CAP_SYS_ADMIN)), SD_BUS_METHOD_WITH_NAMES("ListUnits", NULL,, "a(ssssssouso)", diff --git a/src/core/emergency-action.c b/src/core/emergency-action.c index 4330c0f2c1..1565a79927 100644 --- a/src/core/emergency-action.c +++ b/src/core/emergency-action.c @@ -12,6 +12,18 @@ #include "terminal-util.h" #include "virt.h" +static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = { + [EMERGENCY_ACTION_NONE] = "none", + [EMERGENCY_ACTION_REBOOT] = "reboot", + [EMERGENCY_ACTION_REBOOT_FORCE] = "reboot-force", + [EMERGENCY_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate", + [EMERGENCY_ACTION_POWEROFF] = "poweroff", + [EMERGENCY_ACTION_POWEROFF_FORCE] = "poweroff-force", + [EMERGENCY_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate", + [EMERGENCY_ACTION_EXIT] = "exit", + [EMERGENCY_ACTION_EXIT_FORCE] = "exit-force", +}; + static void log_and_status(Manager *m, bool warn, const char *message, const char *reason) { log_full(warn ? LOG_WARNING : LOG_DEBUG, "%s: %s", message, reason); if (warn) @@ -28,10 +40,22 @@ void emergency_action( int exit_status, const char *reason) { + Unit *u; + assert(m); assert(action >= 0); assert(action < _EMERGENCY_ACTION_MAX); + /* Is the special shutdown target active or queued? If so, we are in shutdown state */ + if (IN_SET(action, EMERGENCY_ACTION_REBOOT, EMERGENCY_ACTION_POWEROFF, EMERGENCY_ACTION_EXIT)) { + u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET); + if (u && unit_active_or_pending(u)) { + log_notice("Shutdown is already active. Skipping emergency action request %s.", + emergency_action_table[action]); + return; + } + } + if (action == EMERGENCY_ACTION_NONE) return; @@ -126,17 +150,6 @@ void emergency_action( } } -static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = { - [EMERGENCY_ACTION_NONE] = "none", - [EMERGENCY_ACTION_REBOOT] = "reboot", - [EMERGENCY_ACTION_REBOOT_FORCE] = "reboot-force", - [EMERGENCY_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate", - [EMERGENCY_ACTION_POWEROFF] = "poweroff", - [EMERGENCY_ACTION_POWEROFF_FORCE] = "poweroff-force", - [EMERGENCY_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate", - [EMERGENCY_ACTION_EXIT] = "exit", - [EMERGENCY_ACTION_EXIT_FORCE] = "exit-force", -}; DEFINE_STRING_TABLE_LOOKUP(emergency_action, EmergencyAction); int parse_emergency_action( diff --git a/src/core/execute.c b/src/core/execute.c index aa253a5ddf..e0835f9b92 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -54,6 +54,7 @@ #include "format-util.h" #include "fs-util.h" #include "glob-util.h" +#include "hexdecoct.h" #include "io-util.h" #include "ioprio.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_system : PROTECT_SYSTEM_NO, 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, error_path); @@ -4195,6 +4197,10 @@ void exec_context_done(ExecContext *c) { c->working_directory = mfree(c->working_directory); c->root_directory = mfree(c->root_directory); 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->syslog_identifier = mfree(c->syslog_identifier); 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) 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) fprintf(f, "%sEnvironment: %s\n", prefix, *e); diff --git a/src/core/execute.h b/src/core/execute.h index 7e1015631f..7c9d63c5e4 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -155,7 +155,9 @@ struct ExecContext { char **unset_environment; 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_home:1; diff --git a/src/core/job.c b/src/core/job.c index d518ac8969..ff49136d70 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -387,62 +387,25 @@ JobType job_type_lookup_merge(JobType a, JobType b) { return job_merging_table[(a - 1) * a / 2 + b]; } -bool job_later_link_matters(Job *j, JobType type, unsigned generation) { - JobDependency *l; - - 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) { +bool job_type_is_redundant(JobType a, UnitActiveState b) { + switch (a) { 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: - 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: - return IN_SET(state, UNIT_ACTIVE, UNIT_RELOADING); + return IN_SET(b, UNIT_ACTIVE, UNIT_RELOADING); case JOB_RELOAD: return - state == UNIT_RELOADING; + b == UNIT_RELOADING; case JOB_RESTART: return - state == UNIT_ACTIVATING; + b == UNIT_ACTIVATING; case JOB_NOP: return true; diff --git a/src/core/job.h b/src/core/job.h index 02b057ee06..03ad640618 100644 --- a/src/core/job.h +++ b/src/core/job.h @@ -196,8 +196,7 @@ _pure_ static inline bool job_type_is_superset(JobType a, JobType b) { return a == job_type_lookup_merge(a, b); } -bool job_later_link_matters(Job *j, JobType type, unsigned generation); -bool job_is_redundant(Job *j, unsigned generation); +bool job_type_is_redundant(JobType a, UnitActiveState b) _pure_; /* 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. */ diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 69598e8430..9cf959edd5 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -23,6 +23,8 @@ m4_define(`EXEC_CONTEXT_CONFIG_ITEMS', `$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.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.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) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index c5664f968b..c3186f3824 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -29,6 +29,7 @@ #include "errno-list.h" #include "escape.h" #include "fd-util.h" +#include "fileio.h" #include "fs-util.h" #include "hexdecoct.h" #include "io-util.h" @@ -1413,6 +1414,64 @@ int config_parse_exec_cpu_sched_prio(const char *unit, 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, const char *filename, unsigned line, @@ -3393,8 +3452,6 @@ int config_parse_memory_limit( } } - /* Keep Memory{Low,Min} unset with empty assignment so that we fall back to DefaultMemory* which in - * contrast means zeroing the property. */ if (streq(lvalue, "DefaultMemoryLow")) { c->default_memory_low = bytes; c->default_memory_low_set = true; @@ -3403,10 +3460,10 @@ int config_parse_memory_limit( c->default_memory_min_set = true; } else if (streq(lvalue, "MemoryMin")) { c->memory_min = bytes; - c->memory_min_set = !isempty(rvalue); + c->memory_min_set = true; } else if (streq(lvalue, "MemoryLow")) { c->memory_low = bytes; - c->memory_low_set = !isempty(rvalue); + c->memory_low_set = true; } else if (streq(lvalue, "MemoryHigh")) c->memory_high = bytes; else if (streq(lvalue, "MemoryMax")) diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 9c30b6f882..f0e109da3a 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -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_affinity); 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_exec_mount_flags); CONFIG_PARSER_PROTOTYPE(config_parse_timer); diff --git a/src/core/main.c b/src/core/main.c index 6e606d412a..a2ff71fa71 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -2559,7 +2559,7 @@ int main(int argc, char *argv[]) { } if (mac_selinux_init() < 0) { - error_message = "Failed to initialize SELinux policy"; + error_message = "Failed to initialize SELinux support"; goto finish; } @@ -2603,6 +2603,11 @@ int main(int argc, char *argv[]) { /* clear the kernel timestamp, * because we are not PID 1 */ kernel_timestamp = DUAL_TIMESTAMP_NULL; + + if (mac_selinux_init() < 0) { + error_message = "Failed to initialize SELinux support"; + goto finish; + } } if (arg_system) { diff --git a/src/core/manager.c b/src/core/manager.c index 48bd86e54f..ab3d0b1192 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -779,6 +779,8 @@ int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager .watchdog_overridden[WATCHDOG_REBOOT] = USEC_INFINITY, .watchdog_overridden[WATCHDOG_KEXEC] = USEC_INFINITY, + .show_status_overridden = _SHOW_STATUS_INVALID, + .notify_fd = -1, .cgroups_agent_fd = -1, .signal_fd = -1, @@ -2759,11 +2761,11 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t switch (sfsi.ssi_signo - SIGRTMIN) { case 20: - manager_set_show_status(m, SHOW_STATUS_YES, "signal"); + manager_override_show_status(m, SHOW_STATUS_YES, "signal"); break; case 21: - manager_set_show_status(m, SHOW_STATUS_NO, "signal"); + manager_override_show_status(m, SHOW_STATUS_NO, "signal"); break; case 22: @@ -3219,9 +3221,9 @@ int manager_serialize( /* After switching root, udevd has not been started yet. So, enumeration results should not be emitted. */ (void) serialize_bool(f, "honor-device-enumeration", !switching_root); - t = show_status_to_string(m->show_status); - if (t) - (void) serialize_item(f, "show-status", t); + if (m->show_status_overridden != _SHOW_STATUS_INVALID) + (void) serialize_item(f, "show-status-overridden", + show_status_to_string(m->show_status_overridden)); if (m->log_level_overridden) (void) serialize_item_format(f, "log-level-override", "%i", log_get_max_level()); @@ -3399,7 +3401,7 @@ void manager_set_watchdog(Manager *m, WatchdogType t, usec_t timeout) { m->watchdog[t] = timeout; } -int manager_set_watchdog_overridden(Manager *m, WatchdogType t, usec_t timeout) { +int manager_override_watchdog(Manager *m, WatchdogType t, usec_t timeout) { int r = 0; assert(m); @@ -3568,14 +3570,14 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { else m->honor_device_enumeration = b; - } else if ((val = startswith(l, "show-status="))) { + } else if ((val = startswith(l, "show-status-overridden="))) { ShowStatus s; s = show_status_from_string(val); if (s < 0) - log_notice("Failed to parse show-status flag '%s', ignoring.", val); + log_notice("Failed to parse show-status-overridden flag '%s', ignoring.", val); else - manager_set_show_status(m, s, "deserialization"); + manager_override_show_status(m, s, "deserialize"); } else if ((val = startswith(l, "log-level-override="))) { int level; @@ -3601,7 +3603,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { if (deserialize_usec(val, &t) < 0) log_notice("Failed to parse runtime-watchdog-overridden value '%s', ignoring.", val); else - manager_set_watchdog_overridden(m, WATCHDOG_RUNTIME, t); + manager_override_watchdog(m, WATCHDOG_RUNTIME, t); } else if ((val = startswith(l, "reboot-watchdog-overridden="))) { usec_t t; @@ -3609,7 +3611,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { if (deserialize_usec(val, &t) < 0) log_notice("Failed to parse reboot-watchdog-overridden value '%s', ignoring.", val); else - manager_set_watchdog_overridden(m, WATCHDOG_REBOOT, t); + manager_override_watchdog(m, WATCHDOG_REBOOT, t); } else if ((val = startswith(l, "kexec-watchdog-overridden="))) { usec_t t; @@ -3617,7 +3619,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { if (deserialize_usec(val, &t) < 0) log_notice("Failed to parse kexec-watchdog-overridden value '%s', ignoring.", val); else - manager_set_watchdog_overridden(m, WATCHDOG_KEXEC, t); + manager_override_watchdog(m, WATCHDOG_KEXEC, t); } else if (startswith(l, "env=")) { r = deserialize_environment(l + 4, &m->client_environment); @@ -4264,49 +4266,78 @@ void manager_recheck_journal(Manager *m) { log_open(); } +static ShowStatus manager_get_show_status(Manager *m) { + assert(m); + + if (MANAGER_IS_USER(m)) + return _SHOW_STATUS_INVALID; + + if (m->show_status_overridden != _SHOW_STATUS_INVALID) + return m->show_status_overridden; + + return m->show_status; +} + +bool manager_get_show_status_on(Manager *m) { + assert(m); + + return show_status_on(manager_get_show_status(m)); +} + +static void set_show_status_marker(bool b) { + if (b) + (void) touch("/run/systemd/show-status"); + else + (void) unlink("/run/systemd/show-status"); +} + void manager_set_show_status(Manager *m, ShowStatus mode, const char *reason) { assert(m); + assert(reason); assert(mode >= 0 && mode < _SHOW_STATUS_MAX); - if (!MANAGER_IS_SYSTEM(m)) + if (MANAGER_IS_USER(m)) return; if (mode == m->show_status) return; - bool enabled = IN_SET(mode, SHOW_STATUS_TEMPORARY, SHOW_STATUS_YES); - log_debug("%s (%s) showing of status (%s).", - enabled ? "Enabling" : "Disabling", - strna(show_status_to_string(mode)), - reason); - m->show_status = mode; + if (m->show_status_overridden == _SHOW_STATUS_INVALID) { + bool enabled; - if (enabled) - (void) touch("/run/systemd/show-status"); - else - (void) unlink("/run/systemd/show-status"); + enabled = show_status_on(mode); + log_debug("%s (%s) showing of status (%s).", + enabled ? "Enabling" : "Disabling", + strna(show_status_to_string(mode)), + reason); + + set_show_status_marker(enabled); + } + + m->show_status = mode; } -static bool manager_get_show_status(Manager *m, StatusType type) { +void manager_override_show_status(Manager *m, ShowStatus mode, const char *reason) { assert(m); + assert(mode < _SHOW_STATUS_MAX); - if (!MANAGER_IS_SYSTEM(m)) - return false; + if (MANAGER_IS_USER(m)) + return; - if (m->no_console_output) - return false; + if (mode == m->show_status_overridden) + return; - if (!IN_SET(manager_state(m), MANAGER_INITIALIZING, MANAGER_STARTING, MANAGER_STOPPING)) - return false; + m->show_status_overridden = mode; - /* If we cannot find out the status properly, just proceed. */ - if (type != STATUS_TYPE_EMERGENCY && manager_check_ask_password(m) > 0) - return false; + if (mode == _SHOW_STATUS_INVALID) + mode = m->show_status; - if (type == STATUS_TYPE_NOTICE && m->show_status != SHOW_STATUS_NO) - return true; + log_debug("%s (%s) showing of status (%s).", + m->show_status_overridden != _SHOW_STATUS_INVALID ? "Overriding" : "Restoring", + strna(show_status_to_string(mode)), + reason); - return show_status_on(m->show_status); + set_show_status_marker(show_status_on(mode)); } const char *manager_get_confirm_spawn(Manager *m) { @@ -4381,12 +4412,34 @@ bool manager_is_confirm_spawn_disabled(Manager *m) { return access("/run/systemd/confirm_spawn_disabled", F_OK) >= 0; } +static bool manager_should_show_status(Manager *m, StatusType type) { + assert(m); + + if (!MANAGER_IS_SYSTEM(m)) + return false; + + if (m->no_console_output) + return false; + + if (!IN_SET(manager_state(m), MANAGER_INITIALIZING, MANAGER_STARTING, MANAGER_STOPPING)) + return false; + + /* If we cannot find out the status properly, just proceed. */ + if (type != STATUS_TYPE_EMERGENCY && manager_check_ask_password(m) > 0) + return false; + + if (type == STATUS_TYPE_NOTICE && m->show_status != SHOW_STATUS_NO) + return true; + + return manager_get_show_status_on(m); +} + void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) { va_list ap; /* If m is NULL, assume we're after shutdown and let the messages through. */ - if (m && !manager_get_show_status(m, type)) + if (m && !manager_should_show_status(m, type)) return; /* XXX We should totally drop the check for ephemeral here diff --git a/src/core/manager.h b/src/core/manager.h index a29d976eae..2cd0dacdb0 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -335,6 +335,7 @@ struct Manager { uint8_t return_value; ShowStatus show_status; + ShowStatus show_status_overridden; StatusUnitFormat status_unit_format; char *confirm_spawn; bool no_console_output; @@ -512,7 +513,10 @@ void disable_printk_ratelimit(void); void manager_recheck_dbus(Manager *m); void manager_recheck_journal(Manager *m); +bool manager_get_show_status_on(Manager *m); void manager_set_show_status(Manager *m, ShowStatus mode, const char *reason); +void manager_override_show_status(Manager *m, ShowStatus mode, const char *reason); + void manager_set_first_boot(Manager *m, bool b); void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) _printf_(4,5); @@ -553,7 +557,7 @@ ManagerTimestamp manager_timestamp_initrd_mangle(ManagerTimestamp s); usec_t manager_get_watchdog(Manager *m, WatchdogType t); void manager_set_watchdog(Manager *m, WatchdogType t, usec_t timeout); -int manager_set_watchdog_overridden(Manager *m, WatchdogType t, usec_t timeout); +int manager_override_watchdog(Manager *m, WatchdogType t, usec_t timeout); const char* oom_policy_to_string(OOMPolicy i) _const_; OOMPolicy oom_policy_from_string(const char *s) _pure_; diff --git a/src/core/namespace.c b/src/core/namespace.c index 6bfc266dc0..423a47c7b8 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -1257,16 +1257,20 @@ int setup_namespace( ProtectHome protect_home, ProtectSystem protect_system, 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, char **error_path) { _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL; _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_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; MountEntry *m = NULL, *mounts = NULL; - size_t n_mounts, root_hash_size = 0; + size_t n_mounts; bool require_prefix = false; const char *root; int r = 0; @@ -1295,16 +1299,16 @@ int setup_namespace( if (r < 0) 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) 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) 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) return log_debug_errno(r, "Failed to decrypt dissected image: %m"); } diff --git a/src/core/namespace.h b/src/core/namespace.h index ef6c9bdc9b..a687be5bfd 100644 --- a/src/core/namespace.h +++ b/src/core/namespace.h @@ -88,6 +88,10 @@ int setup_namespace( ProtectHome protect_home, ProtectSystem protect_system, 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, char **error_path); diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf index 415b3f5d84..9a5912c10f 100644 --- a/src/core/org.freedesktop.systemd1.conf +++ b/src/core/org.freedesktop.systemd1.conf @@ -318,6 +318,10 @@ send_interface="org.freedesktop.systemd1.Manager" send_member="AddDependencyUnitFiles"/> + <allow send_destination="org.freedesktop.systemd1" + send_interface="org.freedesktop.systemd1.Manager" + send_member="SetShowStatus"/> + <!-- Managed via polkit or other criteria: org.freedesktop.systemd1.Job interface --> <allow send_destination="org.freedesktop.systemd1" diff --git a/src/core/transaction.c b/src/core/transaction.c index 0fb52372f1..ef6470656c 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -279,7 +279,7 @@ static int transaction_merge_jobs(Transaction *tr, sd_bus_error *e) { return 0; } -static void transaction_drop_redundant(Transaction *tr, unsigned generation) { +static void transaction_drop_redundant(Transaction *tr) { bool again; /* 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) 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))) { keep = true; break; @@ -735,7 +735,7 @@ int transaction_activate( transaction_minimize_impact(tr); /* Third step: Drop redundant jobs */ - transaction_drop_redundant(tr, generation++); + transaction_drop_redundant(tr); for (;;) { /* 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. */ - transaction_drop_redundant(tr, generation++); + transaction_drop_redundant(tr); /* Ninth step: check whether we can actually apply this */ r = transaction_is_destructive(tr, mode, e); diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c index ed4d06e986..eceb7927af 100644 --- a/src/coredump/coredumpctl.c +++ b/src/coredump/coredumpctl.c @@ -1091,9 +1091,7 @@ static int run(int argc, char *argv[]) { int r, units_active; setlocale(LC_ALL, ""); - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); /* The journal merging logic potentially needs a lot of fds. */ (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE); diff --git a/src/delta/delta.c b/src/delta/delta.c index 2d80d3a664..29e5120375 100644 --- a/src/delta/delta.c +++ b/src/delta/delta.c @@ -643,9 +643,7 @@ static int parse_argv(int argc, char *argv[]) { static int run(int argc, char *argv[]) { int r, k, n_found = 0; - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/detect-virt/detect-virt.c b/src/detect-virt/detect-virt.c index 7fb80ca138..4f38de8e29 100644 --- a/src/detect-virt/detect-virt.c +++ b/src/detect-virt/detect-virt.c @@ -128,9 +128,7 @@ static int run(int argc, char *argv[]) { * to detect whether we are being run in a virtualized * environment or not */ - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c index 9ae632f226..2a8eaca5bd 100644 --- a/src/dissect/dissect.c +++ b/src/dissect/dissect.c @@ -201,7 +201,7 @@ static int run(int argc, char *argv[]) { if (r < 0) 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); if (r < 0) return log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image); diff --git a/src/escape/escape.c b/src/escape/escape.c index 9066c30853..0c543a90f6 100644 --- a/src/escape/escape.c +++ b/src/escape/escape.c @@ -159,9 +159,7 @@ static int run(int argc, char *argv[]) { char **i; int r; - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/home/homectl.c b/src/home/homectl.c index f7237d22d8..7a473b791b 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -3489,9 +3489,7 @@ static int run(int argc, char *argv[]) { int r; - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c index 5596846ed2..e08ab15acd 100644 --- a/src/hostname/hostnamectl.c +++ b/src/hostname/hostnamectl.c @@ -436,9 +436,7 @@ static int run(int argc, char *argv[]) { int r; setlocale(LC_ALL, ""); - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index e694a95a04..36229f3c9b 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -801,7 +801,10 @@ static int run(int argc, char *argv[]) { return r; umask(0022); - mac_selinux_init(); + + r = mac_selinux_init(); + if (r < 0) + return r; assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0); diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c index 651647b3f0..eb038a8b55 100644 --- a/src/hwdb/hwdb.c +++ b/src/hwdb/hwdb.c @@ -125,7 +125,9 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - mac_selinux_init(); + r = mac_selinux_init(); + if (r < 0) + return r; return hwdb_main(argc, argv); } diff --git a/src/id128/id128.c b/src/id128/id128.c index 19435f80fe..13996573ab 100644 --- a/src/id128/id128.c +++ b/src/id128/id128.c @@ -249,9 +249,7 @@ static int id128_main(int argc, char *argv[]) { static int run(int argc, char *argv[]) { int r; - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c index 948b2d2fce..69a111afea 100644 --- a/src/journal-remote/journal-remote-main.c +++ b/src/journal-remote/journal-remote-main.c @@ -1110,7 +1110,7 @@ static int run(int argc, char **argv) { int r; log_show_color(true); - log_parse_environment(); + log_parse_environment_cli(); /* The journal merging logic potentially needs a lot of fds. */ (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE); diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c index bd58fdbcdf..e169a27eb3 100644 --- a/src/journal-remote/journal-upload.c +++ b/src/journal-remote/journal-upload.c @@ -821,7 +821,7 @@ static int run(int argc, char **argv) { int r; log_show_color(true); - log_parse_environment(); + log_parse_environment_cli(); /* The journal merging logic potentially needs a lot of fds. */ (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE); diff --git a/src/journal/cat.c b/src/journal/cat.c index 500b674505..2faaa2e284 100644 --- a/src/journal/cat.c +++ b/src/journal/cat.c @@ -129,9 +129,7 @@ static int run(int argc, char *argv[]) { _cleanup_close_ int outfd = -1, errfd = -1, saved_stderr = -1; int r; - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 36bd9a0148..8d4897b942 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -2110,9 +2110,7 @@ int main(int argc, char *argv[]) { int n_shown = 0, r, poll_fd = -1; setlocale(LC_ALL, ""); - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); /* Increase max number of open files if we can, we might needs this when browsing journal files, which might be * split up into many files. */ diff --git a/src/libsystemd-network/dhcp-lease-internal.h b/src/libsystemd-network/dhcp-lease-internal.h index aed30d6118..66222eaddb 100644 --- a/src/libsystemd-network/dhcp-lease-internal.h +++ b/src/libsystemd-network/dhcp-lease-internal.h @@ -82,6 +82,3 @@ int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const vo int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease); int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len); - -int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file); -int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file); diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index aa61bc2614..e4c11235b6 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -61,9 +61,13 @@ int deserialize_in6_addrs(struct in6_addr **addresses, const char *string); /* don't include "dhcp-lease-internal.h" as it causes conflicts between netinet/ip.h and linux/ip.h */ struct sd_dhcp_route; +struct sd_dhcp_lease; void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size); int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string); /* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */ int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size); + +int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file); +int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file); diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index 8582302cb4..0bc5fa3210 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -1076,7 +1076,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { "ADDRESS", &address, "ROUTER", &router, "NETMASK", &netmask, - "SERVER_IDENTIFIER", &server_address, + "SERVER_ADDRESS", &server_address, "NEXT_SERVER", &next_server, "BROADCAST", &broadcast, "DNS", &dns, diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index 97b732ae42..55e35cd902 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -451,7 +451,7 @@ int bus_message_from_header( if (!IN_SET(h->version, 1, 2)) return -EBADMSG; - if (h->type <= _SD_BUS_MESSAGE_TYPE_INVALID || h->type >= _SD_BUS_MESSAGE_TYPE_MAX) + if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID) return -EBADMSG; if (!IN_SET(h->endian, BUS_LITTLE_ENDIAN, BUS_BIG_ENDIAN)) @@ -589,7 +589,8 @@ _public_ int sd_bus_message_new( assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state != BUS_UNSET, -ENOTCONN); assert_return(m, -EINVAL); - assert_return(type > _SD_BUS_MESSAGE_TYPE_INVALID && type < _SD_BUS_MESSAGE_TYPE_MAX, -EINVAL); + /* Creation of messages with _SD_BUS_MESSAGE_TYPE_INVALID is allowed. */ + assert_return(type < _SD_BUS_MESSAGE_TYPE_MAX, -EINVAL); sd_bus_message *t = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header)); if (!t) @@ -3021,7 +3022,7 @@ int bus_body_part_map(struct bus_body_part *part) { return 0; } - shift = part->memfd_offset - ((part->memfd_offset / page_size()) * page_size()); + shift = PAGE_OFFSET(part->memfd_offset); psz = PAGE_ALIGN(part->size + shift); if (part->memfd >= 0) @@ -3158,7 +3159,8 @@ static struct bus_body_part* find_part(sd_bus_message *m, size_t index, size_t s return NULL; if (p) - *p = (uint8_t*) part->data + index - begin; + *p = part->data ? (uint8_t*) part->data + index - begin + : NULL; /* Avoid dereferencing a NULL pointer. */ m->cached_rindex_part = part; m->cached_rindex_part_begin = begin; @@ -5497,9 +5499,6 @@ int bus_message_parse_fields(sd_bus_message *m) { if (m->reply_cookie == 0 || !m->error.name) return -EBADMSG; break; - - default: - assert_not_reached("Bad message type"); } /* Refuse non-local messages that claim they are local */ diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index 30f47244ad..ce6ae846c5 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -168,10 +168,6 @@ _public_ int sd_network_link_get_address_state(int ifindex, char **state) { return network_link_get_string(ifindex, "ADDRESS_STATE", state); } -_public_ int sd_network_link_get_dhcp4_client_id_string(int ifindex, char **client_id) { - return network_link_get_string(ifindex, "DHCP4_CLIENT_ID", client_id); -} - _public_ int sd_network_link_get_dhcp6_client_iaid_string(int ifindex, char **iaid) { return network_link_get_string(ifindex, "DHCP6_CLIENT_IAID", iaid); } @@ -236,14 +232,6 @@ _public_ int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char return network_link_get_strv(ifindex, "DNSSEC_NTA", nta); } -_public_ int sd_network_link_get_timezone(int ifindex, char **ret) { - return network_link_get_string(ifindex, "TIMEZONE", ret); -} - -_public_ int sd_network_link_get_dhcp4_address(int ifindex, char **ret) { - return network_link_get_string(ifindex, "DHCP4_ADDRESS", ret); -} - _public_ int sd_network_link_get_dns(int ifindex, char ***ret) { return network_link_get_strv(ifindex, "DNS", ret); } diff --git a/src/locale/localectl.c b/src/locale/localectl.c index b7548a0f7f..96fc09a570 100644 --- a/src/locale/localectl.c +++ b/src/locale/localectl.c @@ -502,9 +502,7 @@ static int run(int argc, char *argv[]) { int r; setlocale(LC_ALL, ""); - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/locale/localed.c b/src/locale/localed.c index 8ffcf306b5..715ce5cac7 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -18,6 +18,7 @@ #include "bus-message.h" #include "bus-polkit.h" #include "def.h" +#include "dlfcn-util.h" #include "keymap-util.h" #include "locale-util.h" #include "macro.h" @@ -530,7 +531,7 @@ static int verify_xkb_rmlvo(const char *model, const char *layout, const char *v }; struct xkb_context *ctx = NULL; struct xkb_keymap *km = NULL; - void *dl; + _cleanup_(dlclosep) void *dl = NULL; int r; /* Compile keymap from RMLVO information to check out its validity */ @@ -582,7 +583,6 @@ finish: if (symbol_xkb_context_unref && ctx) symbol_xkb_context_unref(ctx); - (void) dlclose(dl); return r; } @@ -788,7 +788,10 @@ static int run(int argc, char *argv[]) { return r; umask(0022); - mac_selinux_init(); + + r = mac_selinux_init(); + if (r < 0) + return r; assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0); diff --git a/src/locale/meson.build b/src/locale/meson.build index e87a10ebeb..314b0a3d37 100644 --- a/src/locale/meson.build +++ b/src/locale/meson.build @@ -34,5 +34,5 @@ tests += [ 'src/locale/keymap-util.c', 'src/locale/keymap-util.h'], [libshared], - [libdl]], + []], ] diff --git a/src/login/loginctl.c b/src/login/loginctl.c index 7805863d8d..9216224bfc 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -1460,9 +1460,7 @@ static int run(int argc, char *argv[]) { int r; setlocale(LC_ALL, ""); - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); /* The journal merging logic potentially needs a lot of fds. */ (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE); diff --git a/src/login/logind.c b/src/login/logind.c index dc746a2c9e..377fba25cf 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -1173,7 +1173,7 @@ static int run(int argc, char *argv[]) { r = mac_selinux_init(); if (r < 0) - return log_error_errno(r, "Could not initialize labelling: %m"); + return r; /* Always create the directories people can create inotify watches in. Note that some applications might check * for the existence of /run/systemd/seats/ to determine whether logind is available, so please always make diff --git a/src/login/user-runtime-dir.c b/src/login/user-runtime-dir.c index fdf0124c41..38058d7b2a 100644 --- a/src/login/user-runtime-dir.c +++ b/src/login/user-runtime-dir.c @@ -192,11 +192,11 @@ static int run(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "First argument must be either \"start\" or \"stop\"."); + umask(0022); + r = mac_selinux_init(); if (r < 0) - return log_error_errno(r, "Could not initialize labelling: %m\n"); - - umask(0022); + return r; if (streq(argv[1], "start")) return do_mount(argv[2]); diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index d88b2651d2..d8f4526644 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -2882,9 +2882,7 @@ static int run(int argc, char *argv[]) { int r; setlocale(LC_ALL, ""); - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); /* The journal merging logic potentially needs a lot of fds. */ (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE); diff --git a/src/network/networkctl.c b/src/network/networkctl.c index bf663146d6..8b7cf292fa 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ +#include <arpa/inet.h> #include <getopt.h> #include <linux/if_addrlabel.h> #include <net/if.h> @@ -930,12 +931,13 @@ static int dump_gateways( static int dump_addresses( sd_netlink *rtnl, + sd_dhcp_lease *lease, Table *table, int ifindex) { _cleanup_free_ struct local_address *local = NULL; - _cleanup_free_ char *dhcp4_address = NULL; _cleanup_strv_free_ char **buf = NULL; + struct in_addr dhcp4_address = {}; int r, n, i; assert(rtnl); @@ -945,7 +947,8 @@ static int dump_addresses( if (n <= 0) return n; - (void) sd_network_link_get_dhcp4_address(ifindex, &dhcp4_address); + if (lease) + (void) sd_dhcp_lease_get_address(lease, &dhcp4_address); for (i = 0; i < n; i++) { _cleanup_free_ char *pretty = NULL; @@ -955,13 +958,19 @@ static int dump_addresses( if (r < 0) return r; - if (dhcp4_address && streq(pretty, dhcp4_address)) { - _cleanup_free_ char *p = NULL; + if (local[i].family == AF_INET && in4_addr_equal(&local[i].address.in, &dhcp4_address)) { + struct in_addr server_address; + char *p, s[INET_ADDRSTRLEN]; - p = pretty; - pretty = strjoin(pretty , " (DHCP4)"); - if (!pretty) + r = sd_dhcp_lease_get_server_identifier(lease, &server_address); + if (r >= 0 && inet_ntop(AF_INET, &server_address, s, sizeof(s))) + p = strjoin(pretty, " (DHCP4 via ", s, ")"); + else + p = strjoin(pretty, " (DHCP4)"); + if (!p) return log_oom(); + + free_and_replace(pretty, p); } r = strv_extendf(&buf, "%s%s%s", @@ -1379,12 +1388,12 @@ static int link_status_one( const LinkInfo *info) { _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **sip = NULL, **search_domains = NULL, **route_domains = NULL; - _cleanup_free_ char *t = NULL, *network = NULL, *client_id = NULL, *iaid = NULL, *duid = NULL; - const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL; - _cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL; - const char *on_color_operational, *off_color_operational, - *on_color_setup, *off_color_setup; + _cleanup_free_ char *t = NULL, *network = NULL, *iaid = NULL, *duid = NULL, + *setup_state = NULL, *operational_state = NULL, *lease_file = NULL; + const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL, + *on_color_operational, *off_color_operational, *on_color_setup, *off_color_setup; _cleanup_free_ int *carrier_bound_to = NULL, *carrier_bound_by = NULL; + _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; _cleanup_(table_unrefp) Table *table = NULL; TableCell *cell; int r; @@ -1425,6 +1434,11 @@ static int link_status_one( (void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to); (void) sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by); + if (asprintf(&lease_file, "/run/systemd/netif/leases/%d", info->ifindex) < 0) + return log_oom(); + + (void) dhcp_lease_load(&lease, lease_file); + table = table_new("dot", "key", "value"); if (!table) return log_oom(); @@ -2022,7 +2036,7 @@ static int link_status_one( } } - r = dump_addresses(rtnl, table, info->ifindex); + r = dump_addresses(rtnl, lease, table, info->ifindex); if (r < 0) return r; r = dump_gateways(rtnl, hwdb, table, info->ifindex); @@ -2050,24 +2064,35 @@ static int link_status_one( if (r < 0) return r; - (void) sd_network_link_get_timezone(info->ifindex, &tz); - if (tz) { - r = table_add_many(table, - TABLE_EMPTY, - TABLE_STRING, "Time Zone:", - TABLE_STRING, tz); - if (r < 0) - return table_log_add_error(r); - } + if (lease) { + const void *client_id; + size_t client_id_len; + const char *tz; - r = sd_network_link_get_dhcp4_client_id_string(info->ifindex, &client_id); - if (r >= 0) { - r = table_add_many(table, - TABLE_EMPTY, - TABLE_STRING, "DHCP4 Client ID:", - TABLE_STRING, client_id); - if (r < 0) - return table_log_add_error(r); + r = sd_dhcp_lease_get_timezone(lease, &tz); + if (r >= 0) { + r = table_add_many(table, + TABLE_EMPTY, + TABLE_STRING, "Time Zone:", + TABLE_STRING, tz); + if (r < 0) + return table_log_add_error(r); + } + + r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len); + if (r >= 0) { + _cleanup_free_ char *id = NULL; + + r = sd_dhcp_client_id_to_string(client_id, client_id_len, &id); + if (r >= 0) { + r = table_add_many(table, + TABLE_EMPTY, + TABLE_STRING, "DHCP4 Client ID:", + TABLE_STRING, id); + if (r < 0) + return table_log_add_error(r); + } + } } r = sd_network_link_get_dhcp6_client_iaid_string(info->ifindex, &iaid); @@ -2147,7 +2172,7 @@ static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) { if (r < 0) return table_log_add_error(r); - r = dump_addresses(rtnl, table, 0); + r = dump_addresses(rtnl, NULL, table, 0); if (r < 0) return r; r = dump_gateways(rtnl, hwdb, table, 0); @@ -2793,9 +2818,7 @@ static void warn_networkd_missing(void) { static int run(int argc, char* argv[]) { int r; - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/network/networkd-dhcp-server.c b/src/network/networkd-dhcp-server.c index b3ed4a8cea..6f25c9fc96 100644 --- a/src/network/networkd-dhcp-server.c +++ b/src/network/networkd-dhcp-server.c @@ -116,7 +116,7 @@ static int link_push_uplink_to_dhcp_server( case SD_DHCP_LEASE_LPR: /* For the other server types we currently do not allow local configuration of server data, * since there are typically no local consumers of the data. */ - ; + break; default: assert_not_reached("Unexpected server type"); diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index f0766f0af7..27b74407af 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -1065,7 +1065,7 @@ static int dhcp6_assign_delegated_prefix(Link *link, address->in_addr.in6 = *prefix; if (!in_addr_is_null(AF_INET6, &link->network->dhcp6_delegation_prefix_token)) - memcpy(&address->in_addr.in6.s6_addr + 8, &link->network->dhcp6_delegation_prefix_token.in6.s6_addr + 8, 8); + memcpy(address->in_addr.in6.s6_addr + 8, link->network->dhcp6_delegation_prefix_token.in6.s6_addr + 8, 8); else { r = generate_ipv6_eui_64_address(link, &address->in_addr.in6); if (r < 0) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index c2fb21c736..06a467d15b 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -4347,33 +4347,6 @@ int link_save(Link *link) { print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links); if (link->dhcp_lease) { - struct in_addr address; - const char *tz = NULL; - size_t client_id_len; - const void *client_id; - - assert(link->network); - - r = sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz); - if (r >= 0) - fprintf(f, "TIMEZONE=%s\n", tz); - - r = sd_dhcp_lease_get_address(link->dhcp_lease, &address); - if (r >= 0) { - fputs("DHCP4_ADDRESS=", f); - serialize_in_addrs(f, &address, 1, NULL, NULL); - fputc('\n', f); - } - - r = sd_dhcp_lease_get_client_id(link->dhcp_lease, &client_id, &client_id_len); - if (r >= 0) { - _cleanup_free_ char *id = NULL; - - r = sd_dhcp_client_id_to_string(client_id, client_id_len, &id); - if (r >= 0) - fprintf(f, "DHCP4_CLIENT_ID=%s\n", id); - } - r = dhcp_lease_save(link->dhcp_lease, link->lease_file); if (r < 0) goto fail; diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index eb80c2960b..2fbaf65692 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -619,9 +619,9 @@ int mount_all(const char *dest, #if HAVE_SELINUX { "/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, - 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 }; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index f3a3ee8a17..ae6828f2bf 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -5141,7 +5141,7 @@ static int run(int argc, char *argv[]) { 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); if (r < 0) { log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image); diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c index 6a2d9c885e..5dc5aacdff 100644 --- a/src/nss-systemd/nss-systemd.c +++ b/src/nss-systemd/nss-systemd.c @@ -8,6 +8,7 @@ #include "fd-util.h" #include "group-record-nss.h" #include "macro.h" +#include "nss-systemd.h" #include "nss-util.h" #include "pthread-util.h" #include "signal-util.h" @@ -299,7 +300,7 @@ enum nss_status _nss_systemd_setpwent(int stayopen) { PROTECT_ERRNO; BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); - if (userdb_nss_compat_is_enabled() <= 0) + if (_nss_systemd_is_blocked()) return NSS_STATUS_NOTFOUND; _cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL; @@ -323,7 +324,7 @@ enum nss_status _nss_systemd_setgrent(int stayopen) { PROTECT_ERRNO; BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); - if (userdb_nss_compat_is_enabled() <= 0) + if (_nss_systemd_is_blocked()) return NSS_STATUS_NOTFOUND; _cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL; @@ -353,13 +354,7 @@ enum nss_status _nss_systemd_getpwent_r( assert(result); assert(errnop); - r = userdb_nss_compat_is_enabled(); - if (r < 0) { - UNPROTECT_ERRNO; - *errnop = -r; - return NSS_STATUS_UNAVAIL; - } - if (!r) + if (_nss_systemd_is_blocked()) return NSS_STATUS_NOTFOUND; _cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL; @@ -406,14 +401,8 @@ enum nss_status _nss_systemd_getgrent_r( assert(result); assert(errnop); - r = userdb_nss_compat_is_enabled(); - if (r < 0) { - UNPROTECT_ERRNO; - *errnop = -r; - return NSS_STATUS_UNAVAIL; - } - if (!r) - return NSS_STATUS_UNAVAIL; + if (_nss_systemd_is_blocked()) + return NSS_STATUS_NOTFOUND; _cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL; @@ -459,7 +448,7 @@ enum nss_status _nss_systemd_getgrent_r( } if (getgrent_data.by_membership) { - _cleanup_close_ int lock_fd = -1; + _cleanup_(_nss_systemd_unblockp) bool blocked = false; for (;;) { _cleanup_free_ char *user_name = NULL, *group_name = NULL; @@ -479,13 +468,15 @@ enum nss_status _nss_systemd_getgrent_r( continue; /* We are about to recursively call into NSS, let's make sure we disable recursion into our own code. */ - if (lock_fd < 0) { - lock_fd = userdb_nss_compat_disable(); - if (lock_fd < 0 && lock_fd != -EBUSY) { + if (!blocked) { + r = _nss_systemd_block(true); + if (r < 0) { UNPROTECT_ERRNO; - *errnop = -lock_fd; + *errnop = -r; return NSS_STATUS_UNAVAIL; } + + blocked = true; } r = nss_group_record_by_name(group_name, false, &gr); @@ -549,13 +540,7 @@ enum nss_status _nss_systemd_initgroups_dyn( if (STR_IN_SET(user_name, root_passwd.pw_name, nobody_passwd.pw_name)) return NSS_STATUS_NOTFOUND; - r = userdb_nss_compat_is_enabled(); - if (r < 0) { - UNPROTECT_ERRNO; - *errnop = -r; - return NSS_STATUS_UNAVAIL; - } - if (!r) + if (_nss_systemd_is_blocked()) return NSS_STATUS_NOTFOUND; r = membershipdb_by_user(user_name, nss_glue_userdb_flags(), &iterator); @@ -581,7 +566,7 @@ enum nss_status _nss_systemd_initgroups_dyn( /* The group might be defined via traditional NSS only, hence let's do a full look-up without * disabling NSS. This means we are operating recursively here. */ - r = groupdb_by_name(group_name, nss_glue_userdb_flags() & ~USERDB_AVOID_NSS, &g); + r = groupdb_by_name(group_name, (nss_glue_userdb_flags() & ~USERDB_AVOID_NSS) | USERDB_AVOID_SHADOW, &g); if (r == -ESRCH) continue; if (r < 0) { @@ -627,3 +612,29 @@ enum nss_status _nss_systemd_initgroups_dyn( return any ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND; } + +static thread_local unsigned _blocked = 0; + +_public_ int _nss_systemd_block(bool b) { + + /* This blocks recursively: it's blocked for as many times this function is called with `true` until + * it is called an equal time with `false`. */ + + if (b) { + if (_blocked >= UINT_MAX) + return -EOVERFLOW; + + _blocked++; + } else { + if (_blocked <= 0) + return -EOVERFLOW; + + _blocked--; + } + + return b; /* Return what is passed in, i.e. the new state from the PoV of the caller */ +} + +_public_ bool _nss_systemd_is_blocked(void) { + return _blocked > 0; +} diff --git a/src/nss-systemd/nss-systemd.h b/src/nss-systemd/nss-systemd.h new file mode 100644 index 0000000000..ffa75c12c4 --- /dev/null +++ b/src/nss-systemd/nss-systemd.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include <stdbool.h> + +int _nss_systemd_block(bool b); +bool _nss_systemd_is_blocked(void); + +/* For use with the _cleanup_() macro */ +static inline void _nss_systemd_unblockp(bool *b) { + if (*b) + assert_se(_nss_systemd_block(false) >= 0); +} diff --git a/src/nss-systemd/nss-systemd.sym b/src/nss-systemd/nss-systemd.sym index 77e1fbe93f..f86d7643d1 100644 --- a/src/nss-systemd/nss-systemd.sym +++ b/src/nss-systemd/nss-systemd.sym @@ -20,5 +20,9 @@ global: _nss_systemd_setgrent; _nss_systemd_getgrent_r; _nss_systemd_initgroups_dyn; + + /* These two are not used by glibc, but can be used by apps to explicitly disable nss-systemd for the calling thread. */ + _nss_systemd_block; + _nss_systemd_is_blocked; local: *; }; diff --git a/src/nss-systemd/userdb-glue.c b/src/nss-systemd/userdb-glue.c index da1248a132..8e5b3eba6c 100644 --- a/src/nss-systemd/userdb-glue.c +++ b/src/nss-systemd/userdb-glue.c @@ -3,6 +3,7 @@ #include "env-util.h" #include "fd-util.h" #include "group-record-nss.h" +#include "nss-systemd.h" #include "strv.h" #include "user-record.h" #include "userdb-glue.h" @@ -74,12 +75,7 @@ enum nss_status userdb_getpwnam( assert(pwd); assert(errnop); - r = userdb_nss_compat_is_enabled(); - if (r < 0) { - *errnop = -r; - return NSS_STATUS_UNAVAIL; - } - if (!r) + if (_nss_systemd_is_blocked()) return NSS_STATUS_NOTFOUND; r = userdb_by_name(name, nss_glue_userdb_flags(), &hr); @@ -112,12 +108,7 @@ enum nss_status userdb_getpwuid( assert(pwd); assert(errnop); - r = userdb_nss_compat_is_enabled(); - if (r < 0) { - *errnop = -r; - return NSS_STATUS_UNAVAIL; - } - if (!r) + if (_nss_systemd_is_blocked()) return NSS_STATUS_NOTFOUND; r = userdb_by_uid(uid, nss_glue_userdb_flags(), &hr); @@ -214,12 +205,7 @@ enum nss_status userdb_getgrnam( assert(gr); assert(errnop); - r = userdb_nss_compat_is_enabled(); - if (r < 0) { - *errnop = -r; - return NSS_STATUS_UNAVAIL; - } - if (!r) + if (_nss_systemd_is_blocked()) return NSS_STATUS_NOTFOUND; r = groupdb_by_name(name, nss_glue_userdb_flags(), &g); @@ -235,7 +221,7 @@ enum nss_status userdb_getgrnam( } if (!g) { - _cleanup_close_ int lock_fd = -1; + _cleanup_(_nss_systemd_unblockp) bool blocked = false; if (strv_isempty(members)) return NSS_STATUS_NOTFOUND; @@ -245,11 +231,13 @@ enum nss_status userdb_getgrnam( * acquire it, so that we can extend it (that's because glibc's group merging feature will * merge groups only if both GID and name match and thus we need to have both first). It * sucks behaving recursively likely this, but it's apparently what everybody does. We break - * the recursion for ourselves via the userdb_nss_compat_disable() lock. */ + * the recursion for ourselves via the _nss_systemd_block_nss() lock. */ + + r = _nss_systemd_block(true); + if (r < 0) + return r; - lock_fd = userdb_nss_compat_disable(); - if (lock_fd < 0 && lock_fd != -EBUSY) - return lock_fd; + blocked = true; r = nss_group_record_by_name(name, false, &g); if (r == -ESRCH) @@ -285,12 +273,7 @@ enum nss_status userdb_getgrgid( assert(gr); assert(errnop); - r = userdb_nss_compat_is_enabled(); - if (r < 0) { - *errnop = -r; - return NSS_STATUS_UNAVAIL; - } - if (!r) + if (_nss_systemd_is_blocked()) return NSS_STATUS_NOTFOUND; r = groupdb_by_gid(gid, nss_glue_userdb_flags(), &g); @@ -300,20 +283,21 @@ enum nss_status userdb_getgrgid( } if (!g) { - _cleanup_close_ int lock_fd = -1; + _cleanup_(_nss_systemd_unblockp) bool blocked = false; /* So, quite possibly we have to extend an existing group record with additional members. But * to do this we need to know the group name first. The group didn't exist via non-NSS * queries though, hence let's try to acquire it here recursively via NSS. */ - lock_fd = userdb_nss_compat_disable(); - if (lock_fd < 0 && lock_fd != -EBUSY) - return lock_fd; + r = _nss_systemd_block(true); + if (r < 0) + return r; + + blocked = true; r = nss_group_record_by_gid(gid, false, &g); if (r == -ESRCH) return NSS_STATUS_NOTFOUND; - if (r < 0) { *errnop = -r; return NSS_STATUS_UNAVAIL; diff --git a/src/portable/portablectl.c b/src/portable/portablectl.c index 1bde30e90f..01614b6684 100644 --- a/src/portable/portablectl.c +++ b/src/portable/portablectl.c @@ -1119,9 +1119,7 @@ static int run(int argc, char *argv[]) { int r; - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index 3cadac7639..a80b450bc0 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -3174,9 +3174,7 @@ static int run(int argc, char **argv) { int r; setlocale(LC_ALL, ""); - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); if (streq(program_invocation_short_name, "resolvconf")) r = resolvconf_parse_argv(argc, argv); diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index cf332b8cd5..906158c5ce 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -500,7 +500,7 @@ static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) { } static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) { - DnsQueryCandidate *c; + _cleanup_(dns_query_candidate_freep) DnsQueryCandidate *c = NULL; int r; assert(q); @@ -511,24 +511,21 @@ static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) { return r; /* If this a single-label domain on DNS, we might append a suitable search domain first. */ - if ((q->flags & SD_RESOLVED_NO_SEARCH) == 0 && - dns_scope_name_needs_search_domain(s, dns_question_first_name(q->question_idna))) { - /* OK, we need a search domain now. Let's find one for this scope */ + if (!FLAGS_SET(q->flags, SD_RESOLVED_NO_SEARCH) && + dns_scope_name_wants_search_domain(s, dns_question_first_name(q->question_idna))) { + /* OK, we want a search domain now. Let's find one for this scope */ r = dns_query_candidate_next_search_domain(c); - if (r <= 0) /* if there's no search domain, then we won't add any transaction. */ - goto fail; + if (r < 0) + return r; } r = dns_query_candidate_setup_transactions(c); if (r < 0) - goto fail; + return r; + TAKE_PTR(c); return 0; - -fail: - dns_query_candidate_free(c); - return r; } static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) { diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h index fc7ccf553e..fe8a219557 100644 --- a/src/resolve/resolved-dns-query.h +++ b/src/resolve/resolved-dns-query.h @@ -102,6 +102,8 @@ enum { }; DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c); +DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQueryCandidate*, dns_query_candidate_free); + void dns_query_candidate_notify(DnsQueryCandidate *c); int dns_query_new(Manager *m, DnsQuery **q, DnsQuestion *question_utf8, DnsQuestion *question_idna, int family, uint64_t flags); diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 140cd25586..764ccee0e0 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -619,7 +619,7 @@ DnsScopeMatch dns_scope_good_domain( manager_is_own_hostname(s->manager, domain) <= 0)) /* never resolve the local hostname via LLMNR */ return DNS_SCOPE_YES_BASE + 1; /* Return +1, as we consider ourselves authoritative * for single-label names, i.e. one label. This is - * particular relevant as it means a "." route on some + * particularly relevant as it means a "." route on some * other scope won't pull all traffic away from * us. (If people actually want to pull traffic away * from us they should turn off LLMNR on the @@ -651,20 +651,21 @@ bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key) { if (s->protocol == DNS_PROTOCOL_DNS) { - /* On classic DNS, looking up non-address RRs is always - * fine. (Specifically, we want to permit looking up - * DNSKEY and DS records on the root and top-level - * domains.) */ + /* On classic DNS, looking up non-address RRs is always fine. (Specifically, we want to + * permit looking up DNSKEY and DS records on the root and top-level domains.) */ if (!dns_resource_key_is_address(key)) return true; - /* However, we refuse to look up A and AAAA RRs on the - * root and single-label domains, under the assumption - * that those should be resolved via LLMNR or search - * path only, and should not be leaked onto the - * internet. */ - return !(dns_name_is_single_label(dns_resource_key_name(key)) || - dns_name_is_root(dns_resource_key_name(key))); + /* Unless explicitly overridden, we refuse to look up A and AAAA RRs on the root and + * single-label domains, under the assumption that those should be resolved via LLMNR or + * search path only, and should not be leaked onto the internet. */ + const char* name = dns_resource_key_name(key); + + if (!s->manager->resolve_unicast_single_label && + dns_name_is_single_label(name)) + return false; + + return !dns_name_is_root(name); } /* On mDNS and LLMNR, send A and AAAA queries only on the @@ -1169,7 +1170,7 @@ DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s) { return s->manager->search_domains; } -bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name) { +bool dns_scope_name_wants_search_domain(DnsScope *s, const char *name) { assert(s); if (s->protocol != DNS_PROTOCOL_DNS) diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index 974692be5b..b356b92120 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -99,7 +99,7 @@ void dns_scope_dump(DnsScope *s, FILE *f); DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s); -bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name); +bool dns_scope_name_wants_search_domain(DnsScope *s, const char *name); bool dns_scope_network_good(DnsScope *s); diff --git a/src/resolve/resolved-gperf.gperf b/src/resolve/resolved-gperf.gperf index 4a451ccc4c..553da8d251 100644 --- a/src/resolve/resolved-gperf.gperf +++ b/src/resolve/resolved-gperf.gperf @@ -18,13 +18,14 @@ struct ConfigPerfItem; %struct-type %includes %% -Resolve.DNS, config_parse_dns_servers, DNS_SERVER_SYSTEM, 0 -Resolve.FallbackDNS, config_parse_dns_servers, DNS_SERVER_FALLBACK, 0 -Resolve.Domains, config_parse_search_domains, 0, 0 -Resolve.LLMNR, config_parse_resolve_support, 0, offsetof(Manager, llmnr_support) -Resolve.MulticastDNS, config_parse_resolve_support, 0, offsetof(Manager, mdns_support) -Resolve.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Manager, dnssec_mode) -Resolve.DNSOverTLS, config_parse_dns_over_tls_mode, 0, offsetof(Manager, dns_over_tls_mode) -Resolve.Cache, config_parse_dns_cache_mode, DNS_CACHE_MODE_YES, offsetof(Manager, enable_cache) -Resolve.DNSStubListener, config_parse_dns_stub_listener_mode, 0, offsetof(Manager, dns_stub_listener_mode) -Resolve.ReadEtcHosts, config_parse_bool, 0, offsetof(Manager, read_etc_hosts) +Resolve.DNS, config_parse_dns_servers, DNS_SERVER_SYSTEM, 0 +Resolve.FallbackDNS, config_parse_dns_servers, DNS_SERVER_FALLBACK, 0 +Resolve.Domains, config_parse_search_domains, 0, 0 +Resolve.LLMNR, config_parse_resolve_support, 0, offsetof(Manager, llmnr_support) +Resolve.MulticastDNS, config_parse_resolve_support, 0, offsetof(Manager, mdns_support) +Resolve.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Manager, dnssec_mode) +Resolve.DNSOverTLS, config_parse_dns_over_tls_mode, 0, offsetof(Manager, dns_over_tls_mode) +Resolve.Cache, config_parse_dns_cache_mode, DNS_CACHE_MODE_YES, offsetof(Manager, enable_cache) +Resolve.DNSStubListener, config_parse_dns_stub_listener_mode, 0, offsetof(Manager, dns_stub_listener_mode) +Resolve.ReadEtcHosts, config_parse_bool, 0, offsetof(Manager, read_etc_hosts) +Resolve.ResolveUnicastSingleLabel, config_parse_bool, 0, offsetof(Manager, resolve_unicast_single_label) diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index 6fa5e734bb..59944df746 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -70,9 +70,10 @@ struct Manager { LIST_HEAD(DnsSearchDomain, search_domains); unsigned n_search_domains; - bool need_builtin_fallbacks:1; + bool need_builtin_fallbacks; + bool read_resolv_conf; + bool resolve_unicast_single_label; - bool read_resolv_conf:1; struct stat resolv_conf_stat; DnsTrustAnchor trust_anchor; diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c index 50989a6b0a..566b950a63 100644 --- a/src/resolve/resolved.c +++ b/src/resolve/resolved.c @@ -40,7 +40,7 @@ static int run(int argc, char *argv[]) { r = mac_selinux_init(); if (r < 0) - return log_error_errno(r, "SELinux setup failed: %m"); + return r; /* Drop privileges, but only if we have been started as root. If we are not running as root we assume most * privileges are already dropped and we can't create our directory. */ diff --git a/src/resolve/resolved.conf.in b/src/resolve/resolved.conf.in index 85822e316c..082ad71626 100644 --- a/src/resolve/resolved.conf.in +++ b/src/resolve/resolved.conf.in @@ -22,3 +22,4 @@ #Cache=yes #DNSStubListener=yes #ReadEtcHosts=yes +#ResolveUnicastSingleLabel=no diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 4b1145a6ba..d93d5d6013 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -13,6 +13,7 @@ #include "escape.h" #include "exec-util.h" #include "exit-status.h" +#include "fileio.h" #include "hexdecoct.h" #include "hostname-util.h" #include "in-addr-util.h" @@ -24,6 +25,7 @@ #include "nsflags.h" #include "numa-util.h" #include "parse-util.h" +#include "path-util.h" #include "process-util.h" #include "rlimit-util.h" #include "securebits-util.h" @@ -494,18 +496,16 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons if (r < 0) return bus_log_create_error(r); return 1; - } else if (isempty(eq) && STR_IN_SET(field, "DefaultMemoryLow", - "DefaultMemoryMin", - "MemoryLow", - "MemoryMin")) { - /* We can't use CGROUP_LIMIT_MIN nor CGROUP_LIMIT_MAX to convey the empty assignment - * so marshall specially as a boolean. */ - r = sd_bus_message_append(m, "(sv)", field, "b", 0); - if (r < 0) - return bus_log_create_error(r); - return 1; } else if (isempty(eq)) { - r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX); + uint64_t empty_value = STR_IN_SET(field, + "DefaultMemoryLow", + "DefaultMemoryMin", + "MemoryLow", + "MemoryMin") ? + CGROUP_LIMIT_MIN : + CGROUP_LIMIT_MAX; + + r = sd_bus_message_append(m, "(sv)", field, "t", empty_value); if (r < 0) return bus_log_create_error(r); return 1; @@ -849,6 +849,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con "ProtectHome", "SELinuxContext", "RootImage", + "RootVerity", "RuntimeDirectoryPreserve", "Personality", "KeyringMode", @@ -1415,6 +1416,24 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con 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; } diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 2c8a5d85bf..e576518c6b 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -1421,7 +1421,7 @@ int decrypted_image_relinquish(DecryptedImage *d) { 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_ void *roothash_decoded = NULL; 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; assert(ret_roothash_size); - r = getxattr_malloc(image, "user.verity.roothash", &text, true); - if (r < 0) { - char *fn, *e, *n; - - if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT)) + if (root_hash_path) { + /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */ + r = read_one_line_file(root_hash_path, &text); + if (r < 0) return r; + } else { + r = getxattr_malloc(image, "user.verity.roothash", &text, true); + if (r < 0) { + char *fn, *e, *n; + + if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT)) + return r; - fn = newa(char, strlen(image) + STRLEN(".roothash") + 1); - n = stpcpy(fn, image); - e = endswith(fn, ".raw"); - if (e) - n = e; + fn = newa(char, strlen(image) + STRLEN(".roothash") + 1); + n = stpcpy(fn, image); + e = endswith(fn, ".raw"); + if (e) + n = e; - strcpy(n, ".roothash"); + strcpy(n, ".roothash"); - r = read_one_line_file(fn, &text); - if (r < 0 && r != -ENOENT) - return r; + r = read_one_line_file(fn, &text); + if (r < 0 && r != -ENOENT) + return r; + } } if (text) { diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h index 92d223cfec..6a53b94948 100644 --- a/src/shared/dissect-image.h +++ b/src/shared/dissect-image.h @@ -100,6 +100,6 @@ int decrypted_image_relinquish(DecryptedImage *d); const char* partition_designator_to_string(int i) _const_; 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_has_verity(const DissectedImage *image, unsigned partition_designator); diff --git a/src/shared/userdb.c b/src/shared/userdb.c index cd9873c06e..6fedbd6ebe 100644 --- a/src/shared/userdb.c +++ b/src/shared/userdb.c @@ -3,6 +3,7 @@ #include <sys/auxv.h> #include "dirent-util.h" +#include "dlfcn-util.h" #include "errno-util.h" #include "fd-util.h" #include "group-record-nss.h" @@ -32,8 +33,8 @@ struct UserDBIterator { bool nss_iterating:1; bool synthesize_root:1; bool synthesize_nobody:1; + bool nss_systemd_blocked:1; int error; - int nss_lock; unsigned n_found; sd_event *event; UserRecord *found_user; /* when .what == LOOKUP_USER */ @@ -85,7 +86,9 @@ UserDBIterator* userdb_iterator_free(UserDBIterator *iterator) { } sd_event_unref(iterator->event); - safe_close(iterator->nss_lock); + + if (iterator->nss_systemd_blocked) + assert_se(userdb_block_nss_systemd(false) >= 0); return mfree(iterator); } @@ -102,12 +105,27 @@ static UserDBIterator* userdb_iterator_new(LookupWhat what) { *i = (UserDBIterator) { .what = what, - .nss_lock = -1, }; return i; } +static int userdb_iterator_block_nss_systemd(UserDBIterator *iterator) { + int r; + + assert(iterator); + + if (iterator->nss_systemd_blocked) + return 0; + + r = userdb_block_nss_systemd(true); + if (r < 0) + return r; + + iterator->nss_systemd_blocked = true; + return 1; +} + struct user_group_data { JsonVariant *record; bool incomplete; @@ -600,13 +618,11 @@ int userdb_by_name(const char *name, UserDBFlags flags, UserRecord **ret) { return r; } - if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) { - /* Make sure the NSS lookup doesn't recurse back to us. (EBUSY is fine here, it just means we - * already took the lock from our thread, which is totally OK.) */ - r = userdb_nss_compat_disable(); - if (r >= 0 || r == -EBUSY) { - iterator->nss_lock = r; + if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !iterator->nss_covered) { + /* Make sure the NSS lookup doesn't recurse back to us. */ + r = userdb_iterator_block_nss_systemd(iterator); + if (r >= 0) { /* Client-side NSS fallback */ r = nss_user_record_by_name(name, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret); if (r >= 0) @@ -649,11 +665,9 @@ int userdb_by_uid(uid_t uid, UserDBFlags flags, UserRecord **ret) { return r; } - if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) { - r = userdb_nss_compat_disable(); - if (r >= 0 || r == -EBUSY) { - iterator->nss_lock = r; - + if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !iterator->nss_covered) { + r = userdb_iterator_block_nss_systemd(iterator); + if (r >= 0) { /* Client-side NSS fallback */ r = nss_user_record_by_uid(uid, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret); if (r >= 0) @@ -687,9 +701,9 @@ int userdb_all(UserDBFlags flags, UserDBIterator **ret) { r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetUserRecord", true, NULL, flags); if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && (r < 0 || !iterator->nss_covered)) { - iterator->nss_lock = userdb_nss_compat_disable(); - if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY) - return iterator->nss_lock; + r = userdb_iterator_block_nss_systemd(iterator); + if (r < 0) + return r; setpwent(); iterator->nss_iterating = true; @@ -809,10 +823,8 @@ int groupdb_by_name(const char *name, UserDBFlags flags, GroupRecord **ret) { } if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) { - r = userdb_nss_compat_disable(); - if (r >= 0 || r == -EBUSY) { - iterator->nss_lock = r; - + r = userdb_iterator_block_nss_systemd(iterator); + if (r >= 0) { r = nss_group_record_by_name(name, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret); if (r >= 0) return r; @@ -855,10 +867,8 @@ int groupdb_by_gid(gid_t gid, UserDBFlags flags, GroupRecord **ret) { } if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) { - r = userdb_nss_compat_disable(); - if (r >= 0 || r == -EBUSY) { - iterator->nss_lock = r; - + r = userdb_iterator_block_nss_systemd(iterator); + if (r >= 0) { r = nss_group_record_by_gid(gid, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret); if (r >= 0) return r; @@ -891,9 +901,9 @@ int groupdb_all(UserDBFlags flags, UserDBIterator **ret) { r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetGroupRecord", true, NULL, flags); if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && (r < 0 || !iterator->nss_covered)) { - iterator->nss_lock = userdb_nss_compat_disable(); - if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY) - return iterator->nss_lock; + r = userdb_iterator_block_nss_systemd(iterator); + if (r < 0) + return r; setgrent(); iterator->nss_iterating = true; @@ -992,9 +1002,9 @@ int membershipdb_by_user(const char *name, UserDBFlags flags, UserDBIterator **r if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS)) goto finish; - iterator->nss_lock = userdb_nss_compat_disable(); - if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY) - return iterator->nss_lock; + r = userdb_iterator_block_nss_systemd(iterator); + if (r < 0) + return r; iterator->filter_user_name = strdup(name); if (!iterator->filter_user_name) @@ -1035,9 +1045,9 @@ int membershipdb_by_group(const char *name, UserDBFlags flags, UserDBIterator ** if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS)) goto finish; - iterator->nss_lock = userdb_nss_compat_disable(); - if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY) - return iterator->nss_lock; + r = userdb_iterator_block_nss_systemd(iterator); + if (r < 0) + return r; /* We ignore all errors here, since the group might be defined by a userdb native service, and we queried them already above. */ (void) nss_group_record_by_name(name, false, &gr); @@ -1076,9 +1086,9 @@ int membershipdb_all(UserDBFlags flags, UserDBIterator **ret) { if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS)) goto finish; - iterator->nss_lock = userdb_nss_compat_disable(); - if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY) - return iterator->nss_lock; + r = userdb_iterator_block_nss_systemd(iterator); + if (r < 0) + return r; setgrent(); iterator->nss_iterating = true; @@ -1215,115 +1225,24 @@ int membershipdb_by_group_strv(const char *name, UserDBFlags flags, char ***ret) return 0; } -static int userdb_thread_sockaddr(struct sockaddr_un *ret_sa, socklen_t *ret_salen) { - static const uint8_t - k1[16] = { 0x35, 0xc1, 0x1f, 0x41, 0x59, 0xc6, 0xa0, 0xf9, 0x33, 0x4b, 0x17, 0x3d, 0xb9, 0xf6, 0x14, 0xd9 }, - k2[16] = { 0x6a, 0x11, 0x4c, 0x37, 0xe5, 0xa3, 0x8c, 0xa6, 0x93, 0x55, 0x64, 0x8c, 0x93, 0xee, 0xa1, 0x7b }; - - struct siphash sh; - uint64_t x, y; - pid_t tid; - void *p; - - assert(ret_sa); - assert(ret_salen); - - /* This calculates an AF_UNIX socket address in the abstract namespace whose existence works as an - * indicator whether to emulate NSS records for complex user records that are also available via the - * varlink protocol. The name of the socket is picked in a way so that: - * - * → it is per-thread (by hashing from the TID) - * - * → is not guessable for foreign processes (by hashing from the — hopefully secret — AT_RANDOM - * value every process gets passed from the kernel - * - * By using a socket the NSS emulation can be nicely turned off for limited amounts of time only, - * simply controlled by the lifetime of the fd itself. By using an AF_UNIX socket in the abstract - * namespace the lock is automatically cleaned up when the process dies abnormally. - * - */ - - p = ULONG_TO_PTR(getauxval(AT_RANDOM)); - if (!p) - return -EIO; - - tid = gettid(); - - siphash24_init(&sh, k1); - siphash24_compress(p, 16, &sh); - siphash24_compress(&tid, sizeof(tid), &sh); - x = siphash24_finalize(&sh); - - siphash24_init(&sh, k2); - siphash24_compress(p, 16, &sh); - siphash24_compress(&tid, sizeof(tid), &sh); - y = siphash24_finalize(&sh); - - *ret_sa = (struct sockaddr_un) { - .sun_family = AF_UNIX, - }; - - sprintf(ret_sa->sun_path + 1, "userdb-%016" PRIx64 "%016" PRIx64, x, y); - *ret_salen = offsetof(struct sockaddr_un, sun_path) + 1 + 7 + 32; - - return 0; -} - -int userdb_nss_compat_is_enabled(void) { - _cleanup_close_ int fd = -1; - union sockaddr_union sa; - socklen_t salen; - int r; - - /* Tests whether the NSS compatibility logic is currently turned on for the invoking thread. Returns - * true if NSS compatibility is turned on, i.e. whether NSS records shall be synthesized from complex - * user records. */ - - r = userdb_thread_sockaddr(&sa.un, &salen); - if (r < 0) - return r; - - fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); - if (fd < 0) - return -errno; +int userdb_block_nss_systemd(int b) { + _cleanup_(dlclosep) void *dl = NULL; + int (*call)(bool b); - /* Try to connect(). This doesn't do anything really, except that it checks whether the socket - * address is bound at all. */ - if (connect(fd, &sa.sa, salen) < 0) { - if (errno == ECONNREFUSED) /* the socket is not bound, hence NSS emulation shall be done */ - return true; + /* Note that we might be called from libnss_systemd.so.2 itself, but that should be fine, really. */ - return -errno; + dl = dlopen(ROOTLIBDIR "libnss_systemd.so.2", RTLD_LAZY|RTLD_NODELETE); + if (!dl) { + /* If the file isn't installed, don't complain loudly */ + log_debug("Failed to dlopen(libnss_systemd.so.2), ignoring: %s", dlerror()); + return 0; } - return false; -} - -int userdb_nss_compat_disable(void) { - _cleanup_close_ int fd = -1; - union sockaddr_union sa; - socklen_t salen; - int r; - - /* Turn off the NSS compatibility logic for the invoking thread. By default NSS records are - * synthesized for all complex user records looked up via NSS. If this call is invoked this is - * disabled for the invoking thread, but only for it. A caller that natively supports the varlink - * user record protocol may use that to turn off the compatibility for NSS lookups. */ - - r = userdb_thread_sockaddr(&sa.un, &salen); - if (r < 0) - return r; - - fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); - if (fd < 0) - return -errno; - - if (bind(fd, &sa.sa, salen) < 0) { - if (errno == EADDRINUSE) /* lock already taken, convert this into a recognizable error */ - return -EBUSY; - - return -errno; - } + call = (int (*)(bool b)) dlsym(dl, "_nss_systemd_block"); + if (!call) + /* If the file is is installed but lacks the symbol we expect, things are weird, let's complain */ + return log_debug_errno(SYNTHETIC_ERRNO(ELIBBAD), + "Unable to find symbol _nss_systemd_block in libnss_systemd.so.2: %s", dlerror()); - return TAKE_FD(fd); + return call(b); } diff --git a/src/shared/userdb.h b/src/shared/userdb.h index 8af31aa86c..2464f54c3e 100644 --- a/src/shared/userdb.h +++ b/src/shared/userdb.h @@ -38,5 +38,4 @@ int membershipdb_all(UserDBFlags flags, UserDBIterator **ret); int membershipdb_iterator_get(UserDBIterator *iterator, char **user, char **group); int membershipdb_by_group_strv(const char *name, UserDBFlags flags, char ***ret); -int userdb_nss_compat_is_enabled(void); -int userdb_nss_compat_disable(void); +int userdb_block_nss_systemd(int b); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index ad7400bacc..681992b7e5 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -9207,7 +9207,7 @@ static int run(int argc, char *argv[]) { int r; setlocale(LC_ALL, ""); - log_parse_environment(); + log_parse_environment_cli(); log_open(); /* The journal merging logic potentially needs a lot of fds. */ diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h index edb40850b1..42bcd74b74 100644 --- a/src/systemd/sd-network.h +++ b/src/systemd/sd-network.h @@ -110,10 +110,6 @@ int sd_network_link_get_network_file(int ifindex, char **filename); * IP addresses */ int sd_network_link_get_dns(int ifindex, char ***ret); -/* Get DHCP4 address for a given link. This is string representations of - * IPv4 address */ -int sd_network_link_get_dhcp4_address(int ifindex, char **ret); - /* Get NTP entries for a given link. These are domain names or string * representations of IP addresses */ int sd_network_link_get_ntp(int ifindex, char ***ret); @@ -173,12 +169,6 @@ int sd_network_link_get_carrier_bound_to(int ifindex, int **ifindexes); /* Get the CARRIERS that are bound to current link. */ int sd_network_link_get_carrier_bound_by(int ifindex, int **ifindexes); -/* Get the timezone that was learnt on a specific link. */ -int sd_network_link_get_timezone(int ifindex, char **timezone); - -/* Get DHCPv4 client id for a given link. */ -int sd_network_link_get_dhcp4_client_id_string(int ifindex, char **client_id); - /* Get DHCPv6 client IAID for a given link. */ int sd_network_link_get_dhcp6_client_iaid_string(int ifindex, char **iaid); diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 6fbd5985d3..b5e7e08eee 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -1898,7 +1898,7 @@ static int run(int argc, char *argv[]) { r = mac_selinux_init(); if (r < 0) - return log_error_errno(r, "SELinux setup failed: %m"); + return r; /* If command line arguments are specified along with --replace, read all * configuration files and insert the positional arguments at the specified diff --git a/src/test/test-chase-symlinks.c b/src/test/test-chase-symlinks.c index 0b7dd8764f..f7b3dd5e00 100644 --- a/src/test/test-chase-symlinks.c +++ b/src/test/test-chase-symlinks.c @@ -84,9 +84,7 @@ static int parse_argv(int argc, char *argv[]) { static int run(int argc, char **argv) { int r; - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c index f2bfc6c62b..d0b4ec2764 100644 --- a/src/test/test-namespace.c +++ b/src/test/test-namespace.c @@ -152,6 +152,10 @@ static void test_protect_kernel_logs(void) { PROTECT_HOME_NO, PROTECT_SYSTEM_NO, 0, + NULL, + 0, + NULL, + NULL, 0, NULL); assert_se(r == 0); diff --git a/src/test/test-ns.c b/src/test/test-ns.c index cf8b08ba9b..ba2c2ed53b 100644 --- a/src/test/test-ns.c +++ b/src/test/test-ns.c @@ -76,6 +76,10 @@ int main(int argc, char *argv[]) { PROTECT_HOME_NO, PROTECT_SYSTEM_NO, 0, + NULL, + 0, + NULL, + NULL, 0, NULL); if (r < 0) { diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c index 3f34a91a7e..285eba802b 100644 --- a/src/timedate/timedatectl.c +++ b/src/timedate/timedatectl.c @@ -1052,9 +1052,7 @@ static int run(int argc, char *argv[]) { int r; setlocale(LC_ALL, ""); - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index da59dd3314..afe593ff64 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -377,7 +377,10 @@ static int context_write_data_local_rtc(Context *c) { } } - mac_selinux_init(); + r = mac_selinux_init(); + if (r < 0) + return r; + return write_string_file_atomic_label("/etc/adjtime", w); } diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 7938cb3d73..7ad6f13b66 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -3258,7 +3258,9 @@ static int run(int argc, char *argv[]) { umask(0022); - mac_selinux_init(); + r = mac_selinux_init(); + if (r < 0) + return r; items = ordered_hashmap_new(&item_array_hash_ops); globs = ordered_hashmap_new(&item_array_hash_ops); diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c index f1115bff7a..e476f88f00 100644 --- a/src/udev/udevadm.c +++ b/src/udev/udevadm.c @@ -124,7 +124,10 @@ static int run(int argc, char *argv[]) { log_set_max_level_realm(LOG_REALM_SYSTEMD, log_get_max_level()); - mac_selinux_init(); + r = mac_selinux_init(); + if (r < 0) + return r; + return udevadm_main(argc, argv); } diff --git a/src/udev/udevd.c b/src/udev/udevd.c index d86c1484c3..8db19e4f89 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -1863,7 +1863,7 @@ int run_udevd(int argc, char *argv[]) { r = mac_selinux_init(); if (r < 0) - return log_error_errno(r, "Could not initialize labelling: %m"); + return r; r = mkdir_errno_wrapper("/run/udev", 0755); if (r < 0 && r != -EEXIST) diff --git a/src/update-done/update-done.c b/src/update-done/update-done.c index bbd14165d5..c001802dc9 100644 --- a/src/update-done/update-done.c +++ b/src/update-done/update-done.c @@ -49,10 +49,8 @@ int main(int argc, char *argv[]) { } r = mac_selinux_init(); - if (r < 0) { - log_error_errno(r, "SELinux setup failed: %m"); + if (r < 0) return EXIT_FAILURE; - } r = apply_timestamp("/etc/.updated", &st.st_mtim); q = apply_timestamp("/var/.updated", &st.st_mtim); diff --git a/src/user-sessions/user-sessions.c b/src/user-sessions/user-sessions.c index c241429517..cd92b696c0 100644 --- a/src/user-sessions/user-sessions.c +++ b/src/user-sessions/user-sessions.c @@ -25,7 +25,9 @@ static int run(int argc, char *argv[]) { umask(0022); - mac_selinux_init(); + r = mac_selinux_init(); + if (r < 0) + return r; if (streq(argv[1], "start")) { r = unlink_or_warn("/run/nologin"); diff --git a/src/userdb/userdbctl.c b/src/userdb/userdbctl.c index 4b5eb34ca6..648eacd023 100644 --- a/src/userdb/userdbctl.c +++ b/src/userdb/userdbctl.c @@ -761,9 +761,7 @@ static int run(int argc, char *argv[]) { int r; - log_show_color(true); - log_parse_environment(); - log_open(); + log_setup_cli(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/userdb/userwork.c b/src/userdb/userwork.c index 732063f6c7..d7202099be 100644 --- a/src/userdb/userwork.c +++ b/src/userdb/userwork.c @@ -660,7 +660,6 @@ static int process_connection(VarlinkServer *server, int fd) { static int run(int argc, char *argv[]) { usec_t start_time, listen_idle_usec, last_busy_usec = USEC_INFINITY; _cleanup_(varlink_server_unrefp) VarlinkServer *server = NULL; - _cleanup_close_ int lock = -1; unsigned n_iterations = 0; int m, listen_fd, r; @@ -697,8 +696,8 @@ static int run(int argc, char *argv[]) { return log_error_errno(r, "Failed to parse USERDB_FIXED_WORKER: %m"); listen_idle_usec = r ? USEC_INFINITY : LISTEN_IDLE_USEC; - lock = userdb_nss_compat_disable(); - if (lock < 0) + r = userdb_block_nss_systemd(true); + if (r < 0) return log_error_errno(r, "Failed to disable userdb NSS compatibility: %m"); start_time = now(CLOCK_MONOTONIC); diff --git a/src/xdg-autostart-generator/xdg-autostart-service.c b/src/xdg-autostart-generator/xdg-autostart-service.c index 6d10d7052b..0d33c70401 100644 --- a/src/xdg-autostart-generator/xdg-autostart-service.c +++ b/src/xdg-autostart-generator/xdg-autostart-service.c @@ -496,7 +496,7 @@ int xdg_autostart_service_generate_unit( /* Nothing to do if type is not Application. */ if (!streq_ptr(service->type, "Application")) { - log_info("Not generating service for XDG autostart %s, it is hidden.", service->name); + log_info("Not generating service for XDG autostart %s, only Type=Application is supported.", service->name); return 0; } @@ -527,8 +527,9 @@ int xdg_autostart_service_generate_unit( return 0; } - if (streq_ptr(service->gnome_autostart_phase, "EarlyInitialization")) { - log_info("Not generating service for XDG autostart %s, EarlyInitialization needs to be handled separately.", + if (service->gnome_autostart_phase) { + /* There is no explicit value for the "Application" phase. */ + log_info("Not generating service for XDG autostart %s, startup phases are not supported.", service->name); return 0; } @@ -563,10 +564,7 @@ int xdg_autostart_service_generate_unit( fprintf(f, "Description=%s\n", t); } - /* Only start after the session is ready. - * XXX: GNOME has an autostart order which we may want to support. - * It is not clear how this can be implemented reliably, which - * is why it is skipped for now. */ + /* Only start after the session is ready. */ fprintf(f, "After=graphical-session.target\n"); diff --git a/test/TEST-21-SYSUSERS/test.sh b/test/TEST-21-SYSUSERS/test.sh index 527db85b07..2992beaa0b 100755 --- a/test/TEST-21-SYSUSERS/test.sh +++ b/test/TEST-21-SYSUSERS/test.sh @@ -115,9 +115,7 @@ test_run() { echo "*** Running test $f" prepare_testdir ${f%.input} cp $f $TESTDIR/usr/lib/sysusers.d/test.conf - systemd-sysusers --root=$TESTDIR 2> /dev/null - journalctl --sync - journalctl -t systemd-sysusers -o cat | tail -n1 > $TESTDIR/tmp/err + systemd-sysusers --root=$TESTDIR 2>&1 | tail -n1 > $TESTDIR/tmp/err if ! diff -u $TESTDIR/tmp/err ${f%.*}.expected-err; then echo "**** Unexpected error output for $f" cat $TESTDIR/tmp/err diff --git a/test/TEST-52-HONORFIRSTSHUTDOWN/Makefile b/test/TEST-52-HONORFIRSTSHUTDOWN/Makefile new file mode 100644 index 0000000000..a48af97793 --- /dev/null +++ b/test/TEST-52-HONORFIRSTSHUTDOWN/Makefile @@ -0,0 +1,16 @@ +BUILD_DIR=$(shell ../../tools/find-build-dir.sh) + +all setup run clean clean-again: + @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@ + +# finish option is used to run checks that can only be run outside of +# the test execution. Example case, honor first shutdown, proof is obtained +# from the console output as the image shuts down. This does not show up in +# the journal so the output from the do_test is captured in a file in /tmp. +# Without the use of finish the test will still pass because if it fails +# the test will loop and will be terminated via a command timeout. +# This just provides concrete confirmation. +finish: + @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./fini.sh --$@ + +.PHONY: all setup run clean clean-again diff --git a/test/TEST-52-HONORFIRSTSHUTDOWN/fini.sh b/test/TEST-52-HONORFIRSTSHUTDOWN/fini.sh new file mode 100755 index 0000000000..993ada020e --- /dev/null +++ b/test/TEST-52-HONORFIRSTSHUTDOWN/fini.sh @@ -0,0 +1,10 @@ +#!/bin/bash +TEST_DESCRIPTION="test honor first shutdown" + +if grep -q "Shutdown is already active. Skipping emergency action request" /tmp/honorfirstshutdown.log; then + echo "$TEST_DESCRIPTION [pass]" + exit 0 +else + echo "$TEST_DESCRIPTION [fail]" + exit 1 +fi diff --git a/test/TEST-52-HONORFIRSTSHUTDOWN/test.sh b/test/TEST-52-HONORFIRSTSHUTDOWN/test.sh new file mode 100755 index 0000000000..a0848ef672 --- /dev/null +++ b/test/TEST-52-HONORFIRSTSHUTDOWN/test.sh @@ -0,0 +1,19 @@ +#!/bin/bash +set -e +. $TEST_BASE_DIR/test-functions +TEST_REQUIRE_INSTALL_TESTS=0 +TEST_DESCRIPTION="testing honor first shutdown" +#INTERACTIVE_DEBUG=1 +TEST_NO_QEMU=1 + +#Using timeout because if the test fails it can loop. +# The reason is because the poweroff executed by end.service +# could turn into a reboot if the test fails. +NSPAWN_TIMEOUT=20 + +#Remove this file if it exists. this is used along with +# the make target "finish". Since concrete confirmaion is +# only found from the console during the poweroff. +rm -f /tmp/honorfirstshutdown.log >/dev/null + +do_test "$@" 52 > /tmp/honorfirstshutdown.log diff --git a/test/fuzz/fuzz-bus-message/zero-offset-to-null-pointer b/test/fuzz/fuzz-bus-message/zero-offset-to-null-pointer Binary files differnew file mode 100644 index 0000000000..c1380441ed --- /dev/null +++ b/test/fuzz/fuzz-bus-message/zero-offset-to-null-pointer diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service index 7435d7abec..492d2a033b 100644 --- a/test/fuzz/fuzz-unit-file/directives.service +++ b/test/fuzz/fuzz-unit-file/directives.service @@ -196,6 +196,8 @@ ReusePort= RootDirectory= RootDirectoryStartOnly= RootImage= +RootHash= +RootVerity= RuntimeMaxSec= SELinuxContextFromNet= SecureBits= diff --git a/test/meson.build b/test/meson.build index 404b923467..8bda38a2e2 100644 --- a/test/meson.build +++ b/test/meson.build @@ -28,6 +28,8 @@ install_subdir('testsuite-28.units', install_dir : testdata_dir) install_subdir('testsuite-30.units', install_dir : testdata_dir) +install_subdir('testsuite-52.units', + install_dir : testdata_dir) testsuite08_dir = testdata_dir + '/testsuite-08.units' install_data('testsuite-08.units/-.mount', diff --git a/test/test-functions b/test/test-functions index df87261ea2..f7f604aec3 100644 --- a/test/test-functions +++ b/test/test-functions @@ -935,7 +935,7 @@ install_config_files() { inst /etc/login.defs inst /etc/group inst /etc/shells - inst /etc/nsswitch.conf + inst_any /etc/nsswitch.conf /usr/etc/nsswitch.conf inst /etc/pam.conf || : inst /etc/os-release inst /etc/localtime diff --git a/test/testsuite-52.units/testsuite-52.service b/test/testsuite-52.units/testsuite-52.service new file mode 100755 index 0000000000..93f847f044 --- /dev/null +++ b/test/testsuite-52.units/testsuite-52.service @@ -0,0 +1,6 @@ +[Unit] +Description=Testsuite service + +[Service] +ExecStart=/usr/lib/systemd/tests/testdata/%N.units/%N.sh +Type=oneshot diff --git a/test/testsuite-52.units/testsuite-52.sh b/test/testsuite-52.units/testsuite-52.sh new file mode 100755 index 0000000000..9cccf1b6c1 --- /dev/null +++ b/test/testsuite-52.units/testsuite-52.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -ex +set -o pipefail + +if ! test -x /usr/lib/systemd/tests/testdata/units/test-honor-first-shutdown.sh ; then + echo "honor-first-shutdown script not found - FAIL" > /testok + exit 0 +fi + +systemd-analyze log-level debug +systemd-analyze log-target console + +systemctl enable test-honor-first-shutdown.service +systemctl start test-honor-first-shutdown.service + +echo OK > /testok + +exit 0 diff --git a/test/units/test-honor-first-shutdown.service b/test/units/test-honor-first-shutdown.service new file mode 100644 index 0000000000..374f1e6b5f --- /dev/null +++ b/test/units/test-honor-first-shutdown.service @@ -0,0 +1,11 @@ +[Unit] +Description=Honor First Shutdown feature +After=multi-user.target + +[Service] +ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh +ExecStop=sh -c 'kill -SIGKILL $MAINPID' +FailureAction=reboot + +[Install] +WantedBy=multi-user.target
\ No newline at end of file diff --git a/test/units/test-honor-first-shutdown.sh b/test/units/test-honor-first-shutdown.sh new file mode 100755 index 0000000000..17c1ec9686 --- /dev/null +++ b/test/units/test-honor-first-shutdown.sh @@ -0,0 +1,3 @@ +#!/bin/bash +echo "Honor first shutdown test script" +sleep infinity; diff --git a/tools/make-autosuspend-rules.py b/tools/make-autosuspend-rules.py index 25b261ea0d..e13ca33f6f 100755 --- a/tools/make-autosuspend-rules.py +++ b/tools/make-autosuspend-rules.py @@ -1,14 +1,24 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1+ -# Generate autosuspend rules for devices that have been whitelisted (IE tested) -# by the Chromium OS team. Please keep this script in sync with: +# Generate autosuspend rules for devices that have been tested to work properly +# with autosuspend by the Chromium OS team. Based on # https://chromium.googlesource.com/chromiumos/platform2/+/master/power_manager/udev/gen_autosuspend_rules.py -import sys import chromiumos.gen_autosuspend_rules -if __name__ == '__main__': - if len(sys.argv) > 1: - sys.stdout = open(sys.argv[1], 'w') - chromiumos.gen_autosuspend_rules.main() +print('# pci:v<00VENDOR>d<00DEVICE> (8 uppercase hexadecimal digits twice)') +for entry in chromiumos.gen_autosuspend_rules.PCI_IDS: + vendor, device = entry.split(':') + vendor = int(vendor, 16) + device = int(device, 16) + print('pci:v{:08X}d{:08X}*'.format(vendor, device)) + +print('# usb:v<VEND>p<PROD> (4 uppercase hexadecimal digits twice') +for entry in chromiumos.gen_autosuspend_rules.USB_IDS: + vendor, product = entry.split(':') + vendor = int(vendor, 16) + product = int(product, 16) + print('usb:v{:04X}p{:04X}*'.format(vendor, product)) + +print(' ID_AUTOSUSPEND=1') diff --git a/travis-ci/managers/debian.sh b/travis-ci/managers/debian.sh index 60f6237606..a2a987d8fd 100755 --- a/travis-ci/managers/debian.sh +++ b/travis-ci/managers/debian.sh @@ -9,23 +9,25 @@ # export CONT_NAME="my-fancy-container" # 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}" -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_RUN="${DOCKER_RUN:-docker run}" REPO_ROOT="${REPO_ROOT:-$PWD}" -ADDITIONAL_DEPS=(python3-libevdev - python3-pyparsing - clang - perl - libpwquality-dev - fdisk - libfdisk-dev - libp11-kit-dev - libssl-dev - libzstd-dev - zstd) +ADDITIONAL_DEPS=( + clang + fdisk + libfdisk-dev + libp11-kit-dev + libpwquality-dev + libssl-dev + libzstd-dev + perl + python3-libevdev + python3-pyparsing + zstd +) function info() { 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 install "${ADDITIONAL_DEPS[@]}" ;; - RUN|RUN_CLANG) + RUN|RUN_GCC|RUN_CLANG) if [[ "$phase" = "RUN_CLANG" ]]; then ENV_VARS="-e CC=clang -e CXX=clang++" fi @@ -62,8 +64,8 @@ for phase in "${PHASES[@]}"; do $DOCKER_EXEC ninja -v -C build docker exec -e "TRAVIS=$TRAVIS" -it $CONT_NAME ninja -C build test ;; - RUN_ASAN|RUN_CLANG_ASAN) - if [[ "$phase" = "RUN_CLANG_ASAN" ]]; then + RUN_ASAN_UBSAN|RUN_GCC_ASAN_UBSAN|RUN_CLANG_ASAN_UBSAN) + if [[ "$phase" = "RUN_CLANG_ASAN_UBSAN" ]]; then ENV_VARS="-e CC=clang -e CXX=clang++" # Build fuzzer regression tests only with clang (for now), # see: https://github.com/systemd/systemd/pull/15886#issuecomment-632689604 diff --git a/travis-ci/managers/fedora.sh b/travis-ci/managers/fedora.sh index b3c85ebd09..cc665021d4 100755 --- a/travis-ci/managers/fedora.sh +++ b/travis-ci/managers/fedora.sh @@ -9,38 +9,32 @@ # export CONT_NAME="my-fancy-container" # 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}" -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_RUN="${DOCKER_RUN:-docker run}" REPO_ROOT="${REPO_ROOT:-$PWD}" -ADDITIONAL_DEPS=(dnf-plugins-core - jq iputils - hostname libasan - python3-pyparsing - python3-evdev - libubsan - clang - llvm - perl - libfdisk-devel - libpwquality-devel - openssl-devel - p11-kit-devel) +ADDITIONAL_DEPS=( + clang + dnf-plugins-core + hostname libasan + jq iputils + libfdisk-devel + libpwquality-devel + libubsan + llvm + openssl-devel + p11-kit-devel + perl + python3-evdev + python3-pyparsing +) info() { 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 _retry() { local EC=1 @@ -94,8 +88,8 @@ for phase in "${PHASES[@]}"; do $DOCKER_EXEC ninja -v -C build $DOCKER_EXEC ninja -C build test ;; - RUN_ASAN|RUN_CLANG_ASAN) - if [[ "$phase" = "RUN_CLANG_ASAN" ]]; then + RUN_ASAN|RUN_GCC_ASAN_UBSAN|RUN_CLANG_ASAN_UBSAN) + if [[ "$phase" = "RUN_CLANG_ASAN_UBSAN" ]]; then ENV_VARS="-e CC=clang -e CXX=clang++" MESON_ARGS="-Db_lundef=false" # See https://github.com/mesonbuild/meson/issues/764 fi @@ -110,46 +104,6 @@ for phase in "${PHASES[@]}"; do -t $CONT_NAME \ 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) info "Cleanup phase" docker stop $CONT_NAME |