diff --git a/NEWS b/NEWS index d79f859fa..3c1d90046 100644 --- a/NEWS +++ b/NEWS @@ -3867,6 +3867,9 @@ CHANGES WITH 240: Consult the kernel documentation for details on this sysctl: https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt + + * The v239 change to turn on "net.ipv4.tcp_ecn" by default has been + reverted. * CPUAccounting=yes no longer enables the CPU controller when using kernel 4.15+ and the unified cgroup hierarchy, as required accounting diff --git a/docs/PORTABLE_SERVICES.md b/docs/PORTABLE_SERVICES.md index d9171c7b6..ec4a50373 100644 --- a/docs/PORTABLE_SERVICES.md +++ b/docs/PORTABLE_SERVICES.md @@ -86,7 +86,7 @@ If you have a portable service image, maybe in a raw disk image called `foobar_0.7.23.raw`, then attaching the services to the host is as easy as: ``` -# /usr/lib/systemd/portablectl attach foobar_0.7.23.raw +# portablectl attach foobar_0.7.23.raw ``` This command does the following: @@ -268,7 +268,7 @@ include template units such as `foobar@.service`, so that instantiation is as simple as: ``` -# /usr/lib/systemd/portablectl attach foobar_0.7.23.raw +# portablectl attach foobar_0.7.23.raw # systemctl enable --now foobar@instancea.service # systemctl enable --now foobar@instanceb.service … diff --git a/hwdb.d/60-sensor.hwdb b/hwdb.d/60-sensor.hwdb index f1744b8d7..e06d20421 100644 --- a/hwdb.d/60-sensor.hwdb +++ b/hwdb.d/60-sensor.hwdb @@ -226,8 +226,9 @@ sensor:modalias:acpi:BOSC0200*:dmi:*:svnChuwi*:pnHi13:* # Chuwi HiBook does not have its product name filled, so we # match the entire dmi-alias, assuming that the use of a BOSC0200 + # bios-version + bios-date combo is unique -sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/07/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnHampoo:rnCherryTrailCR:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* -sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/28/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnHampoo:rnCherryTrailCR:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* +# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there +sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/07/2016:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnHampoo:rnCherryTrailCR:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* +sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/28/2016:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnHampoo:rnCherryTrailCR:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1 # Chuwi HiBook Pro (CWI526) @@ -237,7 +238,8 @@ sensor:modalias:acpi:BOSC0200*:dmi:*:svnHampoo*:pnP1D6_C109K:* # Chuwi CoreBook # Chuwi CoreBook does not have its product name filled, so we # match the entire dmi-alias -sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvrY13D_KB133.103:bd06/01/2018:svnHampoo:pnDefaultstring:pvrV100:rvnHampoo:rnY13D_KB133:rvrV100:cvnDefaultstring:ct9:cvrDefaultstring:* +# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there +sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvrY13D_KB133.103:bd06/01/2018:*svnHampoo:pnDefaultstring:pvrV100:rvnHampoo:rnY13D_KB133:rvrV100:cvnDefaultstring:ct9:cvrDefaultstring:* ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1 ######################################### @@ -394,13 +396,14 @@ sensor:modalias:acpi:KIOX000A*:dmi:bvnINSYDECorp.:bvrBYT70A.YNCHENG.WIN.007:*:sv # and no other devices have both board_name *and* product_name set to # "Default string". So combined with the sensor modalias and BIOS date this # should be unique enough to identify the GPDwin -sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd10/25/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* -sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd11/18/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* -sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd12/23/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* -sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd12/26/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* -sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd02/21/2017:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* -sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd03/20/2017:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* -sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/25/2017:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* +# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there +sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd10/25/2016:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* +sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd11/18/2016:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* +sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd12/23/2016:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* +sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd12/26/2016:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* +sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd02/21/2017:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* +sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd03/20/2017:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* +sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/25/2017:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* ACCEL_LOCATION=base ######################################### @@ -674,7 +677,8 @@ sensor:modalias:acpi:BMA250E*:dmi:bvnINSYDECorp.:bvrONDA.W89*:svnInsyde:pnONDATa ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1 # Onda v975w, generic DMI strings, match entire dmi modalias inc. bios-date -sensor:modalias:acpi:SMO8500*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd07/25/2014:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:* +# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there +sensor:modalias:acpi:SMO8500*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd07/25/2014:*svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:* ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1 ######################################### @@ -683,7 +687,8 @@ sensor:modalias:acpi:SMO8500*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd07/25/201 # One-netbook OneMix 2s # OneMix 2s has no product name filled, matching entire dmi-alias -sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.12:bd10/26/2018:br5.12:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnDefaultstring:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* +# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there +sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.12:bd10/26/2018:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnDefaultstring:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1 # One-netbook OneMix 3 Pro @@ -692,7 +697,8 @@ sensor:modalias:acpi:BOSC0200*:dmi:*svnONE-NETBOOKTECHNOLOGYCO*:pnOne-Mix3Pro:* # One-netbook OneMix 3s # OneMix 3s has no product name filled, matching entire dmi-alias -sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.12:bd07/17/2019:br5.12:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnDefaultstring:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* +# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there +sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.12:bd07/17/2019:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnDefaultstring:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:* ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1 ######################################### @@ -724,8 +730,9 @@ sensor:modalias:acpi:BMA250E*:dmi:*:svnShenzhenPLOYER*:pnMOMO7W:* # The Point of View TAB-P800W does not have its product name filled, so we # match the entire dmi-alias, assuming that the use of a BMA250E + # bios-version + bios-date combo is unique -sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr3BAIR1013:bd08/22/2014:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:* -sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr3BAIR1014:bd10/24/2014:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:* +# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there +sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr3BAIR1013:bd08/22/2014:*svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:* +sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr3BAIR1014:bd10/24/2014:*svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:* ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1 # Point of View TAB-P1005W-232 (v2.0) @@ -803,7 +810,8 @@ sensor:modalias:acpi:SMO8500*:dmi:*bd12/19/2014:*:rvnTECLAST:rntPAD:* ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1 # Teclast X98 Plus I (A5C6), generic DMI strings, match entire dmi modalias inc. bios-date -sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.011:bd11/03/2015:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnCherryTrailCR:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:* +# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there +sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.011:bd11/03/2015:*svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnCherryTrailCR:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:* ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1 # Teclast X98 Plus II @@ -815,7 +823,8 @@ sensor:modalias:acpi:KIOX000A*:dmi:*:svnTECLAST:pnX98PlusII:* ######################################### # Thundersoft TST168 tablet, generic DMI strings, match entire dmi modalias inc. bios-date -sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd04/15/2014:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:* +# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there +sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd04/15/2014:*svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:* ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1 ######################################### @@ -883,7 +892,8 @@ sensor:modalias:acpi:SMO8500*:dmi:*:svnUMAX:pnVisionBook10WiPlus:* # The Winpad A15 does not have its product name filled, so we # match the entire dmi-alias, assuming that the use of a SMO8500 + # bios-version + bios-date combo is unique -sensor:modalias:acpi:SMO8500*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd11/20/2014:br5.6:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:* +# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there +sensor:modalias:acpi:SMO8500*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd11/20/2014:*svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:* ACCEL_MOUNT_MATRIX=0, -1, 0; 1, 0, 0; 0, 0, -1 ######################################### diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index c14c5b660..eb5245b62 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -1711,7 +1711,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { readonly s OnFailureJobMode = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b IgnoreOnIsolate = ...; - @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly b NeedDaemonReload = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly as Markers = ['...', ...]; diff --git a/man/path-documents.c b/man/path-documents.c index a6c1f9371..082d6c29f 100644 --- a/man/path-documents.c +++ b/man/path-documents.c @@ -1,9 +1,17 @@ #include +#include #include int main(void) { + int r; char *t; - sd_path_lookup(SD_PATH_USER_DOCUMENTS, NULL, &t); + r = sd_path_lookup(SD_PATH_USER_DOCUMENTS, NULL, &t); + if (r < 0) + return EXIT_FAILURE; + printf("~/Documents: %s\n", t); + free(t); + + return EXIT_SUCCESS; } diff --git a/man/timedatectl.xml b/man/timedatectl.xml index ce1415237..974431f53 100644 --- a/man/timedatectl.xml +++ b/man/timedatectl.xml @@ -126,8 +126,9 @@ Takes a boolean argument. Controls whether network time synchronization is active and enabled (if available). If the argument is true, this enables and starts the first existing network synchronization service. If the argument is false, then this disables and stops the known network - synchronization services. The way that the list of services is built is described below. - + synchronization services. The way that the list of services is built is described in + systemd-timedated.service8. + diff --git a/meson.build b/meson.build index 738879eb2..b5a51b6d0 100644 --- a/meson.build +++ b/meson.build @@ -35,7 +35,7 @@ conf.set10('BUILD_MODE_DEVELOPER', get_option('mode') == 'developer', want_ossfuzz = get_option('oss-fuzz') want_libfuzzer = get_option('llvm-fuzz') -if want_ossfuzz + want_libfuzzer > 1 +if want_ossfuzz and want_libfuzzer error('only one of oss-fuzz or llvm-fuzz can be specified') endif @@ -2495,14 +2495,16 @@ if conf.get('ENABLE_LOCALED') == 1 if conf.get('HAVE_XKBCOMMON') == 1 # logind will load libxkbcommon.so dynamically on its own deps = [libdl] + extra_includes = [libxkbcommon.get_pkgconfig_variable('includedir')] else deps = [] + extra_includes = [] endif executable( 'systemd-localed', systemd_localed_sources, - include_directories : includes, + include_directories : includes + extra_includes, link_with : [libshared], dependencies : deps, install_rpath : rootlibexecdir, diff --git a/meson_options.txt b/meson_options.txt index 163c8df87..2f0f4e7b8 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -197,7 +197,7 @@ option('default-hierarchy', type : 'combo', choices : ['legacy', 'hybrid', 'unified'], value : 'unified', description : 'default cgroup hierarchy') option('default-net-naming-scheme', type : 'combo', - choices : ['latest', 'v238', 'v239', 'v240'], + choices : ['latest', 'v238', 'v239', 'v240', 'v241', 'v243', 'v245', 'v247', 'v249'], description : 'default net.naming-scheme= value') option('status-unit-format-default', type : 'combo', choices : ['description', 'name', 'combined'], diff --git a/src/basic/env-util.c b/src/basic/env-util.c index 81b1e3f10..1ca445dab 100644 --- a/src/basic/env-util.c +++ b/src/basic/env-util.c @@ -577,6 +577,7 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) { word = e+1; state = WORD; + nest--; } else if (*e == ':') { if (flags & REPLACE_ENV_ALLOW_EXTENDED) { len = e - word - 2; diff --git a/src/basic/ether-addr-util.c b/src/basic/ether-addr-util.c index e660ac2c6..dc5b5b833 100644 --- a/src/basic/ether-addr-util.c +++ b/src/basic/ether-addr-util.c @@ -7,6 +7,7 @@ #include #include "ether-addr-util.h" +#include "hexdecoct.h" #include "macro.h" #include "string-util.h" @@ -15,12 +16,13 @@ char* hw_addr_to_string(const struct hw_addr_data *addr, char buffer[HW_ADDR_TO_ assert(buffer); assert(addr->length <= HW_ADDR_MAX_SIZE); - for (size_t i = 0; i < addr->length; i++) { - sprintf(&buffer[3*i], "%02"PRIx8, addr->bytes[i]); - if (i < addr->length - 1) - buffer[3*i + 2] = ':'; + for (size_t i = 0, j = 0; i < addr->length; i++) { + buffer[j++] = hexchar(addr->bytes[i] >> 4); + buffer[j++] = hexchar(addr->bytes[i] & 0x0f); + buffer[j++] = ':'; } + buffer[addr->length > 0 ? addr->length * 3 - 1 : 0] = '\0'; return buffer; } diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 99a44fdea..6c8ebe63e 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -30,14 +30,16 @@ /* The maximum size of the file we'll read in one go in read_full_file() (64M). */ #define READ_FULL_BYTES_MAX (64U*1024U*1024U - 1U) -/* The maximum size of virtual files we'll read in one go in read_virtual_file() (4M). Note that this limit - * is different (and much lower) than the READ_FULL_BYTES_MAX limit. This reflects the fact that we use - * different strategies for reading virtual and regular files: virtual files are generally size constrained: - * there we allocate the full buffer size in advance. Regular files OTOH can be much larger, and here we grow - * the allocations exponentially in a loop. In glibc large allocations are immediately backed by mmap() - * making them relatively slow (measurably so). Thus, when allocating the full buffer in advance the large - * limit is a problem. When allocating piecemeal it's not. Hence pick two distinct limits. */ -#define READ_VIRTUAL_BYTES_MAX (4U*1024U*1024U - 1U) +/* The maximum size of virtual files (i.e. procfs, sysfs, and other virtual "API" files) we'll read in one go + * in read_virtual_file(). Note that this limit is different (and much lower) than the READ_FULL_BYTES_MAX + * limit. This reflects the fact that we use different strategies for reading virtual and regular files: + * virtual files we generally have to read in a single read() syscall since the kernel doesn't support + * continuation read()s for them. Thankfully they are somewhat size constrained. Thus we can allocate the + * full potential buffer in advance. Regular files OTOH can be much larger, and there we grow the allocations + * exponentially in a loop. We use a size limit of 4M-2 because 4M-1 is the maximum buffer that /proc/sys/ + * allows us to read() (larger reads will fail with ENOMEM), and we want to read one extra byte so that we + * can detect EOFs. */ +#define READ_VIRTUAL_BYTES_MAX (4U*1024U*1024U - 2U) int fopen_unlocked(const char *path, const char *options, FILE **ret) { assert(ret); @@ -393,7 +395,7 @@ int read_virtual_file(const char *filename, size_t max_size, char **ret_contents * contents* may be returned. (Though the read is still done using one syscall.) Returns 0 on * partial success, 1 if untruncated contents were read. */ - fd = open(filename, O_RDONLY|O_CLOEXEC); + fd = open(filename, O_RDONLY|O_NOCTTY|O_CLOEXEC); if (fd < 0) return -errno; @@ -431,6 +433,11 @@ int read_virtual_file(const char *filename, size_t max_size, char **ret_contents } n_retries--; + } else if (n_retries > 1) { + /* Files in /proc are generally smaller than the page size so let's start with a page size + * buffer from malloc and only use the max buffer on the final try. */ + size = MIN3(page_size() - 1, READ_VIRTUAL_BYTES_MAX, max_size); + n_retries = 1; } else { size = MIN(READ_VIRTUAL_BYTES_MAX, max_size); n_retries = 0; @@ -463,9 +470,14 @@ int read_virtual_file(const char *filename, size_t max_size, char **ret_contents if (n <= size) break; - /* If a maximum size is specified and we already read as much, no need to try again */ - if (max_size != SIZE_MAX && n >= max_size) { - n = max_size; + /* If a maximum size is specified and we already read more we know the file is larger, and + * can handle this as truncation case. Note that if the size of what we read equals the + * maximum size then this doesn't mean truncation, the file might or might not end on that + * byte. We need to rerun the loop in that case, with a larger buffer size, so that we read + * at least one more byte to be able to distinguish EOF from truncation. */ + if (max_size != SIZE_MAX && n > max_size) { + n = size; /* Make sure we never use more than what we sized the buffer for (so that + * we have one free byte in it for the trailing NUL we add below).*/ truncated = true; break; } diff --git a/src/basic/linux/if_arp.h b/src/basic/linux/if_arp.h deleted file mode 100644 index c3cc5a9e5..000000000 --- a/src/basic/linux/if_arp.h +++ /dev/null @@ -1,164 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Global definitions for the ARP (RFC 826) protocol. - * - * Version: @(#)if_arp.h 1.0.1 04/16/93 - * - * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988 - * Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source. - * Ross Biro - * Fred N. van Kempen, - * Florian La Roche, - * Jonathan Layes - * Arnaldo Carvalho de Melo ARPHRD_HWX25 - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _UAPI_LINUX_IF_ARP_H -#define _UAPI_LINUX_IF_ARP_H - -#include - -/* ARP protocol HARDWARE identifiers. */ -#define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */ -#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */ -#define ARPHRD_EETHER 2 /* Experimental Ethernet */ -#define ARPHRD_AX25 3 /* AX.25 Level 2 */ -#define ARPHRD_PRONET 4 /* PROnet token ring */ -#define ARPHRD_CHAOS 5 /* Chaosnet */ -#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */ -#define ARPHRD_ARCNET 7 /* ARCnet */ -#define ARPHRD_APPLETLK 8 /* APPLEtalk */ -#define ARPHRD_DLCI 15 /* Frame Relay DLCI */ -#define ARPHRD_ATM 19 /* ATM */ -#define ARPHRD_METRICOM 23 /* Metricom STRIP (new IANA id) */ -#define ARPHRD_IEEE1394 24 /* IEEE 1394 IPv4 - RFC 2734 */ -#define ARPHRD_EUI64 27 /* EUI-64 */ -#define ARPHRD_INFINIBAND 32 /* InfiniBand */ - -/* Dummy types for non ARP hardware */ -#define ARPHRD_SLIP 256 -#define ARPHRD_CSLIP 257 -#define ARPHRD_SLIP6 258 -#define ARPHRD_CSLIP6 259 -#define ARPHRD_RSRVD 260 /* Notional KISS type */ -#define ARPHRD_ADAPT 264 -#define ARPHRD_ROSE 270 -#define ARPHRD_X25 271 /* CCITT X.25 */ -#define ARPHRD_HWX25 272 /* Boards with X.25 in firmware */ -#define ARPHRD_CAN 280 /* Controller Area Network */ -#define ARPHRD_PPP 512 -#define ARPHRD_CISCO 513 /* Cisco HDLC */ -#define ARPHRD_HDLC ARPHRD_CISCO -#define ARPHRD_LAPB 516 /* LAPB */ -#define ARPHRD_DDCMP 517 /* Digital's DDCMP protocol */ -#define ARPHRD_RAWHDLC 518 /* Raw HDLC */ -#define ARPHRD_RAWIP 519 /* Raw IP */ - -#define ARPHRD_TUNNEL 768 /* IPIP tunnel */ -#define ARPHRD_TUNNEL6 769 /* IP6IP6 tunnel */ -#define ARPHRD_FRAD 770 /* Frame Relay Access Device */ -#define ARPHRD_SKIP 771 /* SKIP vif */ -#define ARPHRD_LOOPBACK 772 /* Loopback device */ -#define ARPHRD_LOCALTLK 773 /* Localtalk device */ -#define ARPHRD_FDDI 774 /* Fiber Distributed Data Interface */ -#define ARPHRD_BIF 775 /* AP1000 BIF */ -#define ARPHRD_SIT 776 /* sit0 device - IPv6-in-IPv4 */ -#define ARPHRD_IPDDP 777 /* IP over DDP tunneller */ -#define ARPHRD_IPGRE 778 /* GRE over IP */ -#define ARPHRD_PIMREG 779 /* PIMSM register interface */ -#define ARPHRD_HIPPI 780 /* High Performance Parallel Interface */ -#define ARPHRD_ASH 781 /* Nexus 64Mbps Ash */ -#define ARPHRD_ECONET 782 /* Acorn Econet */ -#define ARPHRD_IRDA 783 /* Linux-IrDA */ -/* ARP works differently on different FC media .. so */ -#define ARPHRD_FCPP 784 /* Point to point fibrechannel */ -#define ARPHRD_FCAL 785 /* Fibrechannel arbitrated loop */ -#define ARPHRD_FCPL 786 /* Fibrechannel public loop */ -#define ARPHRD_FCFABRIC 787 /* Fibrechannel fabric */ - /* 787->799 reserved for fibrechannel media types */ -#define ARPHRD_IEEE802_TR 800 /* Magic type ident for TR */ -#define ARPHRD_IEEE80211 801 /* IEEE 802.11 */ -#define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */ -#define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */ -#define ARPHRD_IEEE802154 804 -#define ARPHRD_IEEE802154_MONITOR 805 /* IEEE 802.15.4 network monitor */ - -#define ARPHRD_PHONET 820 /* PhoNet media type */ -#define ARPHRD_PHONET_PIPE 821 /* PhoNet pipe header */ -#define ARPHRD_CAIF 822 /* CAIF media type */ -#define ARPHRD_IP6GRE 823 /* GRE over IPv6 */ -#define ARPHRD_NETLINK 824 /* Netlink header */ -#define ARPHRD_6LOWPAN 825 /* IPv6 over LoWPAN */ -#define ARPHRD_VSOCKMON 826 /* Vsock monitor header */ - -#define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */ -#define ARPHRD_NONE 0xFFFE /* zero header length */ - -/* ARP protocol opcodes. */ -#define ARPOP_REQUEST 1 /* ARP request */ -#define ARPOP_REPLY 2 /* ARP reply */ -#define ARPOP_RREQUEST 3 /* RARP request */ -#define ARPOP_RREPLY 4 /* RARP reply */ -#define ARPOP_InREQUEST 8 /* InARP request */ -#define ARPOP_InREPLY 9 /* InARP reply */ -#define ARPOP_NAK 10 /* (ATM)ARP NAK */ - - -/* ARP ioctl request. */ -struct arpreq { - struct sockaddr arp_pa; /* protocol address */ - struct sockaddr arp_ha; /* hardware address */ - int arp_flags; /* flags */ - struct sockaddr arp_netmask; /* netmask (only for proxy arps) */ - char arp_dev[IFNAMSIZ]; -}; - -struct arpreq_old { - struct sockaddr arp_pa; /* protocol address */ - struct sockaddr arp_ha; /* hardware address */ - int arp_flags; /* flags */ - struct sockaddr arp_netmask; /* netmask (only for proxy arps) */ -}; - -/* ARP Flag values. */ -#define ATF_COM 0x02 /* completed entry (ha valid) */ -#define ATF_PERM 0x04 /* permanent entry */ -#define ATF_PUBL 0x08 /* publish entry */ -#define ATF_USETRAILERS 0x10 /* has requested trailers */ -#define ATF_NETMASK 0x20 /* want to use a netmask (only - for proxy entries) */ -#define ATF_DONTPUB 0x40 /* don't answer this addresses */ - -/* - * This structure defines an ethernet arp header. - */ - -struct arphdr { - __be16 ar_hrd; /* format of hardware address */ - __be16 ar_pro; /* format of protocol address */ - unsigned char ar_hln; /* length of hardware address */ - unsigned char ar_pln; /* length of protocol address */ - __be16 ar_op; /* ARP opcode (command) */ - -#if 0 - /* - * Ethernet looks like this : This bit is variable sized however... - */ - unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ - unsigned char ar_sip[4]; /* sender IP address */ - unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ - unsigned char ar_tip[4]; /* target IP address */ -#endif - -}; - - -#endif /* _UAPI_LINUX_IF_ARP_H */ diff --git a/src/basic/meson.build b/src/basic/meson.build index 9b016ce5e..452b965db 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -88,7 +88,6 @@ basic_sources = files(''' linux/hdlc/ioctl.h linux/if.h linux/if_addr.h - linux/if_arp.h linux/if_bonding.h linux/if_bridge.h linux/if_ether.h diff --git a/src/basic/mountpoint-util.c b/src/basic/mountpoint-util.c index 8c836a1b7..e7a5a9955 100644 --- a/src/basic/mountpoint-util.c +++ b/src/basic/mountpoint-util.c @@ -157,6 +157,19 @@ static bool filename_possibly_with_slash_suffix(const char *s) { return filename_is_valid(copied); } +static bool is_name_to_handle_at_fatal_error(int err) { + /* name_to_handle_at() can return "acceptable" errors that are due to the context. For + * example the kernel does not support name_to_handle_at() at all (ENOSYS), or the syscall + * was blocked (EACCES/EPERM; maybe through seccomp, because we are running inside of a + * container), or the mount point is not triggered yet (EOVERFLOW, think nfs4), or some + * general name_to_handle_at() flakiness (EINVAL). However other errors are not supposed to + * happen and therefore are considered fatal ones. */ + + assert(err < 0); + + return !IN_SET(err, -EOPNOTSUPP, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL); +} + int fd_is_mount_point(int fd, const char *filename, int flags) { _cleanup_free_ struct file_handle *h = NULL, *h_parent = NULL; int mount_id = -1, mount_id_parent = -1; @@ -206,39 +219,40 @@ int fd_is_mount_point(int fd, const char *filename, int flags) { return false; /* symlinks are never mount points */ r = name_to_handle_at_loop(fd, filename, &h, &mount_id, flags); - if (IN_SET(r, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL)) - /* This kernel does not support name_to_handle_at() at all (ENOSYS), or the syscall was blocked - * (EACCES/EPERM; maybe through seccomp, because we are running inside of a container?), or the mount - * point is not triggered yet (EOVERFLOW, think nfs4), or some general name_to_handle_at() flakiness - * (EINVAL): fall back to simpler logic. */ - goto fallback_fdinfo; - else if (r == -EOPNOTSUPP) - /* This kernel or file system does not support name_to_handle_at(), hence let's see if the upper fs - * supports it (in which case it is a mount point), otherwise fall back to the traditional stat() - * logic */ + if (r < 0) { + if (is_name_to_handle_at_fatal_error(r)) + return r; + if (r != -EOPNOTSUPP) + goto fallback_fdinfo; + + /* This kernel or file system does not support name_to_handle_at(), hence let's see + * if the upper fs supports it (in which case it is a mount point), otherwise fall + * back to the traditional stat() logic */ nosupp = true; - else if (r < 0) - return r; + } r = name_to_handle_at_loop(fd, "", &h_parent, &mount_id_parent, AT_EMPTY_PATH); - if (r == -EOPNOTSUPP) { - if (nosupp) - /* Neither parent nor child do name_to_handle_at()? We have no choice but to fall back. */ + if (r < 0) { + if (is_name_to_handle_at_fatal_error(r)) + return r; + if (r != -EOPNOTSUPP) + goto fallback_fdinfo; + if (nosupp) + /* Both the parent and the directory can't do name_to_handle_at() */ goto fallback_fdinfo; - else - /* The parent can't do name_to_handle_at() but the directory we are interested in can? If so, - * it must be a mount point. */ - return 1; - } else if (r < 0) - return r; - /* The parent can do name_to_handle_at() but the directory we are interested in can't? If so, it must - * be a mount point. */ + /* The parent can't do name_to_handle_at() but the directory we are + * interested in can? If so, it must be a mount point. */ + return 1; + } + + /* The parent can do name_to_handle_at() but the directory we are interested in can't? If + * so, it must be a mount point. */ if (nosupp) return 1; - /* If the file handle for the directory we are interested in and its parent are identical, we assume - * this is the root directory, which is a mount point. */ + /* If the file handle for the directory we are interested in and its parent are identical, + * we assume this is the root directory, which is a mount point. */ if (h->handle_bytes == h_parent->handle_bytes && h->handle_type == h_parent->handle_type && @@ -338,10 +352,10 @@ int path_get_mnt_id(const char *path, int *ret) { } r = name_to_handle_at_loop(AT_FDCWD, path, NULL, ret, 0); - if (IN_SET(r, -EOPNOTSUPP, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL)) /* kernel/fs don't support this, or seccomp blocks access, or untriggered mount, or name_to_handle_at() is flaky */ - return fd_fdinfo_mnt_id(AT_FDCWD, path, 0, ret); + if (r == 0 || is_name_to_handle_at_fatal_error(r)) + return r; - return r; + return fd_fdinfo_mnt_id(AT_FDCWD, path, 0, ret); } bool fstype_is_network(const char *fstype) { diff --git a/src/basic/path-util.c b/src/basic/path-util.c index e5afb5f5f..13d71ed1b 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -628,7 +628,11 @@ static int check_x_access(const char *path, int *ret_fd) { return r; r = access_fd(fd, X_OK); - if (r < 0) + if (r == -ENOSYS) { + /* /proc is not mounted. Fallback to access(). */ + if (access(path, X_OK) < 0) + return -errno; + } else if (r < 0) return r; if (ret_fd) diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index f92e425fd..09e606614 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -277,6 +277,28 @@ static inline int getsockopt_int(int fd, int level, int optname, int *ret) { int socket_bind_to_ifname(int fd, const char *ifname); int socket_bind_to_ifindex(int fd, int ifindex); +/* Define a 64bit version of timeval/timespec in any case, even on 32bit userspace. */ +struct timeval_large { + uint64_t tvl_sec, tvl_usec; +}; +struct timespec_large { + uint64_t tvl_sec, tvl_nsec; +}; + +/* glibc duplicates timespec/timeval on certain 32bit archs, once in 32bit and once in 64bit. + * See __convert_scm_timestamps() in glibc source code. Hence, we need additional buffer space for them + * to prevent from recvmsg_safe() returning -EXFULL. */ +#define CMSG_SPACE_TIMEVAL \ + ((sizeof(struct timeval) == sizeof(struct timeval_large)) ? \ + CMSG_SPACE(sizeof(struct timeval)) : \ + CMSG_SPACE(sizeof(struct timeval)) + \ + CMSG_SPACE(sizeof(struct timeval_large))) +#define CMSG_SPACE_TIMESPEC \ + ((sizeof(struct timespec) == sizeof(struct timespec_large)) ? \ + CMSG_SPACE(sizeof(struct timespec)) : \ + CMSG_SPACE(sizeof(struct timespec)) + \ + CMSG_SPACE(sizeof(struct timespec_large))) + ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags); int socket_get_family(int fd, int *ret); diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c index 884a0674a..0d58b1c4f 100644 --- a/src/basic/unit-file.c +++ b/src/basic/unit-file.c @@ -284,7 +284,7 @@ int unit_file_build_name_map( continue; } - FOREACH_DIRENT(de, d, log_warning_errno(errno, "Failed to read \"%s\", ignoring: %m", *dir)) { + FOREACH_DIRENT_ALL(de, d, log_warning_errno(errno, "Failed to read \"%s\", ignoring: %m", *dir)) { char *filename; _cleanup_free_ char *_filename_free = NULL, *simplified = NULL; const char *suffix, *dst = NULL; diff --git a/src/basic/virt.c b/src/basic/virt.c index 7e88f09b4..7ed01ba3c 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -235,8 +235,36 @@ static int detect_vm_dmi(void) { /* The DMI vendor tables in /sys/class/dmi/id don't help us distinguish between Amazon EC2 * virtual machines and bare-metal instances, so we need to look at SMBIOS. */ - if (r == VIRTUALIZATION_AMAZON && detect_vm_smbios() == SMBIOS_VM_BIT_UNSET) - return VIRTUALIZATION_NONE; + if (r == VIRTUALIZATION_AMAZON) { + switch (detect_vm_smbios()) { + case SMBIOS_VM_BIT_SET: + return VIRTUALIZATION_AMAZON; + case SMBIOS_VM_BIT_UNSET: + return VIRTUALIZATION_NONE; + case SMBIOS_VM_BIT_UNKNOWN: { + /* The DMI information we are after is only accessible to the root user, + * so we fallback to using the product name which is less restricted + * to distinguish metal systems from virtualized instances */ + _cleanup_free_ char *s = NULL; + + r = read_full_virtual_file("/sys/class/dmi/id/product_name", &s, NULL); + /* In EC2, virtualized is much more common than metal, so if for some reason + * we fail to read the DMI data, assume we are virtualized. */ + if (r < 0) { + log_debug_errno(r, "Can't read /sys/class/dmi/id/product_name," + " assuming virtualized: %m"); + return VIRTUALIZATION_AMAZON; + } + if (endswith(truncate_nl(s), ".metal")) { + log_debug("DMI product name ends with '.metal', assuming no virtualization"); + return VIRTUALIZATION_NONE; + } else + return VIRTUALIZATION_AMAZON; + } + default: + assert_not_reached("Bad virtualization value"); + } + } /* If we haven't identified a VM, but the firmware indicates that there is one, indicate as much. We * have no further information about what it is. */ diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index fa8c60032..bd9681224 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -711,7 +711,7 @@ static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) { for (i = 0; i < n; i++) if (i != options[i]) { *id = i; - return 1; + return 0; } /* use the next one */ diff --git a/src/core/automount.c b/src/core/automount.c index edc958816..0722abef2 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -814,12 +814,6 @@ static int automount_start(Unit *u) { if (r < 0) return r; - r = unit_test_start_limit(u); - if (r < 0) { - automount_enter_dead(a, AUTOMOUNT_FAILURE_START_LIMIT_HIT); - return r; - } - r = unit_acquire_invocation_id(u); if (r < 0) return r; @@ -1065,6 +1059,21 @@ static bool automount_supported(void) { return supported; } +static int automount_test_start_limit(Unit *u) { + Automount *a = AUTOMOUNT(u); + int r; + + assert(a); + + r = unit_test_start_limit(u); + if (r < 0) { + automount_enter_dead(a, AUTOMOUNT_FAILURE_START_LIMIT_HIT); + return r; + } + + return 0; +} + static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = { [AUTOMOUNT_SUCCESS] = "success", [AUTOMOUNT_FAILURE_RESOURCES] = "resources", @@ -1127,4 +1136,6 @@ const UnitVTable automount_vtable = { [JOB_FAILED] = "Failed to unset automount %s.", }, }, + + .test_start_limit = automount_test_start_limit, }; diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 50daef670..902e074bd 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -1421,6 +1421,10 @@ int bus_set_transient_exec_command( if (r < 0) return r; + if (strv_isempty(argv)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "\"%s\" argv cannot be empty", name); + r = is_ex_prop ? sd_bus_message_read_strv(message, &ex_opts) : sd_bus_message_read(message, "b", &b); if (r < 0) return r; diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 124b9e496..fe320f1b0 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -909,7 +909,7 @@ const sd_bus_vtable bus_unit_vtable[] = { SD_BUS_PROPERTY("OnSuccessJobMode", "s", property_get_job_mode, offsetof(Unit, on_success_job_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, 0), SD_BUS_PROPERTY("Markers", "as", property_get_markers, offsetof(Unit, markers), 0), SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("JobRunningTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_running_timeout), SD_BUS_VTABLE_PROPERTY_CONST), diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 8fb3c378e..399a759ad 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -800,7 +800,7 @@ int config_parse_exec( if (!separate_argv0) { char *w = NULL; - if (!GREEDY_REALLOC(n, nlen + 2)) + if (!GREEDY_REALLOC0(n, nlen + 2)) return log_oom(); w = strdup(path); @@ -832,7 +832,7 @@ int config_parse_exec( p += 2; p += strspn(p, WHITESPACE); - if (!GREEDY_REALLOC(n, nlen + 2)) + if (!GREEDY_REALLOC0(n, nlen + 2)) return log_oom(); w = strdup(";"); diff --git a/src/core/main.c b/src/core/main.c index b32a19a1d..c64c73883 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -2454,6 +2454,9 @@ static int parse_configuration(const struct rlimit *saved_rlimit_nofile, /* Push variables into the manager environment block */ setenv_manager_environment(); + /* Parse log environment variables again to take into account any new environment variables. */ + log_parse_environment(); + return 0; } diff --git a/src/core/meson.build b/src/core/meson.build index f0d2c6f64..367c08502 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -193,7 +193,7 @@ foreach item : in_files output: file, command : [meson_render_jinja2, config_h, '@INPUT@'], capture : true, - install : dir != 'no', + install : (dir == pkgsysconfdir) ? install_sysconfdir_samples : (dir != 'no'), install_dir : dir) endforeach diff --git a/src/core/mount.c b/src/core/mount.c index 053deac14..9bec190cb 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -1168,12 +1168,6 @@ static int mount_start(Unit *u) { assert(IN_SET(m->state, MOUNT_DEAD, MOUNT_FAILED)); - r = unit_test_start_limit(u); - if (r < 0) { - mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT); - return r; - } - r = unit_acquire_invocation_id(u); if (r < 0) return r; @@ -1582,6 +1576,10 @@ static int mount_setup_new_unit( if (r < 0) return r; + r = mount_add_non_exec_dependencies(MOUNT(u)); + if (r < 0) + return r; + /* This unit was generated because /proc/self/mountinfo reported it. Remember this, so that by the time we load * the unit file for it (and thus add in extra deps right after) we know what source to attributes the deps * to. */ @@ -2139,6 +2137,21 @@ static int mount_can_clean(Unit *u, ExecCleanMask *ret) { return exec_context_get_clean_mask(&m->exec_context, ret); } +static int mount_test_start_limit(Unit *u) { + Mount *m = MOUNT(u); + int r; + + assert(m); + + r = unit_test_start_limit(u); + if (r < 0) { + mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT); + return r; + } + + return 0; +} + static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = { [MOUNT_EXEC_MOUNT] = "ExecMount", [MOUNT_EXEC_UNMOUNT] = "ExecUnmount", @@ -2236,4 +2249,6 @@ const UnitVTable mount_vtable = { [JOB_TIMEOUT] = "Timed out unmounting %s.", }, }, + + .test_start_limit = mount_test_start_limit, }; diff --git a/src/core/path.c b/src/core/path.c index e098e83a3..2b659696a 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -590,12 +590,6 @@ static int path_start(Unit *u) { if (r < 0) return r; - r = unit_test_start_limit(u); - if (r < 0) { - path_enter_dead(p, PATH_FAILURE_START_LIMIT_HIT); - return r; - } - r = unit_acquire_invocation_id(u); if (r < 0) return r; @@ -811,6 +805,21 @@ static void path_reset_failed(Unit *u) { p->result = PATH_SUCCESS; } +static int path_test_start_limit(Unit *u) { + Path *p = PATH(u); + int r; + + assert(p); + + r = unit_test_start_limit(u); + if (r < 0) { + path_enter_dead(p, PATH_FAILURE_START_LIMIT_HIT); + return r; + } + + return 0; +} + static const char* const path_type_table[_PATH_TYPE_MAX] = { [PATH_EXISTS] = "PathExists", [PATH_EXISTS_GLOB] = "PathExistsGlob", @@ -865,4 +874,6 @@ const UnitVTable path_vtable = { .reset_failed = path_reset_failed, .bus_set_property = bus_path_set_property, + + .test_start_limit = path_test_start_limit, }; diff --git a/src/core/service.c b/src/core/service.c index cb0a528f0..701c14556 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -548,6 +548,22 @@ static int service_verify(Service *s) { assert(s); assert(UNIT(s)->load_state == UNIT_LOADED); + for (ServiceExecCommand c = 0; c < _SERVICE_EXEC_COMMAND_MAX; c++) { + ExecCommand *command; + + LIST_FOREACH(command, command, s->exec_command[c]) { + if (!path_is_absolute(command->path) && !filename_is_valid(command->path)) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), + "Service %s= binary path \"%s\" is neither a valid executable name nor an absolute path. Refusing.", + command->path, + service_exec_command_to_string(c)); + if (strv_isempty(command->argv)) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), + "Service has an empty argv in %s=. Refusing.", + service_exec_command_to_string(c)); + } + } + if (!s->exec_command[SERVICE_EXEC_START] && !s->exec_command[SERVICE_EXEC_STOP] && UNIT(s)->success_action == EMERGENCY_ACTION_NONE) /* FailureAction= only makes sense if one of the start or stop commands is specified. @@ -2440,13 +2456,6 @@ static int service_start(Unit *u) { assert(IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED)); - /* Make sure we don't enter a busy loop of some kind. */ - r = unit_test_start_limit(u); - if (r < 0) { - service_enter_dead(s, SERVICE_FAILURE_START_LIMIT_HIT, false); - return r; - } - r = unit_acquire_invocation_id(u); if (r < 0) return r; @@ -4442,6 +4451,22 @@ static const char *service_finished_job(Unit *u, JobType t, JobResult result) { return NULL; } +static int service_test_start_limit(Unit *u) { + Service *s = SERVICE(u); + int r; + + assert(s); + + /* Make sure we don't enter a busy loop of some kind. */ + r = unit_test_start_limit(u); + if (r < 0) { + service_enter_dead(s, SERVICE_FAILURE_START_LIMIT_HIT, false); + return r; + } + + return 0; +} + static const char* const service_restart_table[_SERVICE_RESTART_MAX] = { [SERVICE_RESTART_NO] = "no", [SERVICE_RESTART_ON_SUCCESS] = "on-success", @@ -4604,4 +4629,6 @@ const UnitVTable service_vtable = { }, .finished_job = service_finished_job, }, + + .test_start_limit = service_test_start_limit, }; diff --git a/src/core/socket.c b/src/core/socket.c index 8144780bf..31d88b71f 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -34,6 +34,7 @@ #include "process-util.h" #include "selinux-util.h" #include "serialize.h" +#include "service.h" #include "signal-util.h" #include "smack-util.h" #include "socket.h" @@ -2514,12 +2515,6 @@ static int socket_start(Unit *u) { assert(IN_SET(s->state, SOCKET_DEAD, SOCKET_FAILED)); - r = unit_test_start_limit(u); - if (r < 0) { - socket_enter_dead(s, SOCKET_FAILURE_START_LIMIT_HIT); - return r; - } - r = unit_acquire_invocation_id(u); if (r < 0) return r; @@ -3428,6 +3423,21 @@ static int socket_can_clean(Unit *u, ExecCleanMask *ret) { return exec_context_get_clean_mask(&s->exec_context, ret); } +static int socket_test_start_limit(Unit *u) { + Socket *s = SOCKET(u); + int r; + + assert(s); + + r = unit_test_start_limit(u); + if (r < 0) { + socket_enter_dead(s, SOCKET_FAILURE_START_LIMIT_HIT); + return r; + } + + return 0; +} + static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = { [SOCKET_EXEC_START_PRE] = "ExecStartPre", [SOCKET_EXEC_START_CHOWN] = "ExecStartChown", @@ -3554,4 +3564,6 @@ const UnitVTable socket_vtable = { [JOB_TIMEOUT] = "Timed out stopping %s.", }, }, + + .test_start_limit = socket_test_start_limit, }; diff --git a/src/core/socket.h b/src/core/socket.h index a65195f2a..6813bdcf8 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -5,7 +5,6 @@ typedef struct Socket Socket; typedef struct SocketPeer SocketPeer; #include "mount.h" -#include "service.h" #include "socket-util.h" #include "unit.h" diff --git a/src/core/swap.c b/src/core/swap.c index 3843b1950..b25f68fb7 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -933,12 +933,6 @@ static int swap_start(Unit *u) { if (UNIT(other)->job && UNIT(other)->job->state == JOB_RUNNING) return -EAGAIN; - r = unit_test_start_limit(u); - if (r < 0) { - swap_enter_dead(s, SWAP_FAILURE_START_LIMIT_HIT); - return r; - } - r = unit_acquire_invocation_id(u); if (r < 0) return r; @@ -1588,6 +1582,21 @@ static int swap_can_clean(Unit *u, ExecCleanMask *ret) { return exec_context_get_clean_mask(&s->exec_context, ret); } +static int swap_test_start_limit(Unit *u) { + Swap *s = SWAP(u); + int r; + + assert(s); + + r = unit_test_start_limit(u); + if (r < 0) { + swap_enter_dead(s, SWAP_FAILURE_START_LIMIT_HIT); + return r; + } + + return 0; +} + static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = { [SWAP_EXEC_ACTIVATE] = "ExecActivate", [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate", @@ -1683,4 +1692,6 @@ const UnitVTable swap_vtable = { [JOB_TIMEOUT] = "Timed out deactivating swap %s.", }, }, + + .test_start_limit = swap_test_start_limit, }; diff --git a/src/core/timer.c b/src/core/timer.c index e064ad9a2..5ecc9f35c 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -635,12 +635,6 @@ static int timer_start(Unit *u) { if (r < 0) return r; - r = unit_test_start_limit(u); - if (r < 0) { - timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT); - return r; - } - r = unit_acquire_invocation_id(u); if (r < 0) return r; @@ -901,6 +895,21 @@ static int timer_can_clean(Unit *u, ExecCleanMask *ret) { return 0; } +static int timer_test_start_limit(Unit *u) { + Timer *t = TIMER(u); + int r; + + assert(t); + + r = unit_test_start_limit(u); + if (r < 0) { + timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT); + return r; + } + + return 0; +} + static const char* const timer_base_table[_TIMER_BASE_MAX] = { [TIMER_ACTIVE] = "OnActiveSec", [TIMER_BOOT] = "OnBootSec", @@ -960,4 +969,6 @@ const UnitVTable timer_vtable = { .timezone_change = timer_timezone_change, .bus_set_property = bus_timer_set_property, + + .test_start_limit = timer_test_start_limit, }; diff --git a/src/core/unit.c b/src/core/unit.c index 38d3eb703..69ed43578 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1851,6 +1851,13 @@ int unit_start(Unit *u) { assert(u); + /* Check start rate limiting early so that failure conditions don't cause us to enter a busy loop. */ + if (UNIT_VTABLE(u)->test_start_limit) { + int r = UNIT_VTABLE(u)->test_start_limit(u); + if (r < 0) + return r; + } + /* If this is already started, then this will succeed. Note that this will even succeed if this unit * is not startable by the user. This is relied on to detect when we need to wait for units and when * waiting is finished. */ diff --git a/src/core/unit.h b/src/core/unit.h index 759104ffa..9babd0718 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -649,6 +649,10 @@ typedef struct UnitVTable { * of this type will immediately fail. */ bool (*supported)(void); + /* If this function is set, it's invoked first as part of starting a unit to allow start rate + * limiting checks to occur before we do anything else. */ + int (*test_start_limit)(Unit *u); + /* The strings to print in status messages */ UnitStatusMessageFormats status_message_formats; diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c index def3650bb..3d44e51e3 100644 --- a/src/coredump/coredumpctl.c +++ b/src/coredump/coredumpctl.c @@ -1186,6 +1186,10 @@ static int check_units_active(void) { return false; r = sd_bus_default_system(&bus); + if (r == -ENOENT) { + log_debug("D-Bus is not running, skipping active unit check"); + return 0; + } if (r < 0) return log_error_errno(r, "Failed to acquire bus: %m"); diff --git a/src/coredump/stacktrace.c b/src/coredump/stacktrace.c index e46b324cd..f855a370f 100644 --- a/src/coredump/stacktrace.c +++ b/src/coredump/stacktrace.c @@ -299,6 +299,8 @@ static int module_callback(Dwfl_Module *mod, void **userdata, const char *name, program_header->p_offset, program_header->p_filesz, ELF_T_NHDR); + if (!data) + continue; Elf *memelf = elf_memory(data->d_buf, data->d_size); if (!memelf) diff --git a/src/home/homework-cifs.c b/src/home/homework-cifs.c index 2254eb59c..04a4db8a9 100644 --- a/src/home/homework-cifs.c +++ b/src/home/homework-cifs.c @@ -58,8 +58,8 @@ int home_prepare_cifs( f = safe_fclose(f); - if (asprintf(&options, "credentials=%s,uid=" UID_FMT ",forceuid,gid=" UID_FMT ",forcegid,file_mode=0%3o,dir_mode=0%3o", - p, h->uid, h->uid, h->access_mode, h->access_mode) < 0) + if (asprintf(&options, "credentials=%s,uid=" UID_FMT ",forceuid,gid=" GID_FMT ",forcegid,file_mode=0%3o,dir_mode=0%3o", + p, h->uid, user_record_gid(h), user_record_access_mode(h), user_record_access_mode(h)) < 0) return log_oom(); r = safe_fork("(mount)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_STDOUT_TO_STDERR, &mount_pid); @@ -71,7 +71,7 @@ int home_prepare_cifs( h->cifs_service, "/run/systemd/user-home-mount", "-o", options, NULL); - log_error_errno(errno, "Failed to execute fsck: %m"); + log_error_errno(errno, "Failed to execute mount: %m"); _exit(EXIT_FAILURE); } @@ -86,7 +86,8 @@ int home_prepare_cifs( } if (!mounted) - return log_error_errno(ENOKEY, "Failed to mount home directory with supplied password."); + return log_error_errno(SYNTHETIC_ERRNO(ENOKEY), + "Failed to mount home directory with supplied password."); setup->root_fd = open("/run/systemd/user-home-mount", O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW); } diff --git a/src/home/homework-mount.c b/src/home/homework-mount.c index 5e737687d..da4f14e08 100644 --- a/src/home/homework-mount.c +++ b/src/home/homework-mount.c @@ -69,9 +69,10 @@ int home_move_mount(const char *user_name_and_realm, const char *target) { const char *d; int r; - assert(user_name_and_realm); assert(target); + /* If user_name_and_realm is set, then we'll mount a subdir of the source mount into the host. If + * it's NULL we'll move the mount itself */ if (user_name_and_realm) { subdir = path_join("/run/systemd/user-home-mount/", user_name_and_realm); if (!subdir) diff --git a/src/home/pam_systemd_home.c b/src/home/pam_systemd_home.c index b7db39dab..27b292f46 100644 --- a/src/home/pam_systemd_home.c +++ b/src/home/pam_systemd_home.c @@ -281,7 +281,6 @@ static int handle_generic_user_record_error( const sd_bus_error *error) { assert(user_name); - assert(secret); assert(error); int r; @@ -301,6 +300,8 @@ static int handle_generic_user_record_error( } else if (sd_bus_error_has_name(error, BUS_ERROR_BAD_PASSWORD)) { _cleanup_(erase_and_freep) char *newp = NULL; + assert(secret); + /* This didn't work? Ask for an (additional?) password */ if (strv_isempty(secret->password)) @@ -326,6 +327,8 @@ static int handle_generic_user_record_error( } else if (sd_bus_error_has_name(error, BUS_ERROR_BAD_PASSWORD_AND_NO_TOKEN)) { _cleanup_(erase_and_freep) char *newp = NULL; + assert(secret); + if (strv_isempty(secret->password)) { (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Security token of user %s not inserted.", user_name); r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Try again with password: "); @@ -350,6 +353,8 @@ static int handle_generic_user_record_error( } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_PIN_NEEDED)) { _cleanup_(erase_and_freep) char *newp = NULL; + assert(secret); + r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Security token PIN: "); if (r != PAM_SUCCESS) return PAM_CONV_ERR; /* no logging here */ @@ -367,6 +372,8 @@ static int handle_generic_user_record_error( } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED)) { + assert(secret); + (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Please authenticate physically on security token of user %s.", user_name); r = user_record_set_pkcs11_protected_authentication_path_permitted(secret, true); @@ -377,6 +384,8 @@ static int handle_generic_user_record_error( } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED)) { + assert(secret); + (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Please confirm presence on security token of user %s.", user_name); r = user_record_set_fido2_user_presence_permitted(secret, true); @@ -387,6 +396,8 @@ static int handle_generic_user_record_error( } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_USER_VERIFICATION_NEEDED)) { + assert(secret); + (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Please verify user on security token of user %s.", user_name); r = user_record_set_fido2_user_verification_permitted(secret, true); @@ -403,6 +414,8 @@ static int handle_generic_user_record_error( } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_BAD_PIN)) { _cleanup_(erase_and_freep) char *newp = NULL; + assert(secret); + (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Security token PIN incorrect for user %s.", user_name); r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Sorry, retry security token PIN: "); if (r != PAM_SUCCESS) @@ -422,6 +435,8 @@ static int handle_generic_user_record_error( } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_BAD_PIN_FEW_TRIES_LEFT)) { _cleanup_(erase_and_freep) char *newp = NULL; + assert(secret); + (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Security token PIN of user %s incorrect (only a few tries left!)", user_name); r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Sorry, retry security token PIN: "); if (r != PAM_SUCCESS) @@ -441,6 +456,8 @@ static int handle_generic_user_record_error( } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_BAD_PIN_ONE_TRY_LEFT)) { _cleanup_(erase_and_freep) char *newp = NULL; + assert(secret); + (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Security token PIN of user %s incorrect (only one try left!)", user_name); r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Sorry, retry security token PIN: "); if (r != PAM_SUCCESS) diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c index 26cc83f31..50b4cb304 100644 --- a/src/hwdb/hwdb.c +++ b/src/hwdb/hwdb.c @@ -43,7 +43,7 @@ static int help(void) { " --version Show package version\n" " -s --strict When updating, return non-zero exit value on any parsing error\n" " --usr Generate in " UDEVLIBEXECDIR " instead of /etc/udev\n" - " -r --root=PATH Alternative root path in the filesystem\n\n" + " -r --root=PATH Alternative root path in the filesystem\n" "\nSee the %s for details.\n", program_invocation_short_name, ansi_highlight(), diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index c8fb726d4..3eac97510 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -2074,6 +2074,11 @@ static int simple_varlink_call(const char *option, const char *method) { } static int flush_to_var(void) { + if (access("/run/systemd/journal/flushed", F_OK) >= 0) + return 0; /* Already flushed, no need to contact journald */ + if (errno != ENOENT) + return log_error_errno(errno, "Unable to check for existence of /run/systemd/journal/flushed: %m"); + return simple_varlink_call("--flush", "io.systemd.Journal.FlushToVar"); } diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index a0695ec51..2d1d9e66d 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1275,11 +1275,14 @@ int server_process_datagram( /* We use NAME_MAX space for the SELinux label here. The kernel currently enforces no limit, but * according to suggestions from the SELinux people this will change and it will probably be * identical to NAME_MAX. For now we use that, but this should be updated one day when the final - * limit is known. */ + * limit is known. + * + * Here, we need to explicitly initialize the buffer with zero, as glibc has a bug in + * __convert_scm_timestamps(), which assumes the buffer is initialized. See #20741. */ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred)) + - CMSG_SPACE(sizeof(struct timeval)) + + CMSG_SPACE_TIMEVAL + CMSG_SPACE(sizeof(int)) + /* fd */ - CMSG_SPACE(NAME_MAX) /* selinux label */) control; + CMSG_SPACE(NAME_MAX) /* selinux label */) control = {}; union sockaddr_union sa = {}; diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c index 67c6b55d8..3832bbd92 100644 --- a/src/libsystemd-network/icmp6-util.c +++ b/src/libsystemd-network/icmp6-util.c @@ -148,8 +148,9 @@ int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) { int icmp6_receive(int fd, void *buffer, size_t size, struct in6_addr *ret_dst, triple_timestamp *ret_timestamp) { + /* This needs to be initialized with zero. See #20741. */ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int)) + /* ttl */ - CMSG_SPACE(sizeof(struct timeval))) control; + CMSG_SPACE_TIMEVAL) control = {}; struct iovec iov = {}; union sockaddr_union sa = {}; struct msghdr msg = { @@ -186,7 +187,6 @@ int icmp6_receive(int fd, void *buffer, size_t size, struct in6_addr *ret_dst, /* namelen == 0 only happens when running the test-suite over a socketpair */ - assert(!(msg.msg_flags & MSG_CTRUNC)); assert(!(msg.msg_flags & MSG_TRUNC)); CMSG_FOREACH(cmsg, &msg) { diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index dc8ff19d1..46191e58f 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -192,7 +192,7 @@ int sd_dhcp_client_id_to_string(const void *data, size_t len, char **ret) { if (len != sizeof_field(sd_dhcp_client_id, eth)) return -EINVAL; - r = asprintf(&t, "%x:%x:%x:%x:%x:%x", + r = asprintf(&t, "%02x:%02x:%02x:%02x:%02x:%02x", client_id->eth.haddr[0], client_id->eth.haddr[1], client_id->eth.haddr[2], @@ -726,7 +726,7 @@ static int client_notify(sd_dhcp_client *client, int event) { static int client_initialize(sd_dhcp_client *client) { assert_return(client, -EINVAL); - client->receive_message = sd_event_source_unref(client->receive_message); + client->receive_message = sd_event_source_disable_unref(client->receive_message); client->fd = safe_close(client->fd); @@ -1492,7 +1492,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) assert(client); - client->receive_message = sd_event_source_unref(client->receive_message); + client->receive_message = sd_event_source_disable_unref(client->receive_message); client->fd = safe_close(client->fd); client->state = DHCP_STATE_REBINDING; @@ -1847,7 +1847,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i client->start_delay = 0; (void) event_source_disable(client->timeout_resend); - client->receive_message = sd_event_source_unref(client->receive_message); + client->receive_message = sd_event_source_disable_unref(client->receive_message); client->fd = safe_close(client->fd); client->state = DHCP_STATE_BOUND; @@ -2229,17 +2229,15 @@ static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) { log_dhcp_client(client, "FREE"); + client_initialize(client); + client->timeout_resend = sd_event_source_unref(client->timeout_resend); client->timeout_t1 = sd_event_source_unref(client->timeout_t1); client->timeout_t2 = sd_event_source_unref(client->timeout_t2); client->timeout_expire = sd_event_source_unref(client->timeout_expire); - client_initialize(client); - sd_dhcp_client_detach_event(client); - sd_dhcp_lease_unref(client->lease); - set_free(client->req_opts); free(client->hostname); free(client->vendor_class_identifier); diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 9ae884b0f..3f4af8440 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -267,8 +267,8 @@ int sd_dhcp_server_stop(sd_dhcp_server *server) { if (!server) return 0; - server->receive_message = sd_event_source_unref(server->receive_message); - server->receive_broadcast = sd_event_source_unref(server->receive_broadcast); + server->receive_message = sd_event_source_disable_unref(server->receive_message); + server->receive_broadcast = sd_event_source_disable_unref(server->receive_broadcast); server->fd_raw = safe_close(server->fd_raw); server->fd = safe_close(server->fd); diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 9a77a3331..ebd476484 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -120,7 +120,7 @@ static void ipv4acd_reset(sd_ipv4acd *acd) { assert(acd); (void) event_source_disable(acd->timer_event_source); - acd->receive_message_event_source = sd_event_source_unref(acd->receive_message_event_source); + acd->receive_message_event_source = sd_event_source_disable_unref(acd->receive_message_event_source); acd->fd = safe_close(acd->fd); @@ -130,9 +130,8 @@ static void ipv4acd_reset(sd_ipv4acd *acd) { static sd_ipv4acd *ipv4acd_free(sd_ipv4acd *acd) { assert(acd); - acd->timer_event_source = sd_event_source_unref(acd->timer_event_source); - ipv4acd_reset(acd); + sd_event_source_unref(acd->timer_event_source); sd_ipv4acd_detach_event(acd); free(acd->ifname); return mfree(acd); diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 49aa876a5..b38d6dbd1 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -239,7 +239,7 @@ static void lldp_reset(sd_lldp *lldp) { assert(lldp); (void) event_source_disable(lldp->timer_event_source); - lldp->io_event_source = sd_event_source_unref(lldp->io_event_source); + lldp->io_event_source = sd_event_source_disable_unref(lldp->io_event_source); lldp->fd = safe_close(lldp->fd); } @@ -365,10 +365,11 @@ const char *sd_lldp_get_ifname(sd_lldp *lldp) { static sd_lldp* lldp_free(sd_lldp *lldp) { assert(lldp); - lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source); - lldp_reset(lldp); + + sd_event_source_unref(lldp->timer_event_source); sd_lldp_detach_event(lldp); + lldp_flush_neighbors(lldp); hashmap_free(lldp->neighbor_by_id); diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index 4d5f1b54c..9b3a89378 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -133,18 +133,19 @@ static void ndisc_reset(sd_ndisc *nd) { (void) event_source_disable(nd->timeout_event_source); (void) event_source_disable(nd->timeout_no_ra); nd->retransmit_time = 0; - nd->recv_event_source = sd_event_source_unref(nd->recv_event_source); + nd->recv_event_source = sd_event_source_disable_unref(nd->recv_event_source); nd->fd = safe_close(nd->fd); } static sd_ndisc *ndisc_free(sd_ndisc *nd) { assert(nd); - nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source); - nd->timeout_no_ra = sd_event_source_unref(nd->timeout_no_ra); - ndisc_reset(nd); + + sd_event_source_unref(nd->timeout_event_source); + sd_event_source_unref(nd->timeout_no_ra); sd_ndisc_detach_event(nd); + free(nd->ifname); return mfree(nd); } diff --git a/src/libsystemd-network/sd-radv.c b/src/libsystemd-network/sd-radv.c index 857401bf6..eac8aa385 100644 --- a/src/libsystemd-network/sd-radv.c +++ b/src/libsystemd-network/sd-radv.c @@ -89,8 +89,7 @@ static void radv_reset(sd_radv *ra) { (void) event_source_disable(ra->timeout_event_source); - ra->recv_event_source = - sd_event_source_unref(ra->recv_event_source); + ra->recv_event_source = sd_event_source_disable_unref(ra->recv_event_source); ra->ra_sent = 0; } @@ -116,10 +115,9 @@ static sd_radv *radv_free(sd_radv *ra) { free(ra->rdnss); free(ra->dnssl); - ra->timeout_event_source = sd_event_source_unref(ra->timeout_event_source); - radv_reset(ra); + sd_event_source_unref(ra->timeout_event_source); sd_radv_detach_event(ra); ra->fd = safe_close(ra->fd); diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index e9199deb4..99c0acfa5 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -4154,7 +4154,7 @@ _public_ int sd_event_loop(sd_event *e) { assert_return(!event_pid_changed(e), -ECHILD); assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); - _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = NULL; + _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); while (e->state != SD_EVENT_FINISHED) { r = sd_event_run(e, UINT64_MAX); diff --git a/src/libsystemd/sd-journal/sd-journal.c b/src/libsystemd/sd-journal/sd-journal.c index 5728c537b..b3240177c 100644 --- a/src/libsystemd/sd-journal/sd-journal.c +++ b/src/libsystemd/sd-journal/sd-journal.c @@ -3158,7 +3158,11 @@ _public_ int sd_journal_enumerate_fields(sd_journal *j, const char **field) { if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) && le64toh(of->header->n_fields) <= 0) continue; - r = journal_file_find_field_object_with_hash(of, o->field.payload, sz, le64toh(o->field.hash), NULL, NULL); + if (!JOURNAL_HEADER_KEYED_HASH(f->header) && !JOURNAL_HEADER_KEYED_HASH(of->header)) + r = journal_file_find_field_object_with_hash(of, o->field.payload, sz, + le64toh(o->field.hash), NULL, NULL); + else + r = journal_file_find_field_object(of, o->field.payload, sz, NULL, NULL); if (r < 0) return r; if (r > 0) { @@ -3174,7 +3178,7 @@ _public_ int sd_journal_enumerate_fields(sd_journal *j, const char **field) { if (memchr(o->field.payload, 0, sz)) return -EBADMSG; - if (sz > j->data_threshold) + if (j->data_threshold > 0 && sz > j->data_threshold) sz = j->data_threshold; if (!GREEDY_REALLOC(j->fields_buffer, sz + 1)) diff --git a/src/locale/localed.c b/src/locale/localed.c index df0eb030d..c228385d0 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -560,7 +560,7 @@ static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char fmt = strjoina("libxkbcommon: ", format); DISABLE_WARNING_FORMAT_NONLITERAL; - log_internalv(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, fmt, args); + log_internalv(LOG_DEBUG, 0, PROJECT_FILE, __LINE__, __func__, fmt, args); REENABLE_WARNING; } diff --git a/src/login/meson.build b/src/login/meson.build index 8c20e6be6..da704d238 100644 --- a/src/login/meson.build +++ b/src/login/meson.build @@ -67,22 +67,24 @@ pam_systemd_c = files('pam_systemd.c') enable_logind = conf.get('ENABLE_LOGIND') == 1 in_files = [ - ['logind.conf', pkgsysconfdir, enable_logind], + ['logind.conf', pkgsysconfdir, enable_logind and install_sysconfdir_samples], ['70-uaccess.rules', udevrulesdir, enable_logind and conf.get('HAVE_ACL') == 1], ['71-seat.rules', udevrulesdir, enable_logind], ['73-seat-late.rules', udevrulesdir, enable_logind], - ['systemd-user', pamconfdir, enable_logind and pamconfdir != 'no']] + ['systemd-user', pamconfdir, enable_logind]] foreach tuple : in_files file = tuple[0] + dir = tuple[1] + install = (dir == pkgsysconfdir) ? install_sysconfdir_samples : (dir != 'no') custom_target( file, input : file + '.in', output: file, command : [meson_render_jinja2, config_h, '@INPUT@'], capture : true, - install : tuple[2], - install_dir : tuple[1]) + install : tuple[2] and install, + install_dir : dir) endforeach if enable_logind diff --git a/src/mount/mount-tool.c b/src/mount/mount-tool.c index c213c905a..70b4c5a76 100644 --- a/src/mount/mount-tool.c +++ b/src/mount/mount-tool.c @@ -332,6 +332,9 @@ static int parse_argv(int argc, char *argv[]) { assert_not_reached("Unhandled option"); } + if (arg_user) + arg_ask_password = false; + if (arg_user && arg_transport != BUS_TRANSPORT_LOCAL) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Execution in user context is not supported on non-local systems."); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index d58b70005..20675f230 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1404,17 +1404,21 @@ static int link_initialized(Link *link, sd_device *device) { assert(link); assert(device); - if (link->state != LINK_STATE_PENDING) - return 0; + /* Always replace with the new sd_device object. As the sysname (and possibly other properties + * or sysattrs) may be outdated. */ + sd_device_ref(device); + sd_device_unref(link->sd_device); + link->sd_device = device; - if (link->sd_device) + /* Do not ignore unamanaged state case here. If an interface is renamed after being once + * configured, and the corresponding .network file has Name= in [Match] section, then the + * interface may be already in unmanaged state. See #20657. */ + if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_UNMANAGED)) return 0; log_link_debug(link, "udev initialized link"); link_set_state(link, LINK_STATE_INITIALIZED); - link->sd_device = sd_device_ref(device); - /* udev has initialized the link, but we don't know if we have yet * processed the NEWLINK messages with the latest state. Do a GETLINK, * when it returns we know that the pending NEWLINKs have already been diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c index 45a087b30..82a403fe2 100644 --- a/src/network/networkd-lldp-tx.c +++ b/src/network/networkd-lldp-tx.c @@ -413,7 +413,7 @@ int link_lldp_emit_start(Link *link) { void link_lldp_emit_stop(Link *link) { assert(link); - link->lldp_emit_event_source = sd_event_source_unref(link->lldp_emit_event_source); + link->lldp_emit_event_source = sd_event_source_disable_unref(link->lldp_emit_event_source); } int config_parse_lldp_mud( diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index b7852f6ee..791fd64c3 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -290,7 +290,7 @@ Route *route_free(Route *route) { ordered_set_free_with_destructor(route->multipath_routes, multipath_route_free); - sd_event_source_unref(route->expire); + sd_event_source_disable_unref(route->expire); return mfree(route); } @@ -1273,7 +1273,7 @@ static int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdat } static int route_add_and_setup_timer_one(Link *link, const Route *route, const MultipathRoute *m, const NextHop *nh, uint8_t nh_weight, Route **ret) { - _cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL; + _cleanup_(sd_event_source_disable_unrefp) sd_event_source *expire = NULL; Route *nr; int r; @@ -1311,7 +1311,7 @@ static int route_add_and_setup_timer_one(Link *link, const Route *route, const M return log_link_error_errno(link, r, "Could not arm expiration timer: %m"); } - sd_event_source_unref(nr->expire); + sd_event_source_disable_unref(nr->expire); nr->expire = TAKE_PTR(expire); *ret = nr; diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index 03ccbd8e8..b7e0fd779 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -1115,7 +1115,7 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man r = routing_policy_rule_update_priority(rule, tmp->priority); if (r < 0) log_warning_errno(r, "Failed to update priority of remembered routing policy rule, ignoring: %m"); - } else if (!m->manage_foreign_routes) + } else if (!m->manage_foreign_rules) log_routing_policy_rule_debug(tmp, "Ignoring received foreign", NULL, m); else { log_routing_policy_rule_debug(tmp, "Remembering foreign", NULL, m); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 04685fecb..575b9da44 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -5354,7 +5354,7 @@ static int cant_be_in_netns(void) { if (fd < 0) return log_error_errno(errno, "Failed to allocate udev control socket: %m"); - if (connect(fd, &sa.un, SOCKADDR_UN_LEN(sa.un)) < 0) { + if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) { if (errno == ENOENT || ERRNO_IS_DISCONNECT(errno)) return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c index 1b0866109..1840a0d50 100644 --- a/src/nss-systemd/nss-systemd.c +++ b/src/nss-systemd/nss-systemd.c @@ -2,6 +2,7 @@ #include #include +#include #include "env-util.h" #include "errno-util.h" @@ -139,6 +140,155 @@ NSS_GRENT_PROTOTYPES(systemd); NSS_SGENT_PROTOTYPES(systemd); NSS_INITGROUPS_PROTOTYPE(systemd); +/* Since our NSS functions implement reentrant glibc APIs, we have to guarantee + * all the string pointers we return point into the buffer provided by the + * caller, not into our own static memory. */ + +static enum nss_status copy_synthesized_passwd( + struct passwd *dest, + const struct passwd *src, + char *buffer, size_t buflen, + int *errnop) { + + size_t required; + + assert(dest); + assert(src); + assert(src->pw_name); + assert(src->pw_passwd); + assert(src->pw_gecos); + assert(src->pw_dir); + assert(src->pw_shell); + + required = strlen(src->pw_name) + 1; + required += strlen(src->pw_passwd) + 1; + required += strlen(src->pw_gecos) + 1; + required += strlen(src->pw_dir) + 1; + required += strlen(src->pw_shell) + 1; + + if (buflen < required) { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + assert(buffer); + + *dest = *src; + + /* String fields point into the user-provided buffer */ + dest->pw_name = buffer; + dest->pw_passwd = stpcpy(dest->pw_name, src->pw_name) + 1; + dest->pw_gecos = stpcpy(dest->pw_passwd, src->pw_passwd) + 1; + dest->pw_dir = stpcpy(dest->pw_gecos, src->pw_gecos) + 1; + dest->pw_shell = stpcpy(dest->pw_dir, src->pw_dir) + 1; + strcpy(dest->pw_shell, src->pw_shell); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status copy_synthesized_spwd( + struct spwd *dest, + const struct spwd *src, + char *buffer, size_t buflen, + int *errnop) { + + size_t required; + + assert(dest); + assert(src); + assert(src->sp_namp); + assert(src->sp_pwdp); + + required = strlen(src->sp_namp) + 1; + required += strlen(src->sp_pwdp) + 1; + + if (buflen < required) { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + assert(buffer); + + *dest = *src; + + /* String fields point into the user-provided buffer */ + dest->sp_namp = buffer; + dest->sp_pwdp = stpcpy(dest->sp_namp, src->sp_namp) + 1; + strcpy(dest->sp_pwdp, src->sp_pwdp); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status copy_synthesized_group( + struct group *dest, + const struct group *src, + char *buffer, size_t buflen, + int *errnop) { + + size_t required; + + assert(dest); + assert(src); + assert(src->gr_name); + assert(src->gr_passwd); + assert(src->gr_mem); + assert(!*src->gr_mem); /* Our synthesized records' gr_mem is always just NULL... */ + + required = strlen(src->gr_name) + 1; + required += strlen(src->gr_passwd) + 1; + required += 1; /* ...but that NULL still needs to be stored into the buffer! */ + + if (buflen < required) { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + assert(buffer); + + *dest = *src; + + /* String fields point into the user-provided buffer */ + dest->gr_name = buffer; + dest->gr_passwd = stpcpy(dest->gr_name, src->gr_name) + 1; + dest->gr_mem = (char **) strcpy(dest->gr_passwd, src->gr_passwd) + 1; + *dest->gr_mem = NULL; + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status copy_synthesized_sgrp( + struct sgrp *dest, + const struct sgrp *src, + char *buffer, size_t buflen, + int *errnop) { + + size_t required; + + assert(dest); + assert(src); + assert(src->sg_namp); + assert(src->sg_passwd); + + required = strlen(src->sg_namp) + 1; + required += strlen(src->sg_passwd) + 1; + + if (buflen < required) { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + assert(buffer); + + *dest = *src; + + /* String fields point into the user-provided buffer */ + dest->sg_namp = buffer; + dest->sg_passwd = stpcpy(dest->sg_namp, src->sg_namp) + 1; + strcpy(dest->sg_passwd, src->sg_passwd); + + return NSS_STATUS_SUCCESS; +} + enum nss_status _nss_systemd_getpwnam_r( const char *name, struct passwd *pwd, @@ -164,17 +314,14 @@ enum nss_status _nss_systemd_getpwnam_r( /* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */ if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) { - if (streq(name, root_passwd.pw_name)) { - *pwd = root_passwd; - return NSS_STATUS_SUCCESS; - } + if (streq(name, root_passwd.pw_name)) + return copy_synthesized_passwd(pwd, &root_passwd, buffer, buflen, errnop); if (streq(name, nobody_passwd.pw_name)) { if (!synthesize_nobody()) return NSS_STATUS_NOTFOUND; - *pwd = nobody_passwd; - return NSS_STATUS_SUCCESS; + return copy_synthesized_passwd(pwd, &nobody_passwd, buffer, buflen, errnop); } } else if (STR_IN_SET(name, root_passwd.pw_name, nobody_passwd.pw_name)) @@ -211,17 +358,14 @@ enum nss_status _nss_systemd_getpwuid_r( /* Synthesize data for the root user and for nobody in case they are missing from /etc/passwd */ if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) { - if (uid == root_passwd.pw_uid) { - *pwd = root_passwd; - return NSS_STATUS_SUCCESS; - } + if (uid == root_passwd.pw_uid) + return copy_synthesized_passwd(pwd, &root_passwd, buffer, buflen, errnop); if (uid == nobody_passwd.pw_uid) { if (!synthesize_nobody()) return NSS_STATUS_NOTFOUND; - *pwd = nobody_passwd; - return NSS_STATUS_SUCCESS; + return copy_synthesized_passwd(pwd, &nobody_passwd, buffer, buflen, errnop); } } else if (uid == root_passwd.pw_uid || uid == nobody_passwd.pw_uid) @@ -259,17 +403,14 @@ enum nss_status _nss_systemd_getspnam_r( /* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */ if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) { - if (streq(name, root_spwd.sp_namp)) { - *spwd = root_spwd; - return NSS_STATUS_SUCCESS; - } + if (streq(name, root_spwd.sp_namp)) + return copy_synthesized_spwd(spwd, &root_spwd, buffer, buflen, errnop); if (streq(name, nobody_spwd.sp_namp)) { if (!synthesize_nobody()) return NSS_STATUS_NOTFOUND; - *spwd = nobody_spwd; - return NSS_STATUS_SUCCESS; + return copy_synthesized_spwd(spwd, &nobody_spwd, buffer, buflen, errnop); } } else if (STR_IN_SET(name, root_spwd.sp_namp, nobody_spwd.sp_namp)) @@ -309,17 +450,14 @@ enum nss_status _nss_systemd_getgrnam_r( /* Synthesize records for root and nobody, in case they are missing from /etc/group */ if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) { - if (streq(name, root_group.gr_name)) { - *gr = root_group; - return NSS_STATUS_SUCCESS; - } + if (streq(name, root_group.gr_name)) + return copy_synthesized_group(gr, &root_group, buffer, buflen, errnop); if (streq(name, nobody_group.gr_name)) { if (!synthesize_nobody()) return NSS_STATUS_NOTFOUND; - *gr = nobody_group; - return NSS_STATUS_SUCCESS; + return copy_synthesized_group(gr, &nobody_group, buffer, buflen, errnop); } } else if (STR_IN_SET(name, root_group.gr_name, nobody_group.gr_name)) @@ -356,17 +494,14 @@ enum nss_status _nss_systemd_getgrgid_r( /* Synthesize records for root and nobody, in case they are missing from /etc/group */ if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) { - if (gid == root_group.gr_gid) { - *gr = root_group; - return NSS_STATUS_SUCCESS; - } + if (gid == root_group.gr_gid) + return copy_synthesized_group(gr, &root_group, buffer, buflen, errnop); if (gid == nobody_group.gr_gid) { if (!synthesize_nobody()) return NSS_STATUS_NOTFOUND; - *gr = nobody_group; - return NSS_STATUS_SUCCESS; + return copy_synthesized_group(gr, &nobody_group, buffer, buflen, errnop); } } else if (gid == root_group.gr_gid || gid == nobody_group.gr_gid) @@ -404,17 +539,14 @@ enum nss_status _nss_systemd_getsgnam_r( /* Synthesize records for root and nobody, in case they are missing from /etc/group */ if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) { - if (streq(name, root_sgrp.sg_namp)) { - *sgrp = root_sgrp; - return NSS_STATUS_SUCCESS; - } + if (streq(name, root_sgrp.sg_namp)) + return copy_synthesized_sgrp(sgrp, &root_sgrp, buffer, buflen, errnop); if (streq(name, nobody_sgrp.sg_namp)) { if (!synthesize_nobody()) return NSS_STATUS_NOTFOUND; - *sgrp = nobody_sgrp; - return NSS_STATUS_SUCCESS; + return copy_synthesized_sgrp(sgrp, &nobody_sgrp, buffer, buflen, errnop); } } else if (STR_IN_SET(name, root_sgrp.sg_namp, nobody_sgrp.sg_namp)) diff --git a/src/nss-systemd/userdb-glue.c b/src/nss-systemd/userdb-glue.c index a55790f64..c865ff0d8 100644 --- a/src/nss-systemd/userdb-glue.c +++ b/src/nss-systemd/userdb-glue.c @@ -35,6 +35,8 @@ int nss_pack_user_record( assert(hr->user_name); required = strlen(hr->user_name) + 1; + required += 2; /* strlen(PASSWORD_SEE_SHADOW) + 1 */ + assert_se(rn = user_record_real_name(hr)); required += strlen(rn) + 1; @@ -51,12 +53,12 @@ int nss_pack_user_record( .pw_name = buffer, .pw_uid = hr->uid, .pw_gid = user_record_gid(hr), - .pw_passwd = (char*) PASSWORD_SEE_SHADOW, }; assert(buffer); - pwd->pw_gecos = stpcpy(pwd->pw_name, hr->user_name) + 1; + pwd->pw_passwd = stpcpy(pwd->pw_name, hr->user_name) + 1; + pwd->pw_gecos = stpcpy(pwd->pw_passwd, PASSWORD_SEE_SHADOW) + 1; pwd->pw_dir = stpcpy(pwd->pw_gecos, rn) + 1; pwd->pw_shell = stpcpy(pwd->pw_dir, hd) + 1; strcpy(pwd->pw_shell, shell); diff --git a/src/partition/repart.c b/src/partition/repart.c index 589acaa49..3c80d1380 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -206,7 +206,12 @@ static const char *encrypt_mode_table[_ENCRYPT_MODE_MAX] = { [ENCRYPT_KEY_FILE_TPM2] = "key-file+tpm2", }; +#if HAVE_LIBCRYPTSETUP DEFINE_PRIVATE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(encrypt_mode, EncryptMode, ENCRYPT_KEY_FILE); +#else +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(encrypt_mode, EncryptMode, ENCRYPT_KEY_FILE); +#endif + static uint64_t round_down_size(uint64_t v, uint64_t p) { return (v / p) * p; @@ -2779,7 +2784,7 @@ static int context_copy_blocks(Context *context) { return log_error_errno(r, "Failed to copy in data from '%s': %m", p->copy_blocks_path); if (fsync(target_fd) < 0) - return log_error_errno(r, "Failed to synchronize copied data blocks: %m"); + return log_error_errno(errno, "Failed to synchronize copied data blocks: %m"); if (p->encrypt != ENCRYPT_OFF) { encrypted_dev_fd = safe_close(encrypted_dev_fd); @@ -3055,7 +3060,7 @@ static int context_mkfs(Context *context) { if (p->encrypt != ENCRYPT_OFF) { if (fsync(encrypted_dev_fd) < 0) - return log_error_errno(r, "Failed to synchronize LUKS volume: %m"); + return log_error_errno(errno, "Failed to synchronize LUKS volume: %m"); encrypted_dev_fd = safe_close(encrypted_dev_fd); r = deactivate_luks(cd, encrypted); diff --git a/src/resolve/resolvconf-compat.c b/src/resolve/resolvconf-compat.c index 93ded6d56..991c62e21 100644 --- a/src/resolve/resolvconf-compat.c +++ b/src/resolve/resolvconf-compat.c @@ -39,8 +39,8 @@ static int resolvconf_help(void) { "This is a compatibility alias for the resolvectl(1) tool, providing native\n" "command line compatibility with the resolvconf(8) tool of various Linux\n" "distributions and BSD systems. Some options supported by other implementations\n" - "are not supported and are ignored: -m, -p. Various options supported by other\n" - "implementations are not supported and will cause the invocation to fail: -u,\n" + "are not supported and are ignored: -m, -p, -u. Various options supported by other\n" + "implementations are not supported and will cause the invocation to fail:\n" "-I, -i, -l, -R, -r, -v, -V, --enable-updates, --disable-updates,\n" "--updates-are-enabled.\n" "\nSee the %2$s for details.\n", @@ -171,8 +171,11 @@ int resolvconf_parse_argv(int argc, char *argv[]) { log_debug("Switch -%c ignored.", c); break; - /* Everybody else can agree on the existence of -u but we don't support it. */ + /* -u supposedly should "update all subscribers". We have no subscribers, hence let's make + this a NOP, and exit immediately, cleanly. */ case 'u': + log_info("Switch -%c ignored.", c); + return 0; /* The following options are openresolv inventions we don't support. */ case 'I': diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c index dd02d368e..d5a77605a 100644 --- a/src/resolve/resolved-resolv-conf.c +++ b/src/resolve/resolved-resolv-conf.c @@ -216,6 +216,13 @@ static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) { return; } + /* resolv.conf simply doesn't support any other ports than 53, hence there's nothing much we can + * do — we have to suppress these entries */ + if (dns_server_port(s) != 53) { + log_debug("DNS server %s with non-standard UDP port number, suppressing from generated resolv.conf.", dns_server_string(s)); + return; + } + /* Check if the scope this DNS server belongs to is suitable as 'default' route for lookups; resolv.conf does * not have a syntax to express that, so it must not appear as a global name server to avoid routing unrelated * domains to it (which is a privacy violation, will most probably fail anyway, and adds unnecessary load) */ diff --git a/src/run/run.c b/src/run/run.c index 38de0322e..1c83e36e4 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -506,6 +506,10 @@ static int parse_argv(int argc, char *argv[]) { assert_not_reached("Unhandled option"); } + /* If we are talking to the per-user instance PolicyKit isn't going to help */ + if (arg_user) + arg_ask_password = false; + with_trigger = !!arg_path_property || !!arg_socket_property || arg_with_timer; /* currently, only single trigger (path, socket, timer) unit can be created simultaneously */ diff --git a/src/shared/libfido2-util.c b/src/shared/libfido2-util.c index 12c644dcf..6d18178b6 100644 --- a/src/shared/libfido2-util.c +++ b/src/shared/libfido2-util.c @@ -58,6 +58,7 @@ bool (*sym_fido_dev_is_fido2)(const fido_dev_t *) = NULL; int (*sym_fido_dev_make_cred)(fido_dev_t *, fido_cred_t *, const char *) = NULL; fido_dev_t* (*sym_fido_dev_new)(void) = NULL; int (*sym_fido_dev_open)(fido_dev_t *, const char *) = NULL; +int (*sym_fido_dev_close)(fido_dev_t *) = NULL; const char* (*sym_fido_strerr)(int) = NULL; int dlopen_libfido2(void) { @@ -106,6 +107,7 @@ int dlopen_libfido2(void) { DLSYM_ARG(fido_dev_make_cred), DLSYM_ARG(fido_dev_new), DLSYM_ARG(fido_dev_open), + DLSYM_ARG(fido_dev_close), DLSYM_ARG(fido_strerr)); } diff --git a/src/shared/libfido2-util.h b/src/shared/libfido2-util.h index 5640cca5e..4ebf8ab77 100644 --- a/src/shared/libfido2-util.h +++ b/src/shared/libfido2-util.h @@ -60,6 +60,7 @@ extern bool (*sym_fido_dev_is_fido2)(const fido_dev_t *); extern int (*sym_fido_dev_make_cred)(fido_dev_t *, fido_cred_t *, const char *); extern fido_dev_t* (*sym_fido_dev_new)(void); extern int (*sym_fido_dev_open)(fido_dev_t *, const char *); +extern int (*sym_fido_dev_close)(fido_dev_t *); extern const char* (*sym_fido_strerr)(int); int dlopen_libfido2(void); @@ -75,8 +76,10 @@ static inline void fido_assert_free_wrapper(fido_assert_t **p) { } static inline void fido_dev_free_wrapper(fido_dev_t **p) { - if (*p) + if (*p) { + sym_fido_dev_close(*p); sym_fido_dev_free(p); + } } static inline void fido_cred_free_wrapper(fido_cred_t **p) { diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index 631ca5dd3..31d6b542c 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -1789,6 +1789,10 @@ int seccomp_restrict_archs(Set *archs) { for (unsigned i = 0; seccomp_local_archs[i] != SECCOMP_LOCAL_ARCH_END; ++i) { uint32_t arch = seccomp_local_archs[i]; + /* See above comment, our "native" architecture is never blocked. */ + if (arch == seccomp_arch_native()) + continue; + /* That architecture might have already been blocked by a previous call to seccomp_restrict_archs. */ if (arch == SECCOMP_LOCAL_ARCH_BLOCKED) continue; diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index dbaecb3a0..8ec3d09a5 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -392,15 +392,17 @@ int find_hibernate_location(HibernateLocation **ret_hibernate_location) { } /* prefer resume device or highest priority swap with most remaining space */ - if (hibernate_location && swap->priority < hibernate_location->swap->priority) { - log_debug("%s: ignoring device with lower priority", swap->device); - continue; - } - if (hibernate_location && - (swap->priority == hibernate_location->swap->priority - && swap->size - swap->used < hibernate_location->swap->size - hibernate_location->swap->used)) { - log_debug("%s: ignoring device with lower usable space", swap->device); - continue; + if (sys_resume == 0) { + if (hibernate_location && swap->priority < hibernate_location->swap->priority) { + log_debug("%s: ignoring device with lower priority", swap->device); + continue; + } + if (hibernate_location && + (swap->priority == hibernate_location->swap->priority + && swap->size - swap->used < hibernate_location->swap->size - hibernate_location->swap->used)) { + log_debug("%s: ignoring device with lower usable space", swap->device); + continue; + } } dev_t swap_device; diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index df6d2eef5..56a7fe622 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -182,7 +182,7 @@ static int tpm2_init(const char *device, struct tpm2_context *ret) { if (!tcti) return log_oom(); - rc = info->init(tcti, &sz, device); + rc = info->init(tcti, &sz, param); if (rc != TPM2_RC_SUCCESS) return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to initialize TCTI context: %s", sym_Tss2_RC_Decode(rc)); diff --git a/src/shared/user-record.c b/src/shared/user-record.c index 17460ceaf..5fb3d4bbf 100644 --- a/src/shared/user-record.c +++ b/src/shared/user-record.c @@ -1913,9 +1913,9 @@ uint64_t user_record_luks_pbkdf_memory_cost(UserRecord *h) { assert(h); /* Returns a value with kb granularity, since that's what libcryptsetup expects */ - if (h->luks_pbkdf_memory_cost == UINT64_MAX) - return 64*1024*1024; /* We default to 64M, since this should work on smaller systems too */ + return streq(user_record_luks_pbkdf_type(h), "pbkdf2") ? 0 : /* doesn't apply for simple pbkdf2 */ + 64*1024*1024; /* We default to 64M, since this should work on smaller systems too */ return MIN(DIV_ROUND_UP(h->luks_pbkdf_memory_cost, 1024), UINT32_MAX) * 1024; } @@ -1923,8 +1923,9 @@ uint64_t user_record_luks_pbkdf_memory_cost(UserRecord *h) { uint64_t user_record_luks_pbkdf_parallel_threads(UserRecord *h) { assert(h); - if (h->luks_pbkdf_memory_cost == UINT64_MAX) - return 1; /* We default to 1, since this should work on smaller systems too */ + if (h->luks_pbkdf_parallel_threads == UINT64_MAX) + return streq(user_record_luks_pbkdf_type(h), "pbkdf2") ? 0 : /* doesn't apply for simple pbkdf2 */ + 1; /* We default to 1, since this should work on smaller systems too */ return MIN(h->luks_pbkdf_parallel_threads, UINT32_MAX); } diff --git a/src/shared/watchdog.c b/src/shared/watchdog.c index d33acafe6..8586a88e5 100644 --- a/src/shared/watchdog.c +++ b/src/shared/watchdog.c @@ -47,8 +47,8 @@ static int update_timeout(void) { flags = WDIOS_ENABLECARD; if (ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags) < 0) { /* ENOTTY means the watchdog is always enabled so we're fine */ - log_full(ERRNO_IS_NOT_SUPPORTED(errno) ? LOG_DEBUG : LOG_WARNING, - "Failed to enable hardware watchdog: %m"); + log_full_errno(ERRNO_IS_NOT_SUPPORTED(errno) ? LOG_DEBUG : LOG_WARNING, errno, + "Failed to enable hardware watchdog, ignoring: %m"); if (!ERRNO_IS_NOT_SUPPORTED(errno)) return -errno; } diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 4cc723aab..2f6f58127 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -925,6 +925,11 @@ static int systemctl_parse_argv(int argc, char *argv[]) { assert_not_reached("Unhandled option"); } + /* If we are in --user mode, there's no point in talking to PolicyKit or the infra to query system + * passwords */ + if (arg_scope != UNIT_FILE_SYSTEM) + arg_ask_password = false; + if (arg_transport == BUS_TRANSPORT_REMOTE && arg_scope != UNIT_FILE_SYSTEM) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot access user instance remotely."); diff --git a/src/test/test-env-util.c b/src/test/test-env-util.c index ed4580e4a..3d5951c46 100644 --- a/src/test/test-env-util.c +++ b/src/test/test-env-util.c @@ -198,7 +198,7 @@ static void test_replace_env2(bool extended) { "BAR=bar", NULL }; - _cleanup_free_ char *t = NULL, *s = NULL, *q = NULL, *r = NULL, *p = NULL, *x = NULL; + _cleanup_free_ char *t = NULL, *s = NULL, *q = NULL, *r = NULL, *p = NULL, *x = NULL, *y = NULL; unsigned flags = REPLACE_ENV_ALLOW_EXTENDED*extended; t = replace_env("FOO=${FOO:-${BAR}}", (char**) env, flags); @@ -218,6 +218,9 @@ static void test_replace_env2(bool extended) { x = replace_env("XXX=${XXX:+${BAR}post}", (char**) env, flags); assert_se(streq(x, extended ? "XXX=" : "XXX=${XXX:+barpost}")); + + y = replace_env("FOO=${FOO}between${BAR:-baz}", (char**) env, flags); + assert_se(streq(y, extended ? "FOO=foobetweenbar" : "FOO=foobetween${BAR:-baz}")); } static void test_replace_env_argv(void) { diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 125e0bbf4..1119ad4ac 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -432,8 +432,10 @@ static void test_exec_systemcallfilter(Manager *m) { test(m, "exec-systemcallfilter-not-failing.service", 0, CLD_EXITED); test(m, "exec-systemcallfilter-not-failing2.service", 0, CLD_EXITED); + test(m, "exec-systemcallfilter-not-failing3.service", 0, CLD_EXITED); test(m, "exec-systemcallfilter-failing.service", SIGSYS, CLD_KILLED); test(m, "exec-systemcallfilter-failing2.service", SIGSYS, CLD_KILLED); + test(m, "exec-systemcallfilter-failing3.service", SIGSYS, CLD_KILLED); r = find_executable("python3", NULL); if (r < 0) { diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index 321b54444..c8d5bf691 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -1028,7 +1028,11 @@ static void test_read_virtual_file(size_t max_size) { FOREACH_STRING(filename, "/proc/1/cmdline", "/etc/nsswitch.conf", - "/sys/kernel/uevent_seqnum") { + "/sys/kernel/uevent_seqnum", + "/proc/kcore", + "/proc/kallsyms", + "/proc/self/exe", + "/proc/self/pagemap") { _cleanup_free_ char *buf = NULL; size_t size = 0; @@ -1036,7 +1040,11 @@ static void test_read_virtual_file(size_t max_size) { r = read_virtual_file(filename, max_size, &buf, &size); if (r < 0) { log_info_errno(r, "read_virtual_file(\"%s\", %zu): %m", filename, max_size); - assert_se(ERRNO_IS_PRIVILEGE(r) || r == -ENOENT); + assert_se(ERRNO_IS_PRIVILEGE(r) || /* /proc/kcore is not accessible to unpriv */ + IN_SET(r, + -ENOENT, /* Some of the files might be absent */ + -EINVAL, /* too small reads from /proc/self/pagemap trigger EINVAL */ + -EFBIG)); /* /proc/kcore and /proc/self/pagemap should be too large */ } else log_info("read_virtual_file(\"%s\", %zu): %s (%zu bytes)", filename, max_size, r ? "non-truncated" : "truncated", size); } diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c index 023c4b6e0..dc3088d4b 100644 --- a/src/test/test-seccomp.c +++ b/src/test/test-seccomp.c @@ -890,6 +890,66 @@ static void test_load_syscall_filter_set_raw(void) { assert_se(wait_for_terminate_and_check("syscallrawseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); } +static void test_native_syscalls_filtered(void) { + pid_t pid; + + log_info("/* %s */", __func__); + + if (!is_seccomp_available()) { + log_notice("Seccomp not available, skipping %s", __func__); + return; + } + if (!have_seccomp_privs()) { + log_notice("Not privileged, skipping %s", __func__); + return; + } + + pid = fork(); + assert_se(pid >= 0); + + if (pid == 0) { + _cleanup_set_free_ Set *arch_s = NULL; + _cleanup_hashmap_free_ Hashmap *s = NULL; + + /* Passing "native" or an empty set is equivalent, just do both here. */ + assert_se(arch_s = set_new(NULL)); + assert_se(seccomp_restrict_archs(arch_s) >= 0); + assert_se(set_put(arch_s, SCMP_ARCH_NATIVE) >= 0); + assert_se(seccomp_restrict_archs(arch_s) >= 0); + + assert_se(access("/", F_OK) >= 0); + assert_se(poll(NULL, 0, 0) == 0); + + assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, NULL, scmp_act_kill_process(), true) >= 0); + assert_se(access("/", F_OK) >= 0); + assert_se(poll(NULL, 0, 0) == 0); + + assert_se(s = hashmap_new(NULL)); +#if defined __NR_access && __NR_access >= 0 + assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_access + 1), INT_TO_PTR(-1)) >= 0); + log_debug("has access()"); +#endif +#if defined __NR_faccessat && __NR_faccessat >= 0 + assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat + 1), INT_TO_PTR(-1)) >= 0); + log_debug("has faccessat()"); +#endif +#if defined __NR_faccessat2 && __NR_faccessat2 >= 0 + assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat2 + 1), INT_TO_PTR(-1)) >= 0); + log_debug("has faccessat2()"); +#endif + + assert_se(!hashmap_isempty(s)); + assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN), true) >= 0); + + assert_se(access("/", F_OK) < 0); + assert_se(errno == EUCLEAN); + + _exit(EXIT_SUCCESS); + } + + assert_se(wait_for_terminate_and_check("nativeseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); +} + static void test_lock_personality(void) { unsigned long current; pid_t pid; @@ -1171,6 +1231,7 @@ int main(int argc, char *argv[]) { test_memory_deny_write_execute_shmat(); test_restrict_archs(); test_load_syscall_filter_set_raw(); + test_native_syscalls_filtered(); test_lock_personality(); test_restrict_suid_sgid(); diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c index 9d874cfc8..e37db1c57 100644 --- a/src/timesync/timesyncd-manager.c +++ b/src/timesync/timesyncd-manager.c @@ -412,7 +412,8 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re .iov_base = &ntpmsg, .iov_len = sizeof(ntpmsg), }; - CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct timespec))) control; + /* This needs to be initialized with zero. See #20741. */ + CMSG_BUFFER_TYPE(CMSG_SPACE_TIMESPEC) control = {}; union sockaddr_union server_addr; struct msghdr msghdr = { .msg_iov = &iov, @@ -467,6 +468,8 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re switch (cmsg->cmsg_type) { case SCM_TIMESTAMPNS: + assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct timespec))); + recv_time = (struct timespec *) CMSG_DATA(cmsg); break; } diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index 92917852b..2699a8929 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -103,7 +103,6 @@ static int get_virtfn_info(sd_device *dev, struct netnames *names, struct virtfn _cleanup_(sd_device_unrefp) sd_device *physfn_pcidev = NULL; const char *physfn_link_file, *syspath; _cleanup_free_ char *physfn_pci_syspath = NULL; - _cleanup_free_ char *virtfn_pci_syspath = NULL; struct dirent *dent; _cleanup_closedir_ DIR *dir = NULL; char suffix[ALTIFNAMSIZ]; @@ -134,7 +133,7 @@ static int get_virtfn_info(sd_device *dev, struct netnames *names, struct virtfn return -errno; FOREACH_DIRENT_ALL(dent, dir, break) { - _cleanup_free_ char *virtfn_link_file = NULL; + _cleanup_free_ char *virtfn_link_file = NULL, *virtfn_pci_syspath = NULL; if (!startswith(dent->d_name, "virtfn")) continue; diff --git a/test/TEST-63-ISSUE-17433/Makefile b/test/TEST-63-ISSUE-17433/Makefile new file mode 120000 index 000000000..e9f93b110 --- /dev/null +++ b/test/TEST-63-ISSUE-17433/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile \ No newline at end of file diff --git a/test/TEST-63-ISSUE-17433/test.sh b/test/TEST-63-ISSUE-17433/test.sh new file mode 100755 index 000000000..c595a9f2d --- /dev/null +++ b/test/TEST-63-ISSUE-17433/test.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -e + +TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/17433" + +# shellcheck source=test/test-functions +. "${TEST_BASE_DIR:?}/test-functions" + +do_test "$@" diff --git a/test/meson.build b/test/meson.build index 47c7f4d49..6f8f257c2 100644 --- a/test/meson.build +++ b/test/meson.build @@ -33,6 +33,8 @@ if install_tests install_dir : testdata_dir) install_subdir('testsuite-52.units', install_dir : testdata_dir) + install_subdir('testsuite-63.units', + install_dir : testdata_dir) testsuite08_dir = testdata_dir + '/testsuite-08.units' install_data('testsuite-08.units/-.mount', diff --git a/test/networkd-test.py b/test/networkd-test.py index 799df0877..60622077a 100755 --- a/test/networkd-test.py +++ b/test/networkd-test.py @@ -635,7 +635,7 @@ Name={} [Network] DHCP=ipv4 IPv6AcceptRA=False -DNSSECNegativeTrustAnchors=megasearch.net +DNSSECNegativeTrustAnchors=search.example.com '''.format(self.iface)) # create second device/dnsmasq for a .company/.lab VPN interface @@ -681,8 +681,8 @@ DNSSECNegativeTrustAnchors=company lab self.assertIn(b'kettle.cantina.company: 10.241.4.4', out) # test general domains - out = subprocess.check_output(['resolvectl', 'query', 'megasearch.net']) - self.assertIn(b'megasearch.net: 192.168.42.1', out) + out = subprocess.check_output(['resolvectl', 'query', 'search.example.com']) + self.assertIn(b'search.example.com: 192.168.42.1', out) with open(self.dnsmasq_log) as f: general_log = f.read() @@ -696,8 +696,8 @@ DNSSECNegativeTrustAnchors=company lab self.assertNotIn('.company', general_log) # general domains should not be sent to the VPN DNS - self.assertRegex(general_log, 'query.*megasearch.net') - self.assertNotIn('megasearch.net', vpn_log) + self.assertRegex(general_log, 'query.*search.example.com') + self.assertNotIn('search.example.com', vpn_log) def test_resolved_etc_hosts(self): '''resolved queries to /etc/hosts''' diff --git a/test/test-execute/exec-systemcallfilter-failing3.service b/test/test-execute/exec-systemcallfilter-failing3.service new file mode 100644 index 000000000..b8c96704d --- /dev/null +++ b/test/test-execute/exec-systemcallfilter-failing3.service @@ -0,0 +1,9 @@ +[Unit] +Description=Test for SystemCallFilter + +[Service] +ExecStart=/bin/sh -c '/bin/echo "This should not be seen"' +Type=oneshot +LimitCORE=0 +SystemCallArchitectures=native +SystemCallFilter=~write open execve fexecve execveat exit_group close mmap munmap fstat DONOTEXIST diff --git a/test/test-execute/exec-systemcallfilter-not-failing3.service b/test/test-execute/exec-systemcallfilter-not-failing3.service new file mode 100644 index 000000000..7d72f5ab8 --- /dev/null +++ b/test/test-execute/exec-systemcallfilter-not-failing3.service @@ -0,0 +1,8 @@ +[Unit] +Description=Test for SystemCallFilter + +[Service] +ExecStart=/bin/sh -c 'echo "Foo bar"' +Type=oneshot +SystemCallArchitectures=native +SystemCallFilter= diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 4a2af0c50..c1bc7e530 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -2008,12 +2008,10 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): print('### ip route show table 42 dev dummy98') print(output) self.assertRegex(output, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1') - self.assertRegex(output, 'broadcast 10.20.33.0 proto kernel scope link src 10.20.33.1') self.assertRegex(output, '10.20.33.0/24 proto kernel scope link src 10.20.33.1') self.assertRegex(output, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1') self.assertRegex(output, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1') self.assertRegex(output, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1') - self.assertRegex(output, 'broadcast 10.20.55.0 proto kernel scope link src 10.20.55.1') self.assertRegex(output, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1') self.assertRegex(output, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1') output = check_output('ip -6 route show table 42 dev dummy98') @@ -2040,11 +2038,9 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): print('### ip route show table local dev test1') print(output) self.assertRegex(output, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1') - self.assertRegex(output, 'broadcast 10.21.33.0 proto kernel scope link src 10.21.33.1') self.assertRegex(output, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1') self.assertRegex(output, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1') self.assertRegex(output, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1') - self.assertRegex(output, 'broadcast 10.21.55.0 proto kernel scope link src 10.21.55.1') self.assertRegex(output, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1') self.assertRegex(output, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1') output = check_output('ip -6 route show dev test1') diff --git a/test/testsuite-10.units/test10.service b/test/testsuite-10.units/test10.service index d0be786b0..2fb476b98 100644 --- a/test/testsuite-10.units/test10.service +++ b/test/testsuite-10.units/test10.service @@ -1,6 +1,9 @@ [Unit] Requires=test10.socket ConditionPathExistsGlob=/tmp/nonexistent +# Make sure we hit the socket trigger limit in the test and not the service start limit. +StartLimitInterval=1000 +StartLimitBurst=1000 [Service] ExecStart=true diff --git a/test/testsuite-63.units/test63.path b/test/testsuite-63.units/test63.path new file mode 100644 index 000000000..a6573bda0 --- /dev/null +++ b/test/testsuite-63.units/test63.path @@ -0,0 +1,2 @@ +[Path] +PathExists=/tmp/test63 diff --git a/test/testsuite-63.units/test63.service b/test/testsuite-63.units/test63.service new file mode 100644 index 000000000..c83801874 --- /dev/null +++ b/test/testsuite-63.units/test63.service @@ -0,0 +1,5 @@ +[Unit] +ConditionPathExists=!/tmp/nonexistent + +[Service] +ExecStart=true diff --git a/test/units/testsuite-23.sh b/test/units/testsuite-23.sh index 4ef7c878a..5488447a8 100755 --- a/test/units/testsuite-23.sh +++ b/test/units/testsuite-23.sh @@ -27,6 +27,37 @@ test "$(systemctl show --value -p RestartKillSignal seven.service)" -eq 2 systemctl restart seven.service systemctl stop seven.service +# For issue #20933 + +# Should work normally +busctl call \ + org.freedesktop.systemd1 /org/freedesktop/systemd1 \ + org.freedesktop.systemd1.Manager StartTransientUnit \ + "ssa(sv)a(sa(sv))" test-20933-ok.service replace 1 \ + ExecStart "a(sasb)" 1 \ + /usr/bin/sleep 2 /usr/bin/sleep 1 true \ + 0 + +# DBus call should fail but not crash systemd +busctl call \ + org.freedesktop.systemd1 /org/freedesktop/systemd1 \ + org.freedesktop.systemd1.Manager StartTransientUnit \ + "ssa(sv)a(sa(sv))" test-20933-bad.service replace 1 \ + ExecStart "a(sasb)" 1 \ + /usr/bin/sleep 0 true \ + 0 && { echo 'unexpected success'; exit 1; } + +# Same but with the empty argv in the middle +busctl call \ + org.freedesktop.systemd1 /org/freedesktop/systemd1 \ + org.freedesktop.systemd1.Manager StartTransientUnit \ + "ssa(sv)a(sa(sv))" test-20933-bad-middle.service replace 1 \ + ExecStart "a(sasb)" 3 \ + /usr/bin/sleep 2 /usr/bin/sleep 1 true \ + /usr/bin/sleep 0 true \ + /usr/bin/sleep 2 /usr/bin/sleep 1 true \ + 0 && { echo 'unexpected success'; exit 1; } + systemd-analyze log-level info echo OK >/testok diff --git a/test/units/testsuite-63.service b/test/units/testsuite-63.service new file mode 100644 index 000000000..04122723d --- /dev/null +++ b/test/units/testsuite-63.service @@ -0,0 +1,16 @@ +[Unit] +Description=TEST-63-ISSUE-17433 + +[Service] +ExecStartPre=rm -f /failed /testok +Type=oneshot +ExecStart=rm -f /tmp/nonexistent +ExecStart=systemctl start test63.path +ExecStart=touch /tmp/test63 +# Make sure systemd has sufficient time to hit the start limit for test63.service. +ExecStart=sleep 2 +ExecStart=sh -x -c 'test "$(systemctl show test63.service -P ActiveState)" = failed' +ExecStart=sh -x -c 'test "$(systemctl show test63.service -P Result)" = start-limit-hit' +ExecStart=sh -x -c 'test "$(systemctl show test63.path -P ActiveState)" = failed' +ExecStart=sh -x -c 'test "$(systemctl show test63.path -P Result)" = unit-start-limit-hit' +ExecStart=sh -x -c 'echo OK >/testok' diff --git a/units/systemd-homed.service.in b/units/systemd-homed.service.in index 0576f8469..f8198c45b 100644 --- a/units/systemd-homed.service.in +++ b/units/systemd-homed.service.in @@ -16,19 +16,18 @@ After=home.mount [Service] BusName=org.freedesktop.home1 -CapabilityBoundingSet=CAP_SYS_ADMIN CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER CAP_FSETID CAP_SETGID CAP_SETUID CAP_SYS_RESOURCE +CapabilityBoundingSet=CAP_SYS_ADMIN CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER CAP_FSETID CAP_SETGID CAP_SETUID CAP_SYS_RESOURCE CAP_SETPCAP CAP_DAC_READ_SEARCH DeviceAllow=/dev/loop-control rw DeviceAllow=/dev/mapper/control rw DeviceAllow=block-* rw DeviceAllow=char-hidraw rw ExecStart={{ROOTLIBEXECDIR}}/systemd-homed -IPAddressDeny=any KillMode=mixed LimitNOFILE={{HIGH_RLIMIT_NOFILE}} LockPersonality=yes MemoryDenyWriteExecute=yes NoNewPrivileges=yes -RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_ALG +RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_ALG AF_INET AF_INET6 RestrictNamespaces=mnt RestrictRealtime=yes StateDirectory=systemd/home diff --git a/units/systemd-oomd.service.in b/units/systemd-oomd.service.in index 0d2d40988..44f71c9e3 100644 --- a/units/systemd-oomd.service.in +++ b/units/systemd-oomd.service.in @@ -14,6 +14,7 @@ DefaultDependencies=no Before=multi-user.target shutdown.target Conflicts=shutdown.target ConditionControlGroupController=v2 +ConditionControlGroupController=memory ConditionPathExists=/proc/pressure/cpu ConditionPathExists=/proc/pressure/io ConditionPathExists=/proc/pressure/memory