import systemd-239-36.el8

This commit is contained in:
CentOS Sources 2020-07-28 10:08:58 -04:00 committed by Stepan Oksanichenko
parent 22bbbfe74c
commit 010588050b
135 changed files with 18264 additions and 8 deletions

View File

@ -0,0 +1,531 @@
From c3513c7bcc27210c89edad1740e1190e693df86f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Mon, 15 Oct 2018 22:41:49 +0200
Subject: [PATCH] catalog: fix name of variable
All the messages would (literally) say "The start-up result is RESULT."
because @RESULT@ was not defined.
Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1639482
and the first part of #8005.
Fixup for 646cc98dc81c4d0edbc1b57e7bca0f474b47e270.
(cherry picked from commit 65d51875c2a7b27b61de090f1bd6311b0cef2016)
Resolves: #1677768
---
catalog/systemd.be.catalog.in | 6 +++---
catalog/systemd.be@latin.catalog.in | 6 +++---
catalog/systemd.bg.catalog.in | 6 +++---
catalog/systemd.catalog.in | 6 +++---
catalog/systemd.da.catalog.in | 6 +++---
catalog/systemd.fr.catalog.in | 6 +++---
catalog/systemd.hr.catalog.in | 6 +++---
catalog/systemd.hu.catalog.in | 6 +++---
catalog/systemd.it.catalog.in | 6 +++---
catalog/systemd.ko.catalog.in | 6 +++---
catalog/systemd.pl.catalog.in | 6 +++---
catalog/systemd.pt_BR.catalog.in | 6 +++---
catalog/systemd.ru.catalog.in | 6 +++---
catalog/systemd.sr.catalog.in | 6 +++---
catalog/systemd.zh_CN.catalog.in | 6 +++---
catalog/systemd.zh_TW.catalog.in | 6 +++---
16 files changed, 48 insertions(+), 48 deletions(-)
diff --git a/catalog/systemd.be.catalog.in b/catalog/systemd.be.catalog.in
index 5011ea268d..2c59898683 100644
--- a/catalog/systemd.be.catalog.in
+++ b/catalog/systemd.be.catalog.in
@@ -175,7 +175,7 @@ Support: %SUPPORT_URL%
Працэс запуску юніта @UNIT@ завершаны.
-Вынік: @RESULT@.
+Вынік: @JOB_RESULT@.
-- de5b426a63be47a7b6ac3eaac82e2f6f
Subject: Юніт @UNIT@ спыняецца
@@ -198,7 +198,7 @@ Support: %SUPPORT_URL%
Збой юніта @UNIT@.
-Вынік: @RESULT@.
+Вынік: @JOB_RESULT@.
-- d34d037fff1847e6ae669a370e694725
Subject: Юніт @UNIT@ перачытвае сваю канфігурацыю
@@ -214,7 +214,7 @@ Support: %SUPPORT_URL%
Юніт @UNIT@ перачытаў сваю канфігурацыю.
-Вынік: @RESULT@.
+Вынік: @JOB_RESULT@.
-- 641257651c1b4ec9a8624d7a40a9e1e7
Subject: Працэс @EXECUTABLE@ не можа быць выкананы
diff --git a/catalog/systemd.be@latin.catalog.in b/catalog/systemd.be@latin.catalog.in
index 6a8b092669..1d024fea12 100644
--- a/catalog/systemd.be@latin.catalog.in
+++ b/catalog/systemd.be@latin.catalog.in
@@ -178,7 +178,7 @@ Support: %SUPPORT_URL%
Praces zapusku junita @UNIT@ zavieršany.
-Vynik: @RESULT@.
+Vynik: @JOB_RESULT@.
-- de5b426a63be47a7b6ac3eaac82e2f6f
Subject: Junit @UNIT@ spyniajecca
@@ -201,7 +201,7 @@ Support: %SUPPORT_URL%
Zboj junita @UNIT@.
-Vynik: @RESULT@.
+Vynik: @JOB_RESULT@.
-- d34d037fff1847e6ae669a370e694725
Subject: Junit @UNIT@ pieračytvaje svaju kanfihuracyju
@@ -217,7 +217,7 @@ Support: %SUPPORT_URL%
Junit @UNIT@ pieračytaŭ svaju kanfihuracyju.
-Vynik: @RESULT@.
+Vynik: @JOB_RESULT@.
-- 641257651c1b4ec9a8624d7a40a9e1e7
Subject: Praces @EXECUTABLE@ nie moža być vykanany
diff --git a/catalog/systemd.bg.catalog.in b/catalog/systemd.bg.catalog.in
index 64d616f381..41f7b21bce 100644
--- a/catalog/systemd.bg.catalog.in
+++ b/catalog/systemd.bg.catalog.in
@@ -178,7 +178,7 @@ Support: %SUPPORT_URL%
Стартирането на модул „@UNIT@“ завърши.
-Резултатът е: @RESULT@
+Резултатът е: @JOB_RESULT@
-- de5b426a63be47a7b6ac3eaac82e2f6f
Subject: Модул „@UNIT@“ се спира
@@ -201,7 +201,7 @@ Support: %SUPPORT_URL%
Модулът „@UNIT@“ не успя да стартира.
-Резултатът е: @RESULT@
+Резултатът е: @JOB_RESULT@
-- d34d037fff1847e6ae669a370e694725
Subject: Модулът „@UNIT@“ започна презареждане на настройките си
@@ -217,7 +217,7 @@ Support: %SUPPORT_URL%
Модулът „@UNIT@“ завърши презареждането на настройките си.
-Резултатът e: @RESULT@
+Резултатът e: @JOB_RESULT@
-- 641257651c1b4ec9a8624d7a40a9e1e7
Subject: Програмата „@EXECUTABLE@“ не успя да се стартира
diff --git a/catalog/systemd.catalog.in b/catalog/systemd.catalog.in
index 8234e387cf..49a45890f6 100644
--- a/catalog/systemd.catalog.in
+++ b/catalog/systemd.catalog.in
@@ -202,7 +202,7 @@ Support: %SUPPORT_URL%
Unit @UNIT@ has finished starting up.
-The start-up result is @RESULT@.
+The start-up result is @JOB_RESULT@.
-- de5b426a63be47a7b6ac3eaac82e2f6f
Subject: Unit @UNIT@ has begun shutting down
@@ -225,7 +225,7 @@ Support: %SUPPORT_URL%
Unit @UNIT@ has failed.
-The result is @RESULT@.
+The result is @JOB_RESULT@.
-- d34d037fff1847e6ae669a370e694725
Subject: Unit @UNIT@ has begun reloading its configuration
@@ -241,7 +241,7 @@ Support: %SUPPORT_URL%
Unit @UNIT@ has finished reloading its configuration
-The result is @RESULT@.
+The result is @JOB_RESULT@.
-- 641257651c1b4ec9a8624d7a40a9e1e7
Subject: Process @EXECUTABLE@ could not be executed
diff --git a/catalog/systemd.da.catalog.in b/catalog/systemd.da.catalog.in
index 4e2bec8a0f..aecfafa05f 100644
--- a/catalog/systemd.da.catalog.in
+++ b/catalog/systemd.da.catalog.in
@@ -159,7 +159,7 @@ Support: %SUPPORT_URL%
Enhed @UNIT@ er færdig med at starte op.
-Resultat for opstart er @RESULT@.
+Resultat for opstart er @JOB_RESULT@.
-- de5b426a63be47a7b6ac3eaac82e2f6f
Subject: Enhed @UNIT@ har påbegyndt nedlukning
@@ -182,7 +182,7 @@ Support: %SUPPORT_URL%
Enhed @UNIT@ har fejlet.
-Resultatet er @RESULT@
+Resultatet er @JOB_RESULT@
-- d34d037fff1847e6ae669a370e694725
Subject: Enhed @UNIT@ har påbegyndt genindlæsning af sin konfiguration
@@ -198,7 +198,7 @@ Support: %SUPPORT_URL%
Enhed @UNIT@ er færdig med at genindlæse sin konfiguration
-Resultatet er: @RESULT@.
+Resultatet er: @JOB_RESULT@.
-- 641257651c1b4ec9a8624d7a40a9e1e7
Subject: Process @EXECUTABLE@ kunne ikke eksekveres
diff --git a/catalog/systemd.fr.catalog.in b/catalog/systemd.fr.catalog.in
index 156b1a37dc..13edd083cb 100644
--- a/catalog/systemd.fr.catalog.in
+++ b/catalog/systemd.fr.catalog.in
@@ -191,7 +191,7 @@ Subject: L'unité (unit) @UNIT@ a terminé son démarrage
Defined-By: systemd
Support: %SUPPORT_URL%
-L'unité (unit) @UNIT@ a terminé son démarrage, avec le résultat @RESULT@.
+L'unité (unit) @UNIT@ a terminé son démarrage, avec le résultat @JOB_RESULT@.
-- de5b426a63be47a7b6ac3eaac82e2f6f
Subject: L'unité (unit) @UNIT@ a commencé à s'arrêter
@@ -212,7 +212,7 @@ Subject: L'unité (unit) @UNIT@ a échoué
Defined-By: systemd
Support: %SUPPORT_URL%
-L'unité (unit) @UNIT@ a échoué, avec le résultat @RESULT@.
+L'unité (unit) @UNIT@ a échoué, avec le résultat @JOB_RESULT@.
-- d34d037fff1847e6ae669a370e694725
Subject: L'unité (unit) @UNIT@ a commencé à recharger sa configuration
@@ -227,7 +227,7 @@ Defined-By: systemd
Support: %SUPPORT_URL%
L'unité (unit) @UNIT@ a terminé de recharger configuration,
-avec le résultat @RESULT@.
+avec le résultat @JOB_RESULT@.
-- 641257651c1b4ec9a8624d7a40a9e1e7
Subject: Le processus @EXECUTABLE@ n'a pas pu être exécuté
diff --git a/catalog/systemd.hr.catalog.in b/catalog/systemd.hr.catalog.in
index c4808b4c7d..4526ae2a8c 100644
--- a/catalog/systemd.hr.catalog.in
+++ b/catalog/systemd.hr.catalog.in
@@ -173,7 +173,7 @@ Support: %SUPPORT_URL%
Jedinica @UNIT@ je završila pokretanje.
-Rezultat pokretanja je @RESULT@.
+Rezultat pokretanja je @JOB_RESULT@.
-- de5b426a63be47a7b6ac3eaac82e2f6f
Subject: Jedinica @UNIT@ je započela isključivanje
@@ -196,7 +196,7 @@ Support: %SUPPORT_URL%
Jedinica @UNIT@ nije uspjela.
-Rezultat je @RESULT@.
+Rezultat je @JOB_RESULT@.
-- d34d037fff1847e6ae669a370e694725
Subject: Jedinica @UNIT@ je započela ponovno učitavati podešavanja
@@ -212,7 +212,7 @@ Support: %SUPPORT_URL%
Jedinica @UNIT@ je završila ponovno učitavati podešavanja
-Rezultat je @RESULT@.
+Rezultat je @JOB_RESULT@.
-- 641257651c1b4ec9a8624d7a40a9e1e7
Subject: Proces @EXECUTABLE@ se ne može pokrenuti
diff --git a/catalog/systemd.hu.catalog.in b/catalog/systemd.hu.catalog.in
index 6c6d7e7934..5565b80b2a 100644
--- a/catalog/systemd.hu.catalog.in
+++ b/catalog/systemd.hu.catalog.in
@@ -161,7 +161,7 @@ Support: %SUPPORT_URL%
A(z) @UNIT@ egység befejezte az indulást
-Az indítás eredménye: @RESULT@.
+Az indítás eredménye: @JOB_RESULT@.
-- de5b426a63be47a7b6ac3eaac82e2f6f
Subject: A(z) @UNIT@ egység megkezdte a leállást
@@ -184,7 +184,7 @@ Support: %SUPPORT_URL%
A(z) @UNIT@ egység hibát jelzett.
-Az eredmény: @RESULT@.
+Az eredmény: @JOB_RESULT@.
-- d34d037fff1847e6ae669a370e694725
Subject: A(z) @UNIT@ egység megkezdte a beállításainak újratöltését
@@ -200,7 +200,7 @@ Support: %SUPPORT_URL%
A(z) @UNIT@ egység befejezte a beállításainak újratöltését.
-Az eredmény: @RESULT@.
+Az eredmény: @JOB_RESULT@.
-- 641257651c1b4ec9a8624d7a40a9e1e7
Subject: A folyamat végrehajtása sikertelen: @EXECUTABLE@
diff --git a/catalog/systemd.it.catalog.in b/catalog/systemd.it.catalog.in
index 4fd1f2a933..8ce4fa5d92 100644
--- a/catalog/systemd.it.catalog.in
+++ b/catalog/systemd.it.catalog.in
@@ -191,7 +191,7 @@ Support: %SUPPORT_URL%
L'unità @UNIT@ ha terminato la fase di avvio.
-La fase di avvio è @RESULT@.
+La fase di avvio è @JOB_RESULT@.
-- de5b426a63be47a7b6ac3eaac82e2f6f
Subject: L'unità @UNIT@ inizia la fase di spegnimento
@@ -214,7 +214,7 @@ Support: %SUPPORT_URL%
L'unità @UNIT@ è fallita.
-Il risultato è @RESULT@.
+Il risultato è @JOB_RESULT@.
-- d34d037fff1847e6ae669a370e694725
Subject: L'unità @UNIT@ inizia a caricare la propria configurazione
@@ -230,7 +230,7 @@ Support: %SUPPORT_URL%
L'unità @UNIT@ è terminata ricaricando la propria configurazione
-Il risultato è @RESULT@.
+Il risultato è @JOB_RESULT@.
-- 641257651c1b4ec9a8624d7a40a9e1e7
Subject: Il processo @EXECUTABLE@ non può essere eseguito
diff --git a/catalog/systemd.ko.catalog.in b/catalog/systemd.ko.catalog.in
index fc0faad02c..59fbde8b62 100644
--- a/catalog/systemd.ko.catalog.in
+++ b/catalog/systemd.ko.catalog.in
@@ -182,7 +182,7 @@ Support: %SUPPORT_URL%
@UNIT@ 유닛 시동을 마쳤습니다.
-시동 결과는 @RESULT@ 입니다.
+시동 결과는 @JOB_RESULT@ 입니다.
-- de5b426a63be47a7b6ac3eaac82e2f6f
Subject: @UNIT@ 유닛 끝내기 동작 시작
@@ -205,7 +205,7 @@ Support: %SUPPORT_URL%
@UNIT@ 유닛 동작에 실패했습니다.
-결과는 @RESULT@ 입니다.
+결과는 @JOB_RESULT@ 입니다.
-- d34d037fff1847e6ae669a370e694725
Subject: @UNIT@ 유닛 설정 다시 읽기 시작
@@ -221,7 +221,7 @@ Support: %SUPPORT_URL%
@UNIT@ 유닛의 설정 다시 읽기 동작을 끝냈습니다.
-결과는 @RESULT@ 입니다.
+결과는 @JOB_RESULT@ 입니다.
-- 641257651c1b4ec9a8624d7a40a9e1e7
Subject: @EXECUTABLE@ 프로세스 시작할 수 없음
diff --git a/catalog/systemd.pl.catalog.in b/catalog/systemd.pl.catalog.in
index 998894bd0a..b73f56ca11 100644
--- a/catalog/systemd.pl.catalog.in
+++ b/catalog/systemd.pl.catalog.in
@@ -201,7 +201,7 @@ Support: %SUPPORT_URL%
Jednostka @UNIT@ ukończyła uruchamianie.
-Wynik uruchamiania: @RESULT@.
+Wynik uruchamiania: @JOB_RESULT@.
-- de5b426a63be47a7b6ac3eaac82e2f6f
Subject: Rozpoczęto wyłączanie jednostki @UNIT@
@@ -224,7 +224,7 @@ Support: %SUPPORT_URL%
Jednostka @UNIT@ się nie powiodła.
-Wynik: @RESULT@.
+Wynik: @JOB_RESULT@.
-- d34d037fff1847e6ae669a370e694725
Subject: Rozpoczęto ponowne wczytywanie konfiguracji jednostki @UNIT@
@@ -240,7 +240,7 @@ Support: %SUPPORT_URL%
Jednostka @UNIT@ ukończyła ponowne wczytywanie swojej konfiguracji.
-Wynik: @RESULT@.
+Wynik: @JOB_RESULT@.
-- 641257651c1b4ec9a8624d7a40a9e1e7
Subject: Nie można wykonać procesu @EXECUTABLE@
diff --git a/catalog/systemd.pt_BR.catalog.in b/catalog/systemd.pt_BR.catalog.in
index db1cb03198..edaefb7164 100644
--- a/catalog/systemd.pt_BR.catalog.in
+++ b/catalog/systemd.pt_BR.catalog.in
@@ -162,7 +162,7 @@ Support: %SUPPORT_URL%
A unidade @UNIT@ concluiu a inicialização.
-The start-up result is @RESULT@.
+The start-up result is @JOB_RESULT@.
-- de5b426a63be47a7b6ac3eaac82e2f6f
Subject: Unidade @UNIT@ sendo desligado
@@ -185,7 +185,7 @@ Support: %SUPPORT_URL%
A unidade @UNIT@ falhou.
-O resultado é @RESULT@.
+O resultado é @JOB_RESULT@.
-- d34d037fff1847e6ae669a370e694725
Subject: Unidade @UNIT@ iniciou recarregamento de sua configuração
@@ -201,7 +201,7 @@ Support: %SUPPORT_URL%
A unidade @UNIT@ concluiu o recarregamento de sua configuração.
-O resultado é @RESULT@.
+O resultado é @JOB_RESULT@.
-- 641257651c1b4ec9a8624d7a40a9e1e7
Subject: Processo @EXECUTABLE@ não pôde ser executado
diff --git a/catalog/systemd.ru.catalog.in b/catalog/systemd.ru.catalog.in
index 645edaa922..ccdc685037 100644
--- a/catalog/systemd.ru.catalog.in
+++ b/catalog/systemd.ru.catalog.in
@@ -227,7 +227,7 @@ Support: %SUPPORT_URL%
Процесс запуска юнита @UNIT@ был завершен.
-Результат: @RESULT@.
+Результат: @JOB_RESULT@.
# Subject: Unit @UNIT@ has begun shutting down
-- de5b426a63be47a7b6ac3eaac82e2f6f
@@ -253,7 +253,7 @@ Support: %SUPPORT_URL%
Произошел сбой юнита @UNIT@.
-Результат: @RESULT@.
+Результат: @JOB_RESULT@.
# Subject: Unit @UNIT@ has begun with reloading its configuration
-- d34d037fff1847e6ae669a370e694725
@@ -271,7 +271,7 @@ Support: %SUPPORT_URL%
Юнит @UNIT@ завершил процесс перечитывания своей конфигурации.
-Результат: @RESULT@.
+Результат: @JOB_RESULT@.
# Subject: Process @EXECUTABLE@ could not be executed
-- 641257651c1b4ec9a8624d7a40a9e1e7
diff --git a/catalog/systemd.sr.catalog.in b/catalog/systemd.sr.catalog.in
index f5746715a4..7cb6546d43 100644
--- a/catalog/systemd.sr.catalog.in
+++ b/catalog/systemd.sr.catalog.in
@@ -158,7 +158,7 @@ Support: %SUPPORT_URL%
Јединица @UNIT@ је завршила са покретањем.
-Исход покретања је @RESULT@.
+Исход покретања је @JOB_RESULT@.
-- de5b426a63be47a7b6ac3eaac82e2f6f
Subject: Јединица @UNIT@ је почела са гашењем
@@ -181,7 +181,7 @@ Support: %SUPPORT_URL%
Јединица @UNIT@ је пукла.
-Исход је @RESULT@.
+Исход је @JOB_RESULT@.
-- d34d037fff1847e6ae669a370e694725
Subject: Јединица @UNIT@ је почела са поновним учитавањем свог подешавања
@@ -197,7 +197,7 @@ Support: %SUPPORT_URL%
Јединица @UNIT@ је завршила са поновним учитавањем свог подешавања
-Исход је @RESULT@.
+Исход је @JOB_RESULT@.
-- 641257651c1b4ec9a8624d7a40a9e1e7
Subject: Процес @EXECUTABLE@ није могао бити извршен
diff --git a/catalog/systemd.zh_CN.catalog.in b/catalog/systemd.zh_CN.catalog.in
index fa58448acf..d6ac2592b8 100644
--- a/catalog/systemd.zh_CN.catalog.in
+++ b/catalog/systemd.zh_CN.catalog.in
@@ -156,7 +156,7 @@ Support: %SUPPORT_URL%
@UNIT@ 单元已结束启动。
-启动结果为“@RESULT@”。
+启动结果为“@JOB_RESULT@”。
-- de5b426a63be47a7b6ac3eaac82e2f6f
Subject: @UNIT@ 单元已开始停止操作
@@ -179,7 +179,7 @@ Support: %SUPPORT_URL%
@UNIT@ 单元已失败。
-结果为“@RESULT@”。
+结果为“@JOB_RESULT@”。
-- d34d037fff1847e6ae669a370e694725
Subject: @UNIT@ 单元已开始重新载入其配置
@@ -195,7 +195,7 @@ Support: %SUPPORT_URL%
@UNIT@ 单元已结束配置重载入操作。
-结果为“@RESULT@”。
+结果为“@JOB_RESULT@”。
-- 641257651c1b4ec9a8624d7a40a9e1e7
Subject: 进程 @EXECUTABLE@ 无法执行
diff --git a/catalog/systemd.zh_TW.catalog.in b/catalog/systemd.zh_TW.catalog.in
index 17bd2bc9af..a468c2f6bf 100644
--- a/catalog/systemd.zh_TW.catalog.in
+++ b/catalog/systemd.zh_TW.catalog.in
@@ -160,7 +160,7 @@ Support: %SUPPORT_URL%
單位 @UNIT@ 啟動已結束。
-啟動結果為 @RESULT@。
+啟動結果為 @JOB_RESULT@。
-- de5b426a63be47a7b6ac3eaac82e2f6f
Subject: 單位 @UNIT@ 已開始關閉
@@ -183,7 +183,7 @@ Support: %SUPPORT_URL%
單位 @UNIT@ 已失敗。
-結果為 @RESULT@。
+結果為 @JOB_RESULT@。
-- d34d037fff1847e6ae669a370e694725
Subject: 單位 @UNIT@ 已開始重新載入其設定
@@ -199,7 +199,7 @@ Support: %SUPPORT_URL%
單位 @UNIT@ 已結束重新載入其設定
-結果為 @RESULT@。
+結果為 @JOB_RESULT@。
-- 641257651c1b4ec9a8624d7a40a9e1e7
Subject: 行程 @EXECUTABLE@ 無法執行

View File

@ -0,0 +1,273 @@
From 0f7a4f49a7ce95e87061afe03ac40662a1eb0e2d Mon Sep 17 00:00:00 2001
From: shinygold <10763595+shinygold@users.noreply.github.com>
Date: Tue, 16 Jul 2019 13:06:16 +0200
Subject: [PATCH] cryptsetup: add keyfile-timeout to allow a keydev timeout and
allow to fallback to a password if it fails.
(cherry picked from commit 50d2eba27b9bfc77ef6b40e5721713846815418b)
Resolves: #1763155
---
src/cryptsetup/cryptsetup-generator.c | 119 ++++++++++++++++++--------
src/cryptsetup/cryptsetup.c | 5 +-
2 files changed, 89 insertions(+), 35 deletions(-)
diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
index 52c1262728..1e8e3ba00d 100644
--- a/src/cryptsetup/cryptsetup-generator.c
+++ b/src/cryptsetup/cryptsetup-generator.c
@@ -40,10 +40,39 @@ static Hashmap *arg_disks = NULL;
static char *arg_default_options = NULL;
static char *arg_default_keyfile = NULL;
-static int generate_keydev_mount(const char *name, const char *keydev, char **unit, char **mount) {
- _cleanup_free_ char *u = NULL, *what = NULL, *where = NULL, *name_escaped = NULL;
+static int split_keyspec(const char *keyspec, char **keyfile, char **keydev) {
+ _cleanup_free_ char *kfile = NULL, *kdev = NULL;
+ char *c;
+
+ assert(keyspec);
+ assert(keyfile);
+ assert(keydev);
+
+ c = strrchr(keyspec, ':');
+ if (c) {
+ kfile = strndup(keyspec, c-keyspec);
+ kdev = strdup(c + 1);
+ if (!*kfile || !*kdev)
+ return log_oom();
+ } else {
+ /* No keydev specified */
+ kfile = strdup(keyspec);
+ kdev = NULL;
+ if (!*kfile)
+ return log_oom();
+ }
+
+ *keyfile = TAKE_PTR(kfile);
+ *keydev = TAKE_PTR(kdev);
+
+ return 0;
+}
+
+static int generate_keydev_mount(const char *name, const char *keydev, const char *keydev_timeout, bool canfail, char **unit, char **mount) {
+ _cleanup_free_ char *u = NULL, *what = NULL, *where = NULL, *name_escaped = NULL, *device_unit = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
+ usec_t timeout_us;
assert(name);
assert(keydev);
@@ -88,7 +117,25 @@ static int generate_keydev_mount(const char *name, const char *keydev, char **un
"[Mount]\n"
"What=%s\n"
"Where=%s\n"
- "Options=ro\n", what, where);
+ "Options=ro%s\n", what, where, canfail ? ",nofail" : "");
+
+ if (keydev_timeout) {
+ r = parse_sec_fix_0(keydev_timeout, &timeout_us);
+ if (r >= 0) {
+ r = unit_name_from_path(what, ".device", &device_unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate unit name: %m");
+
+ r = write_drop_in_format(arg_dest, device_unit, 90, "device-timeout",
+ "# Automatically generated by systemd-cryptsetup-generator \n\n"
+ "[Unit]\nJobRunningTimeoutSec=%s", keydev_timeout);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write device drop-in: %m");
+
+ } else
+ log_warning_errno(r, "Failed to parse %s, ignoring: %m", keydev_timeout);
+
+ }
r = fflush_and_check(f);
if (r < 0)
@@ -103,16 +150,17 @@ static int generate_keydev_mount(const char *name, const char *keydev, char **un
static int create_disk(
const char *name,
const char *device,
- const char *keydev,
const char *password,
+ const char *keydev,
const char *options) {
_cleanup_free_ char *n = NULL, *d = NULL, *u = NULL, *e = NULL,
- *filtered = NULL, *u_escaped = NULL, *password_escaped = NULL, *filtered_escaped = NULL, *name_escaped = NULL, *keydev_mount = NULL;
+ *keydev_mount = NULL, *keyfile_timeout_value = NULL, *password_escaped = NULL,
+ *filtered = NULL, *u_escaped = NULL, *filtered_escaped = NULL, *name_escaped = NULL;
_cleanup_fclose_ FILE *f = NULL;
const char *dmname;
bool noauto, nofail, tmp, swap, netdev;
- int r;
+ int r, keyfile_can_timeout;
assert(name);
assert(device);
@@ -123,6 +171,10 @@ static int create_disk(
swap = fstab_test_option(options, "swap\0");
netdev = fstab_test_option(options, "_netdev\0");
+ keyfile_can_timeout = fstab_filter_options(options, "keyfile-timeout\0", NULL, &keyfile_timeout_value, NULL);
+ if (keyfile_can_timeout < 0)
+ return log_error_errno(keyfile_can_timeout, "Failed to parse keyfile-timeout= option value: %m");
+
if (tmp && swap) {
log_error("Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.", name);
return -EINVAL;
@@ -152,12 +204,6 @@ static int create_disk(
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
- if (password) {
- password_escaped = specifier_escape(password);
- if (!password_escaped)
- return log_oom();
- }
-
if (keydev && !password) {
log_error("Key device is specified, but path to the password file is missing.");
return -EINVAL;
@@ -178,10 +224,16 @@ static int create_disk(
"After=%s\n",
netdev ? "remote-fs-pre.target" : "cryptsetup-pre.target");
+ if (password) {
+ password_escaped = specifier_escape(password);
+ if (!password_escaped)
+ return log_oom();
+ }
+
if (keydev) {
_cleanup_free_ char *unit = NULL, *p = NULL;
- r = generate_keydev_mount(name, keydev, &unit, &keydev_mount);
+ r = generate_keydev_mount(name, keydev, keyfile_timeout_value, keyfile_can_timeout > 0, &unit, &keydev_mount);
if (r < 0)
return log_error_errno(r, "Failed to generate keydev mount unit: %m");
@@ -190,6 +242,12 @@ static int create_disk(
return log_oom();
free_and_replace(password_escaped, p);
+
+ fprintf(f, "After=%s\n", unit);
+ if (keyfile_can_timeout > 0)
+ fprintf(f, "Wants=%s\n", unit);
+ else
+ fprintf(f, "Requires=%s\n", unit);
}
if (!nofail)
@@ -197,7 +255,7 @@ static int create_disk(
"Before=%s\n",
netdev ? "remote-cryptsetup.target" : "cryptsetup.target");
- if (password) {
+ if (password && !keydev) {
if (STR_IN_SET(password, "/dev/urandom", "/dev/random", "/dev/hw_random"))
fputs("After=systemd-random-seed.service\n", f);
else if (!STR_IN_SET(password, "-", "none")) {
@@ -271,7 +329,7 @@ static int create_disk(
if (keydev)
fprintf(f,
- "ExecStartPost=" UMOUNT_PATH " %s\n\n",
+ "ExecStartPost=-" UMOUNT_PATH " %s\n\n",
keydev_mount);
r = fflush_and_check(f);
@@ -394,7 +452,6 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
} else if (streq(key, "luks.key")) {
size_t n;
_cleanup_free_ char *keyfile = NULL, *keydev = NULL;
- char *c;
const char *keyspec;
if (proc_cmdline_value_missing(key, value))
@@ -421,23 +478,13 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
return log_oom();
keyspec = value + n + 1;
- c = strrchr(keyspec, ':');
- if (c) {
- *c = '\0';
- keyfile = strdup(keyspec);
- keydev = strdup(c + 1);
-
- if (!keyfile || !keydev)
- return log_oom();
- } else {
- /* No keydev specified */
- keyfile = strdup(keyspec);
- if (!keyfile)
- return log_oom();
- }
+ r = split_keyspec(keyspec, &keyfile, &keydev);
+ if (r < 0)
+ return r;
free_and_replace(d->keyfile, keyfile);
free_and_replace(d->keydev, keydev);
+
} else if (streq(key, "luks.name")) {
if (proc_cmdline_value_missing(key, value))
@@ -485,7 +532,7 @@ static int add_crypttab_devices(void) {
int r, k;
char line[LINE_MAX], *l, *uuid;
crypto_device *d = NULL;
- _cleanup_free_ char *name = NULL, *device = NULL, *keyfile = NULL, *options = NULL;
+ _cleanup_free_ char *name = NULL, *device = NULL, *keydev = NULL, *keyfile = NULL, *keyspec = NULL, *options = NULL;
if (!fgets(line, sizeof(line), f))
break;
@@ -496,7 +543,7 @@ static int add_crypttab_devices(void) {
if (IN_SET(*l, 0, '#'))
continue;
- k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &keyfile, &options);
+ k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &keyspec, &options);
if (k < 2 || k > 4) {
log_error("Failed to parse /etc/crypttab:%u, ignoring.", crypttab_line);
continue;
@@ -515,7 +562,11 @@ static int add_crypttab_devices(void) {
continue;
}
- r = create_disk(name, device, NULL, keyfile, (d && d->options) ? d->options : options);
+ r = split_keyspec(keyspec, &keyfile, &keydev);
+ if (r < 0)
+ return r;
+
+ r = create_disk(name, device, keyfile, keydev, (d && d->options) ? d->options : options);
if (r < 0)
return r;
@@ -555,7 +606,7 @@ static int add_proc_cmdline_devices(void) {
else
options = "timeout=0";
- r = create_disk(d->name, device, d->keydev, d->keyfile ?: arg_default_keyfile, options);
+ r = create_disk(d->name, device, d->keyfile ?: arg_default_keyfile, d->keydev, options);
if (r < 0)
return r;
}
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 9071126c2e..0881aea915 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -69,7 +69,10 @@ static int parse_one_option(const char *option) {
assert(option);
/* Handled outside of this tool */
- if (STR_IN_SET(option, "noauto", "auto", "nofail", "fail", "_netdev"))
+ if (STR_IN_SET(option, "noauto", "auto", "nofail", "fail", "_netdev", "keyfile-timeout"))
+ return 0;
+
+ if (startswith(option, "keyfile-timeout="))
return 0;
if ((val = startswith(option, "cipher="))) {

View File

@ -0,0 +1,44 @@
From fdb86185b56619c59602c6546fd0710eec4a6e85 Mon Sep 17 00:00:00 2001
From: shinygold <10763595+shinygold@users.noreply.github.com>
Date: Tue, 16 Jul 2019 13:05:34 +0200
Subject: [PATCH] cryptsetup: add documentation for keyfile-timeout
(cherry picked from commit 4e1334512debb27f4a0c4a6da237a4b8d59fea08)
Related: #1763155
---
man/crypttab.xml | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/man/crypttab.xml b/man/crypttab.xml
index 3574ce00da..6074315980 100644
--- a/man/crypttab.xml
+++ b/man/crypttab.xml
@@ -150,6 +150,17 @@
sequential order.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>keyfile-timeout=</option></term>
+
+ <listitem><para> Specifies the timeout for the device on
+ which the key file resides and falls back to a password if
+ it could not be mounted. See
+ <citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ for key files on external devices.
+ </para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>luks</option></term>
@@ -417,7 +428,8 @@
<programlisting>luks UUID=2505567a-9e27-4efe-a4d5-15ad146c258b
swap /dev/sda7 /dev/urandom swap
truecrypt /dev/sda2 /etc/container_password tcrypt
-hidden /mnt/tc_hidden /dev/null tcrypt-hidden,tcrypt-keyfile=/etc/keyfile</programlisting>
+hidden /mnt/tc_hidden /dev/null tcrypt-hidden,tcrypt-keyfile=/etc/keyfile
+external /dev/sda3 keyfile:LABEL=keydev keyfile-timeout=10s</programlisting>
</example>
</refsect1>

View File

@ -0,0 +1,63 @@
From 0577d8378645c1ecd909b74403cefe31ed569398 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Thu, 1 Aug 2019 08:13:13 +0200
Subject: [PATCH] cryptsetup: use unabbrieviated variable names
Now that "ret_" has been added to the output variables, we can name
the internal variables without artificial abbrevs.
(cherry picked from commit 5d2100dc4c32abbce4109e75cbfbbef6e1b2b7b1)
Related: #1763155
---
src/cryptsetup/cryptsetup-generator.c | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
index 1e8e3ba00d..7b234e37be 100644
--- a/src/cryptsetup/cryptsetup-generator.c
+++ b/src/cryptsetup/cryptsetup-generator.c
@@ -40,30 +40,30 @@ static Hashmap *arg_disks = NULL;
static char *arg_default_options = NULL;
static char *arg_default_keyfile = NULL;
-static int split_keyspec(const char *keyspec, char **keyfile, char **keydev) {
- _cleanup_free_ char *kfile = NULL, *kdev = NULL;
- char *c;
+static int split_keyspec(const char *keyspec, char **ret_keyfile, char **ret_keydev) {
+ _cleanup_free_ char *keyfile = NULL, *keydev = NULL;
+ const char *c;
assert(keyspec);
- assert(keyfile);
- assert(keydev);
+ assert(ret_keyfile);
+ assert(ret_keydev);
c = strrchr(keyspec, ':');
if (c) {
- kfile = strndup(keyspec, c-keyspec);
- kdev = strdup(c + 1);
- if (!*kfile || !*kdev)
+ keyfile = strndup(keyspec, c-keyspec);
+ keydev = strdup(c + 1);
+ if (!keyfile || !keydev)
return log_oom();
} else {
/* No keydev specified */
- kfile = strdup(keyspec);
- kdev = NULL;
- if (!*kfile)
+ keyfile = strdup(keyspec);
+ keydev = NULL;
+ if (!keyfile)
return log_oom();
}
- *keyfile = TAKE_PTR(kfile);
- *keydev = TAKE_PTR(kdev);
+ *ret_keyfile = TAKE_PTR(keyfile);
+ *ret_keydev = TAKE_PTR(keydev);
return 0;
}

View File

@ -0,0 +1,37 @@
From 5cdb2b0b2a0f8f89f97053b0633b8419506d4e28 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Thu, 1 Aug 2019 08:15:43 +0200
Subject: [PATCH] cryptsetup: don't assert on variable which is optional
https://github.com/systemd/systemd/commit/50d2eba27b9bfc77ef6b40e5721713846815418b#commitcomment-34519739
In add_crypttab_devices() split_keyspec is called on the keyfile argument,
which may be NULL.
(cherry picked from commit fef716b28be6e866b8afe995805d5ebe2af6bbfa)
Related: #1763155
---
src/cryptsetup/cryptsetup-generator.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
index 7b234e37be..a09983b576 100644
--- a/src/cryptsetup/cryptsetup-generator.c
+++ b/src/cryptsetup/cryptsetup-generator.c
@@ -44,10 +44,14 @@ static int split_keyspec(const char *keyspec, char **ret_keyfile, char **ret_key
_cleanup_free_ char *keyfile = NULL, *keydev = NULL;
const char *c;
- assert(keyspec);
assert(ret_keyfile);
assert(ret_keydev);
+ if (!keyspec) {
+ *ret_keyfile = *ret_keydev = NULL;
+ return 0;
+ }
+
c = strrchr(keyspec, ':');
if (c) {
keyfile = strndup(keyspec, c-keyspec);

View File

@ -0,0 +1,100 @@
From 9040e15cd3cba546b47aeae0ea133afa1a6ad292 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 13 Nov 2019 10:32:30 +0100
Subject: [PATCH] cryptsetup-generator: guess whether the keyfile argument is
two items or one
Fixes #13615.
See the inline comment for documentation.
(cherry picked from commit 32c6237a7c2e697d2fc4f3403319db16858fb8e3)
Related: #1763155
---
src/cryptsetup/cryptsetup-generator.c | 45 ++++++++++++++++++---------
1 file changed, 30 insertions(+), 15 deletions(-)
diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
index a09983b576..4117930925 100644
--- a/src/cryptsetup/cryptsetup-generator.c
+++ b/src/cryptsetup/cryptsetup-generator.c
@@ -54,17 +54,36 @@ static int split_keyspec(const char *keyspec, char **ret_keyfile, char **ret_key
c = strrchr(keyspec, ':');
if (c) {
- keyfile = strndup(keyspec, c-keyspec);
- keydev = strdup(c + 1);
- if (!keyfile || !keydev)
+ /* The keydev part has to be either an absolute path to device node (/dev/something,
+ * /dev/foo/something, or even possibly /dev/foo/something:part), or a fstab device
+ * specification starting with LABEL= or similar. The keyfile part has the same syntax.
+ *
+ * Let's try to guess if the second part looks like a keydev specification, or just part of a
+ * filename with a colon. fstab_node_to_udev_node() will convert the fstab device syntax to
+ * an absolute path. If we didn't get an absolute path, assume that it is just part of the
+ * first keyfile argument. */
+
+ keydev = fstab_node_to_udev_node(c + 1);
+ if (!keydev)
return log_oom();
- } else {
+
+ if (path_is_absolute(keydev))
+ keyfile = strndup(keyspec, c-keyspec);
+ else {
+ log_debug("Keyspec argument contains a colon, but \"%s\" doesn't look like a device specification.\n"
+ "Assuming that \"%s\" is a single device specification.",
+ c + 1, keyspec);
+ keydev = mfree(keydev);
+ c = NULL;
+ }
+ }
+
+ if (!c)
/* No keydev specified */
keyfile = strdup(keyspec);
- keydev = NULL;
- if (!keyfile)
- return log_oom();
- }
+
+ if (!keyfile)
+ return log_oom();
*ret_keyfile = TAKE_PTR(keyfile);
*ret_keydev = TAKE_PTR(keydev);
@@ -73,7 +92,7 @@ static int split_keyspec(const char *keyspec, char **ret_keyfile, char **ret_key
}
static int generate_keydev_mount(const char *name, const char *keydev, const char *keydev_timeout, bool canfail, char **unit, char **mount) {
- _cleanup_free_ char *u = NULL, *what = NULL, *where = NULL, *name_escaped = NULL, *device_unit = NULL;
+ _cleanup_free_ char *u = NULL, *where = NULL, *name_escaped = NULL, *device_unit = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
usec_t timeout_us;
@@ -111,22 +130,18 @@ static int generate_keydev_mount(const char *name, const char *keydev, const cha
if (r < 0)
return r;
- what = fstab_node_to_udev_node(keydev);
- if (!what)
- return -ENOMEM;
-
fprintf(f,
"[Unit]\n"
"DefaultDependencies=no\n\n"
"[Mount]\n"
"What=%s\n"
"Where=%s\n"
- "Options=ro%s\n", what, where, canfail ? ",nofail" : "");
+ "Options=ro%s\n", keydev, where, canfail ? ",nofail" : "");
if (keydev_timeout) {
r = parse_sec_fix_0(keydev_timeout, &timeout_us);
if (r >= 0) {
- r = unit_name_from_path(what, ".device", &device_unit);
+ r = unit_name_from_path(keydev, ".device", &device_unit);
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");

View File

@ -0,0 +1,46 @@
From 05e184dea3f0182e5787812adfd52b68cff9418d Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Mon, 25 Jun 2018 20:33:31 +0200
Subject: [PATCH] crypt-util: Translate libcryptsetup log level instead of
using log_debug()
This makes sure that errors reported by libcryptsetup are shown to the
user instead of getting swallowed up by log_debug().
(cherry picked from commit aa2cc005d77890b07e8c579f25e1333ff8ba8dac)
Resolves: #1776408
---
src/basic/crypt-util.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/src/basic/crypt-util.c b/src/basic/crypt-util.c
index b181ba3ba0..20bdc5489e 100644
--- a/src/basic/crypt-util.c
+++ b/src/basic/crypt-util.c
@@ -5,6 +5,24 @@
#include "log.h"
void cryptsetup_log_glue(int level, const char *msg, void *usrptr) {
- log_debug("%s", msg);
+ switch (level) {
+ case CRYPT_LOG_NORMAL:
+ level = LOG_NOTICE;
+ break;
+ case CRYPT_LOG_ERROR:
+ level = LOG_ERR;
+ break;
+ case CRYPT_LOG_VERBOSE:
+ level = LOG_INFO;
+ break;
+ case CRYPT_LOG_DEBUG:
+ level = LOG_DEBUG;
+ break;
+ default:
+ log_error("Unknown libcryptsetup log level: %d", level);
+ level = LOG_ERR;
+ }
+
+ log_full(level, "%s", msg);
}
#endif

View File

@ -0,0 +1,25 @@
From ea0c4c31f6dff7d01e585bd8d5f962b373844544 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 21 Jan 2019 20:13:11 +0100
Subject: [PATCH] cryptsetup: add some commenting about EAGAIN generation
(cherry picked from commit b7a0fead10959b03a1fa642a5ae7aca3a6a3dee9)
Related: #1776408
---
src/cryptsetup/cryptsetup.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 0881aea915..f2b2557497 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -455,7 +455,7 @@ static int attach_tcrypt(
r = read_one_line_file(key_file, &passphrase);
if (r < 0) {
log_error_errno(r, "Failed to read password file '%s': %m", key_file);
- return -EAGAIN;
+ return -EAGAIN; /* log with the actual error, but return EAGAIN */
}
params.passphrase = passphrase;

View File

@ -0,0 +1,25 @@
From 3bbacfb22a9266769a41dee6f8f594fbeb6287fc Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 21 Jan 2019 20:19:57 +0100
Subject: [PATCH] cryptsetup: downgrade a log message we ignore
(cherry picked from commit 44ce4255147ab308c1f13580147c693204c322e8)
Related: #1776408
---
src/cryptsetup/cryptsetup.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index f2b2557497..53fe04a73f 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -621,7 +621,7 @@ int main(int argc, char *argv[]) {
!streq(argv[4], "none")) {
if (!path_is_absolute(argv[4]))
- log_error("Password file path '%s' is not absolute. Ignoring.", argv[4]);
+ log_warning("Password file path '%s' is not absolute. Ignoring.", argv[4]);
else
key_file = argv[4];
}

View File

@ -0,0 +1,102 @@
From 966ecf0011a02c7823083a7868b8589fdf850be8 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 21 Jan 2019 20:20:35 +0100
Subject: [PATCH] cryptsetup: rework how we log about activation failures
First of all let's always log where the errors happen, and not in an
upper stackframe, in all cases. Previously we'd do this somethis one way
and sometimes another, which resulted in sometimes duplicate logging and
sometimes none.
When we cannot activate something due to bad password the kernel gives
us EPERM. Let's uniformly return this EAGAIN, so tha the next password
is tried. (previously this was done in most cases but not in all)
When we get EPERM let's also explicitly indicate that this probably
means the password is simply wrong.
Fixes: #11498
(cherry picked from commit 6f177c7dc092eb68762b4533d41b14244adb2a73)
Related: #1776408
---
src/cryptsetup/cryptsetup.c | 36 ++++++++++++++++++++++--------------
1 file changed, 22 insertions(+), 14 deletions(-)
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 53fe04a73f..33c215eaa1 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -469,10 +469,15 @@ static int attach_tcrypt(
log_error("Failed to activate using password file '%s'.", key_file);
return -EAGAIN;
}
- return r;
+
+ return log_error_errno(r, "Failed to load tcrypt superblock on device %s: %m", crypt_get_device_name(cd));
}
- return crypt_activate_by_volume_key(cd, name, NULL, 0, flags);
+ r = crypt_activate_by_volume_key(cd, name, NULL, 0, flags);
+ if (r < 0)
+ return log_error_errno(r, "Failed to activate tcrypt device %s: %m", crypt_get_device_name(cd));
+
+ return 0;
}
static int attach_luks_or_plain(struct crypt_device *cd,
@@ -549,22 +554,30 @@ static int attach_luks_or_plain(struct crypt_device *cd,
if (key_file) {
r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags);
- if (r < 0) {
- log_error_errno(r, "Failed to activate with key file '%s': %m", key_file);
- return -EAGAIN;
+ if (r == -EPERM) {
+ log_error_errno(r, "Failed to activate with key file '%s'. (Key data incorrect?)", key_file);
+ return -EAGAIN; /* Log actual error, but return EAGAIN */
}
+ if (r < 0)
+ return log_error_errno(r, "Failed to activate with key file '%s': %m", key_file);
} else {
char **p;
+ r = -EINVAL;
STRV_FOREACH(p, passwords) {
if (pass_volume_key)
r = crypt_activate_by_volume_key(cd, name, *p, arg_key_size, flags);
else
r = crypt_activate_by_passphrase(cd, name, arg_key_slot, *p, strlen(*p), flags);
-
if (r >= 0)
break;
}
+ if (r == -EPERM) {
+ log_error_errno(r, "Failed to activate with specified passphrase. (Passphrase incorrect?)");
+ return -EAGAIN; /* log actual error, but return EAGAIN */
+ }
+ if (r < 0)
+ return log_error_errno(r, "Failed to activate with specified passphrase: %m");
}
return r;
@@ -726,16 +739,11 @@ int main(int argc, char *argv[]) {
flags);
if (r >= 0)
break;
- if (r == -EAGAIN) {
- key_file = NULL;
- continue;
- }
- if (r != -EPERM) {
- log_error_errno(r, "Failed to activate: %m");
+ if (r != -EAGAIN)
goto finish;
- }
- log_warning("Invalid passphrase.");
+ /* Passphrase not correct? Let's try again! */
+ key_file = NULL;
}
if (arg_tries != 0 && tries >= arg_tries) {

View File

@ -0,0 +1,41 @@
From b7f9d757dd6f276203b8b04f0c0ba1c61bcf8937 Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Wed, 18 Dec 2019 09:41:29 +0100
Subject: [PATCH] rules: reintroduce 60-alias-kmsg.rules
Resolves:#1739353
rhel-only
---
rules/60-alias-kmsg.rules | 10 ++++++++++
rules/meson.build | 1 +
2 files changed, 11 insertions(+)
create mode 100644 rules/60-alias-kmsg.rules
diff --git a/rules/60-alias-kmsg.rules b/rules/60-alias-kmsg.rules
new file mode 100644
index 0000000000..9c7236a730
--- /dev/null
+++ b/rules/60-alias-kmsg.rules
@@ -0,0 +1,10 @@
+SUBSYSTEM!="block", GOTO="log_end"
+KERNEL=="loop*|ram*", GOTO="log_end"
+ACTION=="remove", GOTO="log_end"
+ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", GOTO="log_end"
+ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}=="1", GOTO="log_end"
+
+IMPORT{cmdline}="udev.alias"
+ENV{udev.alias}=="1", RUN+="/bin/sh -c 'echo udev-alias: $name \($links\) > /dev/kmsg'"
+
+LABEL="log_end"
diff --git a/rules/meson.build b/rules/meson.build
index 6363f8bf2e..7b5b2472de 100644
--- a/rules/meson.build
+++ b/rules/meson.build
@@ -3,6 +3,7 @@
rules = files('''
40-redhat.rules
40-elevator.rules
+ 60-alias-kmsg.rules
60-block.rules
60-cdrom_id.rules
60-drm.rules

View File

@ -0,0 +1,49 @@
From 1d8e642b0b67f07b0bf469c25126b878380bae6a Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 17 Jan 2019 18:13:03 +0100
Subject: [PATCH] sd-bus: make rqueue/wqueue sizes of type size_t
Let's do this like we usually do and size arrays with size_t.
We already do this for the "allocated" counter correctly, and externally
we expose the queue sizes as uint64_t anyway, hence there's really no
point in usigned "unsigned" internally.
(cherry picked from commit 143d4e045a798ccc87889b2a8a60d7fbe44be441)
Related: CVE-2020-1712
---
src/libsystemd/sd-bus/bus-internal.h | 4 ++--
src/libsystemd/sd-bus/sd-bus.c | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h
index 5d773b14c4..06bd7862cb 100644
--- a/src/libsystemd/sd-bus/bus-internal.h
+++ b/src/libsystemd/sd-bus/bus-internal.h
@@ -221,11 +221,11 @@ struct sd_bus {
size_t rbuffer_size;
sd_bus_message **rqueue;
- unsigned rqueue_size;
+ size_t rqueue_size;
size_t rqueue_allocated;
sd_bus_message **wqueue;
- unsigned wqueue_size;
+ size_t wqueue_size;
size_t windex;
size_t wqueue_allocated;
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 1c9e967ae0..64026f7ee1 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -2080,7 +2080,7 @@ _public_ int sd_bus_call(
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = sd_bus_message_ref(_m);
usec_t timeout;
uint64_t cookie;
- unsigned i;
+ size_t i;
int r;
bus_assert_return(m, -EINVAL, error);

View File

@ -0,0 +1,51 @@
From 9c23ceef0a08ffdf4aed7a96ec440e1b110568ac Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 17 Jan 2019 18:14:17 +0100
Subject: [PATCH] sd-bus: reorder bus ref and bus message ref handling
Let's always place handling of these references together, so that all
reference counting during allocation is at a single place.
(cherry picked from commit e593b6a87a335267e5f7238b14683b7f840a01a3)
Related: CVE-2020-1712
---
src/libsystemd/sd-bus/bus-message.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c
index 19cb2b9a97..e9cdf46c91 100644
--- a/src/libsystemd/sd-bus/bus-message.c
+++ b/src/libsystemd/sd-bus/bus-message.c
@@ -461,7 +461,6 @@ int bus_message_from_header(
if (!m)
return -ENOMEM;
- m->n_ref = 1;
m->sealed = true;
m->header = header;
m->header_accessible = header_accessible;
@@ -515,7 +514,9 @@ int bus_message_from_header(
m->creds.mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
}
+ m->n_ref = 1;
m->bus = sd_bus_ref(bus);
+
*ret = TAKE_PTR(m);
return 0;
@@ -588,13 +589,13 @@ _public_ int sd_bus_message_new(
return -ENOMEM;
t->n_ref = 1;
+ t->bus = sd_bus_ref(bus);
t->header = (struct bus_header*) ((uint8_t*) t + ALIGN(sizeof(struct sd_bus_message)));
t->header->endian = BUS_NATIVE_ENDIAN;
t->header->type = type;
t->header->version = bus->message_version;
t->allow_fds = bus->can_fds || !IN_SET(bus->state, BUS_HELLO, BUS_RUNNING);
t->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(t);
- t->bus = sd_bus_ref(bus);
if (bus->allow_interactive_authorization)
t->header->flags |= BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION;

View File

@ -0,0 +1,32 @@
From 19a9c67b79ebb9a65bc2aec8d8f2799262ef0cb2 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 17 Jan 2019 18:15:37 +0100
Subject: [PATCH] sd-bus: make sure dispatch_rqueue() initializes return
parameter on all types of success
Let's make sure our own code follows coding style and initializes all
return values on all types of success (and leaves it uninitialized in
all types of failure).
(cherry picked from commit c0bc4ec5cc17ac61773d1e9362b0ffa8382c1ff1)
Related: CVE-2020-1712
---
src/libsystemd/sd-bus/sd-bus.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 64026f7ee1..55b008cc9f 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -1814,8 +1814,10 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd
r = bus_read_message(bus, hint_priority, priority);
if (r < 0)
return r;
- if (r == 0)
+ if (r == 0) {
+ *m = NULL;
return ret;
+ }
ret = 1;
}

View File

@ -0,0 +1,31 @@
From 7e9944795e3f0046857379a5f878b365597ed373 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 17 Jan 2019 18:18:18 +0100
Subject: [PATCH] sd-bus: drop two inappropriate empty lines
(cherry picked from commit 39feb2ce417e54cf9746e64b5dfd610cef6ac440)
Related: CVE-2020-1712
---
src/libsystemd/sd-bus/sd-bus.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 55b008cc9f..01060d105c 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -2634,7 +2634,6 @@ static int process_builtin(sd_bus *bus, sd_bus_message *m) {
SD_BUS_ERROR_UNKNOWN_METHOD,
"Unknown method '%s' on interface '%s'.", m->member, m->interface);
}
-
if (r < 0)
return r;
@@ -2758,7 +2757,6 @@ static int process_running(sd_bus *bus, bool hint_priority, int64_t priority, sd
return r;
*ret = TAKE_PTR(m);
-
return 1;
}

View File

@ -0,0 +1,33 @@
From 247d4f826ab189c4dfc4706aaa94782342655218 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 17 Jan 2019 21:06:30 +0100
Subject: [PATCH] sd-bus: initialize mutex after we allocated the wqueue
That way the mutex doesn't have to be destroyed when we exit early due
to OOM.
(cherry picked from commit 2fe9a10d7695c4c3a748969a0d1662c624e50e5e)
Related: CVE-2020-1712
---
src/libsystemd/sd-bus/sd-bus.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 01060d105c..e49d58137d 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -248,12 +248,12 @@ _public_ int sd_bus_new(sd_bus **ret) {
b->original_pid = getpid_cached();
b->n_groups = (size_t) -1;
- assert_se(pthread_mutex_init(&b->memfd_cache_mutex, NULL) == 0);
-
/* We guarantee that wqueue always has space for at least one entry */
if (!GREEDY_REALLOC(b->wqueue, b->wqueue_allocated, 1))
return -ENOMEM;
+ assert_se(pthread_mutex_init(&b->memfd_cache_mutex, NULL) == 0);
+
*ret = TAKE_PTR(b);
return 0;
}

View File

@ -0,0 +1,74 @@
From 6180d5ee908c9c742f816c6922c229aefd533117 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 17 Jan 2019 21:07:42 +0100
Subject: [PATCH] sd-bus: always go through sd_bus_unref() to free messages
Don't try to be smart, don't bypass the ref counting logic if there's no
real reason to.
This matters if we want to tweak the ref counting logic later.
(cherry picked from commit b41812d1e308de03c879cfca490105216d528c4b)
Related: CVE-2020-1712
---
src/libsystemd/sd-bus/bus-message.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c
index e9cdf46c91..306b6d6816 100644
--- a/src/libsystemd/sd-bus/bus-message.c
+++ b/src/libsystemd/sd-bus/bus-message.c
@@ -138,8 +138,6 @@ static sd_bus_message* message_free(sd_bus_message *m) {
return mfree(m);
}
-DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, message_free);
-
static void *message_extend_fields(sd_bus_message *m, size_t align, size_t sz, bool add_offset) {
void *op, *np;
size_t old_size, new_size, start;
@@ -531,7 +529,7 @@ int bus_message_from_malloc(
const char *label,
sd_bus_message **ret) {
- _cleanup_(message_freep) sd_bus_message *m = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
size_t sz;
int r;
@@ -651,7 +649,7 @@ _public_ int sd_bus_message_new_method_call(
const char *interface,
const char *member) {
- _cleanup_(message_freep) sd_bus_message *t = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL;
int r;
assert_return(bus, -ENOTCONN);
@@ -696,7 +694,7 @@ static int message_new_reply(
uint8_t type,
sd_bus_message **m) {
- _cleanup_(message_freep) sd_bus_message *t = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL;
uint64_t cookie;
int r;
@@ -747,7 +745,7 @@ _public_ int sd_bus_message_new_method_error(
sd_bus_message **m,
const sd_bus_error *e) {
- _cleanup_(message_freep) sd_bus_message *t = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL;
int r;
assert_return(sd_bus_error_is_set(e), -EINVAL);
@@ -850,7 +848,7 @@ int bus_message_new_synthetic_error(
const sd_bus_error *e,
sd_bus_message **m) {
- _cleanup_(message_freep) sd_bus_message *t = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL;
int r;
assert(bus);

View File

@ -0,0 +1,182 @@
From bc2d7df4fc21e9e54413169d5aad21616314d65e Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 17 Jan 2019 18:18:54 +0100
Subject: [PATCH] bus-message: introduce two kinds of references to bus
messages
Before this commit bus messages had a single reference count: when it
reached zero the message would be freed. This simple approach meant a
cyclic dependency was typically seen: a message that was enqueued in a
bus connection object would reference the bus connection object but also
itself be referenced by the bus connection object. So far out strategy
to avoid cases like this was: make sure to process the bus connection
regularly so that messages don#t stay queued, and at exit flush/close
the connection so that the message queued would be emptied, and thus the
cyclic dependencies resolved. Im many cases this isn't done properly
however.
With this change, let's address the issue more systematically: let's
break the reference cycle. Specifically, there are now two types of
references to a bus message:
1. A regular one, which keeps both the message and the bus object it is
associated with pinned.
2. A "queue" reference, which is weaker: it pins the message, but not
the bus object it is associated with.
The idea is then that regular user handling uses regular references, but
when a message is enqueued on its connection, then this takes a "queue"
reference instead. This then means that a queued message doesn't imply
the connection itself remains pinned, only regular references to the
connection or a message associated with it do. Thus, if we end up in the
situation where a user allocates a bus and a message and enqueues the
latter in the former and drops all refs to both, then this will detect
this case and free both.
Note that this scheme isn't perfect, it only covers references between
messages and the busses they are associated with. If OTOH a bus message
is enqueued on a different bus than it is associated with cyclic deps
cannot be recognized with this simple algorithm, and thus if you enqueue
a message associated with a bus A on a bus B, and another message
associated with bus B on a bus A, a cyclic ref will be in effect and not
be discovered. However, given that this is an exotic case (though one
that happens, consider systemd-bus-stdio-bridge), it should be OK not to
cover with this, and people have to explicit flush all queues on exit in
that case.
Note that this commit only establishes the separate reference counters
per message. A follow-up commit will start making use of this from the
bus connection object.
(cherry picked from commit 1b3f9dd759ca0ea215e7b89f8ce66d1b724497b9)
Related: CVE-2020-1712
---
src/libsystemd/sd-bus/bus-message.c | 60 ++++++++++++++++++++++++++---
src/libsystemd/sd-bus/bus-message.h | 14 ++++++-
2 files changed, 68 insertions(+), 6 deletions(-)
diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c
index 306b6d6816..7fe8929f82 100644
--- a/src/libsystemd/sd-bus/bus-message.c
+++ b/src/libsystemd/sd-bus/bus-message.c
@@ -120,7 +120,8 @@ static sd_bus_message* message_free(sd_bus_message *m) {
message_reset_parts(m);
- sd_bus_unref(m->bus);
+ /* Note that we don't unref m->bus here. That's already done by sd_bus_message_unref() as each user
+ * reference to the bus message also is considered a reference to the bus connection itself. */
if (m->free_fds) {
close_many(m->fds, m->n_fds);
@@ -893,27 +894,76 @@ int bus_message_new_synthetic_error(
}
_public_ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) {
-
if (!m)
return NULL;
- assert(m->n_ref > 0);
+ /* We are fine if this message so far was either explicitly reffed or not reffed but queued into at
+ * least one bus connection object. */
+ assert(m->n_ref > 0 || m->n_queued > 0);
+
m->n_ref++;
+ /* Each user reference to a bus message shall also be considered a ref on the bus */
+ sd_bus_ref(m->bus);
return m;
}
_public_ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) {
-
if (!m)
return NULL;
assert(m->n_ref > 0);
+
+ sd_bus_unref(m->bus); /* Each regular ref is also a ref on the bus connection. Let's hence drop it
+ * here. Note we have to do this before decrementing our own n_ref here, since
+ * otherwise, if this message is currently queued sd_bus_unref() might call
+ * bus_message_unref_queued() for this which might then destroy the message
+ * while we are still processing it. */
m->n_ref--;
- if (m->n_ref > 0)
+ if (m->n_ref > 0 || m->n_queued > 0)
return NULL;
+ /* Unset the bus field if neither the user has a reference nor this message is queued. We are careful
+ * to reset the field only after the last reference to the bus is dropped, after all we might keep
+ * multiple references to the bus, once for each reference kept on outselves. */
+ m->bus = NULL;
+
+ return message_free(m);
+}
+
+sd_bus_message* bus_message_ref_queued(sd_bus_message *m, sd_bus *bus) {
+ if (!m)
+ return NULL;
+
+ /* If this is a different bus than the message is associated with, then implicitly turn this into a
+ * regular reference. This means that you can create a memory leak by enqueuing a message generated
+ * on one bus onto another at the same time as enqueueing a message from the second one on the first,
+ * as we'll not detect the cyclic references there. */
+ if (bus != m->bus)
+ return sd_bus_message_ref(m);
+
+ assert(m->n_ref > 0 || m->n_queued > 0);
+ m->n_queued++;
+
+ return m;
+}
+
+sd_bus_message* bus_message_unref_queued(sd_bus_message *m, sd_bus *bus) {
+ if (!m)
+ return NULL;
+
+ if (bus != m->bus)
+ return sd_bus_message_unref(m);
+
+ assert(m->n_queued > 0);
+ m->n_queued--;
+
+ if (m->n_ref > 0 || m->n_queued > 0)
+ return NULL;
+
+ m->bus = NULL;
+
return message_free(m);
}
diff --git a/src/libsystemd/sd-bus/bus-message.h b/src/libsystemd/sd-bus/bus-message.h
index 97f6060e30..ded88005e2 100644
--- a/src/libsystemd/sd-bus/bus-message.h
+++ b/src/libsystemd/sd-bus/bus-message.h
@@ -51,7 +51,16 @@ struct bus_body_part {
};
struct sd_bus_message {
- unsigned n_ref;
+ /* Caveat: a message can be referenced in two different ways: the main (user-facing) way will also
+ * pin the bus connection object the message is associated with. The secondary way ("queued") is used
+ * when a message is in the read or write queues of the bus connection object, which will not pin the
+ * bus connection object. This is necessary so that we don't have to have a pair of cyclic references
+ * between a message that is queued and its connection: as soon as a message is only referenced by
+ * the connection (by means of being queued) and the connection itself has no other references it
+ * will be freed. */
+
+ unsigned n_ref; /* Counter of references that pin the connection */
+ unsigned n_queued; /* Counter of references that do not pin the connection */
sd_bus *bus;
@@ -216,3 +225,6 @@ int bus_message_append_sender(sd_bus_message *m, const char *sender);
void bus_message_set_sender_driver(sd_bus *bus, sd_bus_message *m);
void bus_message_set_sender_local(sd_bus *bus, sd_bus_message *m);
+
+sd_bus_message* bus_message_ref_queued(sd_bus_message *m, sd_bus *bus);
+sd_bus_message* bus_message_unref_queued(sd_bus_message *m, sd_bus *bus);

View File

@ -0,0 +1,74 @@
From 8efdae75ddf035c8c04983820f8d8cf767cc17b1 Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Fri, 31 Jan 2020 11:34:45 +0100
Subject: [PATCH] sd-bus: introduce API for re-enqueuing incoming messages
When authorizing via PolicyKit we want to process incoming method calls
twice: once to process and figure out that we need PK authentication,
and a second time after we aquired PK authentication to actually execute
the operation. With this new call sd_bus_enqueue_for_read() we have a
way to put an incoming message back into the read queue for this
purpose.
This might have other uses too, for example debugging.
Related: CVE-2020-1712
---
src/libsystemd/libsystemd.sym | 1 +
src/libsystemd/sd-bus/sd-bus.c | 24 ++++++++++++++++++++++++
src/systemd/sd-bus.h | 1 +
3 files changed, 26 insertions(+)
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index 1eec17db50..e9972593a6 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -569,4 +569,5 @@ global:
sd_event_source_get_inotify_mask;
sd_event_source_set_destroy_callback;
sd_event_source_get_destroy_callback;
+ sd_bus_enqueue_for_read;
} LIBSYSTEMD_238;
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index e49d58137d..68ad6cbe89 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -4120,3 +4120,27 @@ _public_ int sd_bus_get_n_queued_write(sd_bus *bus, uint64_t *ret) {
*ret = bus->wqueue_size;
return 0;
}
+
+_public_ int sd_bus_enqueue_for_read(sd_bus *bus, sd_bus_message *m) {
+ int r;
+
+ assert_return(bus, -EINVAL);
+ assert_return(bus = bus_resolve(bus), -ENOPKG);
+ assert_return(m, -EINVAL);
+ assert_return(m->sealed, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ if (!BUS_IS_OPEN(bus->state))
+ return -ENOTCONN;
+
+ /* Re-enqeue a message for reading. This is primarily useful for PolicyKit-style authentication,
+ * where we want accept a message, then determine we need to interactively authenticate the user, and
+ * when we have that process the message again. */
+
+ r = bus_rqueue_make_room(bus);
+ if (r < 0)
+ return r;
+
+ bus->rqueue[bus->rqueue_size++] = bus_message_ref_queued(m, bus);
+ return 0;
+}
diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
index 54c4b1ca83..9ba757b13d 100644
--- a/src/systemd/sd-bus.h
+++ b/src/systemd/sd-bus.h
@@ -193,6 +193,7 @@ int sd_bus_process(sd_bus *bus, sd_bus_message **r);
int sd_bus_process_priority(sd_bus *bus, int64_t max_priority, sd_bus_message **r);
int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec);
int sd_bus_flush(sd_bus *bus);
+int sd_bus_enqueue_for_read(sd_bus *bus, sd_bus_message *m);
sd_bus_slot* sd_bus_get_current_slot(sd_bus *bus);
sd_bus_message* sd_bus_get_current_message(sd_bus *bus);

View File

@ -0,0 +1,130 @@
From 73b87f8c73af714a32e7b56b217cd4e4f46a5ea7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 8 May 2019 14:39:57 +0200
Subject: [PATCH] sd-event: add sd_event_source_disable_unref() helper
(cherry picked from commit afd15bbb4b6414b9356799c63029e36642dae8e4)
Related: CVE-2020-1712
---
man/rules/meson.build | 4 +++-
man/sd_event_source_unref.xml | 30 +++++++++++++++++++-----------
src/libsystemd/libsystemd.sym | 1 +
src/libsystemd/sd-event/sd-event.c | 6 ++++++
src/systemd/sd-event.h | 1 +
5 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/man/rules/meson.build b/man/rules/meson.build
index 989d11c9b9..7ae94ea265 100644
--- a/man/rules/meson.build
+++ b/man/rules/meson.build
@@ -340,7 +340,9 @@ manpages = [
['sd_event_source_set_userdata', '3', ['sd_event_source_get_userdata'], ''],
['sd_event_source_unref',
'3',
- ['sd_event_source_ref', 'sd_event_source_unrefp'],
+ ['sd_event_source_disable_unref',
+ 'sd_event_source_ref',
+ 'sd_event_source_unrefp'],
''],
['sd_event_wait',
'3',
diff --git a/man/sd_event_source_unref.xml b/man/sd_event_source_unref.xml
index d1b83c57aa..af8fed33f2 100644
--- a/man/sd_event_source_unref.xml
+++ b/man/sd_event_source_unref.xml
@@ -22,6 +22,7 @@
<refname>sd_event_source_unref</refname>
<refname>sd_event_source_unrefp</refname>
<refname>sd_event_source_ref</refname>
+ <refname>sd_event_source_disable_unref</refname>
<refpurpose>Increase or decrease event source reference counters</refpurpose>
</refnamediv>
@@ -45,6 +46,10 @@
<paramdef>sd_event_source *<parameter>source</parameter></paramdef>
</funcprototype>
+ <funcprototype>
+ <funcdef>sd_event_source* <function>sd_event_source_disable_unref</function></funcdef>
+ <paramdef>sd_event_source *<parameter>source</parameter></paramdef>
+ </funcprototype>
</funcsynopsis>
</refsynopsisdiv>
@@ -80,23 +85,26 @@
the passed event source object is
<constant>NULL</constant>.</para>
- <para>Note that event source objects stay alive and may be
- dispatched as long as they have a reference counter greater than
- zero. In order to drop a reference of an event source and make
- sure the associated event source handler function is not called
- anymore it is recommended to combine a call of
+ <para>Note that event source objects stay alive and may be dispatched as long as they have a reference
+ counter greater than zero. In order to drop a reference of an event source and make sure the associated
+ event source handler function is not called anymore it is recommended to combine a call of
<function>sd_event_source_unref()</function> with a prior call to
- <function>sd_event_source_set_enabled()</function> with
- <constant>SD_EVENT_OFF</constant>.</para>
+ <function>sd_event_source_set_enabled()</function> with <constant>SD_EVENT_OFF</constant> or call
+ <function>sd_event_source_disable_unref()</function>, see below.</para>
+
+ <para><function>sd_event_source_disable_unref()</function> combines a call to
+ <function>sd_event_source_set_enabled()</function> with <constant>SD_EVENT_OFF</constant> with
+ <function>sd_event_source_unref()</function>. This ensures that the source is disabled before the local
+ reference to it is lost. The <parameter>source</parameter> parameter is allowed to be
+ <constant>NULL</constant>.</para>
</refsect1>
<refsect1>
<title>Return Value</title>
- <para><function>sd_event_source_unref()</function> always returns
- <constant>NULL</constant>.
- <function>sd_event_source_ref()</function> always returns the
- event source object passed in.</para>
+ <para><function>sd_event_source_unref()</function> and
+ <function>sd_event_source_disable_unref()</function> always return <constant>NULL</constant>.
+ <function>sd_event_source_ref()</function> always returns the event source object passed in.</para>
</refsect1>
<xi:include href="libsystemd-pkgconfig.xml" />
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index e9972593a6..778e88a16c 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -570,4 +570,5 @@ global:
sd_event_source_set_destroy_callback;
sd_event_source_get_destroy_callback;
sd_bus_enqueue_for_read;
+ sd_event_source_disable_unref;
} LIBSYSTEMD_238;
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index d53b9a7026..0d3bf5cbb6 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -580,6 +580,12 @@ _public_ sd_event* sd_event_unref(sd_event *e) {
return NULL;
}
+_public_ sd_event_source* sd_event_source_disable_unref(sd_event_source *s) {
+ if (s)
+ (void) sd_event_source_set_enabled(s, SD_EVENT_OFF);
+ return sd_event_source_unref(s);
+}
+
static bool event_pid_changed(sd_event *e) {
assert(e);
diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h
index 7fcae4ac49..9876be01c6 100644
--- a/src/systemd/sd-event.h
+++ b/src/systemd/sd-event.h
@@ -113,6 +113,7 @@ int sd_event_get_iteration(sd_event *e, uint64_t *ret);
sd_event_source* sd_event_source_ref(sd_event_source *s);
sd_event_source* sd_event_source_unref(sd_event_source *s);
+sd_event_source* sd_event_source_disable_unref(sd_event_source *s);
sd_event *sd_event_source_get_event(sd_event_source *s);
void* sd_event_source_get_userdata(sd_event_source *s);

View File

@ -0,0 +1,156 @@
From 2ec3c78b1d1ba907cd888aac3cdc3a86c03cda90 Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Fri, 31 Jan 2020 15:17:25 +0100
Subject: [PATCH] polkit: when authorizing via PK let's re-resolve
callback/userdata instead of caching it
Previously, when doing an async PK query we'd store the original
callback/userdata pair and call it again after the PK request is
complete. This is problematic, since PK queries might be slow and in the
meantime the userdata might be released and re-acquired. Let's avoid
this by always traversing through the message handlers so that we always
re-resolve the callback and userdata pair and thus can be sure it's
up-to-date and properly valid.
Resolves: CVE-2020-1712
---
src/shared/bus-util.c | 74 +++++++++++++++++++++++++++++--------------
1 file changed, 50 insertions(+), 24 deletions(-)
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 2d908eb45c..5ed68429be 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -319,10 +319,10 @@ int bus_test_polkit(
typedef struct AsyncPolkitQuery {
sd_bus_message *request, *reply;
- sd_bus_message_handler_t callback;
- void *userdata;
sd_bus_slot *slot;
+
Hashmap *registry;
+ sd_event_source *defer_event_source;
} AsyncPolkitQuery;
static void async_polkit_query_free(AsyncPolkitQuery *q) {
@@ -338,9 +338,22 @@ static void async_polkit_query_free(AsyncPolkitQuery *q) {
sd_bus_message_unref(q->request);
sd_bus_message_unref(q->reply);
+ sd_event_source_disable_unref(q->defer_event_source);
free(q);
}
+static int async_polkit_defer(sd_event_source *s, void *userdata) {
+ AsyncPolkitQuery *q = userdata;
+
+ assert(s);
+
+ /* This is called as idle event source after we processed the async polkit reply, hopefully after the
+ * method call we re-enqueued has been properly processed. */
+
+ async_polkit_query_free(q);
+ return 0;
+}
+
static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
AsyncPolkitQuery *q = userdata;
@@ -349,19 +362,45 @@ static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_e
assert(reply);
assert(q);
+ assert(q->slot);
q->slot = sd_bus_slot_unref(q->slot);
+
+ assert(!q->reply);
q->reply = sd_bus_message_ref(reply);
+ /* Now, let's dispatch the original message a second time be re-enqueing. This will then traverse the
+ * whole message processing again, and thus re-validating and re-retrieving the "userdata" field
+ * again.
+ *
+ * We install an idle event loop event to clean-up the PolicyKit request data when we are idle again,
+ * i.e. after the second time the message is processed is complete. */
+
+ assert(!q->defer_event_source);
+ r = sd_event_add_defer(sd_bus_get_event(sd_bus_message_get_bus(reply)), &q->defer_event_source, async_polkit_defer, q);
+ if (r < 0)
+ goto fail;
+
+ r = sd_event_source_set_priority(q->defer_event_source, SD_EVENT_PRIORITY_IDLE);
+ if (r < 0)
+ goto fail;
+
+ r = sd_event_source_set_enabled(q->defer_event_source, SD_EVENT_ONESHOT);
+ if (r < 0)
+ goto fail;
+
r = sd_bus_message_rewind(q->request, true);
- if (r < 0) {
- r = sd_bus_reply_method_errno(q->request, r, NULL);
- goto finish;
- }
+ if (r < 0)
+ goto fail;
- r = q->callback(q->request, q->userdata, &error_buffer);
- r = bus_maybe_reply_error(q->request, r, &error_buffer);
+ r = sd_bus_enqueue_for_read(sd_bus_message_get_bus(q->request), q->request);
+ if (r < 0)
+ goto fail;
-finish:
+ return 1;
+
+fail:
+ log_debug_errno(r, "Processing asynchronous PolicyKit reply failed, ignoring: %m");
+ (void) sd_bus_reply_method_errno(q->request, r, NULL);
async_polkit_query_free(q);
return r;
@@ -382,11 +421,9 @@ int bus_verify_polkit_async(
#if ENABLE_POLKIT
_cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL;
AsyncPolkitQuery *q;
- const char *sender, **k, **v;
- sd_bus_message_handler_t callback;
- void *userdata;
int c;
#endif
+ const char *sender, **k, **v;
int r;
assert(call);
@@ -444,20 +481,11 @@ int bus_verify_polkit_async(
else if (r > 0)
return 1;
-#if ENABLE_POLKIT
- if (sd_bus_get_current_message(call->bus) != call)
- return -EINVAL;
-
- callback = sd_bus_get_current_handler(call->bus);
- if (!callback)
- return -EINVAL;
-
- userdata = sd_bus_get_current_userdata(call->bus);
-
sender = sd_bus_message_get_sender(call);
if (!sender)
return -EBADMSG;
+#if ENABLE_POLKIT
c = sd_bus_message_get_allow_interactive_authorization(call);
if (c < 0)
return c;
@@ -509,8 +537,6 @@ int bus_verify_polkit_async(
return -ENOMEM;
q->request = sd_bus_message_ref(call);
- q->callback = callback;
- q->userdata = userdata;
r = hashmap_put(*registry, call, q);
if (r < 0) {

View File

@ -0,0 +1,70 @@
From b9be2c6b48227642ba85c5a741f121cc99655904 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= <msekleta@redhat.com>
Date: Mon, 6 Jan 2020 12:30:58 +0100
Subject: [PATCH] sysctl: let's by default increase the numeric PID range from
2^16 to 2^22
This should PID collisions a tiny bit less likely, and thus improve
security and robustness.
2^22 isn't particularly a lot either, but it's the current kernel
limitation.
Bumping this limit was suggested by Linus himself:
https://lwn.net/ml/linux-kernel/CAHk-=wiZ40LVjnXSi9iHLE_-ZBsWFGCgdmNiYZUXn1-V5YBg2g@mail.gmail.com/
Let's experiment with this in systemd upstream first. Downstreams and
users can after all still comment this easily.
Besides compat concern the most often heard issue with such high PIDs is
usability, since they are potentially hard to type. I am not entirely sure though
whether 4194304 (as largest new PID) is that much worse to type or to
copy than 65563.
This should also simplify management of per system tasks limits as by
this move the sysctl /proc/sys/kernel/threads-max becomes the primary
knob to control how many processes to have in parallel.
Resolves: #1744214
---
sysctl.d/50-pid-max.conf | 17 +++++++++++++++++
sysctl.d/meson.build | 1 +
2 files changed, 18 insertions(+)
create mode 100644 sysctl.d/50-pid-max.conf
diff --git a/sysctl.d/50-pid-max.conf b/sysctl.d/50-pid-max.conf
new file mode 100644
index 0000000000..3a8393d185
--- /dev/null
+++ b/sysctl.d/50-pid-max.conf
@@ -0,0 +1,17 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+# See sysctl.d(5) and core(5) for documentation.
+
+# To override settings in this file, create a local file in /etc
+# (e.g. /etc/sysctl.d/90-override.conf), and put any assignments
+# there.
+
+# Bump the numeric PID range to its maximum of 2^22 (from the in-kernel default
+# of 2^16), to make PID collisions less likely.
+kernel.pid_max = 4194304
+
diff --git a/sysctl.d/meson.build b/sysctl.d/meson.build
index 64f6ce942e..a95957ad7d 100644
--- a/sysctl.d/meson.build
+++ b/sysctl.d/meson.build
@@ -2,6 +2,7 @@
install_data(
'50-default.conf',
+ '50-pid-max.conf',
install_dir : sysctldir)
in_files = []

View File

@ -0,0 +1,49 @@
From dc4c3a5aa35a5e88adcf210471d9460262c8c0d9 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 28 May 2019 12:40:17 +0900
Subject: [PATCH] journal: do not trigger assertion when journal_file_close()
get NULL
We generally expect destructors to not complain if a NULL argument is passed.
Closes #12400.
(cherry picked from commit c377a6f3ad3d9bed4ce7e873e8e9ec6b1650c57d)
Resolves: #1788085
---
src/journal/journal-file.c | 3 ++-
src/journal/journald-server.c | 7 ++-----
2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index efc3ee052b..8249b11b23 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -335,7 +335,8 @@ bool journal_file_is_offlining(JournalFile *f) {
}
JournalFile* journal_file_close(JournalFile *f) {
- assert(f);
+ if (!f)
+ return NULL;
#if HAVE_GCRYPT
/* Write the final tag */
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 6aecb67d6c..6250eab831 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -1906,11 +1906,8 @@ void server_done(Server *s) {
client_context_flush_all(s);
- if (s->system_journal)
- (void) journal_file_close(s->system_journal);
-
- if (s->runtime_journal)
- (void) journal_file_close(s->runtime_journal);
+ (void) journal_file_close(s->system_journal);
+ (void) journal_file_close(s->runtime_journal);
ordered_hashmap_free_with_destructor(s->user_journals, journal_file_close);

View File

@ -0,0 +1,58 @@
From ceacf935ac9f59bc08b5901f70f227958a2bcf52 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 28 May 2019 18:07:01 +0900
Subject: [PATCH] journal: use cleanup attribute at one more place
(cherry picked from commit 627df1dc42b68a74b0882b06366d1185b1a34332)
Conflicts:
src/journal/journald-server.c
Related: #1788085
---
src/journal/journal-file.h | 1 +
src/journal/journald-server.c | 9 ++++-----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index cd8a48a364..6a44fd39d2 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -144,6 +144,7 @@ int journal_file_open(
int journal_file_set_offline(JournalFile *f, bool wait);
bool journal_file_is_offlining(JournalFile *f);
JournalFile* journal_file_close(JournalFile *j);
+DEFINE_TRIVIAL_CLEANUP_FUNC(JournalFile*, journal_file_close);
int journal_file_open_reliably(
const char *fname,
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 6250eab831..7632e2d9d0 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -253,8 +253,9 @@ static int open_journal(
bool seal,
JournalMetrics *metrics,
JournalFile **ret) {
+
+ _cleanup_(journal_file_closep) JournalFile *f = NULL;
int r;
- JournalFile *f;
assert(s);
assert(fname);
@@ -271,12 +272,10 @@ static int open_journal(
return r;
r = journal_file_enable_post_change_timer(f, s->event, POST_CHANGE_TIMER_INTERVAL_USEC);
- if (r < 0) {
- (void) journal_file_close(f);
+ if (r < 0)
return r;
- }
- *ret = f;
+ *ret = TAKE_PTR(f);
return r;
}

View File

@ -0,0 +1,183 @@
From 781a055c17400e953bb7929434fe7a2e6517d5e8 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 17 Jan 2019 18:31:59 +0100
Subject: [PATCH] sd-bus: use "queue" message references for managing r/w
message queues in connection objects
Let's make use of the new concept the previous commit added.
See: #4846
(cherry picked from commit c1757a70eac0382c4837a3833d683919f6a48ed7)
Related: CVE-2020-1712
---
src/libsystemd/sd-bus/bus-socket.c | 6 ++-
src/libsystemd/sd-bus/sd-bus.c | 60 ++++++++++++++----------------
2 files changed, 32 insertions(+), 34 deletions(-)
diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c
index 17cfa8e1fd..4a72795d2b 100644
--- a/src/libsystemd/sd-bus/bus-socket.c
+++ b/src/libsystemd/sd-bus/bus-socket.c
@@ -1116,8 +1116,10 @@ static int bus_socket_make_message(sd_bus *bus, size_t size) {
bus->fds = NULL;
bus->n_fds = 0;
- if (t)
- bus->rqueue[bus->rqueue_size++] = t;
+ if (t) {
+ bus->rqueue[bus->rqueue_size++] = bus_message_ref_queued(t, bus);
+ sd_bus_message_unref(t);
+ }
return 1;
}
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 68ad6cbe89..a3509f7e89 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -148,13 +148,13 @@ static void bus_reset_queues(sd_bus *b) {
assert(b);
while (b->rqueue_size > 0)
- sd_bus_message_unref(b->rqueue[--b->rqueue_size]);
+ bus_message_unref_queued(b->rqueue[--b->rqueue_size], b);
b->rqueue = mfree(b->rqueue);
b->rqueue_allocated = 0;
while (b->wqueue_size > 0)
- sd_bus_message_unref(b->wqueue[--b->wqueue_size]);
+ bus_message_unref_queued(b->wqueue[--b->wqueue_size], b);
b->wqueue = mfree(b->wqueue);
b->wqueue_allocated = 0;
@@ -493,7 +493,7 @@ static int synthesize_connected_signal(sd_bus *bus) {
/* Insert at the very front */
memmove(bus->rqueue + 1, bus->rqueue, sizeof(sd_bus_message*) * bus->rqueue_size);
- bus->rqueue[0] = TAKE_PTR(m);
+ bus->rqueue[0] = bus_message_ref_queued(m, bus);
bus->rqueue_size++;
return 0;
@@ -1760,7 +1760,7 @@ static int dispatch_wqueue(sd_bus *bus) {
* anyway. */
bus->wqueue_size--;
- sd_bus_message_unref(bus->wqueue[0]);
+ bus_message_unref_queued(bus->wqueue[0], bus);
memmove(bus->wqueue, bus->wqueue + 1, sizeof(sd_bus_message*) * bus->wqueue_size);
bus->windex = 0;
@@ -1789,6 +1789,15 @@ int bus_rqueue_make_room(sd_bus *bus) {
return 0;
}
+static void rqueue_drop_one(sd_bus *bus, size_t i) {
+ assert(bus);
+ assert(i < bus->rqueue_size);
+
+ bus_message_unref_queued(bus->rqueue[i], bus);
+ memmove(bus->rqueue + i, bus->rqueue + i + 1, sizeof(sd_bus_message*) * (bus->rqueue_size - i - 1));
+ bus->rqueue_size--;
+}
+
static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd_bus_message **m) {
int r, ret = 0;
@@ -1803,10 +1812,8 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd
for (;;) {
if (bus->rqueue_size > 0) {
/* Dispatch a queued message */
-
- *m = bus->rqueue[0];
- bus->rqueue_size--;
- memmove(bus->rqueue, bus->rqueue + 1, sizeof(sd_bus_message*) * bus->rqueue_size);
+ *m = sd_bus_message_ref(bus->rqueue[0]);
+ rqueue_drop_one(bus, 0);
return 1;
}
@@ -1884,7 +1891,7 @@ _public_ int sd_bus_send(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie) {
* of the wqueue array is always allocated so
* that we always can remember how much was
* written. */
- bus->wqueue[0] = sd_bus_message_ref(m);
+ bus->wqueue[0] = bus_message_ref_queued(m, bus);
bus->wqueue_size = 1;
bus->windex = idx;
}
@@ -1898,7 +1905,7 @@ _public_ int sd_bus_send(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie) {
if (!GREEDY_REALLOC(bus->wqueue, bus->wqueue_allocated, bus->wqueue_size + 1))
return -ENOMEM;
- bus->wqueue[bus->wqueue_size++] = sd_bus_message_ref(m);
+ bus->wqueue[bus->wqueue_size++] = bus_message_ref_queued(m, bus);
}
finish:
@@ -2124,37 +2131,30 @@ _public_ int sd_bus_call(
usec_t left;
while (i < bus->rqueue_size) {
- sd_bus_message *incoming = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *incoming = NULL;
- incoming = bus->rqueue[i];
+ incoming = sd_bus_message_ref(bus->rqueue[i]);
if (incoming->reply_cookie == cookie) {
/* Found a match! */
- memmove(bus->rqueue + i, bus->rqueue + i + 1, sizeof(sd_bus_message*) * (bus->rqueue_size - i - 1));
- bus->rqueue_size--;
+ rqueue_drop_one(bus, i);
log_debug_bus_message(incoming);
if (incoming->header->type == SD_BUS_MESSAGE_METHOD_RETURN) {
if (incoming->n_fds <= 0 || bus->accept_fd) {
if (reply)
- *reply = incoming;
- else
- sd_bus_message_unref(incoming);
+ *reply = TAKE_PTR(incoming);
return 1;
}
- r = sd_bus_error_setf(error, SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Reply message contained file descriptors which I couldn't accept. Sorry.");
- sd_bus_message_unref(incoming);
- return r;
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Reply message contained file descriptors which I couldn't accept. Sorry.");
- } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR) {
- r = sd_bus_error_copy(error, &incoming->error);
- sd_bus_message_unref(incoming);
- return r;
- } else {
+ } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
+ return sd_bus_error_copy(error, &incoming->error);
+ else {
r = -EIO;
goto fail;
}
@@ -2164,15 +2164,11 @@ _public_ int sd_bus_call(
incoming->sender &&
streq(bus->unique_name, incoming->sender)) {
- memmove(bus->rqueue + i, bus->rqueue + i + 1, sizeof(sd_bus_message*) * (bus->rqueue_size - i - 1));
- bus->rqueue_size--;
+ rqueue_drop_one(bus, i);
- /* Our own message? Somebody is trying
- * to send its own client a message,
- * let's not dead-lock, let's fail
- * immediately. */
+ /* Our own message? Somebody is trying to send its own client a message,
+ * let's not dead-lock, let's fail immediately. */
- sd_bus_message_unref(incoming);
r = -ELOOP;
goto fail;
}

View File

@ -0,0 +1,261 @@
From 77a273e02c1c811485d13ddca0f844512aed2cff Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Wed, 12 Feb 2020 12:58:54 +0100
Subject: [PATCH] pid1: make sure to restore correct default values for some
rlimits
Commit fb39af4ce42d7ef9af63009f271f404038703704 forgot to restore the default
rlimit values (RLIMIT_NOFILE and RLIMIT_MEMLOCK) while PID1 is reloading.
This patch extracts the code in charge of initializing the default values for
those rlimits in order to create dedicated functions, which take care of their
initialization.
These functions are then called in parse_configuration() so we make sure that
the default values for these rlimits get restored every time PID1 is reloading
its configuration.
(cherry picked from commit a9fd4cd1206832a61aaf61fff583bb133e6cb965)
Resolves: #1789930
---
src/core/main.c | 135 +++++++++++++++++++++++++++++++++++++-----------
1 file changed, 106 insertions(+), 29 deletions(-)
diff --git a/src/core/main.c b/src/core/main.c
index c83249a8dc..b8c1e567ad 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -136,7 +136,8 @@ static EmergencyAction arg_cad_burst_action;
static CPUSet arg_cpu_affinity;
static NUMAPolicy arg_numa_policy;
-static int parse_configuration(void);
+static int parse_configuration(const struct rlimit *saved_rlimit_nofile,
+ const struct rlimit *saved_rlimit_memlock);
_noreturn_ static void freeze_or_reboot(void) {
@@ -1149,25 +1150,6 @@ static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching
static int bump_rlimit_nofile(struct rlimit *saved_rlimit) {
int r, nr;
- assert(saved_rlimit);
-
- /* Save the original RLIMIT_NOFILE so that we can reset it
- * later when transitioning from the initrd to the main
- * systemd or suchlike. */
- if (getrlimit(RLIMIT_NOFILE, saved_rlimit) < 0)
- return log_warning_errno(errno, "Reading RLIMIT_NOFILE failed, ignoring: %m");
-
- /* Make sure forked processes get the default kernel setting */
- if (!arg_default_rlimit[RLIMIT_NOFILE]) {
- struct rlimit *rl;
-
- rl = newdup(struct rlimit, saved_rlimit, 1);
- if (!rl)
- return log_oom();
-
- arg_default_rlimit[RLIMIT_NOFILE] = rl;
- }
-
/* Bump up the resource limit for ourselves substantially, all the way to the maximum the kernel allows */
nr = read_nr_open();
r = setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(nr));
@@ -1180,16 +1162,12 @@ static int bump_rlimit_nofile(struct rlimit *saved_rlimit) {
static int bump_rlimit_memlock(struct rlimit *saved_rlimit) {
int r;
- assert(saved_rlimit);
assert(getuid() == 0);
/* BPF_MAP_TYPE_LPM_TRIE bpf maps are charged against RLIMIT_MEMLOCK, even though we have CAP_IPC_LOCK which
* should normally disable such checks. We need them to implement IPAccessAllow= and IPAccessDeny=, hence let's
* bump the value high enough for the root user. */
- if (getrlimit(RLIMIT_MEMLOCK, saved_rlimit) < 0)
- return log_warning_errno(errno, "Reading RLIMIT_MEMLOCK failed, ignoring: %m");
-
r = setrlimit_closest(RLIMIT_MEMLOCK, &RLIMIT_MAKE_CONST(1024ULL*1024ULL*16ULL));
if (r < 0)
return log_warning_errno(r, "Setting RLIMIT_MEMLOCK failed, ignoring: %m");
@@ -1651,6 +1629,8 @@ static void do_reexecute(
static int invoke_main_loop(
Manager *m,
+ const struct rlimit *saved_rlimit_nofile,
+ const struct rlimit *saved_rlimit_memlock,
bool *ret_reexecute,
int *ret_retval, /* Return parameters relevant for shutting down */
const char **ret_shutdown_verb, /* … */
@@ -1662,6 +1642,8 @@ static int invoke_main_loop(
int r;
assert(m);
+ assert(saved_rlimit_nofile);
+ assert(saved_rlimit_memlock);
assert(ret_reexecute);
assert(ret_retval);
assert(ret_shutdown_verb);
@@ -1691,7 +1673,7 @@ static int invoke_main_loop(
saved_log_level = m->log_level_overridden ? log_get_max_level() : -1;
saved_log_target = m->log_target_overridden ? log_get_target() : _LOG_TARGET_INVALID;
- (void) parse_configuration();
+ (void) parse_configuration(saved_rlimit_nofile, saved_rlimit_memlock);
set_manager_defaults(m);
@@ -1983,6 +1965,80 @@ static int do_queue_default_job(
return 0;
}
+static void save_rlimits(struct rlimit *saved_rlimit_nofile,
+ struct rlimit *saved_rlimit_memlock) {
+
+ assert(saved_rlimit_nofile);
+ assert(saved_rlimit_memlock);
+
+ if (getrlimit(RLIMIT_NOFILE, saved_rlimit_nofile) < 0)
+ log_warning_errno(errno, "Reading RLIMIT_NOFILE failed, ignoring: %m");
+
+ if (getrlimit(RLIMIT_MEMLOCK, saved_rlimit_memlock) < 0)
+ log_warning_errno(errno, "Reading RLIMIT_MEMLOCK failed, ignoring: %m");
+}
+
+static void fallback_rlimit_nofile(const struct rlimit *saved_rlimit_nofile) {
+ struct rlimit *rl;
+
+ if (arg_default_rlimit[RLIMIT_NOFILE])
+ return;
+
+ /* Make sure forked processes get limits based on the original kernel setting */
+
+ rl = newdup(struct rlimit, saved_rlimit_nofile, 1);
+ if (!rl) {
+ log_oom();
+ return;
+ }
+
+ /* Bump the hard limit for system services to a substantially higher value. The default
+ * hard limit current kernels set is pretty low (4K), mostly for historical
+ * reasons. According to kernel developers, the fd handling in recent kernels has been
+ * optimized substantially enough, so that we can bump the limit now, without paying too
+ * high a price in memory or performance. Note however that we only bump the hard limit,
+ * not the soft limit. That's because select() works the way it works, and chokes on fds
+ * >= 1024. If we'd bump the soft limit globally, it might accidentally happen to
+ * unexpecting programs that they get fds higher than what they can process using
+ * select(). By only bumping the hard limit but leaving the low limit as it is we avoid
+ * this pitfall: programs that are written by folks aware of the select() problem in mind
+ * (and thus use poll()/epoll instead of select(), the way everybody should) can
+ * explicitly opt into high fds by bumping their soft limit beyond 1024, to the hard limit
+ * we pass. */
+ if (arg_system) {
+ int nr;
+
+ /* Get the underlying absolute limit the kernel enforces */
+ nr = read_nr_open();
+
+ rl->rlim_max = MIN((rlim_t) nr, MAX(rl->rlim_max, (rlim_t) HIGH_RLIMIT_NOFILE));
+ }
+
+ /* If for some reason we were invoked with a soft limit above 1024 (which should never
+ * happen!, but who knows what we get passed in from pam_limit when invoked as --user
+ * instance), then lower what we pass on to not confuse our children */
+ rl->rlim_cur = MIN(rl->rlim_cur, (rlim_t) FD_SETSIZE);
+
+ arg_default_rlimit[RLIMIT_NOFILE] = rl;
+}
+
+static void fallback_rlimit_memlock(const struct rlimit *saved_rlimit_memlock) {
+ struct rlimit *rl;
+
+ /* Pass the original value down to invoked processes */
+
+ if (arg_default_rlimit[RLIMIT_MEMLOCK])
+ return;
+
+ rl = newdup(struct rlimit, saved_rlimit_memlock, 1);
+ if (!rl) {
+ log_oom();
+ return;
+ }
+
+ arg_default_rlimit[RLIMIT_MEMLOCK] = rl;
+}
+
static void reset_arguments(void) {
/* Frees/resets arg_* variables, with a few exceptions commented below. */
@@ -2040,9 +2096,13 @@ static void reset_arguments(void) {
numa_policy_reset(&arg_numa_policy);
}
-static int parse_configuration(void) {
+static int parse_configuration(const struct rlimit *saved_rlimit_nofile,
+ const struct rlimit *saved_rlimit_memlock) {
int r;
+ assert(saved_rlimit_nofile);
+ assert(saved_rlimit_memlock);
+
arg_default_tasks_max = system_tasks_max_scale(DEFAULT_TASKS_MAX_PERCENTAGE, 100U);
/* Assign configuration defaults */
@@ -2058,18 +2118,29 @@ static int parse_configuration(void) {
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
}
+ /* Initialize some default rlimits for services if they haven't been configured */
+ fallback_rlimit_nofile(saved_rlimit_nofile);
+ fallback_rlimit_memlock(saved_rlimit_memlock);
+
/* Note that this also parses bits from the kernel command line, including "debug". */
log_parse_environment();
return 0;
}
-static int load_configuration(int argc, char **argv, const char **ret_error_message) {
+static int load_configuration(
+ int argc,
+ char **argv,
+ const struct rlimit *saved_rlimit_nofile,
+ const struct rlimit *saved_rlimit_memlock,
+ const char **ret_error_message) {
int r;
+ assert(saved_rlimit_nofile);
+ assert(saved_rlimit_memlock);
assert(ret_error_message);
- (void) parse_configuration();
+ (void) parse_configuration(saved_rlimit_nofile, saved_rlimit_memlock);
r = parse_argv(argc, argv);
if (r < 0) {
@@ -2403,11 +2474,15 @@ int main(int argc, char *argv[]) {
}
}
+ /* Save the original RLIMIT_NOFILE/RLIMIT_MEMLOCK so that we can reset it later when
+ * transitioning from the initrd to the main systemd or suchlike. */
+ save_rlimits(&saved_rlimit_nofile, &saved_rlimit_memlock);
+
/* Reset all signal handlers. */
(void) reset_all_signal_handlers();
(void) ignore_signals(SIGNALS_IGNORE, -1);
- r = load_configuration(argc, argv, &error_message);
+ r = load_configuration(argc, argv, &saved_rlimit_nofile, &saved_rlimit_memlock, &error_message);
if (r < 0)
goto finish;
@@ -2522,6 +2597,8 @@ int main(int argc, char *argv[]) {
}
(void) invoke_main_loop(m,
+ &saved_rlimit_nofile,
+ &saved_rlimit_memlock,
&reexecute,
&retval,
&shutdown_verb,

View File

@ -0,0 +1,37 @@
From 0528a880ddf797a42b2de274e5c7bd2d9896c991 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 11 Oct 2018 18:31:11 +0200
Subject: [PATCH] main: introduce a define HIGH_RLIMIT_MEMLOCK similar to
HIGH_RLIMIT_NOFILE
(cherry picked from commit c8884aceefc85245b9bdfb626e2daf27521259bd)
Related: #1789930
---
src/basic/def.h | 3 +++
src/core/main.c | 2 +-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/basic/def.h b/src/basic/def.h
index 4d515c11b6..65ad659999 100644
--- a/src/basic/def.h
+++ b/src/basic/def.h
@@ -75,3 +75,6 @@
_CONF_PATHS_SPLIT_USR(n))
#define LONG_LINE_MAX (1U*1024U*1024U)
+
+#define HIGH_RLIMIT_NOFILE (256*1024)
+#define HIGH_RLIMIT_MEMLOCK (1024ULL*1024ULL*64ULL)
diff --git a/src/core/main.c b/src/core/main.c
index b8c1e567ad..d6550ea161 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -1168,7 +1168,7 @@ static int bump_rlimit_memlock(struct rlimit *saved_rlimit) {
* should normally disable such checks. We need them to implement IPAccessAllow= and IPAccessDeny=, hence let's
* bump the value high enough for the root user. */
- r = setrlimit_closest(RLIMIT_MEMLOCK, &RLIMIT_MAKE_CONST(1024ULL*1024ULL*16ULL));
+ r = setrlimit_closest(RLIMIT_MEMLOCK, &RLIMIT_MAKE_CONST(HIGH_RLIMIT_MEMLOCK));
if (r < 0)
return log_warning_errno(r, "Setting RLIMIT_MEMLOCK failed, ignoring: %m");

View File

@ -0,0 +1,178 @@
From 5a62c0daff82e8343d24f98e1761d27bf8015782 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 20 Mar 2019 19:00:28 +0100
Subject: [PATCH] seccomp: introduce seccomp_restrict_suid_sgid() for blocking
chmod() for suid/sgid files
(cherry picked from commit 3c27973b13724ede05a06a5d346a569794cda433)
Related: #1687512
---
src/shared/seccomp-util.c | 132 ++++++++++++++++++++++++++++++++++++++
src/shared/seccomp-util.h | 1 +
2 files changed, 133 insertions(+)
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
index 92910acf0e..fd46b9f88d 100644
--- a/src/shared/seccomp-util.c
+++ b/src/shared/seccomp-util.c
@@ -1,12 +1,14 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <errno.h>
+#include <fcntl.h>
#include <linux/seccomp.h>
#include <seccomp.h>
#include <stddef.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/shm.h>
+#include <sys/stat.h>
#include "af-list.h"
#include "alloc-util.h"
@@ -1747,3 +1749,133 @@ int seccomp_lock_personality(unsigned long personality) {
return 0;
}
+
+int seccomp_restrict_suid_sgid(void) {
+ uint32_t arch;
+ int r;
+
+ SECCOMP_FOREACH_LOCAL_ARCH(arch) {
+ _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
+
+ r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ALLOW);
+ if (r < 0)
+ return r;
+
+ /* Checks the mode_t parameter of the following system calls:
+ *
+ * → chmod() + fchmod() + fchmodat()
+ * → open() + creat() + openat()
+ * → mkdir() + mkdirat()
+ * → mknod() + mknodat()
+ */
+
+ for (unsigned bit = 0; bit < 2; bit ++) {
+ /* Block S_ISUID in the first iteration, S_ISGID in the second */
+ mode_t m = bit == 0 ? S_ISUID : S_ISGID;
+
+ r = seccomp_rule_add_exact(
+ seccomp,
+ SCMP_ACT_ERRNO(EPERM),
+ SCMP_SYS(chmod),
+ 1,
+ SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
+ if (r < 0)
+ break;
+
+ r = seccomp_rule_add_exact(
+ seccomp,
+ SCMP_ACT_ERRNO(EPERM),
+ SCMP_SYS(fchmod),
+ 1,
+ SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
+ if (r < 0)
+ break;
+
+ r = seccomp_rule_add_exact(
+ seccomp,
+ SCMP_ACT_ERRNO(EPERM),
+ SCMP_SYS(fchmodat),
+ 1,
+ SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
+ if (r < 0)
+ break;
+
+ r = seccomp_rule_add_exact(
+ seccomp,
+ SCMP_ACT_ERRNO(EPERM),
+ SCMP_SYS(mkdir),
+ 1,
+ SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
+ if (r < 0)
+ break;
+
+ r = seccomp_rule_add_exact(
+ seccomp,
+ SCMP_ACT_ERRNO(EPERM),
+ SCMP_SYS(mkdirat),
+ 1,
+ SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
+ if (r < 0)
+ break;
+
+ r = seccomp_rule_add_exact(
+ seccomp,
+ SCMP_ACT_ERRNO(EPERM),
+ SCMP_SYS(mknod),
+ 1,
+ SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
+ if (r < 0)
+ break;
+
+ r = seccomp_rule_add_exact(
+ seccomp,
+ SCMP_ACT_ERRNO(EPERM),
+ SCMP_SYS(mknodat),
+ 1,
+ SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
+ if (r < 0)
+ break;
+
+ r = seccomp_rule_add_exact(
+ seccomp,
+ SCMP_ACT_ERRNO(EPERM),
+ SCMP_SYS(open),
+ 2,
+ SCMP_A1(SCMP_CMP_MASKED_EQ, O_CREAT, O_CREAT),
+ SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
+ if (r < 0)
+ break;
+
+ r = seccomp_rule_add_exact(
+ seccomp,
+ SCMP_ACT_ERRNO(EPERM),
+ SCMP_SYS(openat),
+ 2,
+ SCMP_A2(SCMP_CMP_MASKED_EQ, O_CREAT, O_CREAT),
+ SCMP_A3(SCMP_CMP_MASKED_EQ, m, m));
+ if (r < 0)
+ break;
+
+ r = seccomp_rule_add_exact(
+ seccomp,
+ SCMP_ACT_ERRNO(EPERM),
+ SCMP_SYS(creat),
+ 1,
+ SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
+ if (r < 0)
+ break;
+ }
+ if (r < 0) {
+ log_debug_errno(r, "Failed to add suid/sgid rule for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
+ continue;
+ }
+
+ r = seccomp_load(seccomp);
+ if (IN_SET(r, -EPERM, -EACCES))
+ return r;
+ if (r < 0)
+ log_debug_errno(r, "Failed to apply suid/sgid restrictions for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
+ }
+
+ return 0;
+}
diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h
index d8a36c4e21..602f092255 100644
--- a/src/shared/seccomp-util.h
+++ b/src/shared/seccomp-util.h
@@ -85,6 +85,7 @@ int seccomp_restrict_address_families(Set *address_families, bool whitelist);
int seccomp_restrict_realtime(void);
int seccomp_memory_deny_write_execute(void);
int seccomp_lock_personality(unsigned long personality);
+int seccomp_restrict_suid_sgid(void);
extern const uint32_t seccomp_local_archs[];

View File

@ -0,0 +1,265 @@
From b39697a80ad388e2063c54e56333882f4307c1a1 Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Tue, 12 Nov 2019 13:27:49 +0100
Subject: [PATCH] test: add test case for restrict_suid_sgid()
(cherry picked from commit 167fc10cb352b04d442c9010dab4f8dc24219749)
Related: #1687512
---
src/test/test-seccomp.c | 226 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 226 insertions(+)
diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c
index d177515ac7..4021a06e0e 100644
--- a/src/test/test-seccomp.c
+++ b/src/test/test-seccomp.c
@@ -17,9 +17,11 @@
#include "nsflags.h"
#include "process-util.h"
#include "raw-clone.h"
+#include "rm-rf.h"
#include "seccomp-util.h"
#include "set.h"
#include "string-util.h"
+#include "umask-util.h"
#include "util.h"
#include "virt.h"
@@ -666,6 +668,229 @@ static void test_filter_sets_ordered(void) {
}
}
+static int mkostemp_safe(char *pattern) {
+ _unused_ _cleanup_umask_ mode_t u = umask(0077);
+ int fd;
+
+ assert(pattern);
+
+ fd = mkostemp(pattern, O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ return fd;
+}
+
+static int real_open(const char *path, int flags, mode_t mode) {
+ /* glibc internally calls openat() when open() is requested. Let's hence define our own wrapper for
+ * testing purposes that calls the real syscall, on architectures where SYS_open is defined. On
+ * other architectures, let's just fall back to the glibc call. */
+
+#ifdef SYS_open
+ return (int) syscall(SYS_open, path, flags, mode);
+#else
+ return open(path, flags, mode);
+#endif
+}
+
+static void test_restrict_suid_sgid(void) {
+ pid_t pid;
+
+ log_info("/* %s */", __func__);
+
+ if (!is_seccomp_available()) {
+ log_notice("Seccomp not available, skipping %s", __func__);
+ return;
+ }
+ if (geteuid() != 0) {
+ log_notice("Not root, skipping %s", __func__);
+ return;
+ }
+
+ pid = fork();
+ assert_se(pid >= 0);
+
+ if (pid == 0) {
+ char path[] = "/tmp/suidsgidXXXXXX", dir[] = "/tmp/suidsgiddirXXXXXX";
+ int fd = -1, k = -1;
+ const char *z;
+
+ fd = mkostemp_safe(path);
+ assert_se(fd >= 0);
+
+ assert_se(mkdtemp(dir));
+ z = strjoina(dir, "/test");
+
+ assert_se(chmod(path, 0755 | S_ISUID) >= 0);
+ assert_se(chmod(path, 0755 | S_ISGID) >= 0);
+ assert_se(chmod(path, 0755 | S_ISGID | S_ISUID) >= 0);
+ assert_se(chmod(path, 0755) >= 0);
+
+ assert_se(fchmod(fd, 0755 | S_ISUID) >= 0);
+ assert_se(fchmod(fd, 0755 | S_ISGID) >= 0);
+ assert_se(fchmod(fd, 0755 | S_ISGID | S_ISUID) >= 0);
+ assert_se(fchmod(fd, 0755) >= 0);
+
+ assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISUID, 0) >= 0);
+ assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID, 0) >= 0);
+ assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID | S_ISUID, 0) >= 0);
+ assert_se(fchmodat(AT_FDCWD, path, 0755, 0) >= 0);
+
+ k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID);
+ k = safe_close(k);
+ assert_se(unlink(z) >= 0);
+
+ k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID);
+ k = safe_close(k);
+ assert_se(unlink(z) >= 0);
+
+ k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID);
+ k = safe_close(k);
+ assert_se(unlink(z) >= 0);
+
+ k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644);
+ k = safe_close(k);
+ assert_se(unlink(z) >= 0);
+
+ k = creat(z, 0644 | S_ISUID);
+ k = safe_close(k);
+ assert_se(unlink(z) >= 0);
+
+ k = creat(z, 0644 | S_ISGID);
+ k = safe_close(k);
+ assert_se(unlink(z) >= 0);
+
+ k = creat(z, 0644 | S_ISUID | S_ISGID);
+ k = safe_close(k);
+ assert_se(unlink(z) >= 0);
+
+ k = creat(z, 0644);
+ k = safe_close(k);
+ assert_se(unlink(z) >= 0);
+
+ k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID);
+ k = safe_close(k);
+ assert_se(unlink(z) >= 0);
+
+ k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID);
+ k = safe_close(k);
+ assert_se(unlink(z) >= 0);
+
+ k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID);
+ k = safe_close(k);
+ assert_se(unlink(z) >= 0);
+
+ k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644);
+ k = safe_close(k);
+ assert_se(unlink(z) >= 0);
+
+ assert_se(mkdir(z, 0755 | S_ISUID) >= 0);
+ assert_se(rmdir(z) >= 0);
+ assert_se(mkdir(z, 0755 | S_ISGID) >= 0);
+ assert_se(rmdir(z) >= 0);
+ assert_se(mkdir(z, 0755 | S_ISUID | S_ISGID) >= 0);
+ assert_se(rmdir(z) >= 0);
+ assert_se(mkdir(z, 0755) >= 0);
+ assert_se(rmdir(z) >= 0);
+
+ assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID) >= 0);
+ assert_se(rmdir(z) >= 0);
+ assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISGID) >= 0);
+ assert_se(rmdir(z) >= 0);
+ assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID | S_ISGID) >= 0);
+ assert_se(rmdir(z) >= 0);
+ assert_se(mkdirat(AT_FDCWD, z, 0755) >= 0);
+ assert_se(rmdir(z) >= 0);
+
+ assert_se(mknod(z, S_IFREG | 0755 | S_ISUID, 0) >= 0);
+ assert_se(unlink(z) >= 0);
+ assert_se(mknod(z, S_IFREG | 0755 | S_ISGID, 0) >= 0);
+ assert_se(unlink(z) >= 0);
+ assert_se(mknod(z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) >= 0);
+ assert_se(unlink(z) >= 0);
+ assert_se(mknod(z, S_IFREG | 0755, 0) >= 0);
+ assert_se(unlink(z) >= 0);
+
+ assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID, 0) >= 0);
+ assert_se(unlink(z) >= 0);
+ assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISGID, 0) >= 0);
+ assert_se(unlink(z) >= 0);
+ assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) >= 0);
+ assert_se(unlink(z) >= 0);
+ assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755, 0) >= 0);
+ assert_se(unlink(z) >= 0);
+
+ assert_se(seccomp_restrict_suid_sgid() >= 0);
+
+ assert_se(chmod(path, 0775 | S_ISUID) < 0 && errno == EPERM);
+ assert_se(chmod(path, 0775 | S_ISGID) < 0 && errno == EPERM);
+ assert_se(chmod(path, 0775 | S_ISGID | S_ISUID) < 0 && errno == EPERM);
+ assert_se(chmod(path, 0775) >= 0);
+
+ assert_se(fchmod(fd, 0775 | S_ISUID) < 0 && errno == EPERM);
+ assert_se(fchmod(fd, 0775 | S_ISGID) < 0 && errno == EPERM);
+ assert_se(fchmod(fd, 0775 | S_ISGID | S_ISUID) < 0 && errno == EPERM);
+ assert_se(fchmod(fd, 0775) >= 0);
+
+ assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISUID, 0) < 0 && errno == EPERM);
+ assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID, 0) < 0 && errno == EPERM);
+ assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID | S_ISUID, 0) < 0 && errno == EPERM);
+ assert_se(fchmodat(AT_FDCWD, path, 0755, 0) >= 0);
+
+ assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID) < 0 && errno == EPERM);
+ assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID) < 0 && errno == EPERM);
+ assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
+ k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644);
+ k = safe_close(k);
+ assert_se(unlink(z) >= 0);
+
+ assert_se(creat(z, 0644 | S_ISUID) < 0 && errno == EPERM);
+ assert_se(creat(z, 0644 | S_ISGID) < 0 && errno == EPERM);
+ assert_se(creat(z, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
+ k = creat(z, 0644);
+ k = safe_close(k);
+ assert_se(unlink(z) >= 0);
+
+ assert_se(openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID) < 0 && errno == EPERM);
+ assert_se(openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID) < 0 && errno == EPERM);
+ assert_se(openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
+ k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644);
+ k = safe_close(k);
+ assert_se(unlink(z) >= 0);
+
+ assert_se(mkdir(z, 0755 | S_ISUID) < 0 && errno == EPERM);
+ assert_se(mkdir(z, 0755 | S_ISGID) < 0 && errno == EPERM);
+ assert_se(mkdir(z, 0755 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
+ assert_se(mkdir(z, 0755) >= 0);
+ assert_se(rmdir(z) >= 0);
+
+ assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID) < 0 && errno == EPERM);
+ assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISGID) < 0 && errno == EPERM);
+ assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
+ assert_se(mkdirat(AT_FDCWD, z, 0755) >= 0);
+ assert_se(rmdir(z) >= 0);
+
+ assert_se(mknod(z, S_IFREG | 0755 | S_ISUID, 0) < 0 && errno == EPERM);
+ assert_se(mknod(z, S_IFREG | 0755 | S_ISGID, 0) < 0 && errno == EPERM);
+ assert_se(mknod(z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) < 0 && errno == EPERM);
+ assert_se(mknod(z, S_IFREG | 0755, 0) >= 0);
+ assert_se(unlink(z) >= 0);
+
+ assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID, 0) < 0 && errno == EPERM);
+ assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISGID, 0) < 0 && errno == EPERM);
+ assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) < 0 && errno == EPERM);
+ assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755, 0) >= 0);
+ assert_se(unlink(z) >= 0);
+
+ assert_se(unlink(path) >= 0);
+ assert_se(rm_rf(dir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ assert_se(wait_for_terminate_and_check("suidsgidseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
+}
+
int main(int argc, char *argv[]) {
log_set_max_level(LOG_DEBUG);
@@ -684,6 +909,7 @@ int main(int argc, char *argv[]) {
test_load_syscall_filter_set_raw();
test_lock_personality();
test_filter_sets_ordered();
+ test_restrict_suid_sgid();
return 0;
}

View File

@ -0,0 +1,157 @@
From f79283a86531e3bbf0854b5f126b7b291fadfb43 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 20 Mar 2019 19:09:09 +0100
Subject: [PATCH] core: expose SUID/SGID restriction as new unit setting
RestrictSUIDSGID=
(cherry picked from commit f69567cbe26d09eac9d387c0be0fc32c65a83ada)
Related: #1687512
---
src/core/dbus-execute.c | 4 ++++
src/core/execute.c | 22 +++++++++++++++++++++
src/core/execute.h | 1 +
src/core/load-fragment-gperf.gperf.m4 | 2 ++
src/shared/bus-unit-util.c | 2 +-
test/fuzz/fuzz-unit-file/directives.service | 1 +
6 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 198f149210..e7c0b893d1 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -815,6 +815,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("ConfigurationDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_CONFIGURATION].paths), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MemoryDenyWriteExecute", "b", bus_property_get_bool, offsetof(ExecContext, memory_deny_write_execute), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RestrictRealtime", "b", bus_property_get_bool, offsetof(ExecContext, restrict_realtime), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RestrictSUIDSGID", "b", bus_property_get_bool, offsetof(ExecContext, restrict_suid_sgid), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RestrictNamespaces", "t", bus_property_get_ulong, offsetof(ExecContext, restrict_namespaces), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("BindPaths", "a(ssbt)", property_get_bind_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("BindReadOnlyPaths", "a(ssbt)", property_get_bind_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1179,6 +1180,9 @@ int bus_exec_context_set_transient_property(
if (streq(name, "RestrictRealtime"))
return bus_set_transient_bool(u, name, &c->restrict_realtime, message, flags, error);
+ if (streq(name, "RestrictSUIDSGID"))
+ return bus_set_transient_bool(u, name, &c->restrict_suid_sgid, message, flags, error);
+
if (streq(name, "DynamicUser"))
return bus_set_transient_bool(u, name, &c->dynamic_user, message, flags, error);
diff --git a/src/core/execute.c b/src/core/execute.c
index 56aa89e1ec..f012023224 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -1366,6 +1366,7 @@ static bool context_has_no_new_privileges(const ExecContext *c) {
return context_has_address_families(c) ||
c->memory_deny_write_execute ||
c->restrict_realtime ||
+ c->restrict_suid_sgid ||
exec_context_restrict_namespaces_set(c) ||
c->protect_kernel_tunables ||
c->protect_kernel_modules ||
@@ -1470,6 +1471,19 @@ static int apply_restrict_realtime(const Unit* u, const ExecContext *c) {
return seccomp_restrict_realtime();
}
+static int apply_restrict_suid_sgid(const Unit* u, const ExecContext *c) {
+ assert(u);
+ assert(c);
+
+ if (!c->restrict_suid_sgid)
+ return 0;
+
+ if (skip_seccomp_unavailable(u, "RestrictSUIDSGID="))
+ return 0;
+
+ return seccomp_restrict_suid_sgid();
+}
+
static int apply_protect_sysctl(const Unit *u, const ExecContext *c) {
assert(u);
assert(c);
@@ -3404,6 +3418,12 @@ static int exec_child(
return log_unit_error_errno(unit, r, "Failed to apply realtime restrictions: %m");
}
+ r = apply_restrict_suid_sgid(unit, context);
+ if (r < 0) {
+ *exit_status = EXIT_SECCOMP;
+ return log_unit_error_errno(unit, r, "Failed to apply SUID/SGID restrictions: %m");
+ }
+
r = apply_restrict_namespaces(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
@@ -4023,6 +4043,7 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
"%sIgnoreSIGPIPE: %s\n"
"%sMemoryDenyWriteExecute: %s\n"
"%sRestrictRealtime: %s\n"
+ "%sRestrictSUIDSGID: %s\n"
"%sKeyringMode: %s\n",
prefix, c->umask,
prefix, c->working_directory ? c->working_directory : "/",
@@ -4041,6 +4062,7 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
prefix, yes_no(c->ignore_sigpipe),
prefix, yes_no(c->memory_deny_write_execute),
prefix, yes_no(c->restrict_realtime),
+ prefix, yes_no(c->restrict_suid_sgid),
prefix, exec_keyring_mode_to_string(c->keyring_mode));
if (c->root_image)
diff --git a/src/core/execute.h b/src/core/execute.h
index b2eb55f8f5..2266355962 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -245,6 +245,7 @@ struct ExecContext {
* that the autofs logic detects that it belongs to us and we
* don't enter a trigger loop. */
bool same_pgrp;
+ bool restrict_suid_sgid;
unsigned long personality;
bool lock_personality;
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index cdf4d14c4e..49e938d0ce 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -76,6 +76,7 @@ $1.SystemCallErrorNumber, config_parse_syscall_errno, 0,
$1.MemoryDenyWriteExecute, config_parse_bool, 0, offsetof($1, exec_context.memory_deny_write_execute)
$1.RestrictNamespaces, config_parse_restrict_namespaces, 0, offsetof($1, exec_context)
$1.RestrictRealtime, config_parse_bool, 0, offsetof($1, exec_context.restrict_realtime)
+$1.RestrictSUIDSGID, config_parse_bool, 0, offsetof($1, exec_context.restrict_suid_sgid)
$1.RestrictAddressFamilies, config_parse_address_families, 0, offsetof($1, exec_context)
$1.LockPersonality, config_parse_bool, 0, offsetof($1, exec_context.lock_personality)',
`$1.SystemCallFilter, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
@@ -84,6 +85,7 @@ $1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CO
$1.MemoryDenyWriteExecute, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.RestrictNamespaces, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.RestrictRealtime, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
+$1.RestrictSUIDSGID, config_parse_warn_compat, DISABLED_CONFIGURATION 0
$1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.LockPersonality, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
$1.LimitCPU, config_parse_rlimit, RLIMIT_CPU, offsetof($1, exec_context.rlimit)
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 055edd6e22..3c42e97b7a 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -697,7 +697,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
"PrivateMounts", "NoNewPrivileges", "SyslogLevelPrefix",
"MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC",
"ProtectKernelTunables", "ProtectKernelModules", "ProtectControlGroups",
- "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality"))
+ "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality" "RestrictSUIDSGID"))
return bus_append_parse_boolean(m, field, eq);
diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service
index d8d1fc68b8..eab1820e20 100644
--- a/test/fuzz/fuzz-unit-file/directives.service
+++ b/test/fuzz/fuzz-unit-file/directives.service
@@ -849,6 +849,7 @@ ReserveVT=
RestrictAddressFamilies=
RestrictNamespaces=
RestrictRealtime=
+RestrictSUIDSGID=
RuntimeDirectory=
RuntimeDirectoryMode=
RuntimeDirectoryPreserve=

View File

@ -0,0 +1,52 @@
From 3d338556760632b9c8b646a719d56e02e3ad2088 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 20 Mar 2019 19:20:35 +0100
Subject: [PATCH] analyze: check for RestrictSUIDSGID= in "systemd-analyze
security"
And let's give it a heigh weight, since it pretty much can be used for
bad things only.
(cherry picked from commit 9d880b70ba5c6ca83c82952f4c90e86e56c7b70c)
Related: #1687512
---
src/analyze/analyze-security.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/src/analyze/analyze-security.c b/src/analyze/analyze-security.c
index eec040d5c3..969101c57b 100644
--- a/src/analyze/analyze-security.c
+++ b/src/analyze/analyze-security.c
@@ -69,6 +69,7 @@ struct security_info {
uint64_t restrict_namespaces;
bool restrict_realtime;
+ bool restrict_suid_sgid;
char *root_directory;
char *root_image;
@@ -1130,6 +1131,16 @@ static const struct security_assessor security_assessor_table[] = {
.assess = assess_bool,
.offset = offsetof(struct security_info, restrict_realtime),
},
+ {
+ .id = "RestrictSUIDSGID=",
+ .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictSUIDSGID=",
+ .description_good = "SUID/SGID file creation by service is restricted",
+ .description_bad = "Service may create SUID/SGID files",
+ .weight = 1000,
+ .range = 1,
+ .assess = assess_bool,
+ .offset = offsetof(struct security_info, restrict_suid_sgid),
+ },
{
.id = "RestrictNamespaces=~CLONE_NEWUSER",
.url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
@@ -1862,6 +1873,7 @@ static int acquire_security_info(sd_bus *bus, const char *name, struct security_
{ "RestrictAddressFamilies", "(bas)", property_read_restrict_address_families, 0 },
{ "RestrictNamespaces", "t", NULL, offsetof(struct security_info, restrict_namespaces) },
{ "RestrictRealtime", "b", NULL, offsetof(struct security_info, restrict_realtime) },
+ { "RestrictSUIDSGID", "b", NULL, offsetof(struct security_info, restrict_suid_sgid) },
{ "RootDirectory", "s", NULL, offsetof(struct security_info, root_directory) },
{ "RootImage", "s", NULL, offsetof(struct security_info, root_image) },
{ "SupplementaryGroups", "as", NULL, offsetof(struct security_info, supplementary_groups) },

View File

@ -0,0 +1,83 @@
From 797ebaa8240aefc39de3d1713468b221c83ed3f5 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 20 Mar 2019 19:45:32 +0100
Subject: [PATCH] man: document the new RestrictSUIDSGID= setting
(cherry picked from commit 7445db6eb70e8d5989f481d0c5a08ace7047ae5b)
Related: #1687512
---
doc/TRANSIENT-SETTINGS.md | 1 +
man/systemd.exec.xml | 41 +++++++++++++++++++++++++++------------
2 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/doc/TRANSIENT-SETTINGS.md b/doc/TRANSIENT-SETTINGS.md
index 0ea444b133..c2b5c0dcce 100644
--- a/doc/TRANSIENT-SETTINGS.md
+++ b/doc/TRANSIENT-SETTINGS.md
@@ -149,6 +149,7 @@ All execution-related settings are available for transient units.
✓ MemoryDenyWriteExecute=
✓ RestrictNamespaces=
✓ RestrictRealtime=
+✓ RestrictSUIDSGID=
✓ RestrictAddressFamilies=
✓ LockPersonality=
✓ LimitCPU=
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 87fb8b34f4..45ed1864f8 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -348,18 +348,19 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
<varlistentry>
<term><varname>NoNewPrivileges=</varname></term>
- <listitem><para>Takes a boolean argument. If true, ensures that the service process and all its children can
- never gain new privileges through <function>execve()</function> (e.g. via setuid or setgid bits, or filesystem
- capabilities). This is the simplest and most effective way to ensure that a process and its children can never
- elevate privileges again. Defaults to false, but certain settings override this and ignore the value of this
- setting. This is the case when <varname>SystemCallFilter=</varname>,
- <varname>SystemCallArchitectures=</varname>, <varname>RestrictAddressFamilies=</varname>,
- <varname>RestrictNamespaces=</varname>, <varname>PrivateDevices=</varname>,
- <varname>ProtectKernelTunables=</varname>, <varname>ProtectKernelModules=</varname>,
- <varname>MemoryDenyWriteExecute=</varname>, <varname>RestrictRealtime=</varname>, or
- <varname>LockPersonality=</varname> are specified. Note that even if this setting is overridden by them,
- <command>systemctl show</command> shows the original value of this setting. Also see
- <ulink url="https://www.kernel.org/doc/html/latest/userspace-api/no_new_privs.html">No New Privileges
+ <listitem><para>Takes a boolean argument. If true, ensures that the service process and all its
+ children can never gain new privileges through <function>execve()</function> (e.g. via setuid or
+ setgid bits, or filesystem capabilities). This is the simplest and most effective way to ensure that
+ a process and its children can never elevate privileges again. Defaults to false, but certain
+ settings override this and ignore the value of this setting. This is the case when
+ <varname>SystemCallFilter=</varname>, <varname>SystemCallArchitectures=</varname>,
+ <varname>RestrictAddressFamilies=</varname>, <varname>RestrictNamespaces=</varname>,
+ <varname>PrivateDevices=</varname>, <varname>ProtectKernelTunables=</varname>,
+ <varname>ProtectKernelModules=</varname>, <varname>MemoryDenyWriteExecute=</varname>,
+ <varname>RestrictRealtime=</varname>, <varname>RestrictSUIDSGID=</varname> or
+ <varname>LockPersonality=</varname> are specified. Note that even if this setting is overridden by
+ them, <command>systemctl show</command> shows the original value of this setting. Also see <ulink
+ url="https://www.kernel.org/doc/html/latest/userspace-api/no_new_privs.html">No New Privileges
Flag</ulink>. </para></listitem>
</varlistentry>
@@ -1274,6 +1275,22 @@ RestrictNamespaces=~cgroup net</programlisting>
that actually require them. Defaults to off.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>RestrictSUIDSGID=</varname></term>
+
+ <listitem><para>Takes a boolean argument. If set, any attempts to set the set-user-ID (SUID) or
+ set-group-ID (SGID) bits on files or directories will be denied (for details on these bits see
+ <citerefentry
+ project='man-pages'><refentrytitle>inode</refentrytitle><manvolnum>7</manvolnum></citerefentry>). If
+ running in user mode, or in system mode, but without the <constant>CAP_SYS_ADMIN</constant>
+ capability (e.g. setting <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname> is
+ implied. As the SUID/SGID bits are mechanisms to elevate privileges, and allows users to acquire the
+ identity of other users, it is recommended to restrict creation of SUID/SGID files to the few
+ programs that actually require them. Note that this restricts marking of any type of file system
+ object with these bits, including both regular files and directories (where the SGID is a different
+ meaning than for files, see documentation). Defaults to off.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>RemoveIPC=</varname></term>

View File

@ -0,0 +1,157 @@
From b0573f1a6f8022aed4954d5ca19cc037d25cd5e7 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 20 Mar 2019 19:52:20 +0100
Subject: [PATCH] units: turn on RestrictSUIDSGID= in most of our long-running
daemons
(cherry picked from commit 62aa29247c3d74bcec0607c347f2be23cd90675d)
Related: #1687512
---
units/systemd-coredump@.service.in | 1 +
units/systemd-hostnamed.service.in | 1 +
units/systemd-journal-remote.service.in | 1 +
units/systemd-journald.service.in | 1 +
units/systemd-localed.service.in | 1 +
units/systemd-logind.service.in | 1 +
units/systemd-networkd.service.in | 1 +
units/systemd-resolved.service.in | 1 +
units/systemd-timedated.service.in | 1 +
units/systemd-timesyncd.service.in | 1 +
units/systemd-udevd.service.in | 3 ++-
11 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/units/systemd-coredump@.service.in b/units/systemd-coredump@.service.in
index 68a68a5055..d69ebd8b24 100644
--- a/units/systemd-coredump@.service.in
+++ b/units/systemd-coredump@.service.in
@@ -33,6 +33,7 @@ MemoryDenyWriteExecute=yes
RestrictRealtime=yes
RestrictNamespaces=yes
RestrictAddressFamilies=AF_UNIX
+RestrictSUIDSGID=yes
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
SystemCallArchitectures=native
diff --git a/units/systemd-hostnamed.service.in b/units/systemd-hostnamed.service.in
index 4e5470dd29..97d4e142bc 100644
--- a/units/systemd-hostnamed.service.in
+++ b/units/systemd-hostnamed.service.in
@@ -29,6 +29,7 @@ MemoryDenyWriteExecute=yes
RestrictRealtime=yes
RestrictNamespaces=yes
RestrictAddressFamilies=AF_UNIX
+RestrictSUIDSGID=yes
SystemCallFilter=@system-service sethostname
SystemCallErrorNumber=EPERM
SystemCallArchitectures=native
diff --git a/units/systemd-journal-remote.service.in b/units/systemd-journal-remote.service.in
index a94265f215..3c914f5a40 100644
--- a/units/systemd-journal-remote.service.in
+++ b/units/systemd-journal-remote.service.in
@@ -28,6 +28,7 @@ MemoryDenyWriteExecute=yes
RestrictRealtime=yes
RestrictNamespaces=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
+RestrictSUIDSGID=yes
SystemCallArchitectures=native
LockPersonality=yes
LogsDirectory=journal/remote
diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in
index e109b25792..ab9ec35ff8 100644
--- a/units/systemd-journald.service.in
+++ b/units/systemd-journald.service.in
@@ -21,6 +21,7 @@ Sockets=systemd-journald.socket systemd-journald-dev-log.socket
ExecStart=@rootlibexecdir@/systemd-journald
Restart=always
RestartSec=0
+RestrictSUIDSGID=yes
StandardOutput=null
WatchdogSec=3min
FileDescriptorStoreMax=4224
diff --git a/units/systemd-localed.service.in b/units/systemd-localed.service.in
index ce043db154..b87d60e9eb 100644
--- a/units/systemd-localed.service.in
+++ b/units/systemd-localed.service.in
@@ -29,6 +29,7 @@ MemoryDenyWriteExecute=yes
RestrictRealtime=yes
RestrictNamespaces=yes
RestrictAddressFamilies=AF_UNIX
+RestrictSUIDSGID=yes
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
SystemCallArchitectures=native
diff --git a/units/systemd-logind.service.in b/units/systemd-logind.service.in
index 6953fac55b..086338e03b 100644
--- a/units/systemd-logind.service.in
+++ b/units/systemd-logind.service.in
@@ -30,6 +30,7 @@ MemoryDenyWriteExecute=yes
RestrictRealtime=yes
RestrictNamespaces=yes
RestrictAddressFamilies=AF_UNIX AF_NETLINK
+RestrictSUIDSGID=yes
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
SystemCallArchitectures=native
diff --git a/units/systemd-networkd.service.in b/units/systemd-networkd.service.in
index 371ab3a9cf..a0f34ac738 100644
--- a/units/systemd-networkd.service.in
+++ b/units/systemd-networkd.service.in
@@ -39,6 +39,7 @@ SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
SystemCallArchitectures=native
LockPersonality=yes
+RestrictSUIDSGID=yes
RuntimeDirectory=systemd/netif
RuntimeDirectoryPreserve=yes
diff --git a/units/systemd-resolved.service.in b/units/systemd-resolved.service.in
index aaed406ab2..6c2ad5ca86 100644
--- a/units/systemd-resolved.service.in
+++ b/units/systemd-resolved.service.in
@@ -41,6 +41,7 @@ SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
SystemCallArchitectures=native
LockPersonality=yes
+RestrictSUIDSGID=yes
RuntimeDirectory=systemd/resolve
RuntimeDirectoryPreserve=yes
diff --git a/units/systemd-timedated.service.in b/units/systemd-timedated.service.in
index 662b39557a..1da2bc4bb0 100644
--- a/units/systemd-timedated.service.in
+++ b/units/systemd-timedated.service.in
@@ -27,6 +27,7 @@ MemoryDenyWriteExecute=yes
RestrictRealtime=yes
RestrictNamespaces=yes
RestrictAddressFamilies=AF_UNIX
+RestrictSUIDSGID=yes
SystemCallFilter=@system-service @clock
SystemCallErrorNumber=EPERM
SystemCallArchitectures=native
diff --git a/units/systemd-timesyncd.service.in b/units/systemd-timesyncd.service.in
index 4a490b6e16..c2b9551726 100644
--- a/units/systemd-timesyncd.service.in
+++ b/units/systemd-timesyncd.service.in
@@ -37,6 +37,7 @@ MemoryDenyWriteExecute=yes
RestrictRealtime=yes
RestrictNamespaces=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
+RestrictSUIDSGID=yes
RuntimeDirectory=systemd/timesync
SystemCallFilter=@system-service @clock
SystemCallErrorNumber=EPERM
diff --git a/units/systemd-udevd.service.in b/units/systemd-udevd.service.in
index fd9ead3bb8..970cf0f290 100644
--- a/units/systemd-udevd.service.in
+++ b/units/systemd-udevd.service.in
@@ -27,8 +27,9 @@ WatchdogSec=3min
TasksMax=infinity
PrivateMounts=yes
MemoryDenyWriteExecute=yes
-RestrictRealtime=yes
RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6
+RestrictRealtime=yes
+RestrictSUIDSGID=yes
SystemCallFilter=@system-service @module @raw-io
SystemCallErrorNumber=EPERM
SystemCallArchitectures=native

View File

@ -0,0 +1,89 @@
From 11f5677752f9b78239214b3064e5a2c3712d71b1 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 20 Mar 2019 20:19:38 +0100
Subject: [PATCH] core: imply NNP and SUID/SGID restriction for DynamicUser=yes
service
Let's be safe, rather than sorry. This way DynamicUser=yes services can
neither take benefit of, nor create SUID/SGID binaries.
Given that DynamicUser= is a recent addition only we should be able to
get away with turning this on, even though this is strictly speaking a
binary compatibility breakage.
(cherry picked from commit bf65b7e0c9fc215897b676ab9a7c9d1c688143ba)
Resolves: #1687512
---
man/systemd.exec.xml | 16 ++++++++++------
src/core/unit.c | 10 ++++++++--
2 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 45ed1864f8..bdaed68162 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -229,7 +229,9 @@
created by the executed processes is bound to the runtime of the service, and hence the lifetime of the dynamic
user/group. Since <filename>/tmp</filename> and <filename>/var/tmp</filename> are usually the only
world-writable directories on a system this ensures that a unit making use of dynamic user/group allocation
- cannot leave files around after unit termination. Moreover <varname>ProtectSystem=strict</varname> and
+ cannot leave files around after unit termination. Furthermore <varname>NoNewPrivileges=</varname> and
+ <varname>RestrictSUIDSGID=</varname> are implicitly enabled to ensure that processes invoked cannot take benefit
+ or create SUID/SGID files or directories. Moreover <varname>ProtectSystem=strict</varname> and
<varname>ProtectHome=read-only</varname> are implied, thus prohibiting the service to write to arbitrary file
system locations. In order to allow the service to write to certain directories, they have to be whitelisted
using <varname>ReadWritePaths=</varname>, but care must be taken so that UID/GID recycling doesn't create
@@ -357,11 +359,12 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
<varname>RestrictAddressFamilies=</varname>, <varname>RestrictNamespaces=</varname>,
<varname>PrivateDevices=</varname>, <varname>ProtectKernelTunables=</varname>,
<varname>ProtectKernelModules=</varname>, <varname>MemoryDenyWriteExecute=</varname>,
- <varname>RestrictRealtime=</varname>, <varname>RestrictSUIDSGID=</varname> or
- <varname>LockPersonality=</varname> are specified. Note that even if this setting is overridden by
- them, <command>systemctl show</command> shows the original value of this setting. Also see <ulink
+ <varname>RestrictRealtime=</varname>, <varname>RestrictSUIDSGID=</varname>,
+ <varname>DynamicUser=</varname> or <varname>LockPersonality=</varname> are specified. Note that even
+ if this setting is overridden by them, <command>systemctl show</command> shows the original value of
+ this setting. Also see <ulink
url="https://www.kernel.org/doc/html/latest/userspace-api/no_new_privs.html">No New Privileges
- Flag</ulink>. </para></listitem>
+ Flag</ulink>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -1288,7 +1291,8 @@ RestrictNamespaces=~cgroup net</programlisting>
identity of other users, it is recommended to restrict creation of SUID/SGID files to the few
programs that actually require them. Note that this restricts marking of any type of file system
object with these bits, including both regular files and directories (where the SGID is a different
- meaning than for files, see documentation). Defaults to off.</para></listitem>
+ meaning than for files, see documentation). This option is implied if <varname>DynamicUser=</varname>
+ is enabled. Defaults to off.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/src/core/unit.c b/src/core/unit.c
index 115739f4c6..e1f5e6f7bd 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -4161,14 +4161,20 @@ int unit_patch_contexts(Unit *u) {
return -ENOMEM;
}
- /* If the dynamic user option is on, let's make sure that the unit can't leave its UID/GID
- * around in the file system or on IPC objects. Hence enforce a strict sandbox. */
+ /* If the dynamic user option is on, let's make sure that the unit can't leave its
+ * UID/GID around in the file system or on IPC objects. Hence enforce a strict
+ * sandbox. */
ec->private_tmp = true;
ec->remove_ipc = true;
ec->protect_system = PROTECT_SYSTEM_STRICT;
if (ec->protect_home == PROTECT_HOME_NO)
ec->protect_home = PROTECT_HOME_READ_ONLY;
+
+ /* Make sure this service can neither benefit from SUID/SGID binaries nor create
+ * them. */
+ ec->no_new_privileges = true;
+ ec->restrict_suid_sgid = true;
}
}

View File

@ -0,0 +1,555 @@
From b55c9b8e717d1967e6aa16c1e2646fc81d899ab7 Mon Sep 17 00:00:00 2001
From: Pavel Hrdina <phrdina@redhat.com>
Date: Mon, 29 Jul 2019 17:50:05 +0200
Subject: [PATCH] cgroup: introduce support for cgroup v2 CPUSET controller
Introduce support for configuring cpus and mems for processes using
cgroup v2 CPUSET controller. This allows users to limit which cpus
and memory NUMA nodes can be used by processes to better utilize
system resources.
The cgroup v2 interfaces to control it are cpuset.cpus and cpuset.mems
where the requested configuration is written. However, it doesn't mean
that the requested configuration will be actually used as parent cgroup
may limit the cpus or mems as well. In order to reflect the real
configuration cgroup v2 provides read-only files cpuset.cpus.effective
and cpuset.mems.effective which are exported to users as well.
(cherry picked from commit 047f5d63d7a1ab75073f8485e2f9b550d25b0772)
Related: #1724617
---
doc/TRANSIENT-SETTINGS.md | 2 +
man/systemd.resource-control.xml | 30 +++++++++++++
src/basic/cgroup-util.c | 1 +
src/basic/cgroup-util.h | 2 +
src/core/cgroup.c | 63 +++++++++++++++++++++++++++
src/core/cgroup.h | 5 +++
src/core/dbus-cgroup.c | 59 +++++++++++++++++++++++++
src/core/dbus-unit.c | 48 ++++++++++++++++++++
src/core/load-fragment-gperf.gperf.m4 | 2 +
src/core/load-fragment.c | 38 ++++++++++++++++
src/core/load-fragment.h | 2 +
src/shared/bus-unit-util.c | 16 +++++++
src/systemctl/systemctl.c | 2 +-
src/test/test-cgroup-mask.c | 3 +-
14 files changed, 271 insertions(+), 2 deletions(-)
diff --git a/doc/TRANSIENT-SETTINGS.md b/doc/TRANSIENT-SETTINGS.md
index c2b5c0dcce..0b2ad66dcb 100644
--- a/doc/TRANSIENT-SETTINGS.md
+++ b/doc/TRANSIENT-SETTINGS.md
@@ -218,6 +218,8 @@ All cgroup/resource control settings are available for transient units
✓ CPUShares=
✓ StartupCPUShares=
✓ CPUQuota=
+✓ AllowedCPUs=
+✓ AllowedMemoryNodes=
✓ MemoryAccounting=
✓ MemoryLow=
✓ MemoryHigh=
diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
index 370c110592..4329742e94 100644
--- a/man/systemd.resource-control.xml
+++ b/man/systemd.resource-control.xml
@@ -201,6 +201,36 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>AllowedCPUs=</varname></term>
+
+ <listitem>
+ <para>Restrict processes to be executed on specific CPUs. Takes a list of CPU indices or ranges separated by either
+ whitespace or commas. CPU ranges are specified by the lower and upper CPU indices separated by a dash.</para>
+
+ <para>Setting <varname>AllowedCPUs=</varname> doesn't guarantee that all of the CPUs will be used by the processes
+ as it may be limited by parent units. The effective configuration is reported as <varname>EffectiveCPUs=</varname>.</para>
+
+ <para>This setting is supported only with the unified control group hierarchy.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>AllowedMemoryNodes=</varname></term>
+
+ <listitem>
+ <para>Restrict processes to be executed on specific memory NUMA nodes. Takes a list of memory NUMA nodes indices
+ or ranges separated by either whitespace or commas. Memory NUMA nodes ranges are specified by the lower and upper
+ CPU indices separated by a dash.</para>
+
+ <para>Setting <varname>AllowedMemoryNodes=</varname> doesn't guarantee that all of the memory NUMA nodes will
+ be used by the processes as it may be limited by parent units. The effective configuration is reported as
+ <varname>EffectiveMemoryNodes=</varname>.</para>
+
+ <para>This setting is supported only with the unified control group hierarchy.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>MemoryAccounting=</varname></term>
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index 038ece4b06..6f47c3aacb 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -2763,6 +2763,7 @@ bool fd_is_cgroup_fs(int fd) {
static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
[CGROUP_CONTROLLER_CPU] = "cpu",
[CGROUP_CONTROLLER_CPUACCT] = "cpuacct",
+ [CGROUP_CONTROLLER_CPUSET] = "cpuset",
[CGROUP_CONTROLLER_IO] = "io",
[CGROUP_CONTROLLER_BLKIO] = "blkio",
[CGROUP_CONTROLLER_MEMORY] = "memory",
diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h
index 26e3ae0404..b414600dca 100644
--- a/src/basic/cgroup-util.h
+++ b/src/basic/cgroup-util.h
@@ -21,6 +21,7 @@
typedef enum CGroupController {
CGROUP_CONTROLLER_CPU,
CGROUP_CONTROLLER_CPUACCT, /* v1 only */
+ CGROUP_CONTROLLER_CPUSET, /* v2 only */
CGROUP_CONTROLLER_IO, /* v2 only */
CGROUP_CONTROLLER_BLKIO, /* v1 only */
CGROUP_CONTROLLER_MEMORY,
@@ -36,6 +37,7 @@ typedef enum CGroupController {
typedef enum CGroupMask {
CGROUP_MASK_CPU = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPU),
CGROUP_MASK_CPUACCT = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUACCT),
+ CGROUP_MASK_CPUSET = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUSET),
CGROUP_MASK_IO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_IO),
CGROUP_MASK_BLKIO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BLKIO),
CGROUP_MASK_MEMORY = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_MEMORY),
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 76eafdc082..664d269483 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -161,9 +161,14 @@ void cgroup_context_done(CGroupContext *c) {
c->ip_address_allow = ip_address_access_free_all(c->ip_address_allow);
c->ip_address_deny = ip_address_access_free_all(c->ip_address_deny);
+
+ cpu_set_reset(&c->cpuset_cpus);
+ cpu_set_reset(&c->cpuset_mems);
}
void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
+ _cleanup_free_ char *cpuset_cpus = NULL;
+ _cleanup_free_ char *cpuset_mems = NULL;
CGroupIODeviceLimit *il;
CGroupIODeviceWeight *iw;
CGroupBlockIODeviceBandwidth *b;
@@ -177,6 +182,9 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
prefix = strempty(prefix);
+ cpuset_cpus = cpu_set_to_range_string(&c->cpuset_cpus);
+ cpuset_mems = cpu_set_to_range_string(&c->cpuset_mems);
+
fprintf(f,
"%sCPUAccounting=%s\n"
"%sIOAccounting=%s\n"
@@ -189,6 +197,8 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
"%sCPUShares=%" PRIu64 "\n"
"%sStartupCPUShares=%" PRIu64 "\n"
"%sCPUQuotaPerSecSec=%s\n"
+ "%sAllowedCPUs=%s\n"
+ "%sAllowedMemoryNodes=%s\n"
"%sIOWeight=%" PRIu64 "\n"
"%sStartupIOWeight=%" PRIu64 "\n"
"%sBlockIOWeight=%" PRIu64 "\n"
@@ -212,6 +222,8 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
prefix, c->cpu_shares,
prefix, c->startup_cpu_shares,
prefix, format_timespan(u, sizeof(u), c->cpu_quota_per_sec_usec, 1),
+ prefix, cpuset_cpus,
+ prefix, cpuset_mems,
prefix, c->io_weight,
prefix, c->startup_io_weight,
prefix, c->blockio_weight,
@@ -541,6 +553,21 @@ static uint64_t cgroup_cpu_weight_to_shares(uint64_t weight) {
CGROUP_CPU_SHARES_MIN, CGROUP_CPU_SHARES_MAX);
}
+static void cgroup_apply_unified_cpuset(Unit *u, CPUSet cpus, const char *name) {
+ _cleanup_free_ char *buf = NULL;
+ int r;
+
+ buf = cpu_set_to_range_string(&cpus);
+ if (!buf)
+ return;
+
+ r = cg_set_attribute("cpuset", u->cgroup_path, name, buf);
+ if (r < 0)
+ log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set %s: %m", name);
+
+}
+
static bool cgroup_context_has_io_config(CGroupContext *c) {
return c->io_accounting ||
c->io_weight != CGROUP_WEIGHT_INVALID ||
@@ -766,6 +793,11 @@ static void cgroup_context_apply(
}
}
+ if ((apply_mask & CGROUP_MASK_CPUSET) && !is_root) {
+ cgroup_apply_unified_cpuset(u, c->cpuset_cpus, "cpuset.cpus");
+ cgroup_apply_unified_cpuset(u, c->cpuset_mems, "cpuset.mems");
+ }
+
if (apply_mask & CGROUP_MASK_IO) {
bool has_io = cgroup_context_has_io_config(c);
bool has_blockio = cgroup_context_has_blockio_config(c);
@@ -1068,6 +1100,9 @@ CGroupMask cgroup_context_get_mask(CGroupContext *c) {
c->cpu_quota_per_sec_usec != USEC_INFINITY)
mask |= CGROUP_MASK_CPUACCT | CGROUP_MASK_CPU;
+ if (c->cpuset_cpus.set || c->cpuset_mems.set)
+ mask |= CGROUP_MASK_CPUSET;
+
if (cgroup_context_has_io_config(c) || cgroup_context_has_blockio_config(c))
mask |= CGROUP_MASK_IO | CGROUP_MASK_BLKIO;
@@ -2697,4 +2732,32 @@ static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] =
[CGROUP_STRICT] = "strict",
};
+int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name) {
+ _cleanup_free_ char *v = NULL;
+ int r;
+
+ assert(u);
+ assert(cpus);
+
+ if (!u->cgroup_path)
+ return -ENODATA;
+
+ if ((u->cgroup_realized_mask & CGROUP_MASK_CPUSET) == 0)
+ return -ENODATA;
+
+ r = cg_all_unified();
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ENODATA;
+ if (r > 0)
+ r = cg_get_attribute("cpuset", u->cgroup_path, name, &v);
+ if (r == -ENOENT)
+ return -ENODATA;
+ if (r < 0)
+ return r;
+
+ return parse_cpu_set_full(v, cpus, false, NULL, NULL, 0, NULL);
+}
+
DEFINE_STRING_TABLE_LOOKUP(cgroup_device_policy, CGroupDevicePolicy);
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index 2d2ff6fc3c..da10575394 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -4,6 +4,7 @@
#include <stdbool.h>
#include "cgroup-util.h"
+#include "cpu-set-util.h"
#include "ip-address-access.h"
#include "list.h"
#include "time-util.h"
@@ -77,6 +78,9 @@ struct CGroupContext {
uint64_t startup_cpu_weight;
usec_t cpu_quota_per_sec_usec;
+ CPUSet cpuset_cpus;
+ CPUSet cpuset_mems;
+
uint64_t io_weight;
uint64_t startup_io_weight;
LIST_HEAD(CGroupIODeviceWeight, io_device_weights);
@@ -205,3 +209,4 @@ const char* cgroup_device_policy_to_string(CGroupDevicePolicy i) _const_;
CGroupDevicePolicy cgroup_device_policy_from_string(const char *s) _pure_;
bool unit_cgroup_delegate(Unit *u);
+int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name);
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index 540bc77aed..30d4e83932 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -53,6 +53,27 @@ static int property_get_delegate_controllers(
return sd_bus_message_close_container(reply);
}
+static int property_get_cpuset(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ CPUSet *cpus = userdata;
+ _cleanup_free_ uint8_t *array = NULL;
+ size_t allocated;
+
+ assert(bus);
+ assert(reply);
+ assert(cpus);
+
+ (void) cpu_set_to_dbus(cpus, &array, &allocated);
+ return sd_bus_message_append_array(reply, 'y', array, allocated);
+}
+
static int property_get_io_device_weight(
sd_bus *bus,
const char *path,
@@ -283,6 +304,8 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
SD_BUS_PROPERTY("CPUShares", "t", NULL, offsetof(CGroupContext, cpu_shares), 0),
SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0),
SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0),
+ SD_BUS_PROPERTY("AllowedCPUs", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_cpus), 0),
+ SD_BUS_PROPERTY("AllowedMemoryNodes", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_mems), 0),
SD_BUS_PROPERTY("IOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, io_accounting), 0),
SD_BUS_PROPERTY("IOWeight", "t", NULL, offsetof(CGroupContext, io_weight), 0),
SD_BUS_PROPERTY("StartupIOWeight", "t", NULL, offsetof(CGroupContext, startup_io_weight), 0),
@@ -671,6 +694,42 @@ int bus_cgroup_set_property(
return 1;
+ } else if (STR_IN_SET(name, "AllowedCPUs", "AllowedMemoryNodes")) {
+ const void *a;
+ size_t n;
+ _cleanup_(cpu_set_reset) CPUSet new_set = {};
+
+ r = sd_bus_message_read_array(message, 'y', &a, &n);
+ if (r < 0)
+ return r;
+
+ r = cpu_set_from_dbus(a, n, &new_set);
+ if (r < 0)
+ return r;
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ _cleanup_free_ char *setstr = NULL;
+ _cleanup_free_ char *data = NULL;
+ CPUSet *set;
+
+ setstr = cpu_set_to_range_string(&new_set);
+
+ if (streq(name, "AllowedCPUs"))
+ set = &c->cpuset_cpus;
+ else
+ set = &c->cpuset_mems;
+
+ if (asprintf(&data, "%s=%s", name, setstr) < 0)
+ return -ENOMEM;
+
+ cpu_set_reset(set);
+ cpu_set_add_all(set, &new_set);
+ unit_invalidate_cgroup(u, CGROUP_MASK_CPUSET);
+ unit_write_setting(u, flags, name, data);
+ }
+
+ return 1;
+
} else if ((iol_type = cgroup_io_limit_type_from_string(name)) >= 0) {
const char *path;
unsigned n = 0;
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index c5bca10979..aa15e47754 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -752,6 +752,52 @@ static int property_get_cpu_usage(
return sd_bus_message_append(reply, "t", ns);
}
+static int property_get_cpuset_cpus(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Unit *u = userdata;
+ _cleanup_(cpu_set_reset) CPUSet cpus = {};
+ _cleanup_free_ uint8_t *array = NULL;
+ size_t allocated;
+
+ assert(bus);
+ assert(reply);
+ assert(u);
+
+ (void) unit_get_cpuset(u, &cpus, "cpuset.cpus.effective");
+ (void) cpu_set_to_dbus(&cpus, &array, &allocated);
+ return sd_bus_message_append_array(reply, 'y', array, allocated);
+}
+
+static int property_get_cpuset_mems(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Unit *u = userdata;
+ _cleanup_(cpu_set_reset) CPUSet mems = {};
+ _cleanup_free_ uint8_t *array = NULL;
+ size_t allocated;
+
+ assert(bus);
+ assert(reply);
+ assert(u);
+
+ (void) unit_get_cpuset(u, &mems, "cpuset.mems.effective");
+ (void) cpu_set_to_dbus(&mems, &array, &allocated);
+ return sd_bus_message_append_array(reply, 'y', array, allocated);
+}
+
static int property_get_cgroup(
sd_bus *bus,
const char *path,
@@ -1074,6 +1120,8 @@ const sd_bus_vtable bus_unit_cgroup_vtable[] = {
SD_BUS_PROPERTY("ControlGroup", "s", property_get_cgroup, 0, 0),
SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0),
+ SD_BUS_PROPERTY("EffectiveCPUs", "ay", property_get_cpuset_cpus, 0, 0),
+ SD_BUS_PROPERTY("EffectiveMemoryNodes", "ay", property_get_cpuset_mems, 0, 0),
SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0),
SD_BUS_PROPERTY("IPIngressBytes", "t", property_get_ip_counter, 0, 0),
SD_BUS_PROPERTY("IPIngressPackets", "t", property_get_ip_counter, 0, 0),
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 49e938d0ce..ebb44df487 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -167,6 +167,8 @@ $1.StartupCPUWeight, config_parse_cg_weight, 0,
$1.CPUShares, config_parse_cpu_shares, 0, offsetof($1, cgroup_context.cpu_shares)
$1.StartupCPUShares, config_parse_cpu_shares, 0, offsetof($1, cgroup_context.startup_cpu_shares)
$1.CPUQuota, config_parse_cpu_quota, 0, offsetof($1, cgroup_context)
+$1.CPUSetCpus, config_parse_cpuset_cpus, 0, offsetof($1, cgroup_context)
+$1.CPUSetMems, config_parse_cpuset_mems, 0, offsetof($1, cgroup_context)
$1.MemoryAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.memory_accounting)
$1.MemoryLow, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
$1.MemoryHigh, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 35dd595098..6debf82401 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -3011,6 +3011,44 @@ int config_parse_cpu_quota(
return 0;
}
+int config_parse_cpuset_cpus(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ CGroupContext *c = data;
+
+ (void) parse_cpu_set_extend(rvalue, &c->cpuset_cpus, true, unit, filename, line, lvalue);
+
+ return 0;
+}
+
+int config_parse_cpuset_mems(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ CGroupContext *c = data;
+
+ (void) parse_cpu_set_extend(rvalue, &c->cpuset_mems, true, unit, filename, line, lvalue);
+
+ return 0;
+}
+
int config_parse_memory_limit(
const char *unit,
const char *filename,
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index f2ca1b8ee7..6612e1fb32 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -86,6 +86,8 @@ CONFIG_PARSER_PROTOTYPE(config_parse_set_status);
CONFIG_PARSER_PROTOTYPE(config_parse_namespace_path_strv);
CONFIG_PARSER_PROTOTYPE(config_parse_temporary_filesystems);
CONFIG_PARSER_PROTOTYPE(config_parse_cpu_quota);
+CONFIG_PARSER_PROTOTYPE(config_parse_cpuset_cpus);
+CONFIG_PARSER_PROTOTYPE(config_parse_cpuset_mems);
CONFIG_PARSER_PROTOTYPE(config_parse_protect_home);
CONFIG_PARSER_PROTOTYPE(config_parse_protect_system);
CONFIG_PARSER_PROTOTYPE(config_parse_bus_name);
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 3c42e97b7a..8f3b463c6b 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -396,6 +396,22 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
return bus_append_cg_cpu_shares_parse(m, field, eq);
+ if (STR_IN_SET(field, "AllowedCPUs", "AllowedMemoryNodes")) {
+ _cleanup_(cpu_set_reset) CPUSet cpuset = {};
+ _cleanup_free_ uint8_t *array = NULL;
+ size_t allocated;
+
+ r = parse_cpu_set(eq, &cpuset);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
+
+ r = cpu_set_to_dbus(&cpuset, &array, &allocated);
+ if (r < 0)
+ return log_error_errno(r, "Failed to serialize CPUSet: %m");
+
+ return bus_append_byte_array(m, field, array, allocated);
+ }
+
if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight"))
return bus_append_cg_blkio_weight_parse(m, field, eq);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 7274921e6d..a3074bc5e3 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -4892,7 +4892,7 @@ static int print_property(const char *name, sd_bus_message *m, bool value, bool
print_prop(name, "%s", h);
return 1;
- } else if (contents[0] == SD_BUS_TYPE_BYTE && STR_IN_SET(name, "CPUAffinity", "NUMAMask")) {
+ } else if (contents[0] == SD_BUS_TYPE_BYTE && STR_IN_SET(name, "CPUAffinity", "NUMAMask", "AllowedCPUs", "AllowedMemoryNodes", "EffectiveCPUs", "EffectiveMemoryNodes")) {
_cleanup_free_ char *affinity = NULL;
_cleanup_(cpu_set_reset) CPUSet set = {};
const void *a;
diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c
index d65959edf1..93c3f5d856 100644
--- a/src/test/test-cgroup-mask.c
+++ b/src/test/test-cgroup-mask.c
@@ -104,9 +104,10 @@ static void test_cg_mask_to_string_one(CGroupMask mask, const char *t) {
static void test_cg_mask_to_string(void) {
test_cg_mask_to_string_one(0, NULL);
- test_cg_mask_to_string_one(_CGROUP_MASK_ALL, "cpu cpuacct io blkio memory devices pids");
+ test_cg_mask_to_string_one(_CGROUP_MASK_ALL, "cpu cpuacct cpuset io blkio memory devices pids");
test_cg_mask_to_string_one(CGROUP_MASK_CPU, "cpu");
test_cg_mask_to_string_one(CGROUP_MASK_CPUACCT, "cpuacct");
+ test_cg_mask_to_string_one(CGROUP_MASK_CPUSET, "cpuset");
test_cg_mask_to_string_one(CGROUP_MASK_IO, "io");
test_cg_mask_to_string_one(CGROUP_MASK_BLKIO, "blkio");
test_cg_mask_to_string_one(CGROUP_MASK_MEMORY, "memory");

View File

@ -0,0 +1,38 @@
From e809564cfa5af01a26075682d49f81a987c41dd8 Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Wed, 2 Oct 2019 11:58:16 +0200
Subject: [PATCH] pid1: fix DefaultTasksMax initialization
Otherwise DefaultTasksMax is always set to "inifinity".
This was broken by fb39af4ce42.
(cherry picked from commit c0000de87d2c7934cb1f4ba66a533a85277600ff)
Resolves: #1809037
---
src/core/main.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/core/main.c b/src/core/main.c
index d6550ea161..45d09b1e11 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -2088,7 +2088,7 @@ static void reset_arguments(void) {
arg_default_blockio_accounting = false;
arg_default_memory_accounting = MEMORY_ACCOUNTING_DEFAULT;
arg_default_tasks_accounting = true;
- arg_default_tasks_max = UINT64_MAX;
+ arg_default_tasks_max = system_tasks_max_scale(DEFAULT_TASKS_MAX_PERCENTAGE, 100U);
arg_machine_id = (sd_id128_t) {};
arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE;
@@ -2103,8 +2103,6 @@ static int parse_configuration(const struct rlimit *saved_rlimit_nofile,
assert(saved_rlimit_nofile);
assert(saved_rlimit_memlock);
- arg_default_tasks_max = system_tasks_max_scale(DEFAULT_TASKS_MAX_PERCENTAGE, 100U);
-
/* Assign configuration defaults */
reset_arguments();

View File

@ -0,0 +1,40 @@
From 5fc2d94fbf8271bb340e834f832af5d890c267bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= <msekleta@redhat.com>
Date: Tue, 3 Mar 2020 11:45:00 +0100
Subject: [PATCH] cgroup: make sure that cpuset is supported on cgroup v2 and
disabled with v1
Resolves: #1808940
(rhel-only)
---
src/basic/cgroup-util.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index 6f47c3aacb..92bc1f2543 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -2353,10 +2353,10 @@ int cg_mask_supported(CGroupMask *ret) {
if (r < 0)
return r;
- /* Currently, we support the cpu, memory, io and pids
+ /* Currently, we support the cpu, memory, io, pids and cpuset
* controller in the unified hierarchy, mask
* everything else off. */
- mask &= CGROUP_MASK_CPU | CGROUP_MASK_MEMORY | CGROUP_MASK_IO | CGROUP_MASK_PIDS;
+ mask &= CGROUP_MASK_CPU | CGROUP_MASK_MEMORY | CGROUP_MASK_IO | CGROUP_MASK_PIDS | CGROUP_MASK_CPUSET;
} else {
CGroupController c;
@@ -2367,6 +2367,9 @@ int cg_mask_supported(CGroupMask *ret) {
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
const char *n;
+ if (c == CGROUP_CONTROLLER_CPUSET)
+ continue;
+
n = cgroup_controller_to_string(c);
if (controller_is_accessible(n) >= 0)
mask |= CGROUP_CONTROLLER_TO_MASK(c);

View File

@ -0,0 +1,380 @@
From 90dda340e4adeb1126639a849d4f31ae327fdc4b Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 25 Jun 2019 23:01:40 +0200
Subject: [PATCH] test: introduce TEST-36-NUMAPOLICY
(cherry picked from commit 8f65e26508969610ac934d1aadbade8223bfcaac)
Related: #1808940
---
test/TEST-36-NUMAPOLICY/Makefile | 1 +
test/TEST-36-NUMAPOLICY/test.sh | 51 +++++
test/TEST-36-NUMAPOLICY/testsuite.sh | 292 +++++++++++++++++++++++++++
3 files changed, 344 insertions(+)
create mode 120000 test/TEST-36-NUMAPOLICY/Makefile
create mode 100755 test/TEST-36-NUMAPOLICY/test.sh
create mode 100755 test/TEST-36-NUMAPOLICY/testsuite.sh
diff --git a/test/TEST-36-NUMAPOLICY/Makefile b/test/TEST-36-NUMAPOLICY/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-36-NUMAPOLICY/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-36-NUMAPOLICY/test.sh b/test/TEST-36-NUMAPOLICY/test.sh
new file mode 100755
index 0000000000..a0d8623e8e
--- /dev/null
+++ b/test/TEST-36-NUMAPOLICY/test.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+set -e
+TEST_DESCRIPTION="test MUMAPolicy= and NUMAMask= options"
+TEST_NO_NSPAWN=1
+QEMU_OPTIONS="-numa node,nodeid=0"
+
+. $TEST_BASE_DIR/test-functions
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+ inst_binary mktemp
+
+ # mask some services that we do not want to run in these tests
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service
+
+ # setup the testsuite service
+ cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+
+[Service]
+ExecStart=/bin/bash -x /testsuite.sh
+Type=oneshot
+StandardOutput=tty
+StandardError=tty
+NotifyAccess=all
+EOF
+ cp testsuite.sh $initdir/
+
+ setup_testsuite
+ ) || return 1
+ setup_nspawn_root
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+do_test "$@"
diff --git a/test/TEST-36-NUMAPOLICY/testsuite.sh b/test/TEST-36-NUMAPOLICY/testsuite.sh
new file mode 100755
index 0000000000..e15087b137
--- /dev/null
+++ b/test/TEST-36-NUMAPOLICY/testsuite.sh
@@ -0,0 +1,292 @@
+#!/bin/bash
+set -ex
+set -o pipefail
+
+at_exit() {
+ if [ $? -ne 0 ]; then
+ # We're exiting with a non-zero EC, let's dump test artifacts
+ # for easier debugging
+ [ -f "$straceLog" ] && cat "$straceLog"
+ [ -f "$journalLog" ] && cat "$journalLog"
+ fi
+}
+
+trap at_exit EXIT
+
+systemd-analyze log-level debug
+systemd-analyze log-target journal
+
+# Log files
+straceLog='strace.log'
+journalLog='journal.log'
+
+# Systemd config files
+testUnit='numa-test.service'
+testUnitFile="/etc/systemd/system/$testUnit"
+testUnitNUMAConf="$testUnitFile.d/numa.conf"
+
+# Sleep constants (we should probably figure out something better but nothing comes to mind)
+journalSleep=5
+sleepAfterStart=1
+
+startStrace() {
+ coproc strace -qq -p 1 -o $straceLog -e set_mempolicy -s 1024 $1
+}
+
+stopStrace() {
+ kill -s TERM $COPROC_PID
+}
+
+startJournalctl() {
+ coproc journalctl -u init.scope -f > $journalLog
+}
+
+stopJournalctl() {
+ # Wait a few seconds until the messages get properly queued...
+ sleep $journalSleep
+ # ...and then force journald to write them to the backing storage
+ # Also, using journalctl --sync should be better than using SIGRTMIN+1, as
+ # the --sync wait until the synchronization is complete
+ echo "Force journald to write all queued messages"
+ journalctl --sync
+ kill -s TERM $COPROC_PID
+}
+
+checkNUMA() {
+ # NUMA enabled system should have at least NUMA node0
+ test -e /sys/devices/system/node/node0
+}
+
+writePID1NUMAPolicy() {
+ echo [Manager] > $confDir/numa.conf
+ echo NUMAPolicy=$1 >> $confDir/numa.conf
+ echo NUMAMask=$2>> $confDir/numa.conf
+}
+
+writeTestUnit() {
+ echo [Service] > $testUnitFile
+ echo ExecStart=/bin/sleep 3600 >> $testUnitFile
+ mkdir -p $testUnitFile.d/
+}
+
+writeTestUnitNUMAPolicy() {
+ echo [Service] > $testUnitNUMAConf
+ echo NUMAPolicy=$1 >> $testUnitNUMAConf
+ echo NUMAMask=$2>> $testUnitNUMAConf
+ systemctl daemon-reload
+}
+
+pid1ReloadWithStrace() {
+ startStrace
+ systemctl daemon-reload
+ stopStrace
+}
+
+pid1ReloadWithJournal() {
+ startJournalctl
+ systemctl daemon-reload
+ stopJournalctl
+}
+
+pid1StartUnitWithStrace() {
+ startStrace '-f'
+ systemctl start $1
+ sleep $sleepAfterStart
+ stopStrace
+}
+
+pid1StartUnitWithJournal() {
+ startJournalctl
+ systemctl start $1
+ sleep $sleepAfterStart
+ stopJournalctl
+}
+
+pid1StopUnit() {
+ systemctl stop $1
+}
+
+systemctlCheckNUMAProperties() {
+ local LOGFILE="$(mktemp)"
+ systemctl show -p NUMAPolicy $1 > "$LOGFILE"
+ grep "NUMAPolicy=$2" "$LOGFILE"
+
+ > "$LOGFILE"
+
+ if [ -n $3 ]; then
+ systemctl show -p NUMAMask $1 > "$LOGFILE"
+ grep "NUMAMask=$3" "$LOGFILE"
+ fi
+}
+
+checkNUMA
+writeTestUnit
+
+# Create systemd config drop-in directory
+confDir="/etc/systemd/system.conf.d/"
+mkdir -p "$confDir"
+
+echo "PID1 NUMAPolicy support - Default policy w/o mask"
+writePID1NUMAPolicy "default"
+pid1ReloadWithStrace
+# Kernel requires that nodemask argument is set to NULL when setting default policy
+grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog
+
+echo "PID1 NUMAPolicy support - Default policy w/ mask"
+writePID1NUMAPolicy "default" "0"
+pid1ReloadWithStrace
+grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog
+
+echo "PID1 NUMAPolicy support - Bind policy w/o mask"
+writePID1NUMAPolicy "bind"
+pid1ReloadWithJournal
+grep "Failed to set NUMA memory policy: Invalid argument" $journalLog
+
+echo "PID1 NUMAPolicy support - Bind policy w/ mask"
+writePID1NUMAPolicy "bind" "0"
+pid1ReloadWithStrace
+grep -P "set_mempolicy\(MPOL_BIND, \[0x0*1\]" $straceLog
+
+echo "PID1 NUMAPolicy support - Interleave policy w/o mask"
+writePID1NUMAPolicy "interleave"
+pid1ReloadWithJournal
+grep "Failed to set NUMA memory policy: Invalid argument" $journalLog
+
+echo "PID1 NUMAPolicy support - Interleave policy w/ mask"
+writePID1NUMAPolicy "interleave" "0"
+pid1ReloadWithStrace
+grep -P "set_mempolicy\(MPOL_INTERLEAVE, \[0x0*1\]" $straceLog
+
+echo "PID1 NUMAPolicy support - Preferred policy w/o mask"
+writePID1NUMAPolicy "preferred"
+pid1ReloadWithJournal
+# Preferred policy with empty node mask is actually allowed and should reset allocation policy to default
+! grep "Failed to set NUMA memory policy: Invalid argument" $journalLog
+
+echo "PID1 NUMAPolicy support - Preferred policy w/ mask"
+writePID1NUMAPolicy "preferred" "0"
+pid1ReloadWithStrace
+grep -P "set_mempolicy\(MPOL_PREFERRED, \[0x0*1\]" $straceLog
+
+echo "PID1 NUMAPolicy support - Local policy w/o mask"
+writePID1NUMAPolicy "local"
+pid1ReloadWithStrace
+# Kernel requires that nodemask argument is set to NULL when setting default policy
+grep "set_mempolicy(MPOL_LOCAL, NULL" $straceLog
+
+echo "PID1 NUMAPolicy support - Local policy w/ mask"
+writePID1NUMAPolicy "local" "0"
+pid1ReloadWithStrace
+grep "set_mempolicy(MPOL_LOCAL, NULL" $straceLog
+
+echo "Unit file NUMAPolicy support - Default policy w/o mask"
+writeTestUnitNUMAPolicy "default"
+pid1StartUnitWithStrace $testUnit
+systemctlCheckNUMAProperties $testUnit "default"
+pid1StopUnit $testUnit
+grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog
+
+echo "Unit file NUMAPolicy support - Default policy w/ mask"
+writeTestUnitNUMAPolicy "default" "0"
+pid1StartUnitWithStrace $testUnit
+systemctlCheckNUMAProperties $testUnit "default" "0"
+pid1StopUnit $testUnit
+# Maks must be ignored
+grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog
+
+echo "Unit file NUMAPolicy support - Bind policy w/o mask"
+writeTestUnitNUMAPolicy "bind"
+pid1StartUnitWithJournal $testUnit
+pid1StopUnit $testUnit
+grep "numa-test.service: Main process exited, code=exited, status=242/NUMA" $journalLog
+
+echo "Unit file NUMAPolicy support - Bind policy w/ mask"
+writeTestUnitNUMAPolicy "bind" "0"
+pid1StartUnitWithStrace $testUnit
+systemctlCheckNUMAProperties $testUnit "bind" "0"
+pid1StopUnit $testUnit
+grep -P "set_mempolicy\(MPOL_BIND, \[0x0*1\]" $straceLog
+
+echo "Unit file NUMAPolicy support - Interleave policy w/o mask"
+writeTestUnitNUMAPolicy "interleave"
+pid1StartUnitWithStrace $testUnit
+pid1StopUnit $testUnit
+grep "numa-test.service: Main process exited, code=exited, status=242/NUMA" $journalLog
+
+echo "Unit file NUMAPolicy support - Interleave policy w/ mask"
+writeTestUnitNUMAPolicy "interleave" "0"
+pid1StartUnitWithStrace $testUnit
+systemctlCheckNUMAProperties $testUnit "interleave" "0"
+pid1StopUnit $testUnit
+grep -P "set_mempolicy\(MPOL_INTERLEAVE, \[0x0*1\]" $straceLog
+
+echo "Unit file NUMAPolicy support - Preferred policy w/o mask"
+writeTestUnitNUMAPolicy "preferred"
+pid1StartUnitWithJournal $testUnit
+systemctlCheckNUMAProperties $testUnit "preferred"
+pid1StopUnit $testUnit
+! grep "numa-test.service: Main process exited, code=exited, status=242/NUMA" $journalLog
+
+echo "Unit file NUMAPolicy support - Preferred policy w/ mask"
+writeTestUnitNUMAPolicy "preferred" "0"
+pid1StartUnitWithStrace $testUnit
+systemctlCheckNUMAProperties $testUnit "preferred" "0"
+pid1StopUnit $testUnit
+grep -P "set_mempolicy\(MPOL_PREFERRED, \[0x0*1\]" $straceLog
+
+echo "Unit file NUMAPolicy support - Local policy w/o mask"
+writeTestUnitNUMAPolicy "local"
+pid1StartUnitWithStrace $testUnit
+systemctlCheckNUMAProperties $testUnit "local"
+pid1StopUnit $testUnit
+grep "set_mempolicy(MPOL_LOCAL, NULL" $straceLog
+
+echo "Unit file NUMAPolicy support - Local policy w/ mask"
+writeTestUnitNUMAPolicy "local" "0"
+pid1StartUnitWithStrace $testUnit
+systemctlCheckNUMAProperties $testUnit "local" "0"
+pid1StopUnit $testUnit
+# Maks must be ignored
+grep "set_mempolicy(MPOL_LOCAL, NULL" $straceLog
+
+echo "systemd-run NUMAPolicy support"
+runUnit='numa-systemd-run-test.service'
+
+systemd-run -p NUMAPolicy=default --unit $runUnit sleep 1000
+systemctlCheckNUMAProperties $runUnit "default"
+pid1StopUnit $runUnit
+
+systemd-run -p NUMAPolicy=default -p NUMAMask=0 --unit $runUnit sleep 1000
+systemctlCheckNUMAProperties $runUnit "default" ""
+pid1StopUnit $runUnit
+
+systemd-run -p NUMAPolicy=bind -p NUMAMask=0 --unit $runUnit sleep 1000
+systemctlCheckNUMAProperties $runUnit "bind" "0"
+pid1StopUnit $runUnit
+
+systemd-run -p NUMAPolicy=interleave -p NUMAMask=0 --unit $runUnit sleep 1000
+systemctlCheckNUMAProperties $runUnit "interleave" "0"
+pid1StopUnit $runUnit
+
+systemd-run -p NUMAPolicy=preferred -p NUMAMask=0 --unit $runUnit sleep 1000
+systemctlCheckNUMAProperties $runUnit "preferred" "0"
+pid1StopUnit $runUnit
+
+systemd-run -p NUMAPolicy=local --unit $runUnit sleep 1000
+systemctlCheckNUMAProperties $runUnit "local"
+pid1StopUnit $runUnit
+
+systemd-run -p NUMAPolicy=local -p NUMAMask=0 --unit $runUnit sleep 1000
+systemctlCheckNUMAProperties $runUnit "local" ""
+pid1StopUnit $runUnit
+
+# Cleanup
+rm -rf $testDir
+rm -rf $confDir
+systemctl daemon-reload
+
+systemd-analyze log-level info
+
+echo OK > /testok
+
+exit 0

View File

@ -0,0 +1,52 @@
From b93a2617d49d9636801130d974995cabe6335b71 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Mon, 1 Jul 2019 09:27:59 +0200
Subject: [PATCH] test: replace `tail -f` with journal cursor which should
be...
more reliable
(cherry picked from commit d0b2178f3e79f302702bd7140766eee03643f734)
Related: #1808940
---
test/TEST-36-NUMAPOLICY/testsuite.sh | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/test/TEST-36-NUMAPOLICY/testsuite.sh b/test/TEST-36-NUMAPOLICY/testsuite.sh
index e15087b137..306a96b517 100755
--- a/test/TEST-36-NUMAPOLICY/testsuite.sh
+++ b/test/TEST-36-NUMAPOLICY/testsuite.sh
@@ -29,6 +29,9 @@ testUnitNUMAConf="$testUnitFile.d/numa.conf"
journalSleep=5
sleepAfterStart=1
+# Journal cursor for easier navigation
+journalCursorFile="jounalCursorFile"
+
startStrace() {
coproc strace -qq -p 1 -o $straceLog -e set_mempolicy -s 1024 $1
}
@@ -38,18 +41,16 @@ stopStrace() {
}
startJournalctl() {
- coproc journalctl -u init.scope -f > $journalLog
+ # Save journal's cursor for later navigation
+ journalctl --no-pager --cursor-file="$journalCursorFile" -n0 -ocat
}
stopJournalctl() {
- # Wait a few seconds until the messages get properly queued...
- sleep $journalSleep
- # ...and then force journald to write them to the backing storage
- # Also, using journalctl --sync should be better than using SIGRTMIN+1, as
+ # Using journalctl --sync should be better than using SIGRTMIN+1, as
# the --sync wait until the synchronization is complete
echo "Force journald to write all queued messages"
journalctl --sync
- kill -s TERM $COPROC_PID
+ journalctl -u init.scope --cursor-file="$journalCursorFile" > "$journalLog"
}
checkNUMA() {

View File

@ -0,0 +1,58 @@
From d6d43b81df76d571d57f83ceb050c8b4ac4701b8 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Mon, 1 Jul 2019 13:08:26 +0200
Subject: [PATCH] test: support MPOL_LOCAL matching in unpatched strace
versions
The MPOL_LOCAL constant is not recognized in current strace versions.
Let's match at least the numerical value of this constant until the
strace patch is approved & merged.
(cherry picked from commit ac14396d027023e1be910327989cb422cb2f6724)
Related: #1808940
---
test/TEST-36-NUMAPOLICY/testsuite.sh | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/test/TEST-36-NUMAPOLICY/testsuite.sh b/test/TEST-36-NUMAPOLICY/testsuite.sh
index 306a96b517..a4134bdeca 100755
--- a/test/TEST-36-NUMAPOLICY/testsuite.sh
+++ b/test/TEST-36-NUMAPOLICY/testsuite.sh
@@ -173,12 +173,16 @@ echo "PID1 NUMAPolicy support - Local policy w/o mask"
writePID1NUMAPolicy "local"
pid1ReloadWithStrace
# Kernel requires that nodemask argument is set to NULL when setting default policy
-grep "set_mempolicy(MPOL_LOCAL, NULL" $straceLog
+# The unpatched versions of strace don't recognize the MPOL_LOCAL constant and
+# return a numerical constant instead (with a comment):
+# set_mempolicy(0x4 /* MPOL_??? */, NULL, 0) = 0
+# Let's cover this scenario as well
+grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog
echo "PID1 NUMAPolicy support - Local policy w/ mask"
writePID1NUMAPolicy "local" "0"
pid1ReloadWithStrace
-grep "set_mempolicy(MPOL_LOCAL, NULL" $straceLog
+grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog
echo "Unit file NUMAPolicy support - Default policy w/o mask"
writeTestUnitNUMAPolicy "default"
@@ -240,7 +244,7 @@ writeTestUnitNUMAPolicy "local"
pid1StartUnitWithStrace $testUnit
systemctlCheckNUMAProperties $testUnit "local"
pid1StopUnit $testUnit
-grep "set_mempolicy(MPOL_LOCAL, NULL" $straceLog
+grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog
echo "Unit file NUMAPolicy support - Local policy w/ mask"
writeTestUnitNUMAPolicy "local" "0"
@@ -248,7 +252,7 @@ pid1StartUnitWithStrace $testUnit
systemctlCheckNUMAProperties $testUnit "local" "0"
pid1StopUnit $testUnit
# Maks must be ignored
-grep "set_mempolicy(MPOL_LOCAL, NULL" $straceLog
+grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog
echo "systemd-run NUMAPolicy support"
runUnit='numa-systemd-run-test.service'

View File

@ -0,0 +1,50 @@
From 60813b55f9b5b44b14f38bbc1b8c0d2b30e3f6c7 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Mon, 1 Jul 2019 19:53:45 +0200
Subject: [PATCH] test: make sure the strace process is indeed dead
It may take a few moments for the strace process to properly terminate
and write all logs to the backing storage
(cherry picked from commit 56425e54a2140f47b4560b51c5db08aa2de199a6)
Related: #1808940
---
test/TEST-36-NUMAPOLICY/test.sh | 2 +-
test/TEST-36-NUMAPOLICY/testsuite.sh | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/test/TEST-36-NUMAPOLICY/test.sh b/test/TEST-36-NUMAPOLICY/test.sh
index a0d8623e8e..f0a321e7a1 100755
--- a/test/TEST-36-NUMAPOLICY/test.sh
+++ b/test/TEST-36-NUMAPOLICY/test.sh
@@ -16,7 +16,7 @@ test_setup() {
eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
setup_basic_environment
- inst_binary mktemp
+ dracut_install mktemp
# mask some services that we do not want to run in these tests
ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
diff --git a/test/TEST-36-NUMAPOLICY/testsuite.sh b/test/TEST-36-NUMAPOLICY/testsuite.sh
index a4134bdeca..daed8fcc1c 100755
--- a/test/TEST-36-NUMAPOLICY/testsuite.sh
+++ b/test/TEST-36-NUMAPOLICY/testsuite.sh
@@ -38,6 +38,8 @@ startStrace() {
stopStrace() {
kill -s TERM $COPROC_PID
+ # Make sure the strace process is indeed dead
+ while kill -0 $COPROC_PID 2>/dev/null; do sleep 0.1; done
}
startJournalctl() {
@@ -80,6 +82,7 @@ writeTestUnitNUMAPolicy() {
pid1ReloadWithStrace() {
startStrace
systemctl daemon-reload
+ sleep $sleepAfterStart
stopStrace
}

View File

@ -0,0 +1,36 @@
From ad3e4a0f010c9497b01d89de54213af982f8afd2 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 2 Jul 2019 09:52:45 +0200
Subject: [PATCH] test: skip the test on systems without NUMA support
(cherry picked from commit b030847163e9bd63d3dd6eec6ac7f336411faba6)
Related: #1808940
---
test/TEST-36-NUMAPOLICY/testsuite.sh | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/test/TEST-36-NUMAPOLICY/testsuite.sh b/test/TEST-36-NUMAPOLICY/testsuite.sh
index daed8fcc1c..4b715d305a 100755
--- a/test/TEST-36-NUMAPOLICY/testsuite.sh
+++ b/test/TEST-36-NUMAPOLICY/testsuite.sh
@@ -123,7 +123,18 @@ systemctlCheckNUMAProperties() {
fi
}
-checkNUMA
+if ! checkNUMA; then
+ echo >&2 "NUMA is not supported on this machine, skipping the test"
+
+ # FIXME: add some sanity checks to verify systemd behaves correctly with
+ # NUMA disabled together with NUMAPolicy= and NUMAMask=
+
+ systemd-analyze log-level info
+ echo OK > /testok
+
+ exit 0
+fi
+
writeTestUnit
# Create systemd config drop-in directory

View File

@ -0,0 +1,30 @@
From 66f6f6304d87b2fe0c4f91373c7d1b836de1b054 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 23 Jul 2019 00:56:04 +0200
Subject: [PATCH] test: give strace some time to initialize
The `coproc` implementation seems to be a little bit different in older
bash versions, so the `strace` is sometimes started AFTER `systemctl
daemon-reload`, which causes unexpected fails. Let's help it a little by
sleeping for a bit.
(cherry picked from commit c7367d7cfdfdcec98f8659f0ed3f1d7b77123903)
Related: #1808940
---
test/TEST-36-NUMAPOLICY/testsuite.sh | 2 ++
1 file changed, 2 insertions(+)
diff --git a/test/TEST-36-NUMAPOLICY/testsuite.sh b/test/TEST-36-NUMAPOLICY/testsuite.sh
index 4b715d305a..1c8cf7e6b6 100755
--- a/test/TEST-36-NUMAPOLICY/testsuite.sh
+++ b/test/TEST-36-NUMAPOLICY/testsuite.sh
@@ -34,6 +34,8 @@ journalCursorFile="jounalCursorFile"
startStrace() {
coproc strace -qq -p 1 -o $straceLog -e set_mempolicy -s 1024 $1
+ # Wait for strace to properly "initialize"
+ sleep $sleepAfterStart
}
stopStrace() {

View File

@ -0,0 +1,391 @@
From 8239ecf0b4b8bbe5b3c17964d230d13cee4d900a Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Mon, 5 Aug 2019 14:38:45 +0200
Subject: [PATCH] test: add a simple sanity check for systems without NUMA
support
(cherry picked from commit 92f8e978923f962a57d744c5f358520ac06f7892)
Related: #1808940
---
test/TEST-36-NUMAPOLICY/testsuite.sh | 350 ++++++++++++++-------------
1 file changed, 180 insertions(+), 170 deletions(-)
diff --git a/test/TEST-36-NUMAPOLICY/testsuite.sh b/test/TEST-36-NUMAPOLICY/testsuite.sh
index 1c8cf7e6b6..a5ac788178 100755
--- a/test/TEST-36-NUMAPOLICY/testsuite.sh
+++ b/test/TEST-36-NUMAPOLICY/testsuite.sh
@@ -50,11 +50,12 @@ startJournalctl() {
}
stopJournalctl() {
+ local unit="${1:-init.scope}"
# Using journalctl --sync should be better than using SIGRTMIN+1, as
# the --sync wait until the synchronization is complete
echo "Force journald to write all queued messages"
journalctl --sync
- journalctl -u init.scope --cursor-file="$journalCursorFile" > "$journalLog"
+ journalctl -u $unit --cursor-file="$journalCursorFile" > "$journalLog"
}
checkNUMA() {
@@ -125,181 +126,190 @@ systemctlCheckNUMAProperties() {
fi
}
-if ! checkNUMA; then
- echo >&2 "NUMA is not supported on this machine, skipping the test"
-
- # FIXME: add some sanity checks to verify systemd behaves correctly with
- # NUMA disabled together with NUMAPolicy= and NUMAMask=
-
- systemd-analyze log-level info
- echo OK > /testok
-
- exit 0
-fi
-
writeTestUnit
# Create systemd config drop-in directory
confDir="/etc/systemd/system.conf.d/"
mkdir -p "$confDir"
-echo "PID1 NUMAPolicy support - Default policy w/o mask"
-writePID1NUMAPolicy "default"
-pid1ReloadWithStrace
-# Kernel requires that nodemask argument is set to NULL when setting default policy
-grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog
-
-echo "PID1 NUMAPolicy support - Default policy w/ mask"
-writePID1NUMAPolicy "default" "0"
-pid1ReloadWithStrace
-grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog
-
-echo "PID1 NUMAPolicy support - Bind policy w/o mask"
-writePID1NUMAPolicy "bind"
-pid1ReloadWithJournal
-grep "Failed to set NUMA memory policy: Invalid argument" $journalLog
-
-echo "PID1 NUMAPolicy support - Bind policy w/ mask"
-writePID1NUMAPolicy "bind" "0"
-pid1ReloadWithStrace
-grep -P "set_mempolicy\(MPOL_BIND, \[0x0*1\]" $straceLog
-
-echo "PID1 NUMAPolicy support - Interleave policy w/o mask"
-writePID1NUMAPolicy "interleave"
-pid1ReloadWithJournal
-grep "Failed to set NUMA memory policy: Invalid argument" $journalLog
-
-echo "PID1 NUMAPolicy support - Interleave policy w/ mask"
-writePID1NUMAPolicy "interleave" "0"
-pid1ReloadWithStrace
-grep -P "set_mempolicy\(MPOL_INTERLEAVE, \[0x0*1\]" $straceLog
-
-echo "PID1 NUMAPolicy support - Preferred policy w/o mask"
-writePID1NUMAPolicy "preferred"
-pid1ReloadWithJournal
-# Preferred policy with empty node mask is actually allowed and should reset allocation policy to default
-! grep "Failed to set NUMA memory policy: Invalid argument" $journalLog
-
-echo "PID1 NUMAPolicy support - Preferred policy w/ mask"
-writePID1NUMAPolicy "preferred" "0"
-pid1ReloadWithStrace
-grep -P "set_mempolicy\(MPOL_PREFERRED, \[0x0*1\]" $straceLog
-
-echo "PID1 NUMAPolicy support - Local policy w/o mask"
-writePID1NUMAPolicy "local"
-pid1ReloadWithStrace
-# Kernel requires that nodemask argument is set to NULL when setting default policy
-# The unpatched versions of strace don't recognize the MPOL_LOCAL constant and
-# return a numerical constant instead (with a comment):
-# set_mempolicy(0x4 /* MPOL_??? */, NULL, 0) = 0
-# Let's cover this scenario as well
-grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog
-
-echo "PID1 NUMAPolicy support - Local policy w/ mask"
-writePID1NUMAPolicy "local" "0"
-pid1ReloadWithStrace
-grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog
-
-echo "Unit file NUMAPolicy support - Default policy w/o mask"
-writeTestUnitNUMAPolicy "default"
-pid1StartUnitWithStrace $testUnit
-systemctlCheckNUMAProperties $testUnit "default"
-pid1StopUnit $testUnit
-grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog
-
-echo "Unit file NUMAPolicy support - Default policy w/ mask"
-writeTestUnitNUMAPolicy "default" "0"
-pid1StartUnitWithStrace $testUnit
-systemctlCheckNUMAProperties $testUnit "default" "0"
-pid1StopUnit $testUnit
-# Maks must be ignored
-grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog
-
-echo "Unit file NUMAPolicy support - Bind policy w/o mask"
-writeTestUnitNUMAPolicy "bind"
-pid1StartUnitWithJournal $testUnit
-pid1StopUnit $testUnit
-grep "numa-test.service: Main process exited, code=exited, status=242/NUMA" $journalLog
-
-echo "Unit file NUMAPolicy support - Bind policy w/ mask"
-writeTestUnitNUMAPolicy "bind" "0"
-pid1StartUnitWithStrace $testUnit
-systemctlCheckNUMAProperties $testUnit "bind" "0"
-pid1StopUnit $testUnit
-grep -P "set_mempolicy\(MPOL_BIND, \[0x0*1\]" $straceLog
-
-echo "Unit file NUMAPolicy support - Interleave policy w/o mask"
-writeTestUnitNUMAPolicy "interleave"
-pid1StartUnitWithStrace $testUnit
-pid1StopUnit $testUnit
-grep "numa-test.service: Main process exited, code=exited, status=242/NUMA" $journalLog
-
-echo "Unit file NUMAPolicy support - Interleave policy w/ mask"
-writeTestUnitNUMAPolicy "interleave" "0"
-pid1StartUnitWithStrace $testUnit
-systemctlCheckNUMAProperties $testUnit "interleave" "0"
-pid1StopUnit $testUnit
-grep -P "set_mempolicy\(MPOL_INTERLEAVE, \[0x0*1\]" $straceLog
-
-echo "Unit file NUMAPolicy support - Preferred policy w/o mask"
-writeTestUnitNUMAPolicy "preferred"
-pid1StartUnitWithJournal $testUnit
-systemctlCheckNUMAProperties $testUnit "preferred"
-pid1StopUnit $testUnit
-! grep "numa-test.service: Main process exited, code=exited, status=242/NUMA" $journalLog
-
-echo "Unit file NUMAPolicy support - Preferred policy w/ mask"
-writeTestUnitNUMAPolicy "preferred" "0"
-pid1StartUnitWithStrace $testUnit
-systemctlCheckNUMAProperties $testUnit "preferred" "0"
-pid1StopUnit $testUnit
-grep -P "set_mempolicy\(MPOL_PREFERRED, \[0x0*1\]" $straceLog
-
-echo "Unit file NUMAPolicy support - Local policy w/o mask"
-writeTestUnitNUMAPolicy "local"
-pid1StartUnitWithStrace $testUnit
-systemctlCheckNUMAProperties $testUnit "local"
-pid1StopUnit $testUnit
-grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog
-
-echo "Unit file NUMAPolicy support - Local policy w/ mask"
-writeTestUnitNUMAPolicy "local" "0"
-pid1StartUnitWithStrace $testUnit
-systemctlCheckNUMAProperties $testUnit "local" "0"
-pid1StopUnit $testUnit
-# Maks must be ignored
-grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog
-
-echo "systemd-run NUMAPolicy support"
-runUnit='numa-systemd-run-test.service'
-
-systemd-run -p NUMAPolicy=default --unit $runUnit sleep 1000
-systemctlCheckNUMAProperties $runUnit "default"
-pid1StopUnit $runUnit
-
-systemd-run -p NUMAPolicy=default -p NUMAMask=0 --unit $runUnit sleep 1000
-systemctlCheckNUMAProperties $runUnit "default" ""
-pid1StopUnit $runUnit
-
-systemd-run -p NUMAPolicy=bind -p NUMAMask=0 --unit $runUnit sleep 1000
-systemctlCheckNUMAProperties $runUnit "bind" "0"
-pid1StopUnit $runUnit
-
-systemd-run -p NUMAPolicy=interleave -p NUMAMask=0 --unit $runUnit sleep 1000
-systemctlCheckNUMAProperties $runUnit "interleave" "0"
-pid1StopUnit $runUnit
-
-systemd-run -p NUMAPolicy=preferred -p NUMAMask=0 --unit $runUnit sleep 1000
-systemctlCheckNUMAProperties $runUnit "preferred" "0"
-pid1StopUnit $runUnit
-
-systemd-run -p NUMAPolicy=local --unit $runUnit sleep 1000
-systemctlCheckNUMAProperties $runUnit "local"
-pid1StopUnit $runUnit
-
-systemd-run -p NUMAPolicy=local -p NUMAMask=0 --unit $runUnit sleep 1000
-systemctlCheckNUMAProperties $runUnit "local" ""
-pid1StopUnit $runUnit
+if ! checkNUMA; then
+ echo >&2 "NUMA is not supported on this machine, switching to a simple sanity check"
+
+ echo "PID1 NUMAPolicy=default && NUMAMask=0 check without NUMA support"
+ writePID1NUMAPolicy "default" "0"
+ startJournalctl
+ systemctl daemon-reload
+ stopJournalctl
+ grep "NUMA support not available, ignoring" "$journalLog"
+
+ echo "systemd-run NUMAPolicy=default && NUMAMask=0 check without NUMA support"
+ runUnit='numa-systemd-run-test.service'
+ startJournalctl
+ systemd-run -p NUMAPolicy=default -p NUMAMask=0 --unit $runUnit sleep 1000
+ sleep $sleepAfterStart
+ pid1StopUnit $runUnit
+ stopJournalctl $runUnit
+ grep "NUMA support not available, ignoring" "$journalLog"
+
+else
+ echo "PID1 NUMAPolicy support - Default policy w/o mask"
+ writePID1NUMAPolicy "default"
+ pid1ReloadWithStrace
+ # Kernel requires that nodemask argument is set to NULL when setting default policy
+ grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog
+
+ echo "PID1 NUMAPolicy support - Default policy w/ mask"
+ writePID1NUMAPolicy "default" "0"
+ pid1ReloadWithStrace
+ grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog
+
+ echo "PID1 NUMAPolicy support - Bind policy w/o mask"
+ writePID1NUMAPolicy "bind"
+ pid1ReloadWithJournal
+ grep "Failed to set NUMA memory policy: Invalid argument" $journalLog
+
+ echo "PID1 NUMAPolicy support - Bind policy w/ mask"
+ writePID1NUMAPolicy "bind" "0"
+ pid1ReloadWithStrace
+ grep -P "set_mempolicy\(MPOL_BIND, \[0x0*1\]" $straceLog
+
+ echo "PID1 NUMAPolicy support - Interleave policy w/o mask"
+ writePID1NUMAPolicy "interleave"
+ pid1ReloadWithJournal
+ grep "Failed to set NUMA memory policy: Invalid argument" $journalLog
+
+ echo "PID1 NUMAPolicy support - Interleave policy w/ mask"
+ writePID1NUMAPolicy "interleave" "0"
+ pid1ReloadWithStrace
+ grep -P "set_mempolicy\(MPOL_INTERLEAVE, \[0x0*1\]" $straceLog
+
+ echo "PID1 NUMAPolicy support - Preferred policy w/o mask"
+ writePID1NUMAPolicy "preferred"
+ pid1ReloadWithJournal
+ # Preferred policy with empty node mask is actually allowed and should reset allocation policy to default
+ ! grep "Failed to set NUMA memory policy: Invalid argument" $journalLog
+
+ echo "PID1 NUMAPolicy support - Preferred policy w/ mask"
+ writePID1NUMAPolicy "preferred" "0"
+ pid1ReloadWithStrace
+ grep -P "set_mempolicy\(MPOL_PREFERRED, \[0x0*1\]" $straceLog
+
+ echo "PID1 NUMAPolicy support - Local policy w/o mask"
+ writePID1NUMAPolicy "local"
+ pid1ReloadWithStrace
+ # Kernel requires that nodemask argument is set to NULL when setting default policy
+ # The unpatched versions of strace don't recognize the MPOL_LOCAL constant and
+ # return a numerical constant instead (with a comment):
+ # set_mempolicy(0x4 /* MPOL_??? */, NULL, 0) = 0
+ # Let's cover this scenario as well
+ grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog
+
+ echo "PID1 NUMAPolicy support - Local policy w/ mask"
+ writePID1NUMAPolicy "local" "0"
+ pid1ReloadWithStrace
+ grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog
+
+ echo "Unit file NUMAPolicy support - Default policy w/o mask"
+ writeTestUnitNUMAPolicy "default"
+ pid1StartUnitWithStrace $testUnit
+ systemctlCheckNUMAProperties $testUnit "default"
+ pid1StopUnit $testUnit
+ grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog
+
+ echo "Unit file NUMAPolicy support - Default policy w/ mask"
+ writeTestUnitNUMAPolicy "default" "0"
+ pid1StartUnitWithStrace $testUnit
+ systemctlCheckNUMAProperties $testUnit "default" "0"
+ pid1StopUnit $testUnit
+ # Maks must be ignored
+ grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog
+
+ echo "Unit file NUMAPolicy support - Bind policy w/o mask"
+ writeTestUnitNUMAPolicy "bind"
+ pid1StartUnitWithJournal $testUnit
+ pid1StopUnit $testUnit
+ grep "numa-test.service: Main process exited, code=exited, status=242/NUMA" $journalLog
+
+ echo "Unit file NUMAPolicy support - Bind policy w/ mask"
+ writeTestUnitNUMAPolicy "bind" "0"
+ pid1StartUnitWithStrace $testUnit
+ systemctlCheckNUMAProperties $testUnit "bind" "0"
+ pid1StopUnit $testUnit
+ grep -P "set_mempolicy\(MPOL_BIND, \[0x0*1\]" $straceLog
+
+ echo "Unit file NUMAPolicy support - Interleave policy w/o mask"
+ writeTestUnitNUMAPolicy "interleave"
+ pid1StartUnitWithStrace $testUnit
+ pid1StopUnit $testUnit
+ grep "numa-test.service: Main process exited, code=exited, status=242/NUMA" $journalLog
+
+ echo "Unit file NUMAPolicy support - Interleave policy w/ mask"
+ writeTestUnitNUMAPolicy "interleave" "0"
+ pid1StartUnitWithStrace $testUnit
+ systemctlCheckNUMAProperties $testUnit "interleave" "0"
+ pid1StopUnit $testUnit
+ grep -P "set_mempolicy\(MPOL_INTERLEAVE, \[0x0*1\]" $straceLog
+
+ echo "Unit file NUMAPolicy support - Preferred policy w/o mask"
+ writeTestUnitNUMAPolicy "preferred"
+ pid1StartUnitWithJournal $testUnit
+ systemctlCheckNUMAProperties $testUnit "preferred"
+ pid1StopUnit $testUnit
+ ! grep "numa-test.service: Main process exited, code=exited, status=242/NUMA" $journalLog
+
+ echo "Unit file NUMAPolicy support - Preferred policy w/ mask"
+ writeTestUnitNUMAPolicy "preferred" "0"
+ pid1StartUnitWithStrace $testUnit
+ systemctlCheckNUMAProperties $testUnit "preferred" "0"
+ pid1StopUnit $testUnit
+ grep -P "set_mempolicy\(MPOL_PREFERRED, \[0x0*1\]" $straceLog
+
+ echo "Unit file NUMAPolicy support - Local policy w/o mask"
+ writeTestUnitNUMAPolicy "local"
+ pid1StartUnitWithStrace $testUnit
+ systemctlCheckNUMAProperties $testUnit "local"
+ pid1StopUnit $testUnit
+ grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog
+
+ echo "Unit file NUMAPolicy support - Local policy w/ mask"
+ writeTestUnitNUMAPolicy "local" "0"
+ pid1StartUnitWithStrace $testUnit
+ systemctlCheckNUMAProperties $testUnit "local" "0"
+ pid1StopUnit $testUnit
+ # Maks must be ignored
+ grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog
+
+ echo "systemd-run NUMAPolicy support"
+ runUnit='numa-systemd-run-test.service'
+
+ systemd-run -p NUMAPolicy=default --unit $runUnit sleep 1000
+ systemctlCheckNUMAProperties $runUnit "default"
+ pid1StopUnit $runUnit
+
+ systemd-run -p NUMAPolicy=default -p NUMAMask=0 --unit $runUnit sleep 1000
+ systemctlCheckNUMAProperties $runUnit "default" ""
+ pid1StopUnit $runUnit
+
+ systemd-run -p NUMAPolicy=bind -p NUMAMask=0 --unit $runUnit sleep 1000
+ systemctlCheckNUMAProperties $runUnit "bind" "0"
+ pid1StopUnit $runUnit
+
+ systemd-run -p NUMAPolicy=interleave -p NUMAMask=0 --unit $runUnit sleep 1000
+ systemctlCheckNUMAProperties $runUnit "interleave" "0"
+ pid1StopUnit $runUnit
+
+ systemd-run -p NUMAPolicy=preferred -p NUMAMask=0 --unit $runUnit sleep 1000
+ systemctlCheckNUMAProperties $runUnit "preferred" "0"
+ pid1StopUnit $runUnit
+
+ systemd-run -p NUMAPolicy=local --unit $runUnit sleep 1000
+ systemctlCheckNUMAProperties $runUnit "local"
+ pid1StopUnit $runUnit
+
+ systemd-run -p NUMAPolicy=local -p NUMAMask=0 --unit $runUnit sleep 1000
+ systemctlCheckNUMAProperties $runUnit "local" ""
+ pid1StopUnit $runUnit
+fi
# Cleanup
rm -rf $testDir

View File

@ -0,0 +1,35 @@
From 772f08f8255d7ab921c344ab4243249cbd1c37fc Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Sat, 10 Aug 2019 16:05:07 +0200
Subject: [PATCH] test: drop the missed || exit 1 expression
...as we've already done in the rest of the testsuite, see
cc469c3dfc398210f38f819d367e68646c71d8da
(cherry picked from commit 67c434b03f8a24f5350f017dfb4b2464406046db)
Related: #1808940
---
test/TEST-36-NUMAPOLICY/test.sh | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/test/TEST-36-NUMAPOLICY/test.sh b/test/TEST-36-NUMAPOLICY/test.sh
index f0a321e7a1..3b3b120423 100755
--- a/test/TEST-36-NUMAPOLICY/test.sh
+++ b/test/TEST-36-NUMAPOLICY/test.sh
@@ -1,5 +1,6 @@
#!/bin/bash
set -e
+
TEST_DESCRIPTION="test MUMAPolicy= and NUMAMask= options"
TEST_NO_NSPAWN=1
QEMU_OPTIONS="-numa node,nodeid=0"
@@ -41,7 +42,7 @@ EOF
cp testsuite.sh $initdir/
setup_testsuite
- ) || return 1
+ )
setup_nspawn_root
ddebug "umount $TESTDIR/root"

View File

@ -0,0 +1,59 @@
From 0bef8805c81eecfe3960bf00b6022837e4979198 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <fsumsal@redhat.com>
Date: Tue, 3 Mar 2020 15:54:29 +0100
Subject: [PATCH] test: replace cursor file with a plain cursor
systemd in RHEL 8 doesn't support the --cursor-file option, so let's
fall back to a plain cursor string
Related: #1808940
rhel-only
---
test/TEST-36-NUMAPOLICY/test.sh | 2 +-
test/TEST-36-NUMAPOLICY/testsuite.sh | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/test/TEST-36-NUMAPOLICY/test.sh b/test/TEST-36-NUMAPOLICY/test.sh
index 3b3b120423..7cc909765b 100755
--- a/test/TEST-36-NUMAPOLICY/test.sh
+++ b/test/TEST-36-NUMAPOLICY/test.sh
@@ -17,7 +17,7 @@ test_setup() {
eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
setup_basic_environment
- dracut_install mktemp
+ dracut_install mktemp awk
# mask some services that we do not want to run in these tests
ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
diff --git a/test/TEST-36-NUMAPOLICY/testsuite.sh b/test/TEST-36-NUMAPOLICY/testsuite.sh
index a5ac788178..bffac4ffe6 100755
--- a/test/TEST-36-NUMAPOLICY/testsuite.sh
+++ b/test/TEST-36-NUMAPOLICY/testsuite.sh
@@ -30,7 +30,7 @@ journalSleep=5
sleepAfterStart=1
# Journal cursor for easier navigation
-journalCursorFile="jounalCursorFile"
+journalCursor=""
startStrace() {
coproc strace -qq -p 1 -o $straceLog -e set_mempolicy -s 1024 $1
@@ -46,7 +46,7 @@ stopStrace() {
startJournalctl() {
# Save journal's cursor for later navigation
- journalctl --no-pager --cursor-file="$journalCursorFile" -n0 -ocat
+ journalCursor="$(journalctl --no-pager --show-cursor -n0 -ocat | awk '{print $3}')"
}
stopJournalctl() {
@@ -55,7 +55,7 @@ stopJournalctl() {
# the --sync wait until the synchronization is complete
echo "Force journald to write all queued messages"
journalctl --sync
- journalctl -u $unit --cursor-file="$journalCursorFile" > "$journalLog"
+ journalctl -u $unit --after-cursor="$journalCursor" > "$journalLog"
}
checkNUMA() {

View File

@ -0,0 +1,32 @@
From ed282d8d84fa32aaef21994d92d1d3dbfa281094 Mon Sep 17 00:00:00 2001
From: Ryan Gonzalez <kirbyfan64@users.noreply.github.com>
Date: Fri, 22 Feb 2019 23:45:03 -0600
Subject: [PATCH] cryptsetup: Treat key file errors as a failed password
attempt
6f177c7dc092eb68762b4533d41b14244adb2a73 caused key file errors to immediately fail, which would make it hard to correct an issue due to e.g. a crypttab typo or a damaged key file.
Closes #11723.
(cherry picked from commit c20db3887569e0c0d9c0e2845c5286e7edf0133a)
Related: #1763155
---
src/cryptsetup/cryptsetup.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 33c215eaa1..11162eb722 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -558,6 +558,10 @@ static int attach_luks_or_plain(struct crypt_device *cd,
log_error_errno(r, "Failed to activate with key file '%s'. (Key data incorrect?)", key_file);
return -EAGAIN; /* Log actual error, but return EAGAIN */
}
+ if (r == -EINVAL) {
+ log_error_errno(r, "Failed to activate with key file '%s'. (Key file missing?)", key_file);
+ return -EAGAIN; /* Log actual error, but return EAGAIN */
+ }
if (r < 0)
return log_error_errno(r, "Failed to activate with key file '%s': %m", key_file);
} else {

View File

@ -0,0 +1,79 @@
From b89a1a9d19aa806feb984c8dba25116b5b5a52bc Mon Sep 17 00:00:00 2001
From: HATAYAMA Daisuke <d.hatayama@fujitsu.com>
Date: Wed, 24 Jul 2019 23:54:48 -0400
Subject: [PATCH] swap: finish the secondary swap units' jobs if deactivation
of the primary swap unit fails
Currently, if deactivation of the primary swap unit fails:
# LANG=C systemctl --no-pager stop dev-mapper-fedora\\x2dswap.swap
Job for dev-mapper-fedora\x2dswap.swap failed.
See "systemctl status "dev-mapper-fedora\\x2dswap.swap"" and "journalctl -xe" for details.
then there are still the running stop jobs for all the secondary swap units
that follow the primary one:
# systemctl list-jobs
JOB UNIT TYPE STATE
3233 dev-disk-by\x2duuid-2dc8b9b1\x2da0a5\x2d44d8\x2d89c4\x2d6cdd26cd5ce0.swap stop running
3232 dev-dm\x2d1.swap stop running
3231 dev-disk-by\x2did-dm\x2duuid\x2dLVM\x2dyuXWpCCIurGzz2nkGCVnUFSi7GH6E3ZcQjkKLnF0Fil0RJmhoLN8fcOnDybWCMTj.swap stop running
3230 dev-disk-by\x2did-dm\x2dname\x2dfedora\x2dswap.swap stop running
3234 dev-fedora-swap.swap stop running
5 jobs listed.
This remains endlessly because their JobTimeoutUSec is infinity:
# LANG=C systemctl show -p JobTimeoutUSec dev-fedora-swap.swap
JobTimeoutUSec=infinity
If this issue happens during system shutdown, the system shutdown appears to
get hang and the system will be forcibly shutdown or rebooted 30 minutes later
by the following configuration:
# grep -E "^JobTimeout" /usr/lib/systemd/system/reboot.target
JobTimeoutSec=30min
JobTimeoutAction=reboot-force
The scenario in the real world seems that there is some service unit with
KillMode=none, processes whose memory is being swapped out are not killed
during stop operation in the service unit and then swapoff command fails.
On the other hand, it works well in successful case of swapoff command because
the secondary jobs monitor /proc/swaps file and can detect deletion of the
corresponding swap file.
This commit fixes the issue by finishing the secondary swap units' jobs if
deactivation of the primary swap unit fails.
Fixes: #11577
(cherry picked from commit 9c1f969d40f84d5cc98d810bab8b24148b2d8928)
Resolves: #1749622
---
src/core/swap.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/core/swap.c b/src/core/swap.c
index e717dbb54a..66a62d8a37 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -682,9 +682,15 @@ static void swap_enter_active(Swap *s, SwapResult f) {
static void swap_enter_dead_or_active(Swap *s, SwapResult f) {
assert(s);
- if (s->from_proc_swaps)
+ if (s->from_proc_swaps) {
+ Swap *other;
+
swap_enter_active(s, f);
- else
+
+ LIST_FOREACH_OTHERS(same_devnode, other, s)
+ if (UNIT(other)->job)
+ swap_enter_dead_or_active(other, f);
+ } else
swap_enter_dead(s, f);
}

View File

@ -0,0 +1,41 @@
From d9ae3222cfbd5d2a48e6dbade6617085cc76f1c1 Mon Sep 17 00:00:00 2001
From: HATAYAMA Daisuke <d.hatayama@fujitsu.com>
Date: Tue, 25 Feb 2020 13:35:50 -0500
Subject: [PATCH] resolved: Recover missing PrivateTmp=yes and
ProtectSystem=strict
Since the commit b61e8046ebcb28225423fc0073183d68d4c577c4,
systemd-resolved.service often fails to start with the following message:
Failed at step NAMESPACE spawning /usr/bin/mount: Read-only file system
This is because dropping DynamicUser=yes dropped implicit PrivateTmp=yes and
also implicit After=systemd-tmpfiles-setup.service, and thus
systemd-resolved.service can start before systemd-remount-fs.service. As a
result, mount operations associated with PrivateDevices= can be performed to
still read-only filesystems.
To fix this issue, it's better to recover PrivateTmp=yes and
ProtectSystem=strict just as the upstream commit
62fb7e80fcc45a1530ed58a84980be8cfafa9b3e (Revert "resolve: enable DynamicUser=
for systemd-resolved.service").
Resolves: #1810869
---
units/systemd-resolved.service.in | 2 ++
1 file changed, 2 insertions(+)
diff --git a/units/systemd-resolved.service.in b/units/systemd-resolved.service.in
index 6c2ad5ca86..aad1a53a5f 100644
--- a/units/systemd-resolved.service.in
+++ b/units/systemd-resolved.service.in
@@ -28,7 +28,9 @@ WatchdogSec=3min
User=systemd-resolve
CapabilityBoundingSet=CAP_SETPCAP CAP_NET_RAW CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_SETPCAP CAP_NET_RAW CAP_NET_BIND_SERVICE
+PrivateTmp=yes
PrivateDevices=yes
+ProtectSystems=strict
ProtectHome=yes
ProtectControlGroups=yes
ProtectKernelTunables=yes

View File

@ -0,0 +1,30 @@
From 448b34284c09469eaa2168291ccb34afc3e4cc1d Mon Sep 17 00:00:00 2001
From: ven <2988994+hexiaowen@users.noreply.github.com>
Date: Wed, 22 May 2019 14:24:28 +0800
Subject: [PATCH] =?UTF-8?q?bus=5Fopen=20leak=20sd=5Fevent=5Fsource=20when?=
=?UTF-8?q?=20udevadm=20trigger=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
On my host, when executing the udevadm trigger, I only receive the change event, which causes memleak
(cherry picked from commit b2774a3ae692113e1f47a336a6c09bac9cfb49ad)
Resolves: #1798504
---
src/login/logind-button.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/login/logind-button.c b/src/login/logind-button.c
index 0defa6b9ba..9944eb2316 100644
--- a/src/login/logind-button.c
+++ b/src/login/logind-button.c
@@ -341,6 +341,7 @@ int button_open(Button *b) {
(void) button_set_mask(b);
+ b->io_event_source = sd_event_source_unref(b->io_event_source);
r = sd_event_add_io(b->manager->event, &b->io_event_source, b->fd, EPOLLIN, button_dispatch, b);
if (r < 0) {
log_error_errno(r, "Failed to add button event: %m");

View File

@ -0,0 +1,339 @@
From 5458256264c97eee521caf07c705f549a0f0bd55 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 9 Aug 2018 16:26:27 +0200
Subject: [PATCH] core: rework StopWhenUnneeded= logic
Previously, we'd act immediately on StopWhenUnneeded= when a unit state
changes. With this rework we'll maintain a queue instead: whenever
there's the chance that StopWhenUneeded= might have an effect we enqueue
the unit, and process it later when we have nothing better to do.
This should make the implementation a bit more reliable, as the unit notify event
cannot immediately enqueue tons of side-effect jobs that might
contradict each other, but we do so only in a strictly ordered fashion,
from the main event loop.
This slightly changes the check when to consider a unit "unneeded".
Previously, we'd assume that a unit in "deactivating" state could also
be cleaned up. With this new logic we'll only consider units unneeded
that are fully up and have no job queued. This means that whenever
there's something pending for a unit we won't clean it up.
(cherry picked from commit a3c1168ac293f16d9343d248795bb4c246aaff4a)
Resolves: #1798046
---
src/core/manager.c | 43 ++++++++++++++++
src/core/manager.h | 3 ++
src/core/unit.c | 122 +++++++++++++++++++++++++--------------------
src/core/unit.h | 7 +++
4 files changed, 120 insertions(+), 55 deletions(-)
diff --git a/src/core/manager.c b/src/core/manager.c
index 0eae7d46fb..4c04896aaa 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1211,6 +1211,45 @@ static unsigned manager_dispatch_gc_job_queue(Manager *m) {
return n;
}
+static unsigned manager_dispatch_stop_when_unneeded_queue(Manager *m) {
+ unsigned n = 0;
+ Unit *u;
+ int r;
+
+ assert(m);
+
+ while ((u = m->stop_when_unneeded_queue)) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ assert(m->stop_when_unneeded_queue);
+
+ assert(u->in_stop_when_unneeded_queue);
+ LIST_REMOVE(stop_when_unneeded_queue, m->stop_when_unneeded_queue, u);
+ u->in_stop_when_unneeded_queue = false;
+
+ n++;
+
+ if (!unit_is_unneeded(u))
+ continue;
+
+ log_unit_debug(u, "Unit is not needed anymore.");
+
+ /* If stopping a unit fails continuously we might enter a stop loop here, hence stop acting on the
+ * service being unnecessary after a while. */
+
+ if (!ratelimit_below(&u->auto_stop_ratelimit)) {
+ log_unit_warning(u, "Unit not needed anymore, but not stopping since we tried this too often recently.");
+ continue;
+ }
+
+ /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
+ r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL);
+ if (r < 0)
+ log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r));
+ }
+
+ return n;
+}
+
static void manager_clear_jobs_and_units(Manager *m) {
Unit *u;
@@ -1228,6 +1267,7 @@ static void manager_clear_jobs_and_units(Manager *m) {
assert(!m->cleanup_queue);
assert(!m->gc_unit_queue);
assert(!m->gc_job_queue);
+ assert(!m->stop_when_unneeded_queue);
assert(hashmap_isempty(m->jobs));
assert(hashmap_isempty(m->units));
@@ -2824,6 +2864,9 @@ int manager_loop(Manager *m) {
if (manager_dispatch_cgroup_realize_queue(m) > 0)
continue;
+ if (manager_dispatch_stop_when_unneeded_queue(m) > 0)
+ continue;
+
if (manager_dispatch_dbus_queue(m) > 0)
continue;
diff --git a/src/core/manager.h b/src/core/manager.h
index fa47952d24..40568d3c8b 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -130,6 +130,9 @@ struct Manager {
/* Target units whose default target dependencies haven't been set yet */
LIST_HEAD(Unit, target_deps_queue);
+ /* Units that might be subject to StopWhenUnneeded= clean-up */
+ LIST_HEAD(Unit, stop_when_unneeded_queue);
+
sd_event *event;
/* This maps PIDs we care about to units that are interested in. We allow multiple units to he interested in
diff --git a/src/core/unit.c b/src/core/unit.c
index e1f5e6f7bd..40f138d25c 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -438,6 +438,22 @@ void unit_add_to_dbus_queue(Unit *u) {
u->in_dbus_queue = true;
}
+void unit_add_to_stop_when_unneeded_queue(Unit *u) {
+ assert(u);
+
+ if (u->in_stop_when_unneeded_queue)
+ return;
+
+ if (!u->stop_when_unneeded)
+ return;
+
+ if (!UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u)))
+ return;
+
+ LIST_PREPEND(stop_when_unneeded_queue, u->manager->stop_when_unneeded_queue, u);
+ u->in_stop_when_unneeded_queue = true;
+}
+
static void bidi_set_free(Unit *u, Hashmap *h) {
Unit *other;
Iterator i;
@@ -634,6 +650,9 @@ void unit_free(Unit *u) {
if (u->in_target_deps_queue)
LIST_REMOVE(target_deps_queue, u->manager->target_deps_queue, u);
+ if (u->in_stop_when_unneeded_queue)
+ LIST_REMOVE(stop_when_unneeded_queue, u->manager->stop_when_unneeded_queue, u);
+
safe_close(u->ip_accounting_ingress_map_fd);
safe_close(u->ip_accounting_egress_map_fd);
@@ -1950,55 +1969,71 @@ bool unit_can_reload(Unit *u) {
return UNIT_VTABLE(u)->reload;
}
-static void unit_check_unneeded(Unit *u) {
-
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-
- static const UnitDependency needed_dependencies[] = {
+bool unit_is_unneeded(Unit *u) {
+ static const UnitDependency deps[] = {
UNIT_REQUIRED_BY,
UNIT_REQUISITE_OF,
UNIT_WANTED_BY,
UNIT_BOUND_BY,
};
-
- unsigned j;
- int r;
+ size_t j;
assert(u);
- /* If this service shall be shut down when unneeded then do
- * so. */
-
if (!u->stop_when_unneeded)
- return;
+ return false;
- if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
- return;
+ /* Don't clean up while the unit is transitioning or is even inactive. */
+ if (!UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u)))
+ return false;
+ if (u->job)
+ return false;
- for (j = 0; j < ELEMENTSOF(needed_dependencies); j++) {
+ for (j = 0; j < ELEMENTSOF(deps); j++) {
Unit *other;
Iterator i;
void *v;
- HASHMAP_FOREACH_KEY(v, other, u->dependencies[needed_dependencies[j]], i)
- if (unit_active_or_pending(other) || unit_will_restart(other))
- return;
- }
+ /* If a dependending unit has a job queued, or is active (or in transitioning), or is marked for
+ * restart, then don't clean this one up. */
- /* If stopping a unit fails continuously we might enter a stop
- * loop here, hence stop acting on the service being
- * unnecessary after a while. */
- if (!ratelimit_below(&u->auto_stop_ratelimit)) {
- log_unit_warning(u, "Unit not needed anymore, but not stopping since we tried this too often recently.");
- return;
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[deps[j]], i) {
+ if (u->job)
+ return false;
+
+ if (!UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other)))
+ return false;
+
+ if (unit_will_restart(other))
+ return false;
+ }
}
- log_unit_info(u, "Unit not needed anymore. Stopping.");
+ return true;
+}
- /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
- r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL);
- if (r < 0)
- log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r));
+static void check_unneeded_dependencies(Unit *u) {
+
+ static const UnitDependency deps[] = {
+ UNIT_REQUIRES,
+ UNIT_REQUISITE,
+ UNIT_WANTS,
+ UNIT_BINDS_TO,
+ };
+ size_t j;
+
+ assert(u);
+
+ /* Add all units this unit depends on to the queue that processes StopWhenUnneeded= behaviour. */
+
+ for (j = 0; j < ELEMENTSOF(deps); j++) {
+ Unit *other;
+ Iterator i;
+ void *v;
+
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[deps[j]], i)
+ unit_add_to_stop_when_unneeded_queue(other);
+ }
}
static void unit_check_binds_to(Unit *u) {
@@ -2098,29 +2133,6 @@ static void retroactively_stop_dependencies(Unit *u) {
manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
}
-static void check_unneeded_dependencies(Unit *u) {
- Unit *other;
- Iterator i;
- void *v;
-
- assert(u);
- assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)));
-
- /* Garbage collect services that might not be needed anymore, if enabled */
- HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REQUIRES], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- unit_check_unneeded(other);
- HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_WANTS], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- unit_check_unneeded(other);
- HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REQUISITE], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- unit_check_unneeded(other);
- HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BINDS_TO], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- unit_check_unneeded(other);
-}
-
void unit_start_on_failure(Unit *u) {
Unit *other;
Iterator i;
@@ -2423,7 +2435,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlag
}
/* stop unneeded units regardless if going down was expected or not */
- if (UNIT_IS_INACTIVE_OR_DEACTIVATING(ns))
+ if (UNIT_IS_INACTIVE_OR_FAILED(ns))
check_unneeded_dependencies(u);
if (ns != os && ns == UNIT_FAILED) {
@@ -2483,7 +2495,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlag
if (!MANAGER_IS_RELOADING(u->manager)) {
/* Maybe we finished startup and are now ready for being stopped because unneeded? */
- unit_check_unneeded(u);
+ unit_add_to_stop_when_unneeded_queue(u);
/* Maybe we finished startup, but something we needed has vanished? Let's die then. (This happens when
* something BindsTo= to a Type=oneshot unit, as these units go directly from starting to inactive,
diff --git a/src/core/unit.h b/src/core/unit.h
index 99755823eb..595ee88d43 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -212,6 +212,9 @@ typedef struct Unit {
/* Target dependencies queue */
LIST_FIELDS(Unit, target_deps_queue);
+ /* Queue of units with StopWhenUnneeded set that shell be checked for clean-up. */
+ LIST_FIELDS(Unit, stop_when_unneeded_queue);
+
/* PIDs we keep an eye on. Note that a unit might have many
* more, but these are the ones we care enough about to
* process SIGCHLD for */
@@ -322,6 +325,7 @@ typedef struct Unit {
bool in_cgroup_realize_queue:1;
bool in_cgroup_empty_queue:1;
bool in_target_deps_queue:1;
+ bool in_stop_when_unneeded_queue:1;
bool sent_dbus_new_signal:1;
@@ -615,6 +619,7 @@ void unit_add_to_dbus_queue(Unit *u);
void unit_add_to_cleanup_queue(Unit *u);
void unit_add_to_gc_queue(Unit *u);
void unit_add_to_target_deps_queue(Unit *u);
+void unit_add_to_stop_when_unneeded_queue(Unit *u);
int unit_merge(Unit *u, Unit *other);
int unit_merge_by_name(Unit *u, const char *other);
@@ -751,6 +756,8 @@ bool unit_type_supported(UnitType t);
bool unit_is_pristine(Unit *u);
+bool unit_is_unneeded(Unit *u);
+
pid_t unit_control_pid(Unit *u);
pid_t unit_main_pid(Unit *u);

View File

@ -0,0 +1,81 @@
From 6ecf0a945d6d4187995de7e79e3ed75f4827289a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Sun, 24 Nov 2019 14:14:43 +0100
Subject: [PATCH] pid1: fix the names of AllowedCPUs= and AllowedMemoryNodes=
The original PR was submitted with CPUSetCpus and CPUSetMems, which was later
changed to AllowedCPUs and AllowedMemmoryNodes everywhere (including the parser
used by systemd-run), but not in the parser for unit files.
Since we already released -rc1, let's keep support for the old names. I think
we can remove it in a release or two if anyone remembers to do that.
Fixes #14126. Follow-up for 047f5d63d7a1ab75073f8485e2f9b550d25b0772.
(cherry picked from commit 0b8d3075872a05e0449906d24421ce192f50c29f)
Related: #1818054
---
src/core/load-fragment-gperf.gperf.m4 | 4 ++--
src/core/load-fragment.c | 4 ++--
src/core/load-fragment.h | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index ebb44df487..161c5a2c82 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -161,14 +161,14 @@ $1.KillSignal, config_parse_signal, 0,
)m4_dnl
m4_define(`CGROUP_CONTEXT_CONFIG_ITEMS',
`$1.Slice, config_parse_unit_slice, 0, 0
+$1.AllowedCPUs, config_parse_allowed_cpus, 0, offsetof($1, cgroup_context)
+$1.AllowedMemoryNodes, config_parse_allowed_mems, 0, offsetof($1, cgroup_context)
$1.CPUAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.cpu_accounting)
$1.CPUWeight, config_parse_cg_weight, 0, offsetof($1, cgroup_context.cpu_weight)
$1.StartupCPUWeight, config_parse_cg_weight, 0, offsetof($1, cgroup_context.startup_cpu_weight)
$1.CPUShares, config_parse_cpu_shares, 0, offsetof($1, cgroup_context.cpu_shares)
$1.StartupCPUShares, config_parse_cpu_shares, 0, offsetof($1, cgroup_context.startup_cpu_shares)
$1.CPUQuota, config_parse_cpu_quota, 0, offsetof($1, cgroup_context)
-$1.CPUSetCpus, config_parse_cpuset_cpus, 0, offsetof($1, cgroup_context)
-$1.CPUSetMems, config_parse_cpuset_mems, 0, offsetof($1, cgroup_context)
$1.MemoryAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.memory_accounting)
$1.MemoryLow, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
$1.MemoryHigh, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 6debf82401..2082166afb 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -3011,7 +3011,7 @@ int config_parse_cpu_quota(
return 0;
}
-int config_parse_cpuset_cpus(
+int config_parse_allowed_cpus(
const char *unit,
const char *filename,
unsigned line,
@@ -3030,7 +3030,7 @@ int config_parse_cpuset_cpus(
return 0;
}
-int config_parse_cpuset_mems(
+int config_parse_allowed_mems(
const char *unit,
const char *filename,
unsigned line,
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 6612e1fb32..424fa478a7 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -86,8 +86,8 @@ CONFIG_PARSER_PROTOTYPE(config_parse_set_status);
CONFIG_PARSER_PROTOTYPE(config_parse_namespace_path_strv);
CONFIG_PARSER_PROTOTYPE(config_parse_temporary_filesystems);
CONFIG_PARSER_PROTOTYPE(config_parse_cpu_quota);
-CONFIG_PARSER_PROTOTYPE(config_parse_cpuset_cpus);
-CONFIG_PARSER_PROTOTYPE(config_parse_cpuset_mems);
+CONFIG_PARSER_PROTOTYPE(config_parse_allowed_cpus);
+CONFIG_PARSER_PROTOTYPE(config_parse_allowed_mems);
CONFIG_PARSER_PROTOTYPE(config_parse_protect_home);
CONFIG_PARSER_PROTOTYPE(config_parse_protect_system);
CONFIG_PARSER_PROTOTYPE(config_parse_bus_name);

View File

@ -0,0 +1,62 @@
From ca843e40587fb87fe20bd0561b6ccb42aaafc4ab Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 9 Jan 2020 17:30:31 +0100
Subject: [PATCH] core: fix re-realization of cgroup siblings
This is a fix-up for eef85c4a3f8054d29383a176f6cebd1ef3a15b9a which
broke this.
Tracked down by @w-simon
Fixes: #14453
(cherry picked from commit 65f6b6bdcb500c576674b5838e4cc4c35e18bfde)
Related: #1818054
---
src/core/cgroup.c | 21 +++++++--------------
1 file changed, 7 insertions(+), 14 deletions(-)
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 664d269483..3f7665b755 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -1796,32 +1796,25 @@ unsigned manager_dispatch_cgroup_realize_queue(Manager *m) {
static void unit_add_siblings_to_cgroup_realize_queue(Unit *u) {
Unit *slice;
- /* This adds the siblings of the specified unit and the
- * siblings of all parent units to the cgroup queue. (But
- * neither the specified unit itself nor the parents.) */
+ /* This adds the siblings of the specified unit and the siblings of all parent units to the cgroup
+ * queue. (But neither the specified unit itself nor the parents.) */
while ((slice = UNIT_DEREF(u->slice))) {
Iterator i;
Unit *m;
void *v;
- HASHMAP_FOREACH_KEY(v, m, u->dependencies[UNIT_BEFORE], i) {
- if (m == u)
- continue;
-
- /* Skip units that have a dependency on the slice
- * but aren't actually in it. */
+ HASHMAP_FOREACH_KEY(v, m, slice->dependencies[UNIT_BEFORE], i) {
+ /* Skip units that have a dependency on the slice but aren't actually in it. */
if (UNIT_DEREF(m->slice) != slice)
continue;
- /* No point in doing cgroup application for units
- * without active processes. */
+ /* No point in doing cgroup application for units without active processes. */
if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(m)))
continue;
- /* If the unit doesn't need any new controllers
- * and has current ones realized, it doesn't need
- * any changes. */
+ /* If the unit doesn't need any new controllers and has current ones realized, it
+ * doesn't need any changes. */
if (unit_has_mask_realized(m,
unit_get_target_mask(m),
unit_get_enable_mask(m),

View File

@ -0,0 +1,99 @@
From 9fe3b9c7165afeedcf9f31959c436bcec233bb4d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= <msekleta@redhat.com>
Date: Tue, 14 Apr 2020 16:16:45 +0200
Subject: [PATCH] basic: use comma as separator in cpuset cgroup cpu ranges
This is a workaround for
https://bugzilla.redhat.com/show_bug.cgi?id=1819152 and should be
reverted in RHEL-8.3.
RHEL-only
Related: #1818054
---
src/basic/cpu-set-util.c | 45 ++++++++++++++++++++++++++++++++++++++++
src/basic/cpu-set-util.h | 1 +
src/core/cgroup.c | 2 +-
3 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c
index 36cb017ae7..51752ad1a6 100644
--- a/src/basic/cpu-set-util.c
+++ b/src/basic/cpu-set-util.c
@@ -86,6 +86,51 @@ char *cpu_set_to_range_string(const CPUSet *set) {
return TAKE_PTR(str) ?: strdup("");
}
+/* XXX(msekleta): this is the workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1819152, remove in 8.3 */
+char *cpu_set_to_range_string_kernel(const CPUSet *set) {
+ unsigned range_start = 0, range_end;
+ _cleanup_free_ char *str = NULL;
+ size_t allocated = 0, len = 0;
+ bool in_range = false;
+ int r;
+
+ for (unsigned i = 0; i < set->allocated * 8; i++)
+ if (CPU_ISSET_S(i, set->allocated, set->set)) {
+ if (in_range)
+ range_end++;
+ else {
+ range_start = range_end = i;
+ in_range = true;
+ }
+ } else if (in_range) {
+ in_range = false;
+
+ if (!GREEDY_REALLOC(str, allocated, len + 2 + 2 * DECIMAL_STR_MAX(unsigned)))
+ return NULL;
+
+ if (range_end > range_start)
+ r = sprintf(str + len, len > 0 ? ",%d-%d" : "%d-%d", range_start, range_end);
+ else
+ r = sprintf(str + len, len > 0 ? ",%d" : "%d", range_start);
+ assert_se(r > 0);
+ len += r;
+ }
+
+ if (in_range) {
+ if (!GREEDY_REALLOC(str, allocated, len + 2 + 2 * DECIMAL_STR_MAX(int)))
+ return NULL;
+
+ if (range_end > range_start)
+ r = sprintf(str + len, len > 0 ? ",%d-%d" : "%d-%d", range_start, range_end);
+ else
+ r = sprintf(str + len, len > 0 ? ",%d" : "%d", range_start);
+ assert_se(r > 0);
+ }
+
+ return TAKE_PTR(str) ?: strdup("");
+}
+
+
int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus) {
size_t need;
diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h
index 295028cb54..8519a9b6c8 100644
--- a/src/basic/cpu-set-util.h
+++ b/src/basic/cpu-set-util.h
@@ -27,6 +27,7 @@ int cpu_set_add_all(CPUSet *a, const CPUSet *b);
char* cpu_set_to_string(const CPUSet *a);
char *cpu_set_to_range_string(const CPUSet *a);
+char *cpu_set_to_range_string_kernel(const CPUSet *a);
int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus);
int parse_cpu_set_full(
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 3f7665b755..9e4c3c7dac 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -557,7 +557,7 @@ static void cgroup_apply_unified_cpuset(Unit *u, CPUSet cpus, const char *name)
_cleanup_free_ char *buf = NULL;
int r;
- buf = cpu_set_to_range_string(&cpus);
+ buf = cpu_set_to_range_string_kernel(&cpus);
if (!buf)
return;

View File

@ -0,0 +1,159 @@
From 6e732b6e44ad8eb3e94c47459c64f0bc6ef2fcb0 Mon Sep 17 00:00:00 2001
From: Anita Zhang <the.anitazha@gmail.com>
Date: Sat, 25 Jan 2020 16:46:16 +0100
Subject: [PATCH] core: transition to FINAL_SIGTERM state after ExecStopPost=
Fixes #14566
(cherry picked from commit c1566ef0d22ed786b9ecf4c476e53b8a91e67578)
Resolves: #1766479
---
src/core/service.c | 10 +++++
test/TEST-47-ISSUE-14566/Makefile | 1 +
test/TEST-47-ISSUE-14566/repro.sh | 5 +++
test/TEST-47-ISSUE-14566/test.sh | 55 +++++++++++++++++++++++++++
test/TEST-47-ISSUE-14566/testsuite.sh | 23 +++++++++++
5 files changed, 94 insertions(+)
create mode 120000 test/TEST-47-ISSUE-14566/Makefile
create mode 100755 test/TEST-47-ISSUE-14566/repro.sh
create mode 100755 test/TEST-47-ISSUE-14566/test.sh
create mode 100755 test/TEST-47-ISSUE-14566/testsuite.sh
diff --git a/src/core/service.c b/src/core/service.c
index b1ec52d220..5035dcacac 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -3280,6 +3280,12 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
break;
case SERVICE_STOP_POST:
+
+ if (control_pid_good(s) <= 0)
+ service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
+
+ break;
+
case SERVICE_FINAL_SIGTERM:
case SERVICE_FINAL_SIGKILL:
@@ -3415,6 +3421,10 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
break;
case SERVICE_STOP_POST:
+ if (main_pid_good(s) <= 0)
+ service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
+ break;
+
case SERVICE_FINAL_SIGTERM:
case SERVICE_FINAL_SIGKILL:
if (main_pid_good(s) <= 0)
diff --git a/test/TEST-47-ISSUE-14566/Makefile b/test/TEST-47-ISSUE-14566/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-47-ISSUE-14566/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-47-ISSUE-14566/repro.sh b/test/TEST-47-ISSUE-14566/repro.sh
new file mode 100755
index 0000000000..5217602257
--- /dev/null
+++ b/test/TEST-47-ISSUE-14566/repro.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+sleep infinity &
+echo $! > /leakedtestpid
+wait $!
diff --git a/test/TEST-47-ISSUE-14566/test.sh b/test/TEST-47-ISSUE-14566/test.sh
new file mode 100755
index 0000000000..0ce772164a
--- /dev/null
+++ b/test/TEST-47-ISSUE-14566/test.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+set -e
+TEST_DESCRIPTION="Test that KillMode=mixed does not leave left over proccesses with ExecStopPost="
+. $TEST_BASE_DIR/test-functions
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+
+ # mask some services that we do not want to run in these tests
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service
+
+ # setup the testsuite service
+ cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+
+[Service]
+ExecStart=/testsuite.sh
+Type=oneshot
+EOF
+ cat > $initdir/etc/systemd/system/issue_14566_test.service << EOF
+[Unit]
+Description=Issue 14566 Repro
+
+[Service]
+ExecStart=/repro.sh
+ExecStopPost=/bin/true
+KillMode=mixed
+EOF
+
+ cp testsuite.sh $initdir/
+ cp repro.sh $initdir/
+
+ setup_testsuite
+ )
+ setup_nspawn_root
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+do_test "$@"
diff --git a/test/TEST-47-ISSUE-14566/testsuite.sh b/test/TEST-47-ISSUE-14566/testsuite.sh
new file mode 100755
index 0000000000..d917cf52ff
--- /dev/null
+++ b/test/TEST-47-ISSUE-14566/testsuite.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+set -ex
+set -o pipefail
+
+systemd-analyze log-level debug
+systemd-analyze log-target console
+
+systemctl start issue_14566_test
+systemctl status issue_14566_test
+
+leaked_pid=$(cat /leakedtestpid)
+
+systemctl stop issue_14566_test
+
+# Leaked PID will still be around if we're buggy.
+# I personally prefer to see 42.
+ps -p "$leaked_pid" && exit 42
+
+systemd-analyze log-level info
+
+echo OK > /testok
+
+exit 0

View File

@ -0,0 +1,75 @@
From 45275461f4a5293f15191ec5cb3bb80219ef2474 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= <msekleta@redhat.com>
Date: Tue, 4 Feb 2020 14:23:14 +0100
Subject: [PATCH] sd-journal: close journal files that were deleted by journald
before we've setup inotify watch
Fixes #14695
(cherry picked from commit 28ca867abdb20d0e4ac1901e2ed669cdb41ea3f6)
Related: #1796128
---
src/journal/journal-file.c | 2 +-
src/journal/journal-file.h | 1 +
src/journal/sd-journal.c | 15 +++++++++++++++
3 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 8249b11b23..7ab3c47fc9 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -597,7 +597,7 @@ static int journal_file_verify_header(JournalFile *f) {
return 0;
}
-static int journal_file_fstat(JournalFile *f) {
+int journal_file_fstat(JournalFile *f) {
int r;
assert(f);
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index 6a44fd39d2..6069b35234 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -144,6 +144,7 @@ int journal_file_open(
int journal_file_set_offline(JournalFile *f, bool wait);
bool journal_file_is_offlining(JournalFile *f);
JournalFile* journal_file_close(JournalFile *j);
+int journal_file_fstat(JournalFile *f);
DEFINE_TRIVIAL_CLEANUP_FUNC(JournalFile*, journal_file_close);
int journal_file_open_reliably(
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 323300baec..c06255e273 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -2584,6 +2584,8 @@ _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
assert_return(!journal_pid_changed(j), -ECHILD);
if (j->inotify_fd < 0) {
+ Iterator i;
+ JournalFile *f;
/* This is the first invocation, hence create the
* inotify watch */
@@ -2591,6 +2593,19 @@ _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
if (r < 0)
return r;
+ /* Server might have done some vacuuming while we weren't watching.
+ Get rid of the deleted files now so they don't stay around indefinitely. */
+ ORDERED_HASHMAP_FOREACH(f, j->files, i) {
+ r = journal_file_fstat(f);
+ if (r < 0) {
+ log_debug_errno(r,"Failed to fstat() journal file '%s' : %m", f->path);
+ continue;
+ }
+
+ if (f->last_stat.st_nlink <= 0)
+ remove_file_real(j, f);
+ }
+
/* The journal might have changed since the context
* object was created and we weren't watching before,
* hence don't wait for anything, and return

View File

@ -0,0 +1,42 @@
From 0f7ee0007b8267cc66b638a44da6ddd984ece412 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= <msekleta@redhat.com>
Date: Fri, 27 Mar 2020 17:01:59 +0100
Subject: [PATCH] sd-journal: remove the dead code and actually fix #14695
journal_file_fstat() returns an error if we call it on already unlinked
journal file and hence we never reach remove_file_real() which is the
entire point.
I must have made some mistake while testing the fix that got me thinking
the issue is gone while opposite was true.
Fixes #14695
(cherry picked from commit 8581b9f9732d4c158bb5f773230a65ce77f2c292)
Resolves: #1796128
---
src/journal/sd-journal.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index c06255e273..4c502978de 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -2597,13 +2597,12 @@ _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
Get rid of the deleted files now so they don't stay around indefinitely. */
ORDERED_HASHMAP_FOREACH(f, j->files, i) {
r = journal_file_fstat(f);
- if (r < 0) {
+ if (r == -EIDRM)
+ remove_file_real(j, f);
+ else if (r < 0) {
log_debug_errno(r,"Failed to fstat() journal file '%s' : %m", f->path);
continue;
}
-
- if (f->last_stat.st_nlink <= 0)
- remove_file_real(j, f);
}
/* The journal might have changed since the context

View File

@ -0,0 +1,43 @@
From 38532765172a4e60624b9c24b8d081b34d9f7b86 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 13 Nov 2018 14:53:04 +0100
Subject: [PATCH] udev: downgrade message when we fail to set inotify watch up
My logs are full of:
systemd-udevd[6586]: seq 13515 queued, 'add' 'block'
systemd-udevd[6586]: seq 13516 queued, 'change' 'block'
systemd-udevd[6586]: seq 13517 queued, 'change' 'block'
systemd-udevd[6586]: seq 13518 queued, 'remove' 'bdi'
systemd-udevd[6586]: seq 13519 queued, 'remove' 'block'
systemd-udevd[9865]: seq 13514 processed
systemd-udevd[9865]: seq 13515 running
systemd-udevd[9865]: GROUP 6 /usr/lib/udev/rules.d/50-udev-default.rules:59
systemd-udevd[9865]: IMPORT builtin 'blkid' /usr/lib/udev/rules.d/60-persistent-storage.rules:95
systemd-udevd[9865]: IMPORT builtin 'blkid' fails: No such file or directory
systemd-udevd[9865]: loop4: Failed to add device '/dev/loop4' to watch: No such file or directory
(the last line is at error level).
If we are too slow to set up a watch and the device is already gone by the time
we try, this is not an error.
(cherry picked from commit 7fe0d0d5c0ad5aa3f069bb282868938d414d7ad1)
Resolves: #1808051
---
src/udev/udev-watch.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c
index 7864f57aa5..9c82196add 100644
--- a/src/udev/udev-watch.c
+++ b/src/udev/udev-watch.c
@@ -87,7 +87,8 @@ void udev_watch_begin(struct udev *udev, struct udev_device *dev) {
log_debug("adding watch on '%s'", udev_device_get_devnode(dev));
wd = inotify_add_watch(inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE);
if (wd < 0) {
- log_error_errno(errno, "inotify_add_watch(%d, %s, %o) failed: %m",
+ log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
+ errno, "inotify_add_watch(%d, %s, %o) failed: %m",
inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE);
return;
}

View File

@ -0,0 +1,195 @@
From af20a66874296f71618819ebce9d4335b195728c Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 22 Jan 2020 12:04:38 +0100
Subject: [PATCH] logind: check PolicyKit before allowing VT switch
Let's lock this down a bit. Effectively nothing much changes, since the
default PK policy will allow users on the VT to change VT. Only users
with no local VT session won't be able to switch VTs.
(cherry picked from commit 4acf0cfd2f92edb94ad48d04f1ce6c9ab4e19d55)
Resolves: #1797679
---
src/login/logind-dbus.c | 16 +++++++
src/login/logind-seat-dbus.c | 58 ++++++++++++++++++++++++-
src/login/logind-session-dbus.c | 15 +++++++
src/login/org.freedesktop.login1.policy | 10 +++++
4 files changed, 98 insertions(+), 1 deletion(-)
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index dca7f4a30f..3f122fcbd9 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -913,6 +913,8 @@ static int method_activate_session(sd_bus_message *message, void *userdata, sd_b
if (r < 0)
return r;
+ /* PolicyKit is done by bus_session_method_activate() */
+
return bus_session_method_activate(message, session, error);
}
@@ -944,6 +946,20 @@ static int method_activate_session_on_seat(sd_bus_message *message, void *userda
if (session->seat != seat)
return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", session_name, seat_name);
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.login1.chvt",
+ NULL,
+ false,
+ UID_INVALID,
+ &m->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
r = session_activate(session);
if (r < 0)
return r;
diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c
index c4d9b067c6..2e590a8f21 100644
--- a/src/login/logind-seat-dbus.c
+++ b/src/login/logind-seat-dbus.c
@@ -174,6 +174,20 @@ static int method_activate_session(sd_bus_message *message, void *userdata, sd_b
if (session->seat != s)
return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id);
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.login1.chvt",
+ NULL,
+ false,
+ UID_INVALID,
+ &s->manager->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
r = session_activate(session);
if (r < 0)
return r;
@@ -194,7 +208,21 @@ static int method_switch_to(sd_bus_message *message, void *userdata, sd_bus_erro
return r;
if (to <= 0)
- return -EINVAL;
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid virtual terminal");
+
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.login1.chvt",
+ NULL,
+ false,
+ UID_INVALID,
+ &s->manager->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
r = seat_switch_to(s, to);
if (r < 0)
@@ -210,6 +238,20 @@ static int method_switch_to_next(sd_bus_message *message, void *userdata, sd_bus
assert(message);
assert(s);
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.login1.chvt",
+ NULL,
+ false,
+ UID_INVALID,
+ &s->manager->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
r = seat_switch_to_next(s);
if (r < 0)
return r;
@@ -224,6 +266,20 @@ static int method_switch_to_previous(sd_bus_message *message, void *userdata, sd
assert(message);
assert(s);
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.login1.chvt",
+ NULL,
+ false,
+ UID_INVALID,
+ &s->manager->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
r = seat_switch_to_previous(s);
if (r < 0)
return r;
diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c
index 25c4981dc0..88a2d33dc8 100644
--- a/src/login/logind-session-dbus.c
+++ b/src/login/logind-session-dbus.c
@@ -13,6 +13,7 @@
#include "logind.h"
#include "signal-util.h"
#include "strv.h"
+#include "user-util.h"
#include "util.h"
static int property_get_user(
@@ -182,6 +183,20 @@ int bus_session_method_activate(sd_bus_message *message, void *userdata, sd_bus_
assert(message);
assert(s);
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.login1.chvt",
+ NULL,
+ false,
+ UID_INVALID,
+ &s->manager->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
r = session_activate(s);
if (r < 0)
return r;
diff --git a/src/login/org.freedesktop.login1.policy b/src/login/org.freedesktop.login1.policy
index f1d1f956d3..83760e1580 100644
--- a/src/login/org.freedesktop.login1.policy
+++ b/src/login/org.freedesktop.login1.policy
@@ -357,4 +357,14 @@
</defaults>
</action>
+ <action id="org.freedesktop.login1.chvt">
+ <description gettext-domain="systemd">Change Session</description>
+ <message gettext-domain="systemd">Authentication is required for changing the virtual terminal.</message>
+ <defaults>
+ <allow_any>auth_admin_keep</allow_any>
+ <allow_inactive>auth_admin_keep</allow_inactive>
+ <allow_active>yes</allow_active>
+ </defaults>
+ </action>
+
</policyconfig>

View File

@ -0,0 +1,58 @@
From 35e9e01b2879854a2adb8d571d0204990cad38d9 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 14 Sep 2018 13:25:02 +0900
Subject: [PATCH] test: do not use global variable to pass error
(cherry picked from commit 0013fac248a15be3acce84c17a65e3ae0377294b)
Resolves: #1823767
---
test/TEST-21-SYSUSERS/test.sh | 1 +
test/test-functions | 8 +++++---
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/test/TEST-21-SYSUSERS/test.sh b/test/TEST-21-SYSUSERS/test.sh
index 73cbe10b69..b1049e720d 100755
--- a/test/TEST-21-SYSUSERS/test.sh
+++ b/test/TEST-21-SYSUSERS/test.sh
@@ -15,6 +15,7 @@ prepare_testdir() {
for i in $1.initial-{passwd,group,shadow}; do
test -f $i && cp $i $TESTDIR/etc/${i#*.initial-}
done
+ return 0
}
preprocess() {
diff --git a/test/test-functions b/test/test-functions
index fe25a501da..da83891f46 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -449,7 +449,7 @@ EOF
}
check_result_nspawn() {
- ret=1
+ local ret=1
[[ -e $TESTDIR/$1/testok ]] && ret=0
[[ -f $TESTDIR/$1/failed ]] && cp -a $TESTDIR/$1/failed $TESTDIR
cp -a $TESTDIR/$1/var/log/journal $TESTDIR
@@ -462,7 +462,7 @@ check_result_nspawn() {
# can be overridden in specific test
check_result_qemu() {
- ret=1
+ local ret=1
mkdir -p $TESTDIR/root
mount ${LOOPDEV}p1 $TESTDIR/root
[[ -e $TESTDIR/root/testok ]] && ret=0
@@ -1527,7 +1527,9 @@ do_test() {
case $1 in
--run)
echo "TEST RUN: $TEST_DESCRIPTION"
- if test_run; then
+ test_run
+ ret=$?
+ if (( $ret == 0 )); then
echo "TEST RUN: $TEST_DESCRIPTION [OK]"
else
echo "TEST RUN: $TEST_DESCRIPTION [FAILED]"

View File

@ -0,0 +1,25 @@
From 98e4c0d39a83a325038d0b39715fc534c7613bef Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 12 Sep 2018 18:19:45 +0900
Subject: [PATCH] test: install libraries required by tests
(cherry picked from commit e3d3dada248c5f30e2978840ca1f0a03a4675b53)
Resolves: #1823767
---
test/test-functions | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/test-functions b/test/test-functions
index da83891f46..f7ca3ad975 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -420,7 +420,7 @@ get_ldpath() {
install_missing_libraries() {
# install possible missing libraries
- for i in $initdir{,/usr}/{sbin,bin}/* $initdir{,/usr}/lib/systemd/*; do
+ for i in $initdir{,/usr}/{sbin,bin}/* $initdir{,/usr}/lib/systemd/{,tests/{,manual/,unsafe/}}*; do
LD_LIBRARY_PATH=$(get_ldpath $i) inst_libs $i
done
}

View File

@ -0,0 +1,32 @@
From 73781e52f331f816924232f96c7bfc92ee763e70 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 12 Sep 2018 18:20:31 +0900
Subject: [PATCH] test: introduce install_zoneinfo()
But it is not called by default.
(cherry picked from commit 7d10ec1cda8fed20c36b16d2387f529583645cda)
Resolves: #1823767
---
test/test-functions | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/test/test-functions b/test/test-functions
index f7ca3ad975..4d76ed1f82 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -628,6 +628,13 @@ install_keymaps() {
done
}
+install_zoneinfo() {
+ for i in /usr/share/zoneinfo/{,*/,*/*/}*; do
+ [[ -f $i ]] || continue
+ inst $i
+ done
+}
+
install_fonts() {
for i in \
/usr/lib/kbd/consolefonts/eurlatgr* \

View File

@ -0,0 +1,151 @@
From e39c4e6aee6c2ece5d9b51cc0e7a772016546f5a Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Thu, 13 Sep 2018 03:01:42 +0900
Subject: [PATCH] test: replace duplicated Makefile by symbolic link
(cherry picked from commit dd75c133d81f07c56c82ee4e7a80f391ffebd9ce)
Resolves: #1823767
---
test/TEST-17-UDEV-WANTS/Makefile | 5 +----
test/TEST-18-FAILUREACTION/Makefile | 5 +----
test/TEST-19-DELEGATE/Makefile | 5 +----
test/TEST-20-MAINPIDGAMES/Makefile | 5 +----
test/TEST-21-SYSUSERS/Makefile | 5 +----
test/TEST-22-TMPFILES/Makefile | 5 +----
test/TEST-23-TYPE-EXEC/Makefile | 5 +----
7 files changed, 7 insertions(+), 28 deletions(-)
mode change 100644 => 120000 test/TEST-17-UDEV-WANTS/Makefile
mode change 100644 => 120000 test/TEST-18-FAILUREACTION/Makefile
mode change 100644 => 120000 test/TEST-19-DELEGATE/Makefile
mode change 100644 => 120000 test/TEST-20-MAINPIDGAMES/Makefile
mode change 100644 => 120000 test/TEST-21-SYSUSERS/Makefile
mode change 100644 => 120000 test/TEST-22-TMPFILES/Makefile
mode change 100644 => 120000 test/TEST-23-TYPE-EXEC/Makefile
diff --git a/test/TEST-17-UDEV-WANTS/Makefile b/test/TEST-17-UDEV-WANTS/Makefile
deleted file mode 100644
index 34d7cc6cdf..0000000000
--- a/test/TEST-17-UDEV-WANTS/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-BUILD_DIR=$(shell ../../tools/find-build-dir.sh)
-
-all setup clean run:
- @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@
diff --git a/test/TEST-17-UDEV-WANTS/Makefile b/test/TEST-17-UDEV-WANTS/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-17-UDEV-WANTS/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-18-FAILUREACTION/Makefile b/test/TEST-18-FAILUREACTION/Makefile
deleted file mode 100644
index 34d7cc6cdf..0000000000
--- a/test/TEST-18-FAILUREACTION/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-BUILD_DIR=$(shell ../../tools/find-build-dir.sh)
-
-all setup clean run:
- @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@
diff --git a/test/TEST-18-FAILUREACTION/Makefile b/test/TEST-18-FAILUREACTION/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-18-FAILUREACTION/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-19-DELEGATE/Makefile b/test/TEST-19-DELEGATE/Makefile
deleted file mode 100644
index 34d7cc6cdf..0000000000
--- a/test/TEST-19-DELEGATE/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-BUILD_DIR=$(shell ../../tools/find-build-dir.sh)
-
-all setup clean run:
- @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@
diff --git a/test/TEST-19-DELEGATE/Makefile b/test/TEST-19-DELEGATE/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-19-DELEGATE/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-20-MAINPIDGAMES/Makefile b/test/TEST-20-MAINPIDGAMES/Makefile
deleted file mode 100644
index 34d7cc6cdf..0000000000
--- a/test/TEST-20-MAINPIDGAMES/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-BUILD_DIR=$(shell ../../tools/find-build-dir.sh)
-
-all setup clean run:
- @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@
diff --git a/test/TEST-20-MAINPIDGAMES/Makefile b/test/TEST-20-MAINPIDGAMES/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-20-MAINPIDGAMES/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-21-SYSUSERS/Makefile b/test/TEST-21-SYSUSERS/Makefile
deleted file mode 100644
index 34d7cc6cdf..0000000000
--- a/test/TEST-21-SYSUSERS/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-BUILD_DIR=$(shell ../../tools/find-build-dir.sh)
-
-all setup clean run:
- @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@
diff --git a/test/TEST-21-SYSUSERS/Makefile b/test/TEST-21-SYSUSERS/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-21-SYSUSERS/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-22-TMPFILES/Makefile b/test/TEST-22-TMPFILES/Makefile
deleted file mode 100644
index 34d7cc6cdf..0000000000
--- a/test/TEST-22-TMPFILES/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-BUILD_DIR=$(shell ../../tools/find-build-dir.sh)
-
-all setup clean run:
- @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@
diff --git a/test/TEST-22-TMPFILES/Makefile b/test/TEST-22-TMPFILES/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-22-TMPFILES/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-23-TYPE-EXEC/Makefile b/test/TEST-23-TYPE-EXEC/Makefile
deleted file mode 100644
index 34d7cc6cdf..0000000000
--- a/test/TEST-23-TYPE-EXEC/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-BUILD_DIR=$(shell ../../tools/find-build-dir.sh)
-
-all setup clean run:
- @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@
diff --git a/test/TEST-23-TYPE-EXEC/Makefile b/test/TEST-23-TYPE-EXEC/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-23-TYPE-EXEC/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file

View File

@ -0,0 +1,34 @@
From 1599be6d3625700ded28108c0747b000448fa5dc Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 19 Sep 2018 10:54:16 +0900
Subject: [PATCH] test: add paths of keymaps in install_keymaps()
It seems that the paths of directories storing keymaps are changed.
(cherry picked from commit 83a7051ee1edbfe8cd2278477d23083beb385409)
Resolves: #1823767
---
test/test-functions | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/test/test-functions b/test/test-functions
index 4d76ed1f82..546928c516 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -619,10 +619,14 @@ install_pam() {
}
install_keymaps() {
+ # The first three paths may be deprecated.
+ # It seems now the last two paths are used by many distributions.
for i in \
/usr/lib/kbd/keymaps/include/* \
/usr/lib/kbd/keymaps/i386/include/* \
- /usr/lib/kbd/keymaps/i386/qwerty/us.*; do
+ /usr/lib/kbd/keymaps/i386/qwerty/us.* \
+ /usr/lib/kbd/keymaps/legacy/include/* \
+ /usr/lib/kbd/keymaps/legacy/i386/qwerty/us.*; do
[[ -f $i ]] || continue
inst $i
done

View File

@ -0,0 +1,33 @@
From 8dbd01f7018947fd15d00c25b1aa0ffc72278cb6 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 19 Sep 2018 10:54:28 +0900
Subject: [PATCH] test: make install_keymaps() optionally install more keymaps
(cherry picked from commit ad931fee506e1313e8a520ae0ecc1c8e275d9941)
Resolves: #1823767
---
test/test-functions | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/test/test-functions b/test/test-functions
index 546928c516..0938e6e826 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -630,6 +630,16 @@ install_keymaps() {
[[ -f $i ]] || continue
inst $i
done
+
+ # When it takes any argument, then install more keymaps.
+ if [[ -n $1 ]]; then
+ for i in \
+ /usr/lib/kbd/keymaps/i386/*/* \
+ /usr/lib/kbd/keymaps/legacy/i386/*/*; do
+ [[ -f $i ]] || continue
+ inst $i
+ done
+ fi
}
install_zoneinfo() {

View File

@ -0,0 +1,47 @@
From 15ab55eca3d1f7feb86e55bdc147069f36d198eb Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 14 Sep 2018 15:51:04 +0900
Subject: [PATCH] test-fs-util: skip some tests when running in unprivileged
container
(cherry picked from commit 9590065f37be040996f1c2b9a246b9952fdc0c0b)
Resolves: #1823767
---
src/test/test-fs-util.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c
index 7b7990bb70..e3338ea440 100644
--- a/src/test/test-fs-util.c
+++ b/src/test/test-fs-util.c
@@ -17,6 +17,7 @@
#include "strv.h"
#include "user-util.h"
#include "util.h"
+#include "virt.h"
static void test_chase_symlinks(void) {
_cleanup_free_ char *result = NULL;
@@ -468,6 +469,7 @@ static void test_touch_file(void) {
struct stat st;
const char *a;
usec_t test_mtime;
+ int r;
test_uid = geteuid() == 0 ? 65534 : getuid();
test_gid = geteuid() == 0 ? 65534 : getgid();
@@ -517,7 +519,12 @@ static void test_touch_file(void) {
if (geteuid() == 0) {
a = strjoina(p, "/cdev");
- assert_se(mknod(a, 0775 | S_IFCHR, makedev(0, 0)) >= 0);
+ r = mknod(a, 0775 | S_IFCHR, makedev(0, 0));
+ if (r < 0 && errno == EPERM && detect_container() > 0) {
+ log_notice("Running in unprivileged container? Skipping remaining tests in %s", __func__);
+ return;
+ }
+ assert_se(r >= 0);
assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
assert_se(lstat(a, &st) >= 0);
assert_se(st.st_uid == test_uid);

View File

@ -0,0 +1,39 @@
From b550cc33e762fa209b0740f1874f75ef780b8d90 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Thu, 20 Sep 2018 16:08:38 +0900
Subject: [PATCH] test-process-util: skip several verifications when running in
unprivileged container
(cherry picked from commit 767eab47501b06327a0e6030e5c54860a3fc427f)
Resolves: #1823767
---
src/test/test-process-util.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c
index fd4d17408d..26e3247993 100644
--- a/src/test/test-process-util.c
+++ b/src/test/test-process-util.c
@@ -394,12 +394,17 @@ static void test_rename_process_now(const char *p, int ret) {
log_info("comm = <%s>", comm);
assert_se(strneq(comm, p, TASK_COMM_LEN-1));
- assert_se(get_process_cmdline(0, 0, false, &cmdline) >= 0);
+ r = get_process_cmdline(0, 0, false, &cmdline);
+ assert_se(r >= 0);
/* we cannot expect cmdline to be renamed properly without privileges */
if (geteuid() == 0) {
- log_info("cmdline = <%s>", cmdline);
- assert_se(strneq(p, cmdline, STRLEN("test-process-util")));
- assert_se(startswith(p, cmdline));
+ if (r == 0 && detect_container() > 0)
+ log_info("cmdline = <%s> (not verified, Running in unprivileged container?)", cmdline);
+ else {
+ log_info("cmdline = <%s>", cmdline);
+ assert_se(strneq(p, cmdline, STRLEN("test-process-util")));
+ assert_se(startswith(p, cmdline));
+ }
} else
log_info("cmdline = <%s> (not verified)", cmdline);
}

View File

@ -0,0 +1,59 @@
From a3a3d861496b8c0d061c6ba21278d0326c50f37d Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 12 Sep 2018 18:18:33 +0900
Subject: [PATCH] test-execute: also check python3 is installed or not
(cherry picked from commit 738c74d7b163ea18e3c68115c3ed8ceed166cbf7)
Resolves: #1823767
---
src/test/test-execute.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 6c22995b1e..af64427bc7 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -317,6 +317,8 @@ static void test_exec_temporaryfilesystem(Manager *m) {
static void test_exec_systemcallfilter(Manager *m) {
#if HAVE_SECCOMP
+ int r;
+
if (!is_seccomp_available()) {
log_notice("Seccomp not available, skipping %s", __func__);
return;
@@ -326,6 +328,13 @@ static void test_exec_systemcallfilter(Manager *m) {
test(m, "exec-systemcallfilter-not-failing2.service", 0, CLD_EXITED);
test(m, "exec-systemcallfilter-failing.service", SIGSYS, CLD_KILLED);
test(m, "exec-systemcallfilter-failing2.service", SIGSYS, CLD_KILLED);
+
+ r = find_binary("python3", NULL);
+ if (r < 0) {
+ log_notice_errno(r, "Skipping remaining tests in %s, could not find python3 binary: %m", __func__);
+ return;
+ }
+
test(m, "exec-systemcallfilter-with-errno-name.service", errno_from_name("EILSEQ"), CLD_EXITED);
test(m, "exec-systemcallfilter-with-errno-number.service", 255, CLD_EXITED);
#endif
@@ -333,11 +342,19 @@ static void test_exec_systemcallfilter(Manager *m) {
static void test_exec_systemcallerrornumber(Manager *m) {
#if HAVE_SECCOMP
+ int r;
+
if (!is_seccomp_available()) {
log_notice("Seccomp not available, skipping %s", __func__);
return;
}
+ r = find_binary("python3", NULL);
+ if (r < 0) {
+ log_notice_errno(r, "Skipping %s, could not find python3 binary: %m", __func__);
+ return;
+ }
+
test(m, "exec-systemcallerrornumber-name.service", errno_from_name("EACCES"), CLD_EXITED);
test(m, "exec-systemcallerrornumber-number.service", 255, CLD_EXITED);
#endif

View File

@ -0,0 +1,42 @@
From fb66f2dbf1d228adc6f15edbbdf0ce53eb3be982 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 14 Sep 2018 15:47:42 +0900
Subject: [PATCH] test-execute: skip several tests when running in container
(cherry picked from commit 642d1a6d6e98204ade25816bcc429cb67df92a29)
Resolves: #1823767
---
src/test/test-execute.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index af64427bc7..637ffe96bb 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -616,14 +616,24 @@ static void test_exec_privatenetwork(Manager *m) {
static void test_exec_oomscoreadjust(Manager *m) {
test(m, "exec-oomscoreadjust-positive.service", 0, CLD_EXITED);
+
+ if (detect_container() > 0) {
+ log_notice("Testing in container, skipping remaining tests in %s", __func__);
+ return;
+ }
test(m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED);
}
static void test_exec_ioschedulingclass(Manager *m) {
test(m, "exec-ioschedulingclass-none.service", 0, CLD_EXITED);
test(m, "exec-ioschedulingclass-idle.service", 0, CLD_EXITED);
- test(m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED);
test(m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED);
+
+ if (detect_container() > 0) {
+ log_notice("Testing in container, skipping remaining tests in %s", __func__);
+ return;
+ }
+ test(m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED);
}
static void test_exec_unsetenvironment(Manager *m) {

View File

@ -0,0 +1,70 @@
From b69552ccc0e33f713ae3a2baf1b0173cf221507d Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 11 Sep 2018 09:17:22 +0900
Subject: [PATCH] test: introduce test_is_running_from_builddir()
(cherry picked from commit 8cb10a4f4dabc508a04f76ea55f23ef517881b61)
Resolves: #1823767
---
src/shared/tests.c | 23 ++++++++++++++++++++---
src/shared/tests.h | 1 +
2 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/src/shared/tests.c b/src/shared/tests.c
index b10343650f..c77eb00924 100644
--- a/src/shared/tests.c
+++ b/src/shared/tests.c
@@ -19,6 +19,24 @@ char* setup_fake_runtime_dir(void) {
return p;
}
+bool test_is_running_from_builddir(char **exedir) {
+ _cleanup_free_ char *s = NULL;
+ bool r;
+
+ /* Check if we're running from the builddir. Optionally, this returns
+ * the path to the directory where the binary is located. */
+
+ assert_se(readlink_and_make_absolute("/proc/self/exe", &s) >= 0);
+ r = path_startswith(s, ABS_BUILD_DIR);
+
+ if (exedir) {
+ dirname(s);
+ *exedir = TAKE_PTR(s);
+ }
+
+ return r;
+}
+
const char* get_testdata_dir(const char *suffix) {
const char *env;
/* convenience: caller does not need to free result */
@@ -35,14 +53,13 @@ const char* get_testdata_dir(const char *suffix) {
strncpy(testdir, env, sizeof(testdir) - 1);
} else {
_cleanup_free_ char *exedir = NULL;
- assert_se(readlink_and_make_absolute("/proc/self/exe", &exedir) >= 0);
/* Check if we're running from the builddir. If so, use the compiled in path. */
- if (path_startswith(exedir, ABS_BUILD_DIR))
+ if (test_is_running_from_builddir(&exedir))
assert_se(snprintf(testdir, sizeof(testdir), "%s/test", ABS_SRC_DIR) > 0);
else
/* Try relative path, according to the install-test layout */
- assert_se(snprintf(testdir, sizeof(testdir), "%s/testdata", dirname(exedir)) > 0);
+ assert_se(snprintf(testdir, sizeof(testdir), "%s/testdata", exedir) > 0);
/* test this without the suffix, as it may contain a glob */
if (access(testdir, F_OK) < 0) {
diff --git a/src/shared/tests.h b/src/shared/tests.h
index cad21169f8..7f45c32d32 100644
--- a/src/shared/tests.h
+++ b/src/shared/tests.h
@@ -2,5 +2,6 @@
#pragma once
char* setup_fake_runtime_dir(void);
+bool test_is_running_from_builddir(char **exedir);
const char* get_testdata_dir(const char *suffix);
void test_setup_logging(int level);

View File

@ -0,0 +1,103 @@
From ac476ab0ce970e4a269fee34a15e24f6b20962b7 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 11 Sep 2018 09:18:33 +0900
Subject: [PATCH] test: make test-catalog relocatable
Fixes #10045.
(cherry picked from commit d9b6baa69968132d33e4ad8627c7fe0bd527c859)
Resolves: #1823767
---
catalog/meson.build | 1 -
src/journal/test-catalog.c | 27 +++++++++++++++++++--------
src/test/meson.build | 2 +-
3 files changed, 20 insertions(+), 10 deletions(-)
diff --git a/catalog/meson.build b/catalog/meson.build
index 1b13150894..3db8e390f2 100644
--- a/catalog/meson.build
+++ b/catalog/meson.build
@@ -17,7 +17,6 @@ in_files = '''
support_url = get_option('support-url')
support_sed = 's~%SUPPORT_URL%~@0@~'.format(support_url)
-build_catalog_dir = meson.current_build_dir()
foreach file : in_files
custom_target(
diff --git a/src/journal/test-catalog.c b/src/journal/test-catalog.c
index 8eae993780..0c4da29f31 100644
--- a/src/journal/test-catalog.c
+++ b/src/journal/test-catalog.c
@@ -14,14 +14,13 @@
#include "fileio.h"
#include "log.h"
#include "macro.h"
+#include "path-util.h"
#include "string-util.h"
+#include "strv.h"
+#include "tests.h"
#include "util.h"
-static const char *catalog_dirs[] = {
- CATALOG_DIR,
- NULL,
-};
-
+static char** catalog_dirs = NULL;
static const char *no_catalog_dirs[] = {
"/bin/hopefully/with/no/catalog",
NULL
@@ -167,8 +166,8 @@ static void test_catalog_update(const char *database) {
assert_se(r == 0);
/* Make sure that we at least have some files loaded or the
- catalog_list below will fail. */
- r = catalog_update(database, NULL, catalog_dirs);
+ * catalog_list below will fail. */
+ r = catalog_update(database, NULL, (const char * const *) catalog_dirs);
assert_se(r == 0);
}
@@ -202,14 +201,26 @@ static void test_catalog_file_lang(void) {
int main(int argc, char *argv[]) {
_cleanup_(unlink_tempfilep) char database[] = "/tmp/test-catalog.XXXXXX";
- _cleanup_free_ char *text = NULL;
+ _cleanup_free_ char *text = NULL, *catalog_dir = NULL;
int r;
setlocale(LC_ALL, "de_DE.UTF-8");
+ log_set_max_level(LOG_DEBUG);
log_parse_environment();
log_open();
+ /* If test-catalog is located at the build directory, then use catalogs in that.
+ * If it is not, e.g. installed by systemd-tests package, then use installed catalogs. */
+ if (test_is_running_from_builddir(NULL)) {
+ assert_se(catalog_dir = path_join(NULL, ABS_BUILD_DIR, "catalog"));
+ catalog_dirs = STRV_MAKE(catalog_dir);
+ } else
+ catalog_dirs = STRV_MAKE(CATALOG_DIR);
+
+ assert_se(access(catalog_dirs[0], F_OK) >= 0);
+ log_notice("Using catalog directory '%s'", catalog_dirs[0]);
+
test_catalog_file_lang();
test_catalog_import_invalid();
diff --git a/src/test/meson.build b/src/test/meson.build
index 4259421f98..ead000e30c 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -766,7 +766,7 @@ tests += [
[threads,
libxz,
liblz4],
- '', '', '-DCATALOG_DIR="@0@"'.format(build_catalog_dir)],
+ '', '', '-DCATALOG_DIR="@0@"'.format(catalogdir)],
[['src/journal/test-compress.c'],
[libjournal_core,

View File

@ -0,0 +1,137 @@
From 7ba4a6f5a02f6142d0e28fd475fd008532fb1083 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 5 Mar 2019 13:50:28 +0100
Subject: [PATCH] test: parallelize tasks in TEST-24-UNIT-TESTS
(cherry picked from commit 2f2a0454efd07644a4e0ccb3f00f1db2d7043391)
Related: #1823767
---
test/TEST-24-UNIT-TESTS/test.sh | 2 +
test/TEST-24-UNIT-TESTS/testsuite.sh | 97 +++++++++++++++++++++-------
2 files changed, 77 insertions(+), 22 deletions(-)
diff --git a/test/TEST-24-UNIT-TESTS/test.sh b/test/TEST-24-UNIT-TESTS/test.sh
index 014ee52277..fc8c89fe0a 100755
--- a/test/TEST-24-UNIT-TESTS/test.sh
+++ b/test/TEST-24-UNIT-TESTS/test.sh
@@ -78,6 +78,8 @@ test_setup() {
setup_basic_environment
install_keymaps yes
install_zoneinfo
+ # Install nproc to determine # of CPUs for correct parallelization
+ inst_binary nproc
# setup the testsuite service
cat >$initdir/etc/systemd/system/testsuite.service <<EOF
diff --git a/test/TEST-24-UNIT-TESTS/testsuite.sh b/test/TEST-24-UNIT-TESTS/testsuite.sh
index 7c0e495dbd..7c7a068556 100755
--- a/test/TEST-24-UNIT-TESTS/testsuite.sh
+++ b/test/TEST-24-UNIT-TESTS/testsuite.sh
@@ -4,31 +4,84 @@
#set -ex
#set -o pipefail
-for i in /usr/lib/systemd/tests/test-*; do
- if [[ ! -x $i ]]; then continue; fi
- NAME=${i##*/}
- echo "Running $NAME"
- $i > /$NAME.log 2>&1
- ret=$?
- if (( $ret && $ret != 77 )); then
- echo "$NAME failed with $ret"
- echo $NAME >> /failed-tests
- echo "--- $NAME begin ---" >> /failed
- cat /$NAME.log >> /failed
- echo "--- $NAME end ---" >> /failed
- elif (( $ret == 77 )); then
- echo "$NAME skipped"
- echo $NAME >> /skipped-tests
- echo "--- $NAME begin ---" >> /skipped
- cat /$NAME.log >> /skipped
- echo "--- $NAME end ---" >> /skipped
+NPROC=$(nproc)
+MAX_QUEUE_SIZE=${NPROC:-2}
+IFS=$'\n' TEST_LIST=($(ls /usr/lib/systemd/tests/test-*))
+
+# Check & report test results
+# Arguments:
+# $1: test path
+# $2: test exit code
+function report_result() {
+ if [[ $# -ne 2 ]]; then
+ echo >&2 "check_result: missing arguments"
+ exit 1
+ fi
+
+ local name="${1##*/}"
+ local ret=$2
+
+ if [[ $ret -ne 0 && $ret != 77 ]]; then
+ echo "$name failed with $ret"
+ echo "$name" >> /failed-tests
+ {
+ echo "--- $name begin ---"
+ cat "/$name.log"
+ echo "--- $name end ---"
+ } >> /failed
+ elif [[ $ret == 77 ]]; then
+ echo "$name skipped"
+ echo "$name" >> /skipped-tests
+ {
+ echo "--- $name begin ---"
+ cat "/$name.log"
+ echo "--- $name end ---"
+ } >> /skipped
else
- echo "$NAME OK"
- echo $NAME >> /testok
+ echo "$name OK"
+ echo "$name" >> /testok
+ fi
+
+ systemd-cat echo "--- $name ---"
+ systemd-cat cat "/$name.log"
+}
+
+# Associative array for running tasks, where running[test-path]=PID
+declare -A running=()
+for task in "${TEST_LIST[@]}"; do
+ # If there's MAX_QUEUE_SIZE running tasks, keep checking the running queue
+ # until one of the tasks finishes, so we can replace it.
+ while [[ ${#running[@]} -ge $MAX_QUEUE_SIZE ]]; do
+ for key in "${!running[@]}"; do
+ if ! kill -0 ${running[$key]} &>/dev/null; then
+ # Task has finished, report its result and drop it from the queue
+ wait ${running[$key]}
+ ec=$?
+ report_result "$key" $ec
+ unset running["$key"]
+ # Break from inner for loop and outer while loop to skip
+ # the sleep below when we find a free slot in the queue
+ break 2
+ fi
+ done
+
+ # Precisely* calculated constant to keep the spinlock from burning the CPU(s)
+ sleep 0.01
+ done
+
+ if [[ -x $task ]]; then
+ log_file="/${task##*/}.log"
+ $task &> "$log_file" &
+ running[$task]=$!
fi
+done
- systemd-cat echo "--- $NAME ---"
- systemd-cat cat /$NAME.log
+# Wait for remaining running tasks
+for key in "${!running[@]}"; do
+ wait ${running[$key]}
+ ec=$?
+ report_result "$key" $ec
+ unset running["$key"]
done
exit 0

View File

@ -0,0 +1,41 @@
From fe6e09aa0931112e7e3750801858c66129c7a3a8 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 5 Mar 2019 16:08:00 +0100
Subject: [PATCH] test: try to determine QEMU_SMP dynamically
If the QEMU_SMP value has not been explicitly set, try to determine it
from the number of online CPUs using the nproc utility. If this approach
fails, fall back to the default value QEMU_SMP=1.
This change should significantly help when running integration tests
under QEMU on multicore systems.
(cherry picked from commit 5bfb2a93a4a36bba0d24199553dcda6e560cbb75)
Related: #1823767
---
test/test-functions | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/test/test-functions b/test/test-functions
index 0938e6e826..3f1c327f3c 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -120,7 +120,16 @@ run_qemu() {
fi
fi
- [ "$QEMU_SMP" ] || QEMU_SMP=1
+ # If QEMU_SMP was not explicitly set, try to determine the value 'dynamically'
+ # i.e. use the number of online CPUs on the host machine. If the nproc utility
+ # is not installed or there's some other error when calling it, fall back
+ # to the original value (QEMU_SMP=1).
+ if ! [ "$QEMU_SMP" ]; then
+ if ! QEMU_SMP=$(nproc); then
+ dwarn "nproc utility is not installed, falling back to QEMU_SMP=1"
+ QEMU_SMP=1
+ fi
+ fi
find_qemu_bin || return 1

View File

@ -0,0 +1,31 @@
From 8df2d39a562416e1218e3ff191f3f3af1f9d4844 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 13 Aug 2019 00:14:54 +0200
Subject: [PATCH] test: store coredumps in journal
To make debugging much easier, especially for crashes in tests under
QEMU, let's store the entire coredump bundle in the systemd journal,
which is usually kept around by various CIs. Right now, we usually end
up with a journal, but without the coredump itself, which is pretty
useless.
(cherry picked from commit 215bffe1b8d7cb72fe9f72ed53682d52d5c2a9c5)
Related: #1823767
---
test/test-functions | 2 ++
1 file changed, 2 insertions(+)
diff --git a/test/test-functions b/test/test-functions
index 3f1c327f3c..7c4230b078 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -420,6 +420,8 @@ install_systemd() {
# enable debug logging in PID1
echo LogLevel=debug >> $initdir/etc/systemd/system.conf
+ # store coredumps in journal
+ echo Storage=journal >> $initdir/etc/systemd/coredump.conf
}
get_ldpath() {

View File

@ -0,0 +1,62 @@
From 82156850f6642a363aa2ff06677ad089a460104e Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 26 Nov 2019 09:46:00 +0100
Subject: [PATCH] pid1: add new kernel cmdline arg systemd.cpu_affinity=
Let's allow configuration of the CPU affinity via the kernel cmdline,
overriding CPUAffinity= in /etc/systemd/system.conf
Prompted by:
https://lists.freedesktop.org/archives/systemd-devel/2019-November/043754.html
(cherry picked from commit 68d58f38693e586b5ce5785274f8e42a79625196)
Resolves: #1812894
---
man/kernel-command-line.xml | 11 +++++++++++
src/core/main.c | 9 +++++++++
2 files changed, 20 insertions(+)
diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml
index 0545f9d84b..4d8cb4e50e 100644
--- a/man/kernel-command-line.xml
+++ b/man/kernel-command-line.xml
@@ -366,6 +366,17 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>systemd.cpu_affinity=</varname></term>
+
+ <listitem>
+ <para>Overrides the CPU affinity mask for the service manager and the default for all child
+ processes it forks. This takes precedence over <varname>CPUAffinity=</varname>, see
+ <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for details.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>modules_load=</varname></term>
<term><varname>rd.modules_load=</varname></term>
diff --git a/src/core/main.c b/src/core/main.c
index 45d09b1e11..9f238a8430 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -472,6 +472,15 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
if (arg_default_timeout_start_usec <= 0)
arg_default_timeout_start_usec = USEC_INFINITY;
+ } else if (proc_cmdline_key_streq(key, "systemd.cpu_affinity")) {
+
+ if (proc_cmdline_value_missing(key, value))
+ return 0;
+
+ r = parse_cpu_set(value, &arg_cpu_affinity);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse CPU affinity mask '%s', ignoring: %m", value);
+
} else if (proc_cmdline_key_streq(key, "systemd.watchdog_device")) {
if (proc_cmdline_value_missing(key, value))

View File

@ -0,0 +1,57 @@
From f60e89ea4c38c11a9d0c1e642c0a78faa32aca56 Mon Sep 17 00:00:00 2001
From: Joerg Steffens <joerg.steffens@bareos.com>
Date: Tue, 21 Nov 2017 12:21:49 +0100
Subject: [PATCH] udev-rules: make tape-changers also apprear in
/dev/tape/by-path/
It is important to be able to access tape changer ("Medium Changers") by
persistant name.
While tape devices can be accessed via /dev/tape/by-id/ and
/dev/tape/by-path/, tape-changers could only be accessed by
/dev/tape/by-id/.
However, in some cases, especially when accessing Amazon Webservice
Storage Gateway VTLs (or accessing iSCSI VTLs in general?) this does not
work, as all tape devices and the tape changer have the same ENV{ID_SERIAL}.
The results is, that only the last device is available in
/dev/tape/by-id/, as the former devices have been overwritten.
As this behavior is hard to change without breaking consistentcy,
this additional device in /dev/tape/by-path/ can be used to access the medium changes.
The tape devices can also be accessed by this path.
The content of the directory will now look like:
# SCSI tape device, rewind (unchanged)
/dev/tape/by-path/$env{ID_PATH} -> ../../st*
# SCSI tape device, no-rewind (unchanged)
/dev/tape/by-path/$env{ID_PATH}-nst -> ../../nst*
# SCSI tape changer device (newly added)
/dev/tape/by-path/$env{ID_PATH}-changer -> ../../sg*
Tape devices and tape changer have different ID_PATHs.
SCSI tape changer get the suffix "-changer"
to make them better distinguishable from tape devices.
(cherry picked from commit 7f8ddf96a25162f06bd94a684cf700c128d18142)
Resolves: #1820112
---
rules/60-persistent-storage-tape.rules | 3 +++
1 file changed, 3 insertions(+)
diff --git a/rules/60-persistent-storage-tape.rules b/rules/60-persistent-storage-tape.rules
index b604864ee8..0575f308df 100644
--- a/rules/60-persistent-storage-tape.rules
+++ b/rules/60-persistent-storage-tape.rules
@@ -9,6 +9,9 @@ ENV{UDEV_DISABLE_PERSISTENT_STORAGE_RULES_FLAG}=="1", GOTO="persistent_storage_t
SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="8", IMPORT{program}="scsi_id --sg-version=3 --export --whitelisted -d $devnode", \
SYMLINK+="tape/by-id/scsi-$env{ID_SERIAL}"
+SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="8", IMPORT{builtin}="path_id", \
+ SYMLINK+="tape/by-path/$env{ID_PATH}-changer"
+
SUBSYSTEM!="scsi_tape", GOTO="persistent_storage_tape_end"
KERNEL=="st*[0-9]|nst*[0-9]", ATTRS{ieee1394_id}=="?*", ENV{ID_SERIAL}="$attr{ieee1394_id}", ENV{ID_BUS}="ieee1394"

View File

@ -0,0 +1,75 @@
From b8af9fd65b697e9bb77a32d1a6a70367814aaed5 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 1 Apr 2019 17:30:45 +0200
Subject: [PATCH] man: be clearer that .timer time expressions need to be reset
to override them
let's be clearer about the overriding concept for OnCalendar= settings.
Prompted by this thread:
https://lists.freedesktop.org/archives/systemd-devel/2019-March/042351.html
(cherry picked from commit 58031d99c6320855b86f4890baa9165597e3d841)
Resolves: #1816908
---
man/systemd.timer.xml | 31 ++++++++++++++++++-------------
1 file changed, 18 insertions(+), 13 deletions(-)
diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml
index 44b257c745..ebc1df89f1 100644
--- a/man/systemd.timer.xml
+++ b/man/systemd.timer.xml
@@ -125,12 +125,12 @@
to when the unit the timer is activating was last
deactivated.</para>
- <para>Multiple directives may be combined of the same and of
- different types. For example, by combining
- <varname>OnBootSec=</varname> and
- <varname>OnUnitActiveSec=</varname>, it is possible to define
- a timer that elapses in regular intervals and activates a
- specific service each time.</para>
+ <para>Multiple directives may be combined of the same and of different types, in which case the timer
+ unit will trigger whenever any of the specified timer expressions elapse. For example, by combining
+ <varname>OnBootSec=</varname> and <varname>OnUnitActiveSec=</varname>, it is possible to define a
+ timer that elapses in regular intervals and activates a specific service each time. Moreover, both
+ monotonic time expressions and <varname>OnCalendar=</varname> calendar expressions may be combined in
+ the same timer unit.</para>
<para>The arguments to the directives are time spans
configured in seconds. Example: "OnBootSec=50" means 50s after
@@ -145,13 +145,12 @@
and the configured unit is started. This is not the case for
timers defined in the other directives.</para>
- <para>These are monotonic timers, independent of wall-clock
- time and timezones. If the computer is temporarily suspended,
- the monotonic clock stops too.</para>
+ <para>These are monotonic timers, independent of wall-clock time and timezones. If the computer is
+ temporarily suspended, the monotonic clock pauses, too.</para>
- <para>If the empty string is assigned to any of these options,
- the list of timers is reset, and all prior assignments will
- have no effect.</para>
+ <para>If the empty string is assigned to any of these options, the list of timers is reset (both
+ monotonic timers and <varname>OnCalendar=</varname> timers, see below), and all prior assignments
+ will have no effect.</para>
<para>Note that timers do not necessarily expire at the
precise time configured with these settings, as they are
@@ -175,7 +174,13 @@
the <varname>AccuracySec=</varname> setting
below.</para>
- <para>May be specified more than once.</para></listitem>
+ <para>May be specified more than once, in which case the timer unit will trigger whenever any of the
+ specified expressions elapse. Moreover calendar timers and monotonic timers (see above) may be
+ combined within the same timer unit.</para>
+
+ <para>If the empty string is assigned to any of these options, the list of timers is reset (both
+ <varname>OnCalendar=</varname> timers and monotonic timers, see above), and all prior assignments
+ will have no effect.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -0,0 +1,312 @@
From 2808e53f785e9ca7fdab286678e784b661b4c185 Mon Sep 17 00:00:00 2001
From: Zsolt Dollenstein <zsol.zsol@gmail.com>
Date: Tue, 3 Jul 2018 12:22:29 -0700
Subject: [PATCH] Add support for opening files for appending
Addresses part of #8983
(cherry picked from commit 566b7d23eb747e9c5a74e5647693077b52395fc5)
Resolves: #1809175
---
man/systemd.exec.xml | 16 ++++++----
src/core/dbus-execute.c | 30 ++++++++++++++-----
src/core/execute.c | 20 ++++++++++---
src/core/execute.h | 1 +
src/core/load-fragment.c | 11 +++++++
src/core/main.c | 4 +--
src/test/test-execute.c | 10 +++++++
test/meson.build | 2 ++
.../exec-standardoutput-append.service | 13 ++++++++
.../exec-standardoutput-file.service | 13 ++++++++
10 files changed, 101 insertions(+), 19 deletions(-)
create mode 100644 test/test-execute/exec-standardoutput-append.service
create mode 100644 test/test-execute/exec-standardoutput-file.service
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index bdaed68162..e2a5ede968 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -1792,8 +1792,8 @@ SystemCallErrorNumber=EPERM</programlisting>
of <option>inherit</option>, <option>null</option>, <option>tty</option>, <option>journal</option>,
<option>syslog</option>, <option>kmsg</option>, <option>journal+console</option>,
<option>syslog+console</option>, <option>kmsg+console</option>,
- <option>file:<replaceable>path</replaceable></option>, <option>socket</option> or
- <option>fd:<replaceable>name</replaceable></option>.</para>
+ <option>file:<replaceable>path</replaceable></option>, <option>append:<replaceable>path</replaceable></option>,
+ <option>socket</option> or<option>fd:<replaceable>name</replaceable></option>.</para>
<para><option>inherit</option> duplicates the file descriptor of standard input for standard output.</para>
@@ -1824,11 +1824,17 @@ SystemCallErrorNumber=EPERM</programlisting>
<para>The <option>file:<replaceable>path</replaceable></option> option may be used to connect a specific file
system object to standard output. The semantics are similar to the same option of
- <varname>StandardInput=</varname>, see above. If standard input and output are directed to the same file path,
- it is opened only once, for reading as well as writing and duplicated. This is particular useful when the
- specified path refers to an <constant>AF_UNIX</constant> socket in the file system, as in that case only a
+ <varname>StandardInput=</varname>, see above. If <replaceable>path</replaceable> refers to a regular file
+ on the filesystem, it is opened (created if it doesn't exist yet) for writing at the beginning of the file,
+ but without truncating it.
+ If standard input and output are directed to the same file path, it is opened only once, for reading as well
+ as writing and duplicated. This is particularly useful when the specified path refers to an
+ <constant>AF_UNIX</constant> socket in the file system, as in that case only a
single stream connection is created for both input and output.</para>
+ <para><option>append:<replaceable>path</replaceable></option> is similar to <option>file:<replaceable>path
+ </replaceable></option> above, but it opens the file in append mode.</para>
+
<para><option>socket</option> connects standard output to a socket acquired via socket activation. The
semantics are similar to the same option of <varname>StandardInput=</varname>, see above.</para>
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index e7c0b893d1..f9527e56b2 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -1772,7 +1772,10 @@ int bus_exec_context_set_transient_property(
return 1;
- } else if (STR_IN_SET(name, "StandardInputFile", "StandardOutputFile", "StandardErrorFile")) {
+ } else if (STR_IN_SET(name,
+ "StandardInputFile",
+ "StandardOutputFile", "StandardOutputFileToCreate", "StandardOutputFileToAppend",
+ "StandardErrorFile", "StandardErrorFileToCreate", "StandardErrorFileToAppend")) {
const char *s;
r = sd_bus_message_read(message, "s", &s);
@@ -1796,23 +1799,34 @@ int bus_exec_context_set_transient_property(
c->std_input = EXEC_INPUT_FILE;
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardInput=file:%s", s);
- } else if (streq(name, "StandardOutputFile")) {
+ } else if (STR_IN_SET(name, "StandardOutputFile", "StandardOutputFileToAppend")) {
r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], empty_to_null(s));
if (r < 0)
return r;
- c->std_output = EXEC_OUTPUT_FILE;
- unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=file:%s", s);
-
+ if (streq(name, "StandardOutputFile")) {
+ c->std_output = EXEC_OUTPUT_FILE;
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=file:%s", s);
+ } else {
+ assert(streq(name, "StandardOutputFileToAppend"));
+ c->std_output = EXEC_OUTPUT_FILE_APPEND;
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=append:%s", s);
+ }
} else {
- assert(streq(name, "StandardErrorFile"));
+ assert(STR_IN_SET(name, "StandardErrorFile", "StandardErrorFileToAppend"));
r = free_and_strdup(&c->stdio_file[STDERR_FILENO], empty_to_null(s));
if (r < 0)
return r;
- c->std_error = EXEC_OUTPUT_FILE;
- unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=file:%s", s);
+ if (streq(name, "StandardErrorFile")) {
+ c->std_error = EXEC_OUTPUT_FILE;
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=file:%s", s);
+ } else {
+ assert(streq(name, "StandardErrorFileToAppend"));
+ c->std_error = EXEC_OUTPUT_FILE_APPEND;
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=append:%s", s);
+ }
}
}
diff --git a/src/core/execute.c b/src/core/execute.c
index f012023224..3c54ac1110 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -89,6 +89,7 @@
#include "strv.h"
#include "syslog-util.h"
#include "terminal-util.h"
+#include "umask-util.h"
#include "unit.h"
#include "user-util.h"
#include "util.h"
@@ -675,9 +676,10 @@ static int setup_output(
(void) fd_nonblock(named_iofds[fileno], false);
return dup2(named_iofds[fileno], fileno) < 0 ? -errno : fileno;
- case EXEC_OUTPUT_FILE: {
+ case EXEC_OUTPUT_FILE:
+ case EXEC_OUTPUT_FILE_APPEND: {
bool rw;
- int fd;
+ int fd, flags;
assert(context->stdio_file[fileno]);
@@ -687,11 +689,16 @@ static int setup_output(
if (rw)
return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno;
- fd = acquire_path(context->stdio_file[fileno], O_WRONLY, 0666 & ~context->umask);
+ flags = O_WRONLY;
+ if (o == EXEC_OUTPUT_FILE_APPEND)
+ flags |= O_APPEND;
+
+ fd = acquire_path(context->stdio_file[fileno], flags, 0666 & ~context->umask);
+
if (fd < 0)
return fd;
- return move_fd(fd, fileno, false);
+ return move_fd(fd, fileno, 0);
}
default:
@@ -4168,8 +4175,12 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
fprintf(f, "%sStandardInputFile: %s\n", prefix, c->stdio_file[STDIN_FILENO]);
if (c->std_output == EXEC_OUTPUT_FILE)
fprintf(f, "%sStandardOutputFile: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
+ if (c->std_output == EXEC_OUTPUT_FILE_APPEND)
+ fprintf(f, "%sStandardOutputFileToAppend: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
if (c->std_error == EXEC_OUTPUT_FILE)
fprintf(f, "%sStandardErrorFile: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
+ if (c->std_error == EXEC_OUTPUT_FILE_APPEND)
+ fprintf(f, "%sStandardErrorFileToAppend: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
if (c->tty_path)
fprintf(f,
@@ -5111,6 +5122,7 @@ static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
[EXEC_OUTPUT_SOCKET] = "socket",
[EXEC_OUTPUT_NAMED_FD] = "fd",
[EXEC_OUTPUT_FILE] = "file",
+ [EXEC_OUTPUT_FILE_APPEND] = "append",
};
DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
diff --git a/src/core/execute.h b/src/core/execute.h
index 2266355962..86c1cee84c 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -57,6 +57,7 @@ typedef enum ExecOutput {
EXEC_OUTPUT_SOCKET,
EXEC_OUTPUT_NAMED_FD,
EXEC_OUTPUT_FILE,
+ EXEC_OUTPUT_FILE_APPEND,
_EXEC_OUTPUT_MAX,
_EXEC_OUTPUT_INVALID = -1
} ExecOutput;
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 2082166afb..9b2724307d 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -1016,6 +1016,17 @@ int config_parse_exec_output(
eo = EXEC_OUTPUT_FILE;
+ } else if ((n = startswith(rvalue, "append:"))) {
+
+ r = unit_full_printf(u, n, &resolved);
+ if (r < 0)
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", n);
+
+ r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue);
+ if (r < 0)
+ return -ENOEXEC;
+
+ eo = EXEC_OUTPUT_FILE_APPEND;
} else {
eo = exec_output_from_string(rvalue);
if (eo < 0) {
diff --git a/src/core/main.c b/src/core/main.c
index 9f238a8430..25536054b3 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -620,8 +620,8 @@ static int config_parse_output_restricted(
return 0;
}
- if (IN_SET(t, EXEC_OUTPUT_SOCKET, EXEC_OUTPUT_NAMED_FD, EXEC_OUTPUT_FILE)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Standard output types socket, fd:, file: are not supported as defaults, ignoring: %s", rvalue);
+ if (IN_SET(t, EXEC_OUTPUT_SOCKET, EXEC_OUTPUT_NAMED_FD, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Standard output types socket, fd:, file:, append: are not supported as defaults, ignoring: %s", rvalue);
return 0;
}
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 637ffe96bb..0f8dc883b1 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -651,6 +651,14 @@ static void test_exec_standardinput(Manager *m) {
test(m, "exec-standardinput-file.service", 0, CLD_EXITED);
}
+static void test_exec_standardoutput(Manager *m) {
+ test(m, "exec-standardoutput-file.service", 0, CLD_EXITED);
+}
+
+static void test_exec_standardoutput_append(Manager *m) {
+ test(m, "exec-standardoutput-append.service", 0, CLD_EXITED);
+}
+
static int run_tests(UnitFileScope scope, const test_function_t *tests) {
const test_function_t *test = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
@@ -698,6 +706,8 @@ int main(int argc, char *argv[]) {
test_exec_restrictnamespaces,
test_exec_runtimedirectory,
test_exec_standardinput,
+ test_exec_standardoutput,
+ test_exec_standardoutput_append,
test_exec_supplementarygroups,
test_exec_systemcallerrornumber,
test_exec_systemcallfilter,
diff --git a/test/meson.build b/test/meson.build
index fb9f2cdb9b..4d1c51048c 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -115,6 +115,8 @@ test_data_files = '''
test-execute/exec-specifier@.service
test-execute/exec-standardinput-data.service
test-execute/exec-standardinput-file.service
+ test-execute/exec-standardoutput-file.service
+ test-execute/exec-standardoutput-append.service
test-execute/exec-supplementarygroups-multiple-groups-default-group-user.service
test-execute/exec-supplementarygroups-multiple-groups-withgid.service
test-execute/exec-supplementarygroups-multiple-groups-withuid.service
diff --git a/test/test-execute/exec-standardoutput-append.service b/test/test-execute/exec-standardoutput-append.service
new file mode 100644
index 0000000000..8983bb056b
--- /dev/null
+++ b/test/test-execute/exec-standardoutput-append.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Test for StandardOutput=append:
+
+[Service]
+ExecStartPre=sh -c 'printf "hello\n" > /tmp/test-exec-standardoutput-output'
+ExecStartPre=sh -c 'printf "hello\nhello\n" > /tmp/test-exec-standardoutput-expected'
+StandardInput=data
+StandardInputText=hello
+StandardOutput=append:/tmp/test-exec-standardoutput-output
+StandardError=null
+ExecStart=cat
+ExecStart=cmp /tmp/test-exec-standardoutput-output /tmp/test-exec-standardoutput-expected
+Type=oneshot
diff --git a/test/test-execute/exec-standardoutput-file.service b/test/test-execute/exec-standardoutput-file.service
new file mode 100644
index 0000000000..71e2604b94
--- /dev/null
+++ b/test/test-execute/exec-standardoutput-file.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Test for StandardOutput=file:
+
+[Service]
+ExecStartPre=sh -c 'printf "nooo\nhello\n" > /tmp/test-exec-standardoutput-output'
+ExecStartPre=sh -c 'printf "hello\nello\n" > /tmp/test-exec-standardoutput-expected'
+StandardInput=data
+StandardInputText=hello
+StandardOutput=file:/tmp/test-exec-standardoutput-output
+StandardError=null
+ExecStart=cat
+ExecStart=cmp /tmp/test-exec-standardoutput-expected /tmp/test-exec-standardoutput-output
+Type=oneshot

View File

@ -0,0 +1,36 @@
From 8ee1465520ad49892a0a378626ef93abc03f4d4e Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 5 Mar 2019 18:57:53 +0100
Subject: [PATCH] nspawn: move payload to sub-cgroup first, then sync cgroup
trees
if we sync the legacy and unified trees before moving to the right
subcgroup then ultimately the cgroup paths in the hierarchies will be
out-of-sync... Hence, let's move the payload first, and sync then.
Addresses: https://github.com/systemd/systemd/pull/9762#issuecomment-441187979
(cherry picked from commit 27da7ef0d09e00eae821f3ef26e1a666fe7aa087)
Resolves: #1837094
---
src/nspawn/nspawn.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 08255b5724..8cb7591f0e 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -3960,11 +3960,11 @@ static int run(int master,
} else if (arg_slice || arg_property)
log_notice("Machine and scope registration turned off, --slice= and --property= settings will have no effect.");
- r = sync_cgroup(*pid, arg_unified_cgroup_hierarchy, arg_uid_shift);
+ r = create_subcgroup(*pid, arg_keep_unit, arg_unified_cgroup_hierarchy);
if (r < 0)
return r;
- r = create_subcgroup(*pid, arg_keep_unit, arg_unified_cgroup_hierarchy);
+ r = sync_cgroup(*pid, arg_unified_cgroup_hierarchy, arg_uid_shift);
if (r < 0)
return r;

View File

@ -0,0 +1,31 @@
From f4a34d97bd7e1564a51f590df591cb31a1a3f333 Mon Sep 17 00:00:00 2001
From: Evgeny Vereshchagin <evvers@ya.ru>
Date: Mon, 17 Sep 2018 07:12:38 +0000
Subject: [PATCH] nspawn: chown() the legacy hierarchy when it's used in a
container
This is a follow-up to 720f0a2f3c928cc9379501a52146be9fbb4d9be2.
Closes https://github.com/systemd/systemd/issues/10026
Closes https://github.com/systemd/systemd/issues/9563
(cherry picked from commit 89f180201cd8c0f3ce5cb6e8dd7e2b3cbcf71527)
Resolves: 1837094
---
src/nspawn/nspawn-cgroup.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/nspawn/nspawn-cgroup.c b/src/nspawn/nspawn-cgroup.c
index d8a39a6959..a231622e29 100644
--- a/src/nspawn/nspawn-cgroup.c
+++ b/src/nspawn/nspawn-cgroup.c
@@ -55,7 +55,7 @@ int chown_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift) {
if (r < 0)
return log_error_errno(r, "Failed to chown() cgroup %s: %m", fs);
- if (unified_requested == CGROUP_UNIFIED_SYSTEMD) {
+ if (unified_requested == CGROUP_UNIFIED_SYSTEMD || (unified_requested == CGROUP_UNIFIED_NONE && cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) > 0)) {
_cleanup_free_ char *lfs = NULL;
/* Always propagate access rights from unified to legacy controller */

View File

@ -0,0 +1,354 @@
From 883dfbff6e3e9763d21f9d029a824c63e016cfd9 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 13 Nov 2018 19:57:43 +0100
Subject: [PATCH] core: move unit_status_emit_starting_stopping_reloading() and
related calls to job.c
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This call is only used by job.c and very specific to job handling.
Moreover the very similar logic of job_emit_status_message() is already
in job.c.
Hence, let's clean this up, and move both sets of functions to job.c,
and rename them a bit so that they express precisely what they do:
1. unit_status_emit_starting_stopping_reloading() →
job_emit_begin_status_message()
2. job_emit_status_message() → job_emit_done_status_message()
The first call is after all what we call when we begin with the
execution of a job, and the second call what we call when we are done
wiht it.
Just some moving and renaming, not other changes, and hence no change in
behaviour.
(cherry picked from commit 33a3fdd9781329379f74e11a7a2707816aad8c61)
Related: #1737283
---
src/core/job.c | 119 +++++++++++++++++++++++++++++++++++++++++-------
src/core/unit.c | 86 ----------------------------------
src/core/unit.h | 1 -
3 files changed, 103 insertions(+), 103 deletions(-)
diff --git a/src/core/job.c b/src/core/job.c
index 769ed6d603..561ea14682 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -507,6 +507,93 @@ static void job_change_type(Job *j, JobType newtype) {
j->type = newtype;
}
+_pure_ static const char* job_get_begin_status_message_format(Unit *u, JobType t) {
+ const char *format;
+ const UnitStatusMessageFormats *format_table;
+
+ assert(u);
+ assert(IN_SET(t, JOB_START, JOB_STOP, JOB_RELOAD));
+
+ if (t != JOB_RELOAD) {
+ format_table = &UNIT_VTABLE(u)->status_message_formats;
+ if (format_table) {
+ format = format_table->starting_stopping[t == JOB_STOP];
+ if (format)
+ return format;
+ }
+ }
+
+ /* Return generic strings */
+ if (t == JOB_START)
+ return "Starting %s.";
+ else if (t == JOB_STOP)
+ return "Stopping %s.";
+ else
+ return "Reloading %s.";
+}
+
+static void job_print_begin_status_message(Unit *u, JobType t) {
+ const char *format;
+
+ assert(u);
+
+ /* Reload status messages have traditionally not been printed to console. */
+ if (!IN_SET(t, JOB_START, JOB_STOP))
+ return;
+
+ format = job_get_begin_status_message_format(u, t);
+
+ DISABLE_WARNING_FORMAT_NONLITERAL;
+ unit_status_printf(u, "", format);
+ REENABLE_WARNING;
+}
+
+static void job_log_begin_status_message(Unit *u, JobType t) {
+ const char *format, *mid;
+ char buf[LINE_MAX];
+
+ assert(u);
+
+ if (!IN_SET(t, JOB_START, JOB_STOP, JOB_RELOAD))
+ return;
+
+ if (log_on_console())
+ return;
+
+ /* We log status messages for all units and all operations. */
+
+ format = job_get_begin_status_message_format(u, t);
+
+ DISABLE_WARNING_FORMAT_NONLITERAL;
+ (void) snprintf(buf, sizeof buf, format, unit_description(u));
+ REENABLE_WARNING;
+
+ mid = t == JOB_START ? "MESSAGE_ID=" SD_MESSAGE_UNIT_STARTING_STR :
+ t == JOB_STOP ? "MESSAGE_ID=" SD_MESSAGE_UNIT_STOPPING_STR :
+ "MESSAGE_ID=" SD_MESSAGE_UNIT_RELOADING_STR;
+
+ /* Note that we deliberately use LOG_MESSAGE() instead of
+ * LOG_UNIT_MESSAGE() here, since this is supposed to mimic
+ * closely what is written to screen using the status output,
+ * which is supposed the highest level, friendliest output
+ * possible, which means we should avoid the low-level unit
+ * name. */
+ log_struct(LOG_INFO,
+ LOG_MESSAGE("%s", buf),
+ LOG_UNIT_ID(u),
+ LOG_UNIT_INVOCATION_ID(u),
+ mid);
+}
+
+static void job_emit_begin_status_message(Unit *u, JobType t) {
+ assert(u);
+ assert(t >= 0);
+ assert(t < _JOB_TYPE_MAX);
+
+ job_log_begin_status_message(u, t);
+ job_print_begin_status_message(u, t);
+}
+
static int job_perform_on_unit(Job **j) {
uint32_t id;
Manager *m;
@@ -552,7 +639,7 @@ static int job_perform_on_unit(Job **j) {
* actually did something. */
*j = manager_get_job(m, id);
if (*j && r > 0)
- unit_status_emit_starting_stopping_reloading(u, t);
+ job_emit_begin_status_message(u, t);
return r;
}
@@ -638,7 +725,7 @@ int job_run_and_invalidate(Job *j) {
return r;
}
-_pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) {
+_pure_ static const char *job_get_done_status_message_format(Unit *u, JobType t, JobResult result) {
static const char *const generic_finished_start_job[_JOB_RESULT_MAX] = {
[JOB_DONE] = "Started %s.",
@@ -699,7 +786,7 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR
static const struct {
const char *color, *word;
-} job_print_status_messages [_JOB_RESULT_MAX] = {
+} job_print_done_status_messages[_JOB_RESULT_MAX] = {
[JOB_DONE] = { ANSI_OK_COLOR, " OK " },
[JOB_TIMEOUT] = { ANSI_HIGHLIGHT_RED, " TIME " },
[JOB_FAILED] = { ANSI_HIGHLIGHT_RED, "FAILED" },
@@ -711,7 +798,7 @@ static const struct {
[JOB_ONCE] = { ANSI_HIGHLIGHT_RED, " ONCE " },
};
-static void job_print_status_message(Unit *u, JobType t, JobResult result) {
+static void job_print_done_status_message(Unit *u, JobType t, JobResult result) {
const char *format;
const char *status;
@@ -723,19 +810,19 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
if (t == JOB_RELOAD)
return;
- if (!job_print_status_messages[result].word)
+ if (!job_print_done_status_messages[result].word)
return;
- format = job_get_status_message_format(u, t, result);
+ format = job_get_done_status_message_format(u, t, result);
if (!format)
return;
if (log_get_show_color())
- status = strjoina(job_print_status_messages[result].color,
- job_print_status_messages[result].word,
+ status = strjoina(job_print_done_status_messages[result].color,
+ job_print_done_status_messages[result].word,
ANSI_NORMAL);
else
- status = job_print_status_messages[result].word;
+ status = job_print_done_status_messages[result].word;
if (result != JOB_DONE)
manager_flip_auto_status(u->manager, true);
@@ -752,7 +839,7 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
}
}
-static void job_log_status_message(Unit *u, JobType t, JobResult result) {
+static void job_log_done_status_message(Unit *u, uint32_t job_id, JobType t, JobResult result) {
const char *format, *mid;
char buf[LINE_MAX];
static const int job_result_log_level[_JOB_RESULT_MAX] = {
@@ -775,10 +862,10 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
/* Skip printing if output goes to the console, and job_print_status_message()
will actually print something to the console. */
- if (log_on_console() && job_print_status_messages[result].word)
+ if (log_on_console() && job_print_done_status_messages[result].word)
return;
- format = job_get_status_message_format(u, t, result);
+ format = job_get_done_status_message_format(u, t, result);
if (!format)
return;
@@ -827,15 +914,15 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
mid);
}
-static void job_emit_status_message(Unit *u, JobType t, JobResult result) {
+static void job_emit_done_status_message(Unit *u, uint32_t job_id, JobType t, JobResult result) {
assert(u);
/* No message if the job did not actually do anything due to failed condition. */
if (t == JOB_START && result == JOB_DONE && !u->condition_result)
return;
- job_log_status_message(u, t, result);
- job_print_status_message(u, t, result);
+ job_log_done_status_message(u, job_id, t, result);
+ job_print_done_status_message(u, t, result);
}
static void job_fail_dependencies(Unit *u, UnitDependency d) {
@@ -890,7 +977,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr
/* If this job did nothing to respective unit we don't log the status message */
if (!already)
- job_emit_status_message(u, t, result);
+ job_emit_done_status_message(u, j->id, t, result);
/* Patch restart jobs so that they become normal start jobs */
if (result == JOB_DONE && t == JOB_RESTART) {
diff --git a/src/core/unit.c b/src/core/unit.c
index 40f138d25c..f5e251123d 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -1624,92 +1624,6 @@ void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg
REENABLE_WARNING;
}
-_pure_ static const char* unit_get_status_message_format(Unit *u, JobType t) {
- const char *format;
- const UnitStatusMessageFormats *format_table;
-
- assert(u);
- assert(IN_SET(t, JOB_START, JOB_STOP, JOB_RELOAD));
-
- if (t != JOB_RELOAD) {
- format_table = &UNIT_VTABLE(u)->status_message_formats;
- if (format_table) {
- format = format_table->starting_stopping[t == JOB_STOP];
- if (format)
- return format;
- }
- }
-
- /* Return generic strings */
- if (t == JOB_START)
- return "Starting %s.";
- else if (t == JOB_STOP)
- return "Stopping %s.";
- else
- return "Reloading %s.";
-}
-
-static void unit_status_print_starting_stopping(Unit *u, JobType t) {
- const char *format;
-
- assert(u);
-
- /* Reload status messages have traditionally not been printed to console. */
- if (!IN_SET(t, JOB_START, JOB_STOP))
- return;
-
- format = unit_get_status_message_format(u, t);
-
- DISABLE_WARNING_FORMAT_NONLITERAL;
- unit_status_printf(u, "", format);
- REENABLE_WARNING;
-}
-
-static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
- const char *format, *mid;
- char buf[LINE_MAX];
-
- assert(u);
-
- if (!IN_SET(t, JOB_START, JOB_STOP, JOB_RELOAD))
- return;
-
- if (log_on_console())
- return;
-
- /* We log status messages for all units and all operations. */
-
- format = unit_get_status_message_format(u, t);
-
- DISABLE_WARNING_FORMAT_NONLITERAL;
- (void) snprintf(buf, sizeof buf, format, unit_description(u));
- REENABLE_WARNING;
-
- mid = t == JOB_START ? "MESSAGE_ID=" SD_MESSAGE_UNIT_STARTING_STR :
- t == JOB_STOP ? "MESSAGE_ID=" SD_MESSAGE_UNIT_STOPPING_STR :
- "MESSAGE_ID=" SD_MESSAGE_UNIT_RELOADING_STR;
-
- /* Note that we deliberately use LOG_MESSAGE() instead of
- * LOG_UNIT_MESSAGE() here, since this is supposed to mimic
- * closely what is written to screen using the status output,
- * which is supposed the highest level, friendliest output
- * possible, which means we should avoid the low-level unit
- * name. */
- log_struct(LOG_INFO,
- LOG_MESSAGE("%s", buf),
- LOG_UNIT_ID(u),
- LOG_UNIT_INVOCATION_ID(u),
- mid);
-}
-
-void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t) {
- assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
-
- unit_status_log_starting_stopping_reloading(u, t);
- unit_status_print_starting_stopping(u, t);
-}
int unit_start_limit_test(Unit *u) {
assert(u);
diff --git a/src/core/unit.h b/src/core/unit.h
index 595ee88d43..4d9539790a 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -699,7 +699,6 @@ int unit_coldplug(Unit *u);
void unit_catchup(Unit *u);
void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) _printf_(3, 0);
-void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t);
bool unit_need_daemon_reload(Unit *u);

View File

@ -0,0 +1,63 @@
From 9c543783dbe560f4dafa4c2f276e03a4bce0389e Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 14 Nov 2018 11:08:16 +0100
Subject: [PATCH] job: when a job was skipped due to a failed condition, log
about it
Previously we'd neither show console status output nor log output. Let's
fix that, and still log something.
(cherry picked from commit 9a80f2f4533883d272e6a436512aa7e88cedc549)
Related: #1737283
---
src/core/job.c | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/src/core/job.c b/src/core/job.c
index 561ea14682..b9eee91cf3 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -810,6 +810,10 @@ static void job_print_done_status_message(Unit *u, JobType t, JobResult result)
if (t == JOB_RELOAD)
return;
+ /* No message if the job did not actually do anything due to failed condition. */
+ if (t == JOB_START && result == JOB_DONE && !u->condition_result)
+ return;
+
if (!job_print_done_status_messages[result].word)
return;
@@ -865,6 +869,20 @@ static void job_log_done_status_message(Unit *u, uint32_t job_id, JobType t, Job
if (log_on_console() && job_print_done_status_messages[result].word)
return;
+ /* Show condition check message if the job did not actually do anything due to failed condition. */
+ if (t == JOB_START && result == JOB_DONE && !u->condition_result) {
+ log_struct(LOG_INFO,
+ "MESSAGE=Condition check resulted in %s being skipped.", unit_description(u),
+ "JOB_ID=%" PRIu32, job_id,
+ "JOB_TYPE=%s", job_type_to_string(t),
+ "JOB_RESULT=%s", job_result_to_string(result),
+ LOG_UNIT_ID(u),
+ LOG_UNIT_INVOCATION_ID(u),
+ "MESSAGE_ID=" SD_MESSAGE_UNIT_STARTED_STR);
+
+ return;
+ }
+
format = job_get_done_status_message_format(u, t, result);
if (!format)
return;
@@ -917,10 +935,6 @@ static void job_log_done_status_message(Unit *u, uint32_t job_id, JobType t, Job
static void job_emit_done_status_message(Unit *u, uint32_t job_id, JobType t, JobResult result) {
assert(u);
- /* No message if the job did not actually do anything due to failed condition. */
- if (t == JOB_START && result == JOB_DONE && !u->condition_result)
- return;
-
job_log_done_status_message(u, job_id, t, result);
job_print_done_status_message(u, t, result);
}

View File

@ -0,0 +1,169 @@
From 81c3f90d41c973a18e157c1106926711815adc0e Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 10 Dec 2018 20:56:57 +0100
Subject: [PATCH] core: split out all logic that updates a Job on a unit's
unit_notify() invocation
Just some refactoring, no change in behaviour.
(cherry picked from commit 16c74914d233ec93012d77e5f93cf90e42939669)
Related: #1737283
---
src/core/unit.c | 136 +++++++++++++++++++++++++-----------------------
1 file changed, 71 insertions(+), 65 deletions(-)
diff --git a/src/core/unit.c b/src/core/unit.c
index f5e251123d..a4865c1da5 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -2225,6 +2225,73 @@ static void unit_update_on_console(Unit *u) {
manager_unref_console(u->manager);
}
+static bool unit_process_job(Job *j, UnitActiveState ns, UnitNotifyFlags flags) {
+ bool unexpected = false;
+
+ assert(j);
+
+ if (j->state == JOB_WAITING)
+
+ /* So we reached a different state for this job. Let's see if we can run it now if it failed previously
+ * due to EAGAIN. */
+ job_add_to_run_queue(j);
+
+ /* Let's check whether the unit's new state constitutes a finished job, or maybe contradicts a running job and
+ * hence needs to invalidate jobs. */
+
+ switch (j->type) {
+
+ case JOB_START:
+ case JOB_VERIFY_ACTIVE:
+
+ if (UNIT_IS_ACTIVE_OR_RELOADING(ns))
+ job_finish_and_invalidate(j, JOB_DONE, true, false);
+ else if (j->state == JOB_RUNNING && ns != UNIT_ACTIVATING) {
+ unexpected = true;
+
+ if (UNIT_IS_INACTIVE_OR_FAILED(ns))
+ job_finish_and_invalidate(j, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true, false);
+ }
+
+ break;
+
+ case JOB_RELOAD:
+ case JOB_RELOAD_OR_START:
+ case JOB_TRY_RELOAD:
+
+ if (j->state == JOB_RUNNING) {
+ if (ns == UNIT_ACTIVE)
+ job_finish_and_invalidate(j, (flags & UNIT_NOTIFY_RELOAD_FAILURE) ? JOB_FAILED : JOB_DONE, true, false);
+ else if (!IN_SET(ns, UNIT_ACTIVATING, UNIT_RELOADING)) {
+ unexpected = true;
+
+ if (UNIT_IS_INACTIVE_OR_FAILED(ns))
+ job_finish_and_invalidate(j, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true, false);
+ }
+ }
+
+ break;
+
+ case JOB_STOP:
+ case JOB_RESTART:
+ case JOB_TRY_RESTART:
+
+ if (UNIT_IS_INACTIVE_OR_FAILED(ns))
+ job_finish_and_invalidate(j, JOB_DONE, true, false);
+ else if (j->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) {
+ unexpected = true;
+ job_finish_and_invalidate(j, JOB_FAILED, true, false);
+ }
+
+ break;
+
+ default:
+ assert_not_reached("Job type unknown");
+ }
+
+ return unexpected;
+}
+
void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlags flags) {
bool unexpected;
Manager *m;
@@ -2265,71 +2332,10 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlag
unit_update_on_console(u);
- if (u->job) {
- unexpected = false;
-
- if (u->job->state == JOB_WAITING)
-
- /* So we reached a different state for this
- * job. Let's see if we can run it now if it
- * failed previously due to EAGAIN. */
- job_add_to_run_queue(u->job);
-
- /* Let's check whether this state change constitutes a
- * finished job, or maybe contradicts a running job and
- * hence needs to invalidate jobs. */
-
- switch (u->job->type) {
-
- case JOB_START:
- case JOB_VERIFY_ACTIVE:
-
- if (UNIT_IS_ACTIVE_OR_RELOADING(ns))
- job_finish_and_invalidate(u->job, JOB_DONE, true, false);
- else if (u->job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) {
- unexpected = true;
-
- if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true, false);
- }
-
- break;
-
- case JOB_RELOAD:
- case JOB_RELOAD_OR_START:
- case JOB_TRY_RELOAD:
-
- if (u->job->state == JOB_RUNNING) {
- if (ns == UNIT_ACTIVE)
- job_finish_and_invalidate(u->job, (flags & UNIT_NOTIFY_RELOAD_FAILURE) ? JOB_FAILED : JOB_DONE, true, false);
- else if (!IN_SET(ns, UNIT_ACTIVATING, UNIT_RELOADING)) {
- unexpected = true;
-
- if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true, false);
- }
- }
-
- break;
-
- case JOB_STOP:
- case JOB_RESTART:
- case JOB_TRY_RESTART:
-
- if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->job, JOB_DONE, true, false);
- else if (u->job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) {
- unexpected = true;
- job_finish_and_invalidate(u->job, JOB_FAILED, true, false);
- }
-
- break;
-
- default:
- assert_not_reached("Job type unknown");
- }
-
- } else
+ /* Let's propagate state changes to the job */
+ if (u->job)
+ unexpected = unit_process_job(u->job, ns, flags);
+ else
unexpected = true;
if (!MANAGER_IS_RELOADING(m)) {

View File

@ -0,0 +1,200 @@
From d5245b46716cf53ce4d95966ea99499cf7aa209a Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 13 Nov 2018 21:25:22 +0100
Subject: [PATCH] core: make log messages about units entering a 'failed' state
recognizable
Let's make this recognizable, and carry result information in a
structure fashion.
(cherry picked from commit 7c047d7443347c109daf67023a01c118b5f361eb)
Related: #1737283
---
catalog/systemd.catalog.in | 7 +++++++
src/core/automount.c | 2 +-
src/core/mount.c | 2 +-
src/core/path.c | 2 +-
src/core/scope.c | 2 +-
src/core/service.c | 2 +-
src/core/socket.c | 2 +-
src/core/swap.c | 2 +-
src/core/timer.c | 2 +-
src/core/unit.c | 12 ++++++++++++
src/core/unit.h | 2 ++
src/systemd/sd-messages.h | 4 ++++
12 files changed, 33 insertions(+), 8 deletions(-)
diff --git a/catalog/systemd.catalog.in b/catalog/systemd.catalog.in
index 49a45890f6..54a0f46921 100644
--- a/catalog/systemd.catalog.in
+++ b/catalog/systemd.catalog.in
@@ -344,6 +344,13 @@ Support: %SUPPORT_URL%
The unit @UNIT@ completed and consumed the indicated resources.
+-- d9b373ed55a64feb8242e02dbe79a49c
+Subject: Unit failed
+Defined-By: systemd
+Support: %SUPPORT_URL%
+
+The unit @UNIT@ has entered the 'failed' state with result '@UNIT_RESULT@'.
+
-- 50876a9db00f4c40bde1a2ad381c3a1b
Subject: The system is configured in a way that might cause problems
Defined-By: systemd
diff --git a/src/core/automount.c b/src/core/automount.c
index 1b96a52c00..c78562c549 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -315,7 +315,7 @@ static void automount_enter_dead(Automount *a, AutomountResult f) {
a->result = f;
if (a->result != AUTOMOUNT_SUCCESS)
- log_unit_warning(UNIT(a), "Failed with result '%s'.", automount_result_to_string(a->result));
+ unit_log_failure(UNIT(a), automount_result_to_string(a->result));
automount_set_state(a, a->result != AUTOMOUNT_SUCCESS ? AUTOMOUNT_FAILED : AUTOMOUNT_DEAD);
}
diff --git a/src/core/mount.c b/src/core/mount.c
index 5878814b1b..3cd0e479e9 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -797,7 +797,7 @@ static void mount_enter_dead(Mount *m, MountResult f) {
m->result = f;
if (m->result != MOUNT_SUCCESS)
- log_unit_warning(UNIT(m), "Failed with result '%s'.", mount_result_to_string(m->result));
+ unit_log_failure(UNIT(m), mount_result_to_string(m->result));
mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
diff --git a/src/core/path.c b/src/core/path.c
index 5ef178a46b..f8b69e7804 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -449,7 +449,7 @@ static void path_enter_dead(Path *p, PathResult f) {
p->result = f;
if (p->result != PATH_SUCCESS)
- log_unit_warning(UNIT(p), "Failed with result '%s'.", path_result_to_string(p->result));
+ unit_log_failure(UNIT(p), path_result_to_string(p->result));
path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
}
diff --git a/src/core/scope.c b/src/core/scope.c
index 751556fecf..79ecfd992f 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -240,7 +240,7 @@ static void scope_enter_dead(Scope *s, ScopeResult f) {
s->result = f;
if (s->result != SCOPE_SUCCESS)
- log_unit_warning(UNIT(s), "Failed with result '%s'.", scope_result_to_string(s->result));
+ unit_log_failure(UNIT(s), scope_result_to_string(s->result));
scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD);
}
diff --git a/src/core/service.c b/src/core/service.c
index 5035dcacac..efceb0614c 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1680,7 +1680,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
s->result = f;
if (s->result != SERVICE_SUCCESS)
- log_unit_warning(UNIT(s), "Failed with result '%s'.", service_result_to_string(s->result));
+ unit_log_failure(UNIT(s), service_result_to_string(s->result));
if (allow_restart && service_shall_restart(s))
s->will_auto_restart = true;
diff --git a/src/core/socket.c b/src/core/socket.c
index b034549634..160f11765c 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -1991,7 +1991,7 @@ static void socket_enter_dead(Socket *s, SocketResult f) {
s->result = f;
if (s->result != SOCKET_SUCCESS)
- log_unit_warning(UNIT(s), "Failed with result '%s'.", socket_result_to_string(s->result));
+ unit_log_failure(UNIT(s), socket_result_to_string(s->result));
socket_set_state(s, s->result != SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD);
diff --git a/src/core/swap.c b/src/core/swap.c
index 66a62d8a37..b5926d8644 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -657,7 +657,7 @@ static void swap_enter_dead(Swap *s, SwapResult f) {
s->result = f;
if (s->result != SWAP_SUCCESS)
- log_unit_warning(UNIT(s), "Failed with result '%s'.", swap_result_to_string(s->result));
+ unit_log_failure(UNIT(s), swap_result_to_string(s->result));
swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
diff --git a/src/core/timer.c b/src/core/timer.c
index db202971d3..6ac310cbe0 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -288,7 +288,7 @@ static void timer_enter_dead(Timer *t, TimerResult f) {
t->result = f;
if (t->result != TIMER_SUCCESS)
- log_unit_warning(UNIT(t), "Failed with result '%s'.", timer_result_to_string(t->result));
+ unit_log_failure(UNIT(t), timer_result_to_string(t->result));
timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
}
diff --git a/src/core/unit.c b/src/core/unit.c
index a4865c1da5..f55bddc00f 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -5462,6 +5462,18 @@ int unit_pid_attachable(Unit *u, pid_t pid, sd_bus_error *error) {
return 0;
}
+void unit_log_failure(Unit *u, const char *result) {
+ assert(u);
+ assert(result);
+
+ log_struct(LOG_WARNING,
+ "MESSAGE_ID=" SD_MESSAGE_UNIT_FAILURE_RESULT_STR,
+ LOG_UNIT_ID(u),
+ LOG_UNIT_INVOCATION_ID(u),
+ LOG_UNIT_MESSAGE(u, "Failed with result '%s'.", result),
+ "UNIT_RESULT=%s", result);
+}
+
static const char* const collect_mode_table[_COLLECT_MODE_MAX] = {
[COLLECT_INACTIVE] = "inactive",
[COLLECT_INACTIVE_OR_FAILED] = "inactive-or-failed",
diff --git a/src/core/unit.h b/src/core/unit.h
index 4d9539790a..9d226fb3e0 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -804,6 +804,8 @@ const char *unit_label_path(Unit *u);
int unit_pid_attachable(Unit *unit, pid_t pid, sd_bus_error *error);
+void unit_log_failure(Unit *u, const char *result);
+
/* Macros which append UNIT= or USER_UNIT= to the message */
#define log_unit_full(unit, level, error, ...) \
diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h
index 2adfe16062..846b28fc2b 100644
--- a/src/systemd/sd-messages.h
+++ b/src/systemd/sd-messages.h
@@ -106,6 +106,10 @@ _SD_BEGIN_DECLARATIONS;
#define SD_MESSAGE_UNIT_RESOURCES SD_ID128_MAKE(ae,8f,7b,86,6b,03,47,b9,af,31,fe,1c,80,b1,27,c0)
#define SD_MESSAGE_UNIT_RESOURCES_STR SD_ID128_MAKE_STR(ae,8f,7b,86,6b,03,47,b9,af,31,fe,1c,80,b1,27,c0)
+#define SD_MESSAGE_UNIT_FAILURE_RESULT SD_ID128_MAKE(d9,b3,73,ed,55,a6,4f,eb,82,42,e0,2d,be,79,a4,9c)
+#define SD_MESSAGE_UNIT_FAILURE_RESULT_STR \
+ SD_ID128_MAKE_STR(d9,b3,73,ed,55,a6,4f,eb,82,42,e0,2d,be,79,a4,9c)
+
#define SD_MESSAGE_SPAWN_FAILED SD_ID128_MAKE(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7)
#define SD_MESSAGE_SPAWN_FAILED_STR SD_ID128_MAKE_STR(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7)

View File

@ -0,0 +1,210 @@
From 40c2b0a20ff133f2050642dc7230424ddcb2987b Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 13 Nov 2018 23:28:09 +0100
Subject: [PATCH] core: log a recognizable message when a unit succeeds, too
We already are doing it on failure, let's do it on success, too.
Fixes: #10265
(cherry picked from commit 523ee2d41471bfb738f52d59de9b469301842644)
Related: #1737283
---
catalog/systemd.catalog.in | 7 +++++++
src/core/automount.c | 4 +++-
src/core/mount.c | 4 +++-
src/core/path.c | 4 +++-
src/core/scope.c | 4 +++-
src/core/service.c | 4 +++-
src/core/socket.c | 4 +++-
src/core/swap.c | 4 +++-
src/core/timer.c | 4 +++-
src/core/unit.c | 10 ++++++++++
src/core/unit.h | 1 +
src/systemd/sd-messages.h | 2 ++
12 files changed, 44 insertions(+), 8 deletions(-)
diff --git a/catalog/systemd.catalog.in b/catalog/systemd.catalog.in
index 54a0f46921..2492ad2028 100644
--- a/catalog/systemd.catalog.in
+++ b/catalog/systemd.catalog.in
@@ -344,6 +344,13 @@ Support: %SUPPORT_URL%
The unit @UNIT@ completed and consumed the indicated resources.
+-- 7ad2d189f7e94e70a38c781354912448
+Subject: Unit succeeded
+Defined-By: systemd
+Support: %SUPPORT_URL%
+
+The unit @UNIT@ has successfully entered the 'dead' state.
+
-- d9b373ed55a64feb8242e02dbe79a49c
Subject: Unit failed
Defined-By: systemd
diff --git a/src/core/automount.c b/src/core/automount.c
index c78562c549..b1a155d8d4 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -314,7 +314,9 @@ static void automount_enter_dead(Automount *a, AutomountResult f) {
if (a->result == AUTOMOUNT_SUCCESS)
a->result = f;
- if (a->result != AUTOMOUNT_SUCCESS)
+ if (a->result == AUTOMOUNT_SUCCESS)
+ unit_log_success(UNIT(a));
+ else
unit_log_failure(UNIT(a), automount_result_to_string(a->result));
automount_set_state(a, a->result != AUTOMOUNT_SUCCESS ? AUTOMOUNT_FAILED : AUTOMOUNT_DEAD);
diff --git a/src/core/mount.c b/src/core/mount.c
index 3cd0e479e9..30aaf5ae55 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -796,7 +796,9 @@ static void mount_enter_dead(Mount *m, MountResult f) {
if (m->result == MOUNT_SUCCESS)
m->result = f;
- if (m->result != MOUNT_SUCCESS)
+ if (m->result == MOUNT_SUCCESS)
+ unit_log_success(UNIT(m));
+ else
unit_log_failure(UNIT(m), mount_result_to_string(m->result));
mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
diff --git a/src/core/path.c b/src/core/path.c
index f8b69e7804..dda4a3036b 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -448,7 +448,9 @@ static void path_enter_dead(Path *p, PathResult f) {
if (p->result == PATH_SUCCESS)
p->result = f;
- if (p->result != PATH_SUCCESS)
+ if (p->result == PATH_SUCCESS)
+ unit_log_success(UNIT(p));
+ else
unit_log_failure(UNIT(p), path_result_to_string(p->result));
path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
diff --git a/src/core/scope.c b/src/core/scope.c
index 79ecfd992f..a1a5363244 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -239,7 +239,9 @@ static void scope_enter_dead(Scope *s, ScopeResult f) {
if (s->result == SCOPE_SUCCESS)
s->result = f;
- if (s->result != SCOPE_SUCCESS)
+ if (s->result == SCOPE_SUCCESS)
+ unit_log_success(UNIT(s));
+ else
unit_log_failure(UNIT(s), scope_result_to_string(s->result));
scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD);
diff --git a/src/core/service.c b/src/core/service.c
index efceb0614c..2c31e70ef6 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1679,7 +1679,9 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
if (s->result == SERVICE_SUCCESS)
s->result = f;
- if (s->result != SERVICE_SUCCESS)
+ if (s->result == SERVICE_SUCCESS)
+ unit_log_success(UNIT(s));
+ else
unit_log_failure(UNIT(s), service_result_to_string(s->result));
if (allow_restart && service_shall_restart(s))
diff --git a/src/core/socket.c b/src/core/socket.c
index 160f11765c..7c6d3dfad1 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -1990,7 +1990,9 @@ static void socket_enter_dead(Socket *s, SocketResult f) {
if (s->result == SOCKET_SUCCESS)
s->result = f;
- if (s->result != SOCKET_SUCCESS)
+ if (s->result == SOCKET_SUCCESS)
+ unit_log_success(UNIT(s));
+ else
unit_log_failure(UNIT(s), socket_result_to_string(s->result));
socket_set_state(s, s->result != SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD);
diff --git a/src/core/swap.c b/src/core/swap.c
index b5926d8644..a8f127f660 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -656,7 +656,9 @@ static void swap_enter_dead(Swap *s, SwapResult f) {
if (s->result == SWAP_SUCCESS)
s->result = f;
- if (s->result != SWAP_SUCCESS)
+ if (s->result == SWAP_SUCCESS)
+ unit_log_success(UNIT(s));
+ else
unit_log_failure(UNIT(s), swap_result_to_string(s->result));
swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
diff --git a/src/core/timer.c b/src/core/timer.c
index 6ac310cbe0..2876d54a59 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -287,7 +287,9 @@ static void timer_enter_dead(Timer *t, TimerResult f) {
if (t->result == TIMER_SUCCESS)
t->result = f;
- if (t->result != TIMER_SUCCESS)
+ if (t->result == TIMER_SUCCESS)
+ unit_log_success(UNIT(t));
+ else
unit_log_failure(UNIT(t), timer_result_to_string(t->result));
timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
diff --git a/src/core/unit.c b/src/core/unit.c
index f55bddc00f..ccb0106719 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -5462,6 +5462,16 @@ int unit_pid_attachable(Unit *u, pid_t pid, sd_bus_error *error) {
return 0;
}
+void unit_log_success(Unit *u) {
+ assert(u);
+
+ log_struct(LOG_INFO,
+ "MESSAGE_ID=" SD_MESSAGE_UNIT_SUCCESS_STR,
+ LOG_UNIT_ID(u),
+ LOG_UNIT_INVOCATION_ID(u),
+ LOG_UNIT_MESSAGE(u, "Succeeded."));
+}
+
void unit_log_failure(Unit *u, const char *result) {
assert(u);
assert(result);
diff --git a/src/core/unit.h b/src/core/unit.h
index 9d226fb3e0..4ae1b38624 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -804,6 +804,7 @@ const char *unit_label_path(Unit *u);
int unit_pid_attachable(Unit *unit, pid_t pid, sd_bus_error *error);
+void unit_log_success(Unit *u);
void unit_log_failure(Unit *u, const char *result);
/* Macros which append UNIT= or USER_UNIT= to the message */
diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h
index 846b28fc2b..e7ef81b597 100644
--- a/src/systemd/sd-messages.h
+++ b/src/systemd/sd-messages.h
@@ -106,6 +106,8 @@ _SD_BEGIN_DECLARATIONS;
#define SD_MESSAGE_UNIT_RESOURCES SD_ID128_MAKE(ae,8f,7b,86,6b,03,47,b9,af,31,fe,1c,80,b1,27,c0)
#define SD_MESSAGE_UNIT_RESOURCES_STR SD_ID128_MAKE_STR(ae,8f,7b,86,6b,03,47,b9,af,31,fe,1c,80,b1,27,c0)
+#define SD_MESSAGE_UNIT_SUCCESS SD_ID128_MAKE(7a,d2,d1,89,f7,e9,4e,70,a3,8c,78,13,54,91,24,48)
+#define SD_MESSAGE_UNIT_SUCCESS_STR SD_ID128_MAKE_STR(7a,d2,d1,89,f7,e9,4e,70,a3,8c,78,13,54,91,24,48)
#define SD_MESSAGE_UNIT_FAILURE_RESULT SD_ID128_MAKE(d9,b3,73,ed,55,a6,4f,eb,82,42,e0,2d,be,79,a4,9c)
#define SD_MESSAGE_UNIT_FAILURE_RESULT_STR \
SD_ID128_MAKE_STR(d9,b3,73,ed,55,a6,4f,eb,82,42,e0,2d,be,79,a4,9c)

View File

@ -0,0 +1,113 @@
From 9a6fa8659e7c6b18c95754e6fa9417f03b6341df Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 19 Nov 2018 14:48:28 +0100
Subject: [PATCH] tests: always use the right vtable wrapper calls
Prompted by https://github.com/systemd/systemd/pull/10836#discussion_r234598868
(cherry picked from commit bd7989a3d90e5d97e09f1eef33d09b2469a79f4d)
Related: #1737283
---
src/test/test-execute.c | 2 +-
src/test/test-path.c | 18 +++++++++---------
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 0f8dc883b1..d88de52d2a 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -129,7 +129,7 @@ static void test(Manager *m, const char *unit_name, int status_expected, int cod
assert_se(unit_name);
assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0);
- assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
+ assert_se(unit_start(unit) >= 0);
check(m, unit, status_expected, code_expected);
}
diff --git a/src/test/test-path.c b/src/test/test-path.c
index 209eb2e366..3a1469ae02 100644
--- a/src/test/test-path.c
+++ b/src/test/test-path.c
@@ -106,7 +106,7 @@ static void check_stop_unlink(Manager *m, Unit *unit, const char *test_path, con
}
}
- assert_se(UNIT_VTABLE(unit)->stop(unit) >= 0);
+ assert_se(unit_stop(unit) >= 0);
(void) rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL);
}
@@ -117,7 +117,7 @@ static void test_path_exists(Manager *m) {
assert_se(m);
assert_se(manager_load_startable_unit_or_warn(m, "path-exists.path", NULL, &unit) >= 0);
- assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
+ assert_se(unit_start(unit) >= 0);
assert_se(touch(test_path) >= 0);
@@ -130,7 +130,7 @@ static void test_path_existsglob(Manager *m) {
assert_se(m);
assert_se(manager_load_startable_unit_or_warn(m, "path-existsglob.path", NULL, &unit) >= 0);
- assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
+ assert_se(unit_start(unit) >= 0);
assert_se(touch(test_path) >= 0);
@@ -147,7 +147,7 @@ static void test_path_changed(Manager *m) {
assert_se(touch(test_path) >= 0);
assert_se(manager_load_startable_unit_or_warn(m, "path-changed.path", NULL, &unit) >= 0);
- assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
+ assert_se(unit_start(unit) >= 0);
f = fopen(test_path, "w");
assert_se(f);
@@ -166,7 +166,7 @@ static void test_path_modified(Manager *m) {
assert_se(touch(test_path) >= 0);
assert_se(manager_load_startable_unit_or_warn(m, "path-modified.path", NULL, &unit) >= 0);
- assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
+ assert_se(unit_start(unit) >= 0);
f = fopen(test_path, "w");
assert_se(f);
@@ -182,7 +182,7 @@ static void test_path_unit(Manager *m) {
assert_se(m);
assert_se(manager_load_startable_unit_or_warn(m, "path-unit.path", NULL, &unit) >= 0);
- assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
+ assert_se(unit_start(unit) >= 0);
assert_se(touch(test_path) >= 0);
@@ -198,7 +198,7 @@ static void test_path_directorynotempty(Manager *m) {
assert_se(access(test_path, F_OK) < 0);
assert_se(manager_load_startable_unit_or_warn(m, "path-directorynotempty.path", NULL, &unit) >= 0);
- assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
+ assert_se(unit_start(unit) >= 0);
/* MakeDirectory default to no */
assert_se(access(test_path, F_OK) < 0);
@@ -219,7 +219,7 @@ static void test_path_makedirectory_directorymode(Manager *m) {
assert_se(access(test_path, F_OK) < 0);
assert_se(manager_load_startable_unit_or_warn(m, "path-makedirectory.path", NULL, &unit) >= 0);
- assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
+ assert_se(unit_start(unit) >= 0);
/* Check if the directory has been created */
assert_se(access(test_path, F_OK) >= 0);
@@ -230,7 +230,7 @@ static void test_path_makedirectory_directorymode(Manager *m) {
assert_se((s.st_mode & S_IRWXG) == 0040);
assert_se((s.st_mode & S_IRWXO) == 0004);
- assert_se(UNIT_VTABLE(unit)->stop(unit) >= 0);
+ assert_se(unit_stop(unit) >= 0);
(void) rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL);
}

View File

@ -0,0 +1,153 @@
From 9beae637a919326ddc072c4dd53cb66e80273c8f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 15 Mar 2019 13:42:55 +0100
Subject: [PATCH] test-execute: allow filtering test cases by pattern
When debugging failure in one of the cases, it's annoying to have to wade
through the output from all the other cases. Let's allow picking select
cases.
(cherry picked from commit 9efb96315ae502dabeb94ab35816ea8955563b7a)
Related: #1737283
---
src/test/test-execute.c | 104 ++++++++++++++++++++++------------------
1 file changed, 58 insertions(+), 46 deletions(-)
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index d88de52d2a..d077674efc 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -659,8 +659,15 @@ static void test_exec_standardoutput_append(Manager *m) {
test(m, "exec-standardoutput-append.service", 0, CLD_EXITED);
}
-static int run_tests(UnitFileScope scope, const test_function_t *tests) {
- const test_function_t *test = NULL;
+typedef struct test_entry {
+ test_function_t f;
+ const char *name;
+} test_entry;
+
+#define entry(x) {x, #x}
+
+static int run_tests(UnitFileScope scope, const test_entry tests[], char **patterns) {
+ const test_entry *test = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
int r;
@@ -674,55 +681,60 @@ static int run_tests(UnitFileScope scope, const test_function_t *tests) {
assert_se(r >= 0);
assert_se(manager_startup(m, NULL, NULL) >= 0);
- for (test = tests; test && *test; test++)
- (*test)(m);
+ for (test = tests; test && test->f; test++)
+ if (strv_fnmatch_or_empty(patterns, test->name, FNM_NOESCAPE))
+ test->f(m);
+ else
+ log_info("Skipping %s because it does not match any pattern.", test->name);
return 0;
}
+
int main(int argc, char *argv[]) {
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
- static const test_function_t user_tests[] = {
- test_exec_basic,
- test_exec_ambientcapabilities,
- test_exec_bindpaths,
- test_exec_capabilityboundingset,
- test_exec_cpuaffinity,
- test_exec_environment,
- test_exec_environmentfile,
- test_exec_group,
- test_exec_ignoresigpipe,
- test_exec_inaccessiblepaths,
- test_exec_ioschedulingclass,
- test_exec_oomscoreadjust,
- test_exec_passenvironment,
- test_exec_personality,
- test_exec_privatedevices,
- test_exec_privatenetwork,
- test_exec_privatetmp,
- test_exec_protectkernelmodules,
- test_exec_readonlypaths,
- test_exec_readwritepaths,
- test_exec_restrictnamespaces,
- test_exec_runtimedirectory,
- test_exec_standardinput,
- test_exec_standardoutput,
- test_exec_standardoutput_append,
- test_exec_supplementarygroups,
- test_exec_systemcallerrornumber,
- test_exec_systemcallfilter,
- test_exec_temporaryfilesystem,
- test_exec_umask,
- test_exec_unsetenvironment,
- test_exec_user,
- test_exec_workingdirectory,
- NULL,
+ _cleanup_free_ char *test_execute_path = NULL;
+ static const test_entry user_tests[] = {
+ entry(test_exec_basic),
+ entry(test_exec_ambientcapabilities),
+ entry(test_exec_bindpaths),
+ entry(test_exec_capabilityboundingset),
+ entry(test_exec_cpuaffinity),
+ entry(test_exec_environment),
+ entry(test_exec_environmentfile),
+ entry(test_exec_group),
+ entry(test_exec_ignoresigpipe),
+ entry(test_exec_inaccessiblepaths),
+ entry(test_exec_ioschedulingclass),
+ entry(test_exec_oomscoreadjust),
+ entry(test_exec_passenvironment),
+ entry(test_exec_personality),
+ entry(test_exec_privatedevices),
+ entry(test_exec_privatenetwork),
+ entry(test_exec_privatetmp),
+ entry(test_exec_protectkernelmodules),
+ entry(test_exec_readonlypaths),
+ entry(test_exec_readwritepaths),
+ entry(test_exec_restrictnamespaces),
+ entry(test_exec_runtimedirectory),
+ entry(test_exec_standardinput),
+ entry(test_exec_standardoutput),
+ entry(test_exec_standardoutput_append),
+ entry(test_exec_supplementarygroups),
+ entry(test_exec_systemcallerrornumber),
+ entry(test_exec_systemcallfilter),
+ entry(test_exec_temporaryfilesystem),
+ entry(test_exec_umask),
+ entry(test_exec_unsetenvironment),
+ entry(test_exec_user),
+ entry(test_exec_workingdirectory),
+ {},
};
- static const test_function_t system_tests[] = {
- test_exec_dynamicuser,
- test_exec_specifier,
- test_exec_systemcallfilter_system,
- NULL,
+ static const test_entry system_tests[] = {
+ entry(test_exec_dynamicuser),
+ entry(test_exec_specifier),
+ entry(test_exec_systemcallfilter_system),
+ {},
};
int r;
@@ -759,9 +771,9 @@ int main(int argc, char *argv[]) {
assert_se(unsetenv("VAR2") == 0);
assert_se(unsetenv("VAR3") == 0);
- r = run_tests(UNIT_FILE_USER, user_tests);
+ r = run_tests(UNIT_FILE_USER, user_tests, argv + 1);
if (r != 0)
return r;
- return run_tests(UNIT_FILE_SYSTEM, system_tests);
+ return run_tests(UNIT_FILE_SYSTEM, system_tests, argv + 1);
}

View File

@ -0,0 +1,568 @@
From ad8f0b480799aa7e312dacbcb0c01a3a9e6aa6db Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 26 Mar 2019 11:38:55 +0100
Subject: [PATCH] test-execute: provide custom failure message
test_exec_ambientcapabilities: exec-ambientcapabilities-nobody.service: exit status 0, expected 1
Sometimes we get just the last line, for example from the failure summary,
so make it as useful as possible.
(cherry picked from commit 6aed6a11577b108b9a39f26aeae5e45d98f20c90)
Related: #1737283
---
src/test/test-execute.c | 236 +++++++++++++++++++++-------------------
1 file changed, 123 insertions(+), 113 deletions(-)
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index d077674efc..e42d0d30a8 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -30,7 +30,7 @@
typedef void (*test_function_t)(Manager *m);
-static void check(Manager *m, Unit *unit, int status_expected, int code_expected) {
+static void check(const char *func, Manager *m, Unit *unit, int status_expected, int code_expected) {
Service *service = NULL;
usec_t ts;
usec_t timeout = 2 * USEC_PER_MINUTE;
@@ -56,8 +56,18 @@ static void check(Manager *m, Unit *unit, int status_expected, int code_expected
}
}
exec_status_dump(&service->main_exec_status, stdout, "\t");
- assert_se(service->main_exec_status.status == status_expected);
- assert_se(service->main_exec_status.code == code_expected);
+ if (service->main_exec_status.status != status_expected) {
+ log_error("%s: %s: exit status %d, expected %d",
+ func, unit->id,
+ service->main_exec_status.status, status_expected);
+ abort();
+ }
+ if (service->main_exec_status.code != code_expected) {
+ log_error("%s: %s: exit code %d, expected %d",
+ func, unit->id,
+ service->main_exec_status.code, code_expected);
+ abort();
+ }
}
static bool check_nobody_user_and_group(void) {
@@ -123,21 +133,21 @@ static bool is_inaccessible_available(void) {
return true;
}
-static void test(Manager *m, const char *unit_name, int status_expected, int code_expected) {
+static void test(const char *func, Manager *m, const char *unit_name, int status_expected, int code_expected) {
Unit *unit;
assert_se(unit_name);
assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0);
assert_se(unit_start(unit) >= 0);
- check(m, unit, status_expected, code_expected);
+ check(func, m, unit, status_expected, code_expected);
}
static void test_exec_bindpaths(Manager *m) {
assert_se(mkdir_p("/tmp/test-exec-bindpaths", 0755) >= 0);
assert_se(mkdir_p("/tmp/test-exec-bindreadonlypaths", 0755) >= 0);
- test(m, "exec-bindpaths.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-bindpaths.service", 0, CLD_EXITED);
(void) rm_rf("/tmp/test-exec-bindpaths", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/tmp/test-exec-bindreadonlypaths", REMOVE_ROOT|REMOVE_PHYSICAL);
@@ -154,8 +164,8 @@ static void test_exec_cpuaffinity(Manager *m) {
return;
}
- test(m, "exec-cpuaffinity1.service", 0, CLD_EXITED);
- test(m, "exec-cpuaffinity2.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-cpuaffinity1.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-cpuaffinity2.service", 0, CLD_EXITED);
if (!CPU_ISSET_S(1, c.allocated, c.set) ||
!CPU_ISSET_S(2, c.allocated, c.set)) {
@@ -163,52 +173,52 @@ static void test_exec_cpuaffinity(Manager *m) {
return;
}
- test(m, "exec-cpuaffinity3.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-cpuaffinity3.service", 0, CLD_EXITED);
}
static void test_exec_workingdirectory(Manager *m) {
assert_se(mkdir_p("/tmp/test-exec_workingdirectory", 0755) >= 0);
- test(m, "exec-workingdirectory.service", 0, CLD_EXITED);
- test(m, "exec-workingdirectory-trailing-dot.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-workingdirectory.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-workingdirectory-trailing-dot.service", 0, CLD_EXITED);
(void) rm_rf("/tmp/test-exec_workingdirectory", REMOVE_ROOT|REMOVE_PHYSICAL);
}
static void test_exec_personality(Manager *m) {
#if defined(__x86_64__)
- test(m, "exec-personality-x86-64.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-personality-x86-64.service", 0, CLD_EXITED);
#elif defined(__s390__)
- test(m, "exec-personality-s390.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-personality-s390.service", 0, CLD_EXITED);
#elif defined(__powerpc64__)
# if __BYTE_ORDER == __BIG_ENDIAN
- test(m, "exec-personality-ppc64.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-personality-ppc64.service", 0, CLD_EXITED);
# else
- test(m, "exec-personality-ppc64le.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-personality-ppc64le.service", 0, CLD_EXITED);
# endif
#elif defined(__aarch64__)
- test(m, "exec-personality-aarch64.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-personality-aarch64.service", 0, CLD_EXITED);
#elif defined(__i386__)
- test(m, "exec-personality-x86.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-personality-x86.service", 0, CLD_EXITED);
#else
log_notice("Unknown personality, skipping %s", __func__);
#endif
}
static void test_exec_ignoresigpipe(Manager *m) {
- test(m, "exec-ignoresigpipe-yes.service", 0, CLD_EXITED);
- test(m, "exec-ignoresigpipe-no.service", SIGPIPE, CLD_KILLED);
+ test(__func__, m, "exec-ignoresigpipe-yes.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-ignoresigpipe-no.service", SIGPIPE, CLD_KILLED);
}
static void test_exec_privatetmp(Manager *m) {
assert_se(touch("/tmp/test-exec_privatetmp") >= 0);
- test(m, "exec-privatetmp-yes.service", 0, CLD_EXITED);
- test(m, "exec-privatetmp-no.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-privatetmp-yes.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-privatetmp-no.service", 0, CLD_EXITED);
unlink("/tmp/test-exec_privatetmp");
}
@@ -225,9 +235,9 @@ static void test_exec_privatedevices(Manager *m) {
return;
}
- test(m, "exec-privatedevices-yes.service", 0, CLD_EXITED);
- test(m, "exec-privatedevices-no.service", 0, CLD_EXITED);
- test(m, "exec-privatedevices-disabled-by-prefix.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-privatedevices-yes.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-privatedevices-no.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-privatedevices-disabled-by-prefix.service", 0, CLD_EXITED);
/* We use capsh to test if the capabilities are
* properly set, so be sure that it exists */
@@ -237,10 +247,10 @@ static void test_exec_privatedevices(Manager *m) {
return;
}
- test(m, "exec-privatedevices-yes-capability-mknod.service", 0, CLD_EXITED);
- test(m, "exec-privatedevices-no-capability-mknod.service", 0, CLD_EXITED);
- test(m, "exec-privatedevices-yes-capability-sys-rawio.service", 0, CLD_EXITED);
- test(m, "exec-privatedevices-no-capability-sys-rawio.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-privatedevices-yes-capability-mknod.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-privatedevices-no-capability-mknod.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-privatedevices-yes-capability-sys-rawio.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-privatedevices-no-capability-sys-rawio.service", 0, CLD_EXITED);
}
static void test_exec_protectkernelmodules(Manager *m) {
@@ -261,23 +271,23 @@ static void test_exec_protectkernelmodules(Manager *m) {
return;
}
- test(m, "exec-protectkernelmodules-no-capabilities.service", 0, CLD_EXITED);
- test(m, "exec-protectkernelmodules-yes-capabilities.service", 0, CLD_EXITED);
- test(m, "exec-protectkernelmodules-yes-mount-propagation.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-protectkernelmodules-no-capabilities.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-protectkernelmodules-yes-capabilities.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-protectkernelmodules-yes-mount-propagation.service", 0, CLD_EXITED);
}
static void test_exec_readonlypaths(Manager *m) {
- test(m, "exec-readonlypaths-simple.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-readonlypaths-simple.service", 0, CLD_EXITED);
if (path_is_read_only_fs("/var") > 0) {
log_notice("Directory /var is readonly, skipping remaining tests in %s", __func__);
return;
}
- test(m, "exec-readonlypaths.service", 0, CLD_EXITED);
- test(m, "exec-readonlypaths-mount-propagation.service", 0, CLD_EXITED);
- test(m, "exec-readonlypaths-with-bindpaths.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-readonlypaths.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-readonlypaths-mount-propagation.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-readonlypaths-with-bindpaths.service", 0, CLD_EXITED);
}
static void test_exec_readwritepaths(Manager *m) {
@@ -287,7 +297,7 @@ static void test_exec_readwritepaths(Manager *m) {
return;
}
- test(m, "exec-readwritepaths-mount-propagation.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-readwritepaths-mount-propagation.service", 0, CLD_EXITED);
}
static void test_exec_inaccessiblepaths(Manager *m) {
@@ -297,22 +307,22 @@ static void test_exec_inaccessiblepaths(Manager *m) {
return;
}
- test(m, "exec-inaccessiblepaths-proc.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-inaccessiblepaths-proc.service", 0, CLD_EXITED);
if (path_is_read_only_fs("/") > 0) {
log_notice("Root directory is readonly, skipping remaining tests in %s", __func__);
return;
}
- test(m, "exec-inaccessiblepaths-mount-propagation.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-inaccessiblepaths-mount-propagation.service", 0, CLD_EXITED);
}
static void test_exec_temporaryfilesystem(Manager *m) {
- test(m, "exec-temporaryfilesystem-options.service", 0, CLD_EXITED);
- test(m, "exec-temporaryfilesystem-ro.service", 0, CLD_EXITED);
- test(m, "exec-temporaryfilesystem-rw.service", 0, CLD_EXITED);
- test(m, "exec-temporaryfilesystem-usr.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-temporaryfilesystem-options.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-temporaryfilesystem-ro.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-temporaryfilesystem-rw.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-temporaryfilesystem-usr.service", 0, CLD_EXITED);
}
static void test_exec_systemcallfilter(Manager *m) {
@@ -324,10 +334,10 @@ static void test_exec_systemcallfilter(Manager *m) {
return;
}
- test(m, "exec-systemcallfilter-not-failing.service", 0, CLD_EXITED);
- test(m, "exec-systemcallfilter-not-failing2.service", 0, CLD_EXITED);
- test(m, "exec-systemcallfilter-failing.service", SIGSYS, CLD_KILLED);
- test(m, "exec-systemcallfilter-failing2.service", SIGSYS, CLD_KILLED);
+ test(__func__, m, "exec-systemcallfilter-not-failing.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-systemcallfilter-not-failing2.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-systemcallfilter-failing.service", SIGSYS, CLD_KILLED);
+ test(__func__, m, "exec-systemcallfilter-failing2.service", SIGSYS, CLD_KILLED);
r = find_binary("python3", NULL);
if (r < 0) {
@@ -335,8 +345,8 @@ static void test_exec_systemcallfilter(Manager *m) {
return;
}
- test(m, "exec-systemcallfilter-with-errno-name.service", errno_from_name("EILSEQ"), CLD_EXITED);
- test(m, "exec-systemcallfilter-with-errno-number.service", 255, CLD_EXITED);
+ test(__func__, m, "exec-systemcallfilter-with-errno-name.service", errno_from_name("EILSEQ"), CLD_EXITED);
+ test(__func__, m, "exec-systemcallfilter-with-errno-number.service", 255, CLD_EXITED);
#endif
}
@@ -355,8 +365,8 @@ static void test_exec_systemcallerrornumber(Manager *m) {
return;
}
- test(m, "exec-systemcallerrornumber-name.service", errno_from_name("EACCES"), CLD_EXITED);
- test(m, "exec-systemcallerrornumber-number.service", 255, CLD_EXITED);
+ test(__func__, m, "exec-systemcallerrornumber-name.service", errno_from_name("EACCES"), CLD_EXITED);
+ test(__func__, m, "exec-systemcallerrornumber-number.service", 255, CLD_EXITED);
#endif
}
@@ -367,13 +377,13 @@ static void test_exec_restrictnamespaces(Manager *m) {
return;
}
- test(m, "exec-restrictnamespaces-no.service", 0, CLD_EXITED);
- test(m, "exec-restrictnamespaces-yes.service", 1, CLD_EXITED);
- test(m, "exec-restrictnamespaces-mnt.service", 0, CLD_EXITED);
- test(m, "exec-restrictnamespaces-mnt-blacklist.service", 1, CLD_EXITED);
- test(m, "exec-restrictnamespaces-merge-and.service", 0, CLD_EXITED);
- test(m, "exec-restrictnamespaces-merge-or.service", 0, CLD_EXITED);
- test(m, "exec-restrictnamespaces-merge-all.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-restrictnamespaces-no.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-restrictnamespaces-yes.service", 1, CLD_EXITED);
+ test(__func__, m, "exec-restrictnamespaces-mnt.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-restrictnamespaces-mnt-blacklist.service", 1, CLD_EXITED);
+ test(__func__, m, "exec-restrictnamespaces-merge-and.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-restrictnamespaces-merge-or.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-restrictnamespaces-merge-all.service", 0, CLD_EXITED);
#endif
}
@@ -384,7 +394,7 @@ static void test_exec_systemcallfilter_system(Manager *m) {
return;
}
- test(m, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED);
if (!check_nobody_user_and_group()) {
log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@@ -396,12 +406,12 @@ static void test_exec_systemcallfilter_system(Manager *m) {
return;
}
- test(m, "exec-systemcallfilter-system-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
+ test(__func__, m, "exec-systemcallfilter-system-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
#endif
}
static void test_exec_user(Manager *m) {
- test(m, "exec-user.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-user.service", 0, CLD_EXITED);
if (!check_nobody_user_and_group()) {
log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@@ -413,11 +423,11 @@ static void test_exec_user(Manager *m) {
return;
}
- test(m, "exec-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
+ test(__func__, m, "exec-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
}
static void test_exec_group(Manager *m) {
- test(m, "exec-group.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-group.service", 0, CLD_EXITED);
if (!check_nobody_user_and_group()) {
log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@@ -429,31 +439,31 @@ static void test_exec_group(Manager *m) {
return;
}
- test(m, "exec-group-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
+ test(__func__, m, "exec-group-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
}
static void test_exec_supplementarygroups(Manager *m) {
- test(m, "exec-supplementarygroups.service", 0, CLD_EXITED);
- test(m, "exec-supplementarygroups-single-group.service", 0, CLD_EXITED);
- test(m, "exec-supplementarygroups-single-group-user.service", 0, CLD_EXITED);
- test(m, "exec-supplementarygroups-multiple-groups-default-group-user.service", 0, CLD_EXITED);
- test(m, "exec-supplementarygroups-multiple-groups-withgid.service", 0, CLD_EXITED);
- test(m, "exec-supplementarygroups-multiple-groups-withuid.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-supplementarygroups.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-supplementarygroups-single-group.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-supplementarygroups-single-group-user.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-supplementarygroups-multiple-groups-default-group-user.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-supplementarygroups-multiple-groups-withgid.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-supplementarygroups-multiple-groups-withuid.service", 0, CLD_EXITED);
}
static void test_exec_dynamicuser(Manager *m) {
- test(m, "exec-dynamicuser-fixeduser.service", 0, CLD_EXITED);
- test(m, "exec-dynamicuser-fixeduser-one-supplementarygroup.service", 0, CLD_EXITED);
- test(m, "exec-dynamicuser-supplementarygroups.service", 0, CLD_EXITED);
- test(m, "exec-dynamicuser-statedir.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-dynamicuser-fixeduser.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-dynamicuser-fixeduser-one-supplementarygroup.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-dynamicuser-supplementarygroups.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-dynamicuser-statedir.service", 0, CLD_EXITED);
(void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/var/lib/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/var/lib/private/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/var/lib/private/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
- test(m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED);
- test(m, "exec-dynamicuser-statedir-migrate-step2.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-dynamicuser-statedir-migrate-step2.service", 0, CLD_EXITED);
(void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/var/lib/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
@@ -462,9 +472,9 @@ static void test_exec_dynamicuser(Manager *m) {
}
static void test_exec_environment(Manager *m) {
- test(m, "exec-environment.service", 0, CLD_EXITED);
- test(m, "exec-environment-multiple.service", 0, CLD_EXITED);
- test(m, "exec-environment-empty.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-environment.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-environment-multiple.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-environment-empty.service", 0, CLD_EXITED);
}
static void test_exec_environmentfile(Manager *m) {
@@ -484,7 +494,7 @@ static void test_exec_environmentfile(Manager *m) {
r = write_string_file("/tmp/test-exec_environmentfile.conf", e, WRITE_STRING_FILE_CREATE);
assert_se(r == 0);
- test(m, "exec-environmentfile.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-environmentfile.service", 0, CLD_EXITED);
(void) unlink("/tmp/test-exec_environmentfile.conf");
}
@@ -506,26 +516,26 @@ static void test_exec_passenvironment(Manager *m) {
assert_se(setenv("VAR3", "$word 5 6", 1) == 0);
assert_se(setenv("VAR4", "new\nline", 1) == 0);
assert_se(setenv("VAR5", "passwordwithbackslashes", 1) == 0);
- test(m, "exec-passenvironment.service", 0, CLD_EXITED);
- test(m, "exec-passenvironment-repeated.service", 0, CLD_EXITED);
- test(m, "exec-passenvironment-empty.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-passenvironment.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-passenvironment-repeated.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-passenvironment-empty.service", 0, CLD_EXITED);
assert_se(unsetenv("VAR1") == 0);
assert_se(unsetenv("VAR2") == 0);
assert_se(unsetenv("VAR3") == 0);
assert_se(unsetenv("VAR4") == 0);
assert_se(unsetenv("VAR5") == 0);
- test(m, "exec-passenvironment-absent.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-passenvironment-absent.service", 0, CLD_EXITED);
}
static void test_exec_umask(Manager *m) {
- test(m, "exec-umask-default.service", 0, CLD_EXITED);
- test(m, "exec-umask-0177.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-umask-default.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-umask-0177.service", 0, CLD_EXITED);
}
static void test_exec_runtimedirectory(Manager *m) {
- test(m, "exec-runtimedirectory.service", 0, CLD_EXITED);
- test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED);
- test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-runtimedirectory.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
if (!check_nobody_user_and_group()) {
log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@@ -537,7 +547,7 @@ static void test_exec_runtimedirectory(Manager *m) {
return;
}
- test(m, "exec-runtimedirectory-owner-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
+ test(__func__, m, "exec-runtimedirectory-owner-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
}
static void test_exec_capabilityboundingset(Manager *m) {
@@ -556,14 +566,14 @@ static void test_exec_capabilityboundingset(Manager *m) {
return;
}
- test(m, "exec-capabilityboundingset-simple.service", 0, CLD_EXITED);
- test(m, "exec-capabilityboundingset-reset.service", 0, CLD_EXITED);
- test(m, "exec-capabilityboundingset-merge.service", 0, CLD_EXITED);
- test(m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-capabilityboundingset-simple.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-capabilityboundingset-reset.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-capabilityboundingset-merge.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED);
}
static void test_exec_basic(Manager *m) {
- test(m, "exec-basic.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-basic.service", 0, CLD_EXITED);
}
static void test_exec_ambientcapabilities(Manager *m) {
@@ -585,8 +595,8 @@ static void test_exec_ambientcapabilities(Manager *m) {
return;
}
- test(m, "exec-ambientcapabilities.service", 0, CLD_EXITED);
- test(m, "exec-ambientcapabilities-merge.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-ambientcapabilities.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-ambientcapabilities-merge.service", 0, CLD_EXITED);
if (!check_nobody_user_and_group()) {
log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@@ -598,8 +608,8 @@ static void test_exec_ambientcapabilities(Manager *m) {
return;
}
- test(m, "exec-ambientcapabilities-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
- test(m, "exec-ambientcapabilities-merge-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
+ test(__func__, m, "exec-ambientcapabilities-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
+ test(__func__, m, "exec-ambientcapabilities-merge-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
}
static void test_exec_privatenetwork(Manager *m) {
@@ -611,52 +621,52 @@ static void test_exec_privatenetwork(Manager *m) {
return;
}
- test(m, "exec-privatenetwork-yes.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-privatenetwork-yes.service", 0, CLD_EXITED);
}
static void test_exec_oomscoreadjust(Manager *m) {
- test(m, "exec-oomscoreadjust-positive.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-oomscoreadjust-positive.service", 0, CLD_EXITED);
if (detect_container() > 0) {
log_notice("Testing in container, skipping remaining tests in %s", __func__);
return;
}
- test(m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED);
}
static void test_exec_ioschedulingclass(Manager *m) {
- test(m, "exec-ioschedulingclass-none.service", 0, CLD_EXITED);
- test(m, "exec-ioschedulingclass-idle.service", 0, CLD_EXITED);
- test(m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-ioschedulingclass-none.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-ioschedulingclass-idle.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED);
if (detect_container() > 0) {
log_notice("Testing in container, skipping remaining tests in %s", __func__);
return;
}
- test(m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED);
}
static void test_exec_unsetenvironment(Manager *m) {
- test(m, "exec-unsetenvironment.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-unsetenvironment.service", 0, CLD_EXITED);
}
static void test_exec_specifier(Manager *m) {
- test(m, "exec-specifier.service", 0, CLD_EXITED);
- test(m, "exec-specifier@foo-bar.service", 0, CLD_EXITED);
- test(m, "exec-specifier-interpolation.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-specifier.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-specifier@foo-bar.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-specifier-interpolation.service", 0, CLD_EXITED);
}
static void test_exec_standardinput(Manager *m) {
- test(m, "exec-standardinput-data.service", 0, CLD_EXITED);
- test(m, "exec-standardinput-file.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-standardinput-data.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-standardinput-file.service", 0, CLD_EXITED);
}
static void test_exec_standardoutput(Manager *m) {
- test(m, "exec-standardoutput-file.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-standardoutput-file.service", 0, CLD_EXITED);
}
static void test_exec_standardoutput_append(Manager *m) {
- test(m, "exec-standardoutput-append.service", 0, CLD_EXITED);
+ test(__func__, m, "exec-standardoutput-append.service", 0, CLD_EXITED);
}
typedef struct test_entry {

View File

@ -0,0 +1,738 @@
From ab9c835796a27f0fbaee75a90f0311ec456941d8 Mon Sep 17 00:00:00 2001
From: Anita Zhang <the.anitazha@gmail.com>
Date: Fri, 28 Jun 2019 17:02:30 -0700
Subject: [PATCH] core: ExecCondition= for services
Closes #10596
(cherry picked from commit 31cd5f63ce86a0784c4ef869c4d323a11ff14adc)
Resolves: #1737283
---
TODO | 2 -
catalog/systemd.catalog.in | 7 ++
doc/TRANSIENT-SETTINGS.md | 1 +
man/systemd.service.xml | 20 ++++
src/basic/unit-def.c | 1 +
src/basic/unit-def.h | 1 +
src/core/dbus-service.c | 1 +
src/core/job.c | 3 +-
src/core/job.h | 2 +-
src/core/load-fragment-gperf.gperf.m4 | 1 +
src/core/service.c | 93 ++++++++++++++++---
src/core/service.h | 2 +
src/core/unit.c | 25 ++++-
src/core/unit.h | 4 +
src/shared/bus-unit-util.c | 2 +-
src/systemd/sd-messages.h | 2 +
src/test/test-execute.c | 50 +++++++++-
test/fuzz/fuzz-unit-file/directives.service | 1 +
test/meson.build | 2 +
.../exec-condition-failed.service | 11 +++
test/test-execute/exec-condition-skip.service | 15 +++
21 files changed, 222 insertions(+), 24 deletions(-)
create mode 100644 test/test-execute/exec-condition-failed.service
create mode 100644 test/test-execute/exec-condition-skip.service
diff --git a/TODO b/TODO
index ff1008accf..8f78000089 100644
--- a/TODO
+++ b/TODO
@@ -626,8 +626,6 @@ Features:
* merge unit_kill_common() and unit_kill_context()
-* introduce ExecCondition= in services
-
* EFI:
- honor language efi variables for default language selection (if there are any?)
- honor timezone efi variables for default timezone selection (if there are any?)
diff --git a/catalog/systemd.catalog.in b/catalog/systemd.catalog.in
index 2492ad2028..dc44414f9d 100644
--- a/catalog/systemd.catalog.in
+++ b/catalog/systemd.catalog.in
@@ -358,6 +358,13 @@ Support: %SUPPORT_URL%
The unit @UNIT@ has entered the 'failed' state with result '@UNIT_RESULT@'.
+-- 0e4284a0caca4bfc81c0bb6786972673
+Subject: Unit skipped
+Defined-By: systemd
+Support: %SUPPORT_URL%
+
+The unit @UNIT@ was skipped and has entered the 'dead' state with result '@UNIT_RESULT@'.
+
-- 50876a9db00f4c40bde1a2ad381c3a1b
Subject: The system is configured in a way that might cause problems
Defined-By: systemd
diff --git a/doc/TRANSIENT-SETTINGS.md b/doc/TRANSIENT-SETTINGS.md
index 0b2ad66dcb..23fe84e4d1 100644
--- a/doc/TRANSIENT-SETTINGS.md
+++ b/doc/TRANSIENT-SETTINGS.md
@@ -267,6 +267,7 @@ Most service unit settings are available for transient units.
```
✓ PIDFile=
+✓ ExecCondition=
✓ ExecStartPre=
✓ ExecStart=
✓ ExecStartPost=
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index 315b80e704..54586d1948 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -414,6 +414,26 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>ExecCondition=</varname></term>
+ <listitem><para>Optional commands that are executed before the command(s) in <varname>ExecStartPre=</varname>.
+ Syntax is the same as for <varname>ExecStart=</varname>, except that multiple command lines are allowed and the
+ commands are executed one after the other, serially.</para>
+
+ <para>The behavior is like an <varname>ExecStartPre=</varname> and condition check hybrid: when an
+ <varname>ExecCondition=</varname> command exits with exit code 1 through 254 (inclusive), the remaining
+ commands are skipped and the unit is <emphasis>not</emphasis> marked as failed. However, if an
+ <varname>ExecCondition=</varname> command exits with 255 or abnormally (e.g. timeout, killed by a
+ signal, etc.), the unit will be considered failed (and remaining commands will be skipped). Exit code of 0 or
+ those matching <varname>SuccessExitStatus=</varname> will continue execution to the next command(s).</para>
+
+ <para>The same recommendations about not running long-running processes in <varname>ExecStartPre=</varname>
+ also applies to <varname>ExecCondition=</varname>. <varname>ExecCondition=</varname> will also run the commands
+ in <varname>ExecStopPost=</varname>, as part of stopping the service, in the case of any non-zero or abnormal
+ exits, like the ones described above.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>ExecReload=</varname></term>
<listitem><para>Commands to execute to trigger a configuration
diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c
index ac6a9b37e8..46593f6e65 100644
--- a/src/basic/unit-def.c
+++ b/src/basic/unit-def.c
@@ -162,6 +162,7 @@ DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
static const char* const service_state_table[_SERVICE_STATE_MAX] = {
[SERVICE_DEAD] = "dead",
+ [SERVICE_CONDITION] = "condition",
[SERVICE_START_PRE] = "start-pre",
[SERVICE_START] = "start",
[SERVICE_START_POST] = "start-post",
diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h
index d7e2d74669..db397a31ed 100644
--- a/src/basic/unit-def.h
+++ b/src/basic/unit-def.h
@@ -101,6 +101,7 @@ typedef enum ScopeState {
typedef enum ServiceState {
SERVICE_DEAD,
+ SERVICE_CONDITION,
SERVICE_START_PRE,
SERVICE_START,
SERVICE_START_POST,
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index 1b4c98c7d2..5f768a77c8 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -127,6 +127,7 @@ const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_PROPERTY("NRestarts", "u", bus_property_get_unsigned, offsetof(Service, n_restarts), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_EXEC_STATUS_VTABLE("ExecMain", offsetof(Service, main_exec_status), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ BUS_EXEC_COMMAND_LIST_VTABLE("ExecCondition", offsetof(Service, exec_command[SERVICE_EXEC_CONDITION]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Service, exec_command[SERVICE_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStart", offsetof(Service, exec_command[SERVICE_EXEC_START]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Service, exec_command[SERVICE_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
diff --git a/src/core/job.c b/src/core/job.c
index b9eee91cf3..870ec0a387 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -870,7 +870,8 @@ static void job_log_done_status_message(Unit *u, uint32_t job_id, JobType t, Job
return;
/* Show condition check message if the job did not actually do anything due to failed condition. */
- if (t == JOB_START && result == JOB_DONE && !u->condition_result) {
+ if ((t == JOB_START && result == JOB_DONE && !u->condition_result) ||
+ (t == JOB_START && result == JOB_SKIPPED)) {
log_struct(LOG_INFO,
"MESSAGE=Condition check resulted in %s being skipped.", unit_description(u),
"JOB_ID=%" PRIu32, job_id,
diff --git a/src/core/job.h b/src/core/job.h
index 2f5f3f3989..189fea20ca 100644
--- a/src/core/job.h
+++ b/src/core/job.h
@@ -85,7 +85,7 @@ enum JobResult {
JOB_TIMEOUT, /* Job timeout elapsed */
JOB_FAILED, /* Job failed */
JOB_DEPENDENCY, /* A required dependency job did not result in JOB_DONE */
- JOB_SKIPPED, /* Negative result of JOB_VERIFY_ACTIVE */
+ JOB_SKIPPED, /* Negative result of JOB_VERIFY_ACTIVE or skip due to ExecCondition= */
JOB_INVALID, /* JOB_RELOAD of inactive unit */
JOB_ASSERT, /* Couldn't start a unit, because an assert didn't hold */
JOB_UNSUPPORTED, /* Couldn't start a unit, because the unit type is not supported on the system */
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 161c5a2c82..8883818ff2 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -291,6 +291,7 @@ Unit.AssertNull, config_parse_unit_condition_null, 0,
Unit.CollectMode, config_parse_collect_mode, 0, offsetof(Unit, collect_mode)
m4_dnl
Service.PIDFile, config_parse_unit_path_printf, 0, offsetof(Service, pid_file)
+Service.ExecCondition, config_parse_exec, SERVICE_EXEC_CONDITION, offsetof(Service, exec_command)
Service.ExecStartPre, config_parse_exec, SERVICE_EXEC_START_PRE, offsetof(Service, exec_command)
Service.ExecStart, config_parse_exec, SERVICE_EXEC_START, offsetof(Service, exec_command)
Service.ExecStartPost, config_parse_exec, SERVICE_EXEC_START_POST, offsetof(Service, exec_command)
diff --git a/src/core/service.c b/src/core/service.c
index 2c31e70ef6..92be4280f6 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -41,6 +41,7 @@
static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
[SERVICE_DEAD] = UNIT_INACTIVE,
+ [SERVICE_CONDITION] = UNIT_ACTIVATING,
[SERVICE_START_PRE] = UNIT_ACTIVATING,
[SERVICE_START] = UNIT_ACTIVATING,
[SERVICE_START_POST] = UNIT_ACTIVATING,
@@ -62,6 +63,7 @@ static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
* consider idle jobs active as soon as we start working on them */
static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] = {
[SERVICE_DEAD] = UNIT_INACTIVE,
+ [SERVICE_CONDITION] = UNIT_ACTIVE,
[SERVICE_START_PRE] = UNIT_ACTIVE,
[SERVICE_START] = UNIT_ACTIVE,
[SERVICE_START_POST] = UNIT_ACTIVE,
@@ -1024,7 +1026,7 @@ static void service_set_state(Service *s, ServiceState state) {
service_unwatch_pid_file(s);
if (!IN_SET(state,
- SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
+ SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING,
SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
@@ -1042,7 +1044,7 @@ static void service_set_state(Service *s, ServiceState state) {
}
if (!IN_SET(state,
- SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
+ SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
@@ -1057,7 +1059,7 @@ static void service_set_state(Service *s, ServiceState state) {
}
if (!IN_SET(state,
- SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
+ SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) &&
@@ -1080,7 +1082,8 @@ static void service_set_state(Service *s, ServiceState state) {
unit_notify(UNIT(s), table[old_state], table[state],
(s->reload_result == SERVICE_SUCCESS ? 0 : UNIT_NOTIFY_RELOAD_FAILURE) |
- (s->will_auto_restart ? UNIT_NOTIFY_WILL_AUTO_RESTART : 0));
+ (s->will_auto_restart ? UNIT_NOTIFY_WILL_AUTO_RESTART : 0) |
+ (s->result == SERVICE_SKIP_CONDITION ? UNIT_NOTIFY_SKIP_CONDITION : 0));
}
static usec_t service_coldplug_timeout(Service *s) {
@@ -1088,6 +1091,7 @@ static usec_t service_coldplug_timeout(Service *s) {
switch (s->deserialized_state) {
+ case SERVICE_CONDITION:
case SERVICE_START_PRE:
case SERVICE_START:
case SERVICE_START_POST:
@@ -1143,7 +1147,7 @@ static int service_coldplug(Unit *u) {
if (s->control_pid > 0 &&
pid_is_unwaited(s->control_pid) &&
IN_SET(s->deserialized_state,
- SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
+ SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
@@ -1667,6 +1671,7 @@ static bool service_will_restart(Unit *u) {
}
static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) {
+ ServiceState end_state;
int r;
assert(s);
@@ -1679,10 +1684,16 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
if (s->result == SERVICE_SUCCESS)
s->result = f;
- if (s->result == SERVICE_SUCCESS)
+ if (s->result == SERVICE_SUCCESS) {
unit_log_success(UNIT(s));
- else
+ end_state = SERVICE_DEAD;
+ } else if (s->result == SERVICE_SKIP_CONDITION) {
+ unit_log_skip(UNIT(s), service_result_to_string(s->result));
+ end_state = SERVICE_DEAD;
+ } else {
unit_log_failure(UNIT(s), service_result_to_string(s->result));
+ end_state = SERVICE_FAILED;
+ }
if (allow_restart && service_shall_restart(s))
s->will_auto_restart = true;
@@ -1691,7 +1702,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
* SERVICE_FAILED/SERVICE_DEAD before entering into SERVICE_AUTO_RESTART. */
s->n_keep_fd_store ++;
- service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
+ service_set_state(s, end_state);
if (s->will_auto_restart) {
s->will_auto_restart = false;
@@ -2110,6 +2121,40 @@ fail:
service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
}
+static void service_enter_condition(Service *s) {
+ int r;
+
+ assert(s);
+
+ service_unwatch_control_pid(s);
+
+ s->control_command = s->exec_command[SERVICE_EXEC_CONDITION];
+ if (s->control_command) {
+
+ unit_warn_leftover_processes(UNIT(s));
+
+ s->control_command_id = SERVICE_EXEC_CONDITION;
+
+ r = service_spawn(s,
+ s->control_command,
+ s->timeout_start_usec,
+ EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_APPLY_TTY_STDIN,
+ &s->control_pid);
+
+ if (r < 0)
+ goto fail;
+
+ service_set_state(s, SERVICE_CONDITION);
+ } else
+ service_enter_start_pre(s);
+
+ return;
+
+fail:
+ log_unit_warning_errno(UNIT(s), r, "Failed to run 'exec-condition' task: %m");
+ service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
+}
+
static void service_enter_restart(Service *s) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
@@ -2222,7 +2267,7 @@ static void service_run_next_control(Service *s) {
s->control_command = s->control_command->command_next;
service_unwatch_control_pid(s);
- if (IN_SET(s->state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
+ if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
timeout = s->timeout_start_usec;
else
timeout = s->timeout_stop_usec;
@@ -2231,7 +2276,7 @@ static void service_run_next_control(Service *s) {
s->control_command,
timeout,
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|
- (IN_SET(s->control_command_id, SERVICE_EXEC_START_PRE, SERVICE_EXEC_STOP_POST) ? EXEC_APPLY_TTY_STDIN : 0)|
+ (IN_SET(s->control_command_id, SERVICE_EXEC_CONDITION, SERVICE_EXEC_START_PRE, SERVICE_EXEC_STOP_POST) ? EXEC_APPLY_TTY_STDIN : 0)|
(IN_SET(s->control_command_id, SERVICE_EXEC_STOP, SERVICE_EXEC_STOP_POST) ? EXEC_SETENV_RESULT : 0),
&s->control_pid);
if (r < 0)
@@ -2242,7 +2287,7 @@ static void service_run_next_control(Service *s) {
fail:
log_unit_warning_errno(UNIT(s), r, "Failed to run next control task: %m");
- if (IN_SET(s->state, SERVICE_START_PRE, SERVICE_START_POST, SERVICE_STOP))
+ if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START_POST, SERVICE_STOP))
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
else if (s->state == SERVICE_STOP_POST)
service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
@@ -2296,7 +2341,7 @@ static int service_start(Unit *u) {
return -EAGAIN;
/* Already on it! */
- if (IN_SET(s->state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST))
+ if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST))
return 0;
/* A service that will be restarted must be stopped first to
@@ -2344,7 +2389,9 @@ static int service_start(Unit *u) {
s->flush_n_restarts = false;
}
- service_enter_start_pre(s);
+ u->reset_accounting = true;
+
+ service_enter_condition(s);
return 1;
}
@@ -2370,7 +2417,7 @@ static int service_stop(Unit *u) {
/* If there's already something running we go directly into
* kill mode. */
- if (IN_SET(s->state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD)) {
+ if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD)) {
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
return 0;
}
@@ -3303,6 +3350,10 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
} else if (s->control_pid == pid) {
s->control_pid = 0;
+ /* ExecCondition= calls that exit with (0, 254] should invoke skip-like behavior instead of failing */
+ if (f == SERVICE_FAILURE_EXIT_CODE && s->state == SERVICE_CONDITION && status < 255)
+ f = SERVICE_SKIP_CONDITION;
+
if (s->control_command) {
exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
@@ -3338,6 +3389,13 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
switch (s->state) {
+ case SERVICE_CONDITION:
+ if (f == SERVICE_SUCCESS)
+ service_enter_start_pre(s);
+ else
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
+ break;
+
case SERVICE_START_PRE:
if (f == SERVICE_SUCCESS)
service_enter_start(s);
@@ -3462,9 +3520,10 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
switch (s->state) {
+ case SERVICE_CONDITION:
case SERVICE_START_PRE:
case SERVICE_START:
- log_unit_warning(UNIT(s), "%s operation timed out. Terminating.", s->state == SERVICE_START ? "Start" : "Start-pre");
+ log_unit_warning(UNIT(s), "%s operation timed out. Terminating.", service_state_to_string(s->state));
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
break;
@@ -3975,6 +4034,7 @@ static bool service_needs_console(Unit *u) {
return false;
return IN_SET(s->state,
+ SERVICE_CONDITION,
SERVICE_START_PRE,
SERVICE_START,
SERVICE_START_POST,
@@ -4014,6 +4074,7 @@ static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType);
static const char* const service_exec_command_table[_SERVICE_EXEC_COMMAND_MAX] = {
+ [SERVICE_EXEC_CONDITION] = "ExecCondition",
[SERVICE_EXEC_START_PRE] = "ExecStartPre",
[SERVICE_EXEC_START] = "ExecStart",
[SERVICE_EXEC_START_POST] = "ExecStartPost",
@@ -4043,6 +4104,7 @@ static const char* const service_result_table[_SERVICE_RESULT_MAX] = {
[SERVICE_FAILURE_CORE_DUMP] = "core-dump",
[SERVICE_FAILURE_WATCHDOG] = "watchdog",
[SERVICE_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
+ [SERVICE_SKIP_CONDITION] = "exec-condition",
};
DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult);
@@ -4118,6 +4180,7 @@ const UnitVTable service_vtable = {
.finished_start_job = {
[JOB_DONE] = "Started %s.",
[JOB_FAILED] = "Failed to start %s.",
+ [JOB_SKIPPED] = "Skipped %s.",
},
.finished_stop_job = {
[JOB_DONE] = "Stopped %s.",
diff --git a/src/core/service.h b/src/core/service.h
index 1206e3cdda..62b78cadf1 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -36,6 +36,7 @@ typedef enum ServiceType {
} ServiceType;
typedef enum ServiceExecCommand {
+ SERVICE_EXEC_CONDITION,
SERVICE_EXEC_START_PRE,
SERVICE_EXEC_START,
SERVICE_EXEC_START_POST,
@@ -67,6 +68,7 @@ typedef enum ServiceResult {
SERVICE_FAILURE_CORE_DUMP,
SERVICE_FAILURE_WATCHDOG,
SERVICE_FAILURE_START_LIMIT_HIT,
+ SERVICE_SKIP_CONDITION,
_SERVICE_RESULT_MAX,
_SERVICE_RESULT_INVALID = -1
} ServiceResult;
diff --git a/src/core/unit.c b/src/core/unit.c
index ccb0106719..61799bf9e3 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -2227,6 +2227,7 @@ static void unit_update_on_console(Unit *u) {
static bool unit_process_job(Job *j, UnitActiveState ns, UnitNotifyFlags flags) {
bool unexpected = false;
+ JobResult result;
assert(j);
@@ -2249,8 +2250,16 @@ static bool unit_process_job(Job *j, UnitActiveState ns, UnitNotifyFlags flags)
else if (j->state == JOB_RUNNING && ns != UNIT_ACTIVATING) {
unexpected = true;
- if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(j, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true, false);
+ if (UNIT_IS_INACTIVE_OR_FAILED(ns)) {
+ if (ns == UNIT_FAILED)
+ result = JOB_FAILED;
+ else if (FLAGS_SET(flags, UNIT_NOTIFY_SKIP_CONDITION))
+ result = JOB_SKIPPED;
+ else
+ result = JOB_DONE;
+
+ job_finish_and_invalidate(j, result, true, false);
+ }
}
break;
@@ -5484,6 +5493,18 @@ void unit_log_failure(Unit *u, const char *result) {
"UNIT_RESULT=%s", result);
}
+void unit_log_skip(Unit *u, const char *result) {
+ assert(u);
+ assert(result);
+
+ log_struct(LOG_INFO,
+ "MESSAGE_ID=" SD_MESSAGE_UNIT_SKIPPED_STR,
+ LOG_UNIT_ID(u),
+ LOG_UNIT_INVOCATION_ID(u),
+ LOG_UNIT_MESSAGE(u, "Skipped due to '%s'.", result),
+ "UNIT_RESULT=%s", result);
+}
+
static const char* const collect_mode_table[_COLLECT_MODE_MAX] = {
[COLLECT_INACTIVE] = "inactive",
[COLLECT_INACTIVE_OR_FAILED] = "inactive-or-failed",
diff --git a/src/core/unit.h b/src/core/unit.h
index 4ae1b38624..39179f5fd4 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -658,6 +658,7 @@ int unit_kill_common(Unit *u, KillWho who, int signo, pid_t main_pid, pid_t cont
typedef enum UnitNotifyFlags {
UNIT_NOTIFY_RELOAD_FAILURE = 1 << 0,
UNIT_NOTIFY_WILL_AUTO_RESTART = 1 << 1,
+ UNIT_NOTIFY_SKIP_CONDITION = 1 << 2,
} UnitNotifyFlags;
void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlags flags);
@@ -806,6 +807,9 @@ int unit_pid_attachable(Unit *unit, pid_t pid, sd_bus_error *error);
void unit_log_success(Unit *u);
void unit_log_failure(Unit *u, const char *result);
+/* unit_log_skip is for cases like ExecCondition= where a unit is considered "done"
+ * after some execution, rather than succeeded or failed. */
+void unit_log_skip(Unit *u, const char *result);
/* Macros which append UNIT= or USER_UNIT= to the message */
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 8f3b463c6b..e0b2cfb170 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -1334,7 +1334,7 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con
return bus_append_safe_atou(m, field, eq);
if (STR_IN_SET(field,
- "ExecStartPre", "ExecStart", "ExecStartPost",
+ "ExecCondition", "ExecStartPre", "ExecStart", "ExecStartPost",
"ExecReload", "ExecStop", "ExecStopPost"))
return bus_append_exec_command(m, field, eq);
diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h
index e7ef81b597..bdd4fd3974 100644
--- a/src/systemd/sd-messages.h
+++ b/src/systemd/sd-messages.h
@@ -111,6 +111,8 @@ _SD_BEGIN_DECLARATIONS;
#define SD_MESSAGE_UNIT_FAILURE_RESULT SD_ID128_MAKE(d9,b3,73,ed,55,a6,4f,eb,82,42,e0,2d,be,79,a4,9c)
#define SD_MESSAGE_UNIT_FAILURE_RESULT_STR \
SD_ID128_MAKE_STR(d9,b3,73,ed,55,a6,4f,eb,82,42,e0,2d,be,79,a4,9c)
+#define SD_MESSAGE_UNIT_SKIPPED SD_ID128_MAKE(0e,42,84,a0,ca,ca,4b,fc,81,c0,bb,67,86,97,26,73)
+#define SD_MESSAGE_UNIT_SKIPPED_STR SD_ID128_MAKE_STR(0e,42,84,a0,ca,ca,4b,fc,81,c0,bb,67,86,97,26,73)
#define SD_MESSAGE_SPAWN_FAILED SD_ID128_MAKE(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7)
#define SD_MESSAGE_SPAWN_FAILED_STR SD_ID128_MAKE_STR(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7)
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index e42d0d30a8..882e866ea9 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -30,7 +30,7 @@
typedef void (*test_function_t)(Manager *m);
-static void check(const char *func, Manager *m, Unit *unit, int status_expected, int code_expected) {
+static void wait_for_service_finish(Manager *m, Unit *unit) {
Service *service = NULL;
usec_t ts;
usec_t timeout = 2 * USEC_PER_MINUTE;
@@ -55,6 +55,17 @@ static void check(const char *func, Manager *m, Unit *unit, int status_expected,
exit(EXIT_FAILURE);
}
}
+}
+
+static void check_main_result(const char *func, Manager *m, Unit *unit, int status_expected, int code_expected) {
+ Service *service = NULL;
+
+ assert_se(m);
+ assert_se(unit);
+
+ wait_for_service_finish(m, unit);
+
+ service = SERVICE(unit);
exec_status_dump(&service->main_exec_status, stdout, "\t");
if (service->main_exec_status.status != status_expected) {
log_error("%s: %s: exit status %d, expected %d",
@@ -70,6 +81,25 @@ static void check(const char *func, Manager *m, Unit *unit, int status_expected,
}
}
+static void check_service_result(const char *func, Manager *m, Unit *unit, ServiceResult result_expected) {
+ Service *service = NULL;
+
+ assert_se(m);
+ assert_se(unit);
+
+ wait_for_service_finish(m, unit);
+
+ service = SERVICE(unit);
+
+ if (service->result != result_expected) {
+ log_error("%s: %s: service end result %s, expected %s",
+ func, unit->id,
+ service_result_to_string(service->result),
+ service_result_to_string(result_expected));
+ abort();
+ }
+}
+
static bool check_nobody_user_and_group(void) {
static int cache = -1;
struct passwd *p;
@@ -140,7 +170,17 @@ static void test(const char *func, Manager *m, const char *unit_name, int status
assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0);
assert_se(unit_start(unit) >= 0);
- check(func, m, unit, status_expected, code_expected);
+ check_main_result(func, m, unit, status_expected, code_expected);
+}
+
+static void test_service(const char *func, Manager *m, const char *unit_name, ServiceResult result_expected) {
+ Unit *unit;
+
+ assert_se(unit_name);
+
+ assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0);
+ assert_se(unit_start(unit) >= 0);
+ check_service_result(func, m, unit, result_expected);
}
static void test_exec_bindpaths(Manager *m) {
@@ -669,6 +709,11 @@ static void test_exec_standardoutput_append(Manager *m) {
test(__func__, m, "exec-standardoutput-append.service", 0, CLD_EXITED);
}
+static void test_exec_condition(Manager *m) {
+ test_service(__func__, m, "exec-condition-failed.service", SERVICE_FAILURE_EXIT_CODE);
+ test_service(__func__, m, "exec-condition-skip.service", SERVICE_SKIP_CONDITION);
+}
+
typedef struct test_entry {
test_function_t f;
const char *name;
@@ -709,6 +754,7 @@ int main(int argc, char *argv[]) {
entry(test_exec_ambientcapabilities),
entry(test_exec_bindpaths),
entry(test_exec_capabilityboundingset),
+ entry(test_exec_condition),
entry(test_exec_cpuaffinity),
entry(test_exec_environment),
entry(test_exec_environmentfile),
diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service
index eab1820e20..9d0530df72 100644
--- a/test/fuzz/fuzz-unit-file/directives.service
+++ b/test/fuzz/fuzz-unit-file/directives.service
@@ -83,6 +83,7 @@ DirectoryNotEmpty=
Documentation=
DynamicUser=
ExecReload=
+ExecCondition=
ExecStart=
ExecStartPost=
ExecStartPre=
diff --git a/test/meson.build b/test/meson.build
index 4d1c51048c..070731c4a9 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -42,6 +42,8 @@ test_data_files = '''
test-execute/exec-capabilityboundingset-merge.service
test-execute/exec-capabilityboundingset-reset.service
test-execute/exec-capabilityboundingset-simple.service
+ test-execute/exec-condition-failed.service
+ test-execute/exec-condition-skip.service
test-execute/exec-cpuaffinity1.service
test-execute/exec-cpuaffinity2.service
test-execute/exec-cpuaffinity3.service
diff --git a/test/test-execute/exec-condition-failed.service b/test/test-execute/exec-condition-failed.service
new file mode 100644
index 0000000000..4a406dc17f
--- /dev/null
+++ b/test/test-execute/exec-condition-failed.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Test for exec condition that fails the unit
+
+[Service]
+Type=oneshot
+
+# exit 255 will fail the unit
+ExecCondition=/bin/sh -c 'exit 255'
+
+# This should not get run
+ExecStart=/bin/sh -c 'true'
diff --git a/test/test-execute/exec-condition-skip.service b/test/test-execute/exec-condition-skip.service
new file mode 100644
index 0000000000..9450e8442a
--- /dev/null
+++ b/test/test-execute/exec-condition-skip.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=Test for exec condition that triggers skipping
+
+[Service]
+Type=oneshot
+
+# exit codes [1, 254] will result in skipping the rest of execution
+ExecCondition=/bin/sh -c 'exit 0'
+ExecCondition=/bin/sh -c 'exit 254'
+
+# This would normally fail the unit but will not get run due to the skip above
+ExecCondition=/bin/sh -c 'exit 255'
+
+# This should not get run
+ExecStart=/bin/sh -c 'true'

View File

@ -0,0 +1,75 @@
From 09c96d5ef3f2b0bc4e5f1cf69e9b66248e325509 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Mon, 29 Oct 2018 18:32:51 +0100
Subject: [PATCH] Drop support for lz4 < 1.3.0
lz4-r130 was released on May 29th, 2015. Let's drop the work-around for older
versions. In particular, we won't test any new code against those ancient
releases, so we shouldn't pretend they are supported.
(cherry picked from commit e0a1d4b049e6991919a0eacd5d96f7f39dc6ddd1)
Resolves: #1843871
---
README | 2 +-
meson.build | 1 +
src/journal/compress.c | 4 ----
src/journal/test-compress.c | 4 ----
4 files changed, 2 insertions(+), 9 deletions(-)
diff --git a/README b/README
index 7d06e04800..859152fbde 100644
--- a/README
+++ b/README
@@ -148,7 +148,7 @@ REQUIREMENTS:
libacl (optional)
libselinux (optional)
liblzma (optional)
- liblz4 >= 119 (optional)
+ liblz4 >= 1.3.0 / 130 (optional)
libgcrypt (optional)
libqrencode (optional)
libmicrohttpd (optional)
diff --git a/meson.build b/meson.build
index 70811c29cf..c8ae1e15bd 100644
--- a/meson.build
+++ b/meson.build
@@ -1076,6 +1076,7 @@ conf.set10('HAVE_XZ', have)
want_lz4 = get_option('lz4')
if want_lz4 != 'false' and not fuzzer_build
liblz4 = dependency('liblz4',
+ version : '>= 1.3.0',
required : want_lz4 == 'true')
have = liblz4.found()
else
diff --git a/src/journal/compress.c b/src/journal/compress.c
index 6baf15c8ff..a4a5e63840 100644
--- a/src/journal/compress.c
+++ b/src/journal/compress.c
@@ -95,11 +95,7 @@ int compress_blob_lz4(const void *src, uint64_t src_size,
if (src_size < 9)
return -ENOBUFS;
-#if LZ4_VERSION_NUMBER >= 10700
r = LZ4_compress_default(src, (char*)dst + 8, src_size, (int) dst_alloc_size - 8);
-#else
- r = LZ4_compress_limitedOutput(src, (char*)dst + 8, src_size, (int) dst_alloc_size - 8);
-#endif
if (r <= 0)
return -ENOBUFS;
diff --git a/src/journal/test-compress.c b/src/journal/test-compress.c
index 791c6fdffb..eb3dc3eb6b 100644
--- a/src/journal/test-compress.c
+++ b/src/journal/test-compress.c
@@ -207,11 +207,7 @@ static void test_lz4_decompress_partial(void) {
memset(huge, 'x', HUGE_SIZE);
memcpy(huge, "HUGE=", 5);
-#if LZ4_VERSION_NUMBER >= 10700
r = LZ4_compress_default(huge, buf, HUGE_SIZE, buf_size);
-#else
- r = LZ4_compress_limitedOutput(huge, buf, HUGE_SIZE, buf_size);
-#endif
assert_se(r >= 0);
compressed = r;
log_info("Compressed %i → %zu", HUGE_SIZE, compressed);

View File

@ -0,0 +1,72 @@
From fc1e6209f622ff96c24259a50d98ca6f57a55426 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Mon, 29 Oct 2018 22:21:28 +0100
Subject: [PATCH] test-compress: add test for short decompress_startswith calls
I thought this might fail with lz4 < 1.8.3, but it seems that because of
greedy_realloc, we always use a buffer that is large enough, and it always
passes.
(cherry picked from commit ba17efce44e6a1e139c1671205e9a6ed3824af1b)
Resolves: #1843871
---
src/journal/test-compress.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/src/journal/test-compress.c b/src/journal/test-compress.c
index eb3dc3eb6b..65cd3fbfeb 100644
--- a/src/journal/test-compress.c
+++ b/src/journal/test-compress.c
@@ -131,6 +131,32 @@ static void test_decompress_startswith(int compression,
assert_se(r > 0);
}
+static void test_decompress_startswith_short(int compression,
+ compress_blob_t compress,
+ decompress_sw_t decompress_sw) {
+
+#define TEXT "HUGE=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+
+ char buf[1024];
+ size_t i, csize;
+ int r;
+
+ log_info("/* %s with %s */", __func__, object_compressed_to_string(compression));
+
+ r = compress(TEXT, sizeof TEXT, buf, sizeof buf, &csize);
+ assert_se(r == 0);
+
+ for (i = 1; i < strlen(TEXT); i++) {
+ size_t alloc_size = i;
+ _cleanup_free_ void *buf2 = NULL;
+
+ assert_se(buf2 = malloc(i));
+
+ assert_se(decompress_sw(buf, csize, &buf2, &alloc_size, TEXT, i, TEXT[i]) == 1);
+ assert_se(decompress_sw(buf, csize, &buf2, &alloc_size, TEXT, i, 'y') == 0);
+ }
+}
+
static void test_compress_stream(int compression,
const char* cat,
compress_stream_t compress,
@@ -271,6 +297,9 @@ int main(int argc, char *argv[]) {
test_compress_stream(OBJECT_COMPRESSED_XZ, "xzcat",
compress_stream_xz, decompress_stream_xz, srcfile);
+
+ test_decompress_startswith_short(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_startswith_xz);
+
#else
log_info("/* XZ test skipped */");
#endif
@@ -295,6 +324,9 @@ int main(int argc, char *argv[]) {
compress_stream_lz4, decompress_stream_lz4, srcfile);
test_lz4_decompress_partial();
+
+ test_decompress_startswith_short(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_startswith_lz4);
+
#else
log_info("/* LZ4 test skipped */");
#endif

View File

@ -0,0 +1,180 @@
From 696d56fc75e72f47e4d3232a2140fac10b6b44de Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Mon, 29 Oct 2018 14:55:33 +0100
Subject: [PATCH] journal: adapt for new improved LZ4_decompress_safe_partial()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
With lz4 1.8.3, this function can now decompress partial results into a smaller
buffer. The release news don't say anything interesting, but the test case that
was previously failing now works OK.
Fixes #10259.
A test is added. It shows that with *older* lz4, a partial decompression can
occur with the returned size smaller then the requested number of bytes _and_
smaller then the size of the compressed data:
(lz4-libs-1.8.2-1.fc29.x86_64)
Compressed 4194304 → 16464
Decompressed → 4194304
Decompressed partial 12/4194304 → 4194304
Decompressed partial 1/1 → -2 (bad)
Decompressed partial 2/2 → -2 (bad)
Decompressed partial 3/3 → -2 (bad)
Decompressed partial 4/4 → -2 (bad)
Decompressed partial 5/5 → -2 (bad)
Decompressed partial 6/6 → 6 (good)
Decompressed partial 7/7 → 6 (good)
Decompressed partial 8/8 → 6 (good)
Decompressed partial 9/9 → 6 (good)
Decompressed partial 10/10 → 6 (good)
Decompressed partial 11/11 → 6 (good)
Decompressed partial 12/12 → 6 (good)
Decompressed partial 13/13 → 6 (good)
Decompressed partial 14/14 → 6 (good)
Decompressed partial 15/15 → 6 (good)
Decompressed partial 16/16 → 6 (good)
Decompressed partial 17/17 → 6 (good)
Decompressed partial 18/18 → -16459 (bad)
(lz4-libs-1.8.3-1.fc29.x86_64)
Compressed 4194304 → 16464
Decompressed → 4194304
Decompressed partial 12/4194304 → 12
Decompressed partial 1/1 → 1 (good)
Decompressed partial 2/2 → 2 (good)
Decompressed partial 3/3 → 3 (good)
Decompressed partial 4/4 → 4 (good)
...
If we got such a short "successful" decompression in decompress_startswith() as
implemented before this patch, we could be confused and return a false negative
result. But it turns out that this only occurs with small output buffer
sizes. We use greedy_realloc() to manager the buffer, so it is always at least
64 bytes. I couldn't hit a case where decompress_startswith() would actually
return a bogus result. But since the lack of proof is not conclusive, the code
for *older* lz4 is changed too, just to be safe. We cannot rule out that on a
different architecture or with some unlucky compressed string we could hit this
corner case.
The fallback code is guarded by a version check. The check uses a function not
the compile-time define, because there was no soversion bump in lz4 or new
symbols, and we could be compiled against a newer lz4 and linked at runtime
with an older one. (This happens routinely e.g. when somebody upgrades a subset
of distro packages.)
(cherry picked from commit e41ef6fd0027d3619dc1cf062100b2d224d0ee7e)
Resolves: #1843871
---
src/journal/compress.c | 39 ++++++++++++++++++++++++-------------
src/journal/test-compress.c | 21 ++++++++++----------
2 files changed, 37 insertions(+), 23 deletions(-)
diff --git a/src/journal/compress.c b/src/journal/compress.c
index a4a5e63840..e95ce2bcaa 100644
--- a/src/journal/compress.c
+++ b/src/journal/compress.c
@@ -290,7 +290,6 @@ int decompress_startswith_lz4(const void *src, uint64_t src_size,
* prefix */
int r;
- size_t size;
assert(src);
assert(src_size > 0);
@@ -307,23 +306,37 @@ int decompress_startswith_lz4(const void *src, uint64_t src_size,
r = LZ4_decompress_safe_partial((char*)src + 8, *buffer, src_size - 8,
prefix_len + 1, *buffer_size);
- if (r >= 0)
- size = (unsigned) r;
- else {
- /* lz4 always tries to decode full "sequence", so in
- * pathological cases might need to decompress the
- * full field. */
+ /* One lz4 < 1.8.3, we might get "failure" (r < 0), or "success" where
+ * just a part of the buffer is decompressed. But if we get a smaller
+ * amount of bytes than requested, we don't know whether there isn't enough
+ * data to fill the requested size or whether we just got a partial answer.
+ */
+ if (r < 0 || (size_t) r < prefix_len + 1) {
+ size_t size;
+
+ if (LZ4_versionNumber() >= 10803)
+ /* We trust that the newer lz4 decompresses the number of bytes we
+ * requested if available in the compressed string. */
+ return 0;
+
+ if (r > 0)
+ /* Compare what we have first, in case of mismatch we can
+ * shortcut the full comparison. */
+ if (memcmp(*buffer, prefix, r) != 0)
+ return 0;
+
+ /* Before version 1.8.3, lz4 always tries to decode full a "sequence",
+ * so in pathological cases might need to decompress the full field. */
r = decompress_blob_lz4(src, src_size, buffer, buffer_size, &size, 0);
if (r < 0)
return r;
- }
- if (size >= prefix_len + 1)
- return memcmp(*buffer, prefix, prefix_len) == 0 &&
- ((const uint8_t*) *buffer)[prefix_len] == extra;
- else
- return 0;
+ if (size < prefix_len + 1)
+ return 0;
+ }
+ return memcmp(*buffer, prefix, prefix_len) == 0 &&
+ ((const uint8_t*) *buffer)[prefix_len] == extra;
#else
return -EPROTONOSUPPORT;
#endif
diff --git a/src/journal/test-compress.c b/src/journal/test-compress.c
index 65cd3fbfeb..f60c4ae3d7 100644
--- a/src/journal/test-compress.c
+++ b/src/journal/test-compress.c
@@ -223,13 +223,13 @@ static void test_compress_stream(int compression,
#if HAVE_LZ4
static void test_lz4_decompress_partial(void) {
- char buf[20000];
+ char buf[20000], buf2[100];
size_t buf_size = sizeof(buf), compressed;
int r;
_cleanup_free_ char *huge = NULL;
#define HUGE_SIZE (4096*1024)
- huge = malloc(HUGE_SIZE);
+ assert_se(huge = malloc(HUGE_SIZE));
memset(huge, 'x', HUGE_SIZE);
memcpy(huge, "HUGE=", 5);
@@ -248,14 +248,15 @@ static void test_lz4_decompress_partial(void) {
assert_se(r >= 0);
log_info("Decompressed partial %i/%i → %i", 12, HUGE_SIZE, r);
- /* We expect this to fail, because that's how current lz4 works. If this
- * call succeeds, then lz4 has been fixed, and we need to change our code.
- */
- r = LZ4_decompress_safe_partial(buf, huge,
- compressed,
- 12, HUGE_SIZE-1);
- assert_se(r < 0);
- log_info("Decompressed partial %i/%i → %i", 12, HUGE_SIZE-1, r);
+ for (size_t size = 1; size < sizeof(buf2); size++) {
+ /* This failed in older lz4s but works in newer ones. */
+ r = LZ4_decompress_safe_partial(buf, buf2, compressed, size, size);
+ log_info("Decompressed partial %zu/%zu → %i (%s)", size, size, r,
+ r < 0 ? "bad" : "good");
+ if (r >= 0 && LZ4_versionNumber() >= 10803)
+ /* lz4 <= 1.8.2 should fail that test, let's only check for newer ones */
+ assert_se(memcmp(buf2, huge, r) == 0);
+ }
}
#endif

View File

@ -0,0 +1,118 @@
From 242273e1afd456e86ebc48d7d601cb28297f8efb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 30 Oct 2018 09:02:26 +0100
Subject: [PATCH] fuzz-compress: add fuzzer for compression and decompression
(cherry picked from commit 029427043b2e0523a21f54374f872b23cf744350)
Resolves: #1843871
---
src/fuzz/fuzz-compress.c | 80 ++++++++++++++++++++++++++++++++++++++++
src/fuzz/meson.build | 7 +++-
2 files changed, 86 insertions(+), 1 deletion(-)
create mode 100644 src/fuzz/fuzz-compress.c
diff --git a/src/fuzz/fuzz-compress.c b/src/fuzz/fuzz-compress.c
new file mode 100644
index 0000000000..9c5dfc92c0
--- /dev/null
+++ b/src/fuzz/fuzz-compress.c
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <errno.h>
+
+#include "alloc-util.h"
+#include "compress.h"
+#include "fuzz.h"
+
+static int compress(int alg,
+ const void *src, uint64_t src_size,
+ void *dst, size_t dst_alloc_size, size_t *dst_size) {
+
+ if (alg == OBJECT_COMPRESSED_LZ4)
+ return compress_blob_lz4(src, src_size, dst, dst_alloc_size, dst_size);
+ if (alg == OBJECT_COMPRESSED_XZ)
+ return compress_blob_xz(src, src_size, dst, dst_alloc_size, dst_size);
+ return -EOPNOTSUPP;
+}
+
+typedef struct header {
+ uint32_t alg:2; /* We have only two compression algorithms so far, but we might add
+ * more in the future. Let's make this a bit wider so our fuzzer
+ * cases remain stable in the future. */
+ uint32_t sw_len;
+ uint32_t sw_alloc;
+ uint32_t reserved[3]; /* Extra space to keep fuzz cases stable in case we need to
+ * add stuff in the future. */
+ uint8_t data[];
+} header;
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ _cleanup_free_ void *buf = NULL, *buf2 = NULL;
+ int r;
+
+ if (size < offsetof(header, data) + 1)
+ return 0;
+
+ const header *h = (struct header*) data;
+ const size_t data_len = size - offsetof(header, data);
+
+ int alg = h->alg;
+
+ /* We don't want to fill the logs with messages about parse errors.
+ * Disable most logging if not running standalone */
+ if (!getenv("SYSTEMD_LOG_LEVEL"))
+ log_set_max_level(LOG_CRIT);
+
+ log_info("Using compression %s, data size=%zu",
+ object_compressed_to_string(alg) ?: "(none)",
+ data_len);
+
+ buf = malloc(MAX(size, 128u)); /* Make the buffer a bit larger for very small data */
+ if (!buf) {
+ log_oom();
+ return 0;
+ }
+
+ size_t csize;
+ r = compress(alg, h->data, data_len, buf, size, &csize);
+ if (r < 0) {
+ log_error_errno(r, "Compression failed: %m");
+ return 0;
+ }
+
+ log_debug("Compressed %zu bytes to → %zu bytes", data_len, csize);
+
+ size_t sw_alloc = MAX(h->sw_alloc, 1u);
+ buf2 = malloc(sw_alloc);
+ if (!buf) {
+ log_oom();
+ return 0;
+ }
+
+ size_t sw_len = MIN(data_len - 1, h->sw_len);
+
+ r = decompress_startswith(alg, buf, csize, &buf2, &sw_alloc, h->data, sw_len, h->data[sw_len]);
+ assert_se(r > 0);
+
+ return 0;
+}
diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build
index 5315d2771c..b8d5979d3c 100644
--- a/src/fuzz/meson.build
+++ b/src/fuzz/meson.build
@@ -73,8 +73,13 @@ fuzzers += [
[libsystemd_journal_remote,
libshared],
[]],
+
[['src/fuzz/fuzz-fido-id-desc.c',
'src/udev/fido_id/fido_id_desc.c'],
[],
- []]
+ []],
+
+ [['src/fuzz/fuzz-compress.c'],
+ [libshared],
+ []],
]

View File

@ -0,0 +1,35 @@
From 65a066aae68744e889c114cee56dff5b48d872df Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Thu, 4 Jun 2020 16:55:52 +0200
Subject: [PATCH] seccomp: fix __NR__sysctl usage
Loosely based on
https://github.com/systemd/systemd/pull/14032 and
https://github.com/systemd/systemd/pull/14268.
Related: #1843871
---
src/test/test-seccomp.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c
index 4021a06e0e..009a2e1922 100644
--- a/src/test/test-seccomp.c
+++ b/src/test/test-seccomp.c
@@ -237,14 +237,14 @@ static void test_protect_sysctl(void) {
assert_se(pid >= 0);
if (pid == 0) {
-#if __NR__sysctl > 0
+#if defined __NR__sysctl && __NR__sysctl >= 0
assert_se(syscall(__NR__sysctl, NULL) < 0);
assert_se(errno == EFAULT);
#endif
assert_se(seccomp_protect_sysctl() >= 0);
-#if __NR__sysctl > 0
+#if defined __NR__sysctl && __NR__sysctl >= 0
assert_se(syscall(__NR__sysctl, 0, 0, 0) < 0);
assert_se(errno == EPERM);
#endif

View File

@ -0,0 +1,174 @@
From 3569b29eb8b082229dd97b8aae60bbe4d2f96ef5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 19 Dec 2018 23:05:48 +0100
Subject: [PATCH] tmpfiles: fix crash with NULL in arg_root and other fixes and
tests
The function to replacement paths into the configuration file list was borked.
Apart from the crash with empty root prefix, it would incorrectly handle the
case where root *was* set, and the replacement file was supposed to override
an existing file.
prefix_root is used instead of path_join because prefix_root removes duplicate
slashes (when --root=dir/ is used).
A test is added.
Fixes #11124.
(cherry picked from commit 082bb1c59bd4300bcdc08488c94109680cfadf57)
Resolves: #1836024
---
src/basic/conf-files.c | 21 ++++++++-----
src/test/test-conf-files.c | 61 +++++++++++++++++++++++++++++++++++++-
2 files changed, 73 insertions(+), 9 deletions(-)
diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c
index d6ef0e941e..5ca83091c9 100644
--- a/src/basic/conf-files.c
+++ b/src/basic/conf-files.c
@@ -204,14 +204,17 @@ int conf_files_insert(char ***strv, const char *root, char **dirs, const char *p
if (c == 0) {
char **dir;
- /* Oh, we found our spot and it already contains something. */
+ /* Oh, there already is an entry with a matching name (the last component). */
+
STRV_FOREACH(dir, dirs) {
+ _cleanup_free_ char *rdir = NULL;
char *p1, *p2;
- p1 = path_startswith((*strv)[i], root);
- if (p1)
- /* Skip "/" in *dir, because p1 is without "/" too */
- p1 = path_startswith(p1, *dir + 1);
+ rdir = prefix_root(root, *dir);
+ if (!rdir)
+ return -ENOMEM;
+
+ p1 = path_startswith((*strv)[i], rdir);
if (p1)
/* Existing entry with higher priority
* or same priority, no need to do anything. */
@@ -220,7 +223,8 @@ int conf_files_insert(char ***strv, const char *root, char **dirs, const char *p
p2 = path_startswith(path, *dir);
if (p2) {
/* Our new entry has higher priority */
- t = path_join(root, path, NULL);
+
+ t = prefix_root(root, path);
if (!t)
return log_oom();
@@ -236,7 +240,8 @@ int conf_files_insert(char ***strv, const char *root, char **dirs, const char *p
/* … we are not there yet, let's continue */
}
- t = path_join(root, path, NULL);
+ /* The new file has lower priority than all the existing entries */
+ t = prefix_root(root, path);
if (!t)
return log_oom();
@@ -322,7 +327,7 @@ int conf_files_list_with_replacement(
if (r < 0)
return log_error_errno(r, "Failed to extend config file list: %m");
- p = path_join(root, replacement, NULL);
+ p = prefix_root(root, replacement);
if (!p)
return log_oom();
}
diff --git a/src/test/test-conf-files.c b/src/test/test-conf-files.c
index 2ec2dfc261..5789767161 100644
--- a/src/test/test-conf-files.c
+++ b/src/test/test-conf-files.c
@@ -13,6 +13,7 @@
#include "macro.h"
#include "mkdir.h"
#include "parse-util.h"
+#include "path-util.h"
#include "rm-rf.h"
#include "string-util.h"
#include "strv.h"
@@ -42,7 +43,7 @@ static void test_conf_files_list(bool use_root) {
_cleanup_strv_free_ char **found_files = NULL, **found_files2 = NULL;
const char *root_dir, *search_1, *search_2, *expect_a, *expect_b, *expect_c, *mask;
- log_debug("/* %s */", __func__);
+ log_debug("/* %s(%s) */", __func__, yes_no(use_root));
setup_test_dir(tmp_dir,
"/dir1/a.conf",
@@ -92,6 +93,60 @@ static void test_conf_files_list(bool use_root) {
assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
}
+static void test_conf_files_insert(const char *root) {
+ _cleanup_strv_free_ char **s = NULL;
+
+ log_info("/* %s root=%s */", __func__, strempty(root));
+
+ char **dirs = STRV_MAKE("/dir1", "/dir2", "/dir3");
+
+ _cleanup_free_ const char
+ *foo1 = prefix_root(root, "/dir1/foo.conf"),
+ *foo2 = prefix_root(root, "/dir2/foo.conf"),
+ *bar2 = prefix_root(root, "/dir2/bar.conf"),
+ *zzz3 = prefix_root(root, "/dir3/zzz.conf"),
+ *whatever = prefix_root(root, "/whatever.conf");
+
+ assert_se(conf_files_insert(&s, root, dirs, "/dir2/foo.conf") == 0);
+ assert_se(strv_equal(s, STRV_MAKE(foo2)));
+
+ /* The same file again, https://github.com/systemd/systemd/issues/11124 */
+ assert_se(conf_files_insert(&s, root, dirs, "/dir2/foo.conf") == 0);
+ assert_se(strv_equal(s, STRV_MAKE(foo2)));
+
+ /* Lower priority → new entry is ignored */
+ assert_se(conf_files_insert(&s, root, dirs, "/dir3/foo.conf") == 0);
+ assert_se(strv_equal(s, STRV_MAKE(foo2)));
+
+ /* Higher priority → new entry replaces */
+ assert_se(conf_files_insert(&s, root, dirs, "/dir1/foo.conf") == 0);
+ assert_se(strv_equal(s, STRV_MAKE(foo1)));
+
+ /* Earlier basename */
+ assert_se(conf_files_insert(&s, root, dirs, "/dir2/bar.conf") == 0);
+ assert_se(strv_equal(s, STRV_MAKE(bar2, foo1)));
+
+ /* Later basename */
+ assert_se(conf_files_insert(&s, root, dirs, "/dir3/zzz.conf") == 0);
+ assert_se(strv_equal(s, STRV_MAKE(bar2, foo1, zzz3)));
+
+ /* All lower priority → all ignored */
+ assert_se(conf_files_insert(&s, root, dirs, "/dir3/zzz.conf") == 0);
+ assert_se(conf_files_insert(&s, root, dirs, "/dir2/bar.conf") == 0);
+ assert_se(conf_files_insert(&s, root, dirs, "/dir3/bar.conf") == 0);
+ assert_se(conf_files_insert(&s, root, dirs, "/dir2/foo.conf") == 0);
+ assert_se(strv_equal(s, STRV_MAKE(bar2, foo1, zzz3)));
+
+ /* Two entries that don't match any of the directories, but match basename */
+ assert_se(conf_files_insert(&s, root, dirs, "/dir4/zzz.conf") == 0);
+ assert_se(conf_files_insert(&s, root, dirs, "/zzz.conf") == 0);
+ assert_se(strv_equal(s, STRV_MAKE(bar2, foo1, zzz3)));
+
+ /* An entry that doesn't match any of the directories, no match at all */
+ assert_se(conf_files_insert(&s, root, dirs, "/whatever.conf") == 0);
+ assert_se(strv_equal(s, STRV_MAKE(bar2, foo1, whatever, zzz3)));
+}
+
int main(int argc, char **argv) {
log_set_max_level(LOG_DEBUG);
log_parse_environment();
@@ -99,5 +154,9 @@ int main(int argc, char **argv) {
test_conf_files_list(false);
test_conf_files_list(true);
+ test_conf_files_insert(NULL);
+ test_conf_files_insert("/root");
+ test_conf_files_insert("/root/");
+
return 0;
}

View File

@ -0,0 +1,85 @@
From d8ae33a302f01601e9e98b4aca3516e93c634a54 Mon Sep 17 00:00:00 2001
From: Andreas Henriksson <andreas@fatal.se>
Date: Sun, 14 Oct 2018 14:53:09 +0200
Subject: [PATCH] sulogin-shell: Use force if SYSTEMD_SULOGIN_FORCE set
When the root account is locked sulogin will either inform you of
this and not allow you in or if --force is used it will hand
you passwordless root (if using a recent enough version of util-linux).
Not being allowed a shell is ofcourse inconvenient, but at the same
time handing out passwordless root unconditionally is probably not
a good idea everywhere.
This patch thus allows to control which behaviour you want by
setting the SYSTEMD_SULOGIN_FORCE environment variable to true
or false to control the behaviour, eg. via adding this to
'systemctl edit rescue.service' (or emergency.service):
[Service]
Environment=SYSTEMD_SULOGIN_FORCE=1
Distributions who used locked root accounts and want the passwordless
behaviour could thus simply drop in the override file in
/etc/systemd/system/rescue.service.d/override.conf
Fixes: #7115
Addresses: https://bugs.debian.org/802211
(cherry picked from commit 33eb44fe4a8d7971b5614bc4c2d90f8d91cce66c)
Resolves: #1625929
---
doc/ENVIRONMENT.md | 6 ++++++
src/sulogin-shell/sulogin-shell.c | 11 ++++++++++-
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/doc/ENVIRONMENT.md b/doc/ENVIRONMENT.md
index 1e648be640..39a36a52cc 100644
--- a/doc/ENVIRONMENT.md
+++ b/doc/ENVIRONMENT.md
@@ -101,3 +101,9 @@ systemd-timedated:
NTP client services. If set, `timedatectl set-ntp on` enables and starts the
first existing unit listed in the environment variable, and
`timedatectl set-ntp off` disables and stops all listed units.
+
+systemd-sulogin-shell:
+
+* `$SYSTEMD_SULOGIN_FORCE=1` — This skips asking for the root password if the
+ root password is not available (such as when the root account is locked).
+ See `sulogin(8)` for more details.
diff --git a/src/sulogin-shell/sulogin-shell.c b/src/sulogin-shell/sulogin-shell.c
index 5db3592d6f..a1ea2333de 100644
--- a/src/sulogin-shell/sulogin-shell.c
+++ b/src/sulogin-shell/sulogin-shell.c
@@ -9,6 +9,7 @@
#include "bus-util.h"
#include "bus-error.h"
#include "def.h"
+#include "env-util.h"
#include "log.h"
#include "process-util.h"
#include "sd-bus.h"
@@ -89,7 +90,11 @@ static void print_mode(const char* mode) {
}
int main(int argc, char *argv[]) {
- static const char* const sulogin_cmdline[] = {SULOGIN, NULL};
+ const char* sulogin_cmdline[] = {
+ SULOGIN,
+ NULL, /* --force */
+ NULL
+ };
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
@@ -99,6 +104,10 @@ int main(int argc, char *argv[]) {
print_mode(argc > 1 ? argv[1] : "");
+ if (getenv_bool("SYSTEMD_SULOGIN_FORCE") > 0)
+ /* allows passwordless logins if root account is locked. */
+ sulogin_cmdline[1] = "--force";
+
(void) fork_wait(sulogin_cmdline);
r = bus_connect_system_systemd(&bus);

View File

@ -0,0 +1,62 @@
From 9b7aa39e7db5a6446d3c034741e64cda1a9dd200 Mon Sep 17 00:00:00 2001
From: Filipe Brandenburger <filbranden@google.com>
Date: Mon, 25 Jun 2018 18:07:48 -0700
Subject: [PATCH] resolvconf: fixes for the compatibility interface
Also use compat_main() when called as `resolvconf`, since the interface
is closer to that of `systemd-resolve`.
Use a heap allocated string to set arg_ifname, since a stack allocated
one would be lost after the function returns. (This last one broke the
case where an interface name was suffixed with a dot, such as in
`resolvconf -a tap0.dhcp`.)
Tested:
$ build/resolvconf -a nonexistent.abc </etc/resolv.conf
Unknown interface 'nonexistent': No such device
Fixes #9423.
(cherry picked from commit 5a01b3f35d7b6182c78b6973db8d99bdabd4f9c3)
Resolves: #1835594
---
src/resolve/resolvconf-compat.c | 4 +++-
src/resolve/resolvectl.c | 2 +-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/resolve/resolvconf-compat.c b/src/resolve/resolvconf-compat.c
index d7e68003e6..0723458945 100644
--- a/src/resolve/resolvconf-compat.c
+++ b/src/resolve/resolvconf-compat.c
@@ -53,6 +53,8 @@ static int parse_nameserver(const char *string) {
if (strv_push(&arg_set_dns, word) < 0)
return log_oom();
+
+ word = NULL;
}
return 0;
@@ -202,7 +204,7 @@ int resolvconf_parse_argv(int argc, char *argv[]) {
dot = strchr(argv[optind], '.');
if (dot) {
- iface = strndupa(argv[optind], dot - argv[optind]);
+ iface = strndup(argv[optind], dot - argv[optind]);
log_debug("Ignoring protocol specifier '%s'.", dot + 1);
} else
iface = argv[optind];
diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c
index cf1ec323a4..355e5c62b1 100644
--- a/src/resolve/resolvectl.c
+++ b/src/resolve/resolvectl.c
@@ -3090,7 +3090,7 @@ int main(int argc, char **argv) {
goto finish;
}
- if (streq(program_invocation_short_name, "systemd-resolve"))
+ if (STR_IN_SET(program_invocation_short_name, "systemd-resolve", "resolvconf"))
r = compat_main(argc, argv, bus);
else
r = native_main(argc, argv, bus);

View File

@ -0,0 +1,26 @@
From 56bc690688957abe24d434b7ede16cbe0f2d1233 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Tue, 17 Mar 2020 10:49:44 +0100
Subject: [PATCH] mount: don't add Requires for tmp.mount
This is a follow-up to #1619292.
rhel-only
Resolves: #1748840
---
src/core/mount.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/core/mount.c b/src/core/mount.c
index 30aaf5ae55..2746372db2 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -305,7 +305,7 @@ static int mount_add_mount_dependencies(Mount *m) {
if (r < 0)
return r;
- if (UNIT(m)->fragment_path) {
+ if (UNIT(m)->fragment_path && !streq(UNIT(m)->id, "tmp.mount")) {
/* If we have fragment configuration, then make this dependency required */
r = unit_add_dependency(other, UNIT_REQUIRES, UNIT(m), true, UNIT_DEPENDENCY_PATH);
if (r < 0)

View File

@ -0,0 +1,55 @@
From 4a1405998671caaaad5b24d4cef309c05175b1c1 Mon Sep 17 00:00:00 2001
From: ypf791 <ypf791@gmail.com>
Date: Fri, 19 Jul 2019 18:28:04 +0800
Subject: [PATCH] core: coldplug possible nop_job
When a unit in a state INACTIVE or DEACTIVATING, JobType JOB_TRY_RESTART or
JOB_TRY_RELOAD will be collapsed to JOB_NOP. And use u->nop_job instead
of u->job.
If a JOB_NOP job is going on with a waiting state, a parallel daemon-reload
just install it during deserialization. Without a coldplug, the job will
not be in m->run_queue, which results in a hung try-restart or
try-reload process.
Reproduce:
run systemctl try-restart test.servcie (inactive) repeatly in a terminal.
run systemctl daemon-reload repeatly in other terminals.
After successful reproduce, systemctl list-jobs will list the hang job.
Upsteam:
systemd/systemd#13124
(cherry picked from commit b49e14d5f3081dfcd363d8199a14c0924ae9152f)
Resolves: #1829798
---
src/core/unit.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/core/unit.c b/src/core/unit.c
index 61799bf9e3..f57260727f 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -3696,6 +3696,7 @@ int unit_add_node_dependency(Unit *u, const char *what, bool wants, UnitDependen
int unit_coldplug(Unit *u) {
int r = 0, q;
char **i;
+ Job *uj;
assert(u);
@@ -3718,8 +3719,9 @@ int unit_coldplug(Unit *u) {
r = q;
}
- if (u->job) {
- q = job_coldplug(u->job);
+ uj = u->job ?: u->nop_job;
+ if (uj) {
+ q = job_coldplug(uj);
if (q < 0 && r >= 0)
r = q;
}

View File

@ -0,0 +1,584 @@
From 2240e7955d64260e94dd52a3ab9855d267c2af89 Mon Sep 17 00:00:00 2001
From: Tejun Heo <tj@kernel.org>
Date: Wed, 13 Jun 2018 14:16:35 -0700
Subject: [PATCH] core: add IODeviceLatencyTargetSec
This adds support for the following proposed latency based IO control
mechanism.
https://lkml.org/lkml/2018/6/5/428
(cherry picked from commit 6ae4283cb14c4e4a895f4bbba703804e4128c86c)
Resolves: #1831519
---
man/systemd.resource-control.xml | 29 +++++--
src/core/cgroup.c | 56 +++++++++++--
src/core/cgroup.h | 9 +++
src/core/dbus-cgroup.c | 111 ++++++++++++++++++++++++++
src/core/load-fragment-gperf.gperf.m4 | 1 +
src/core/load-fragment.c | 72 +++++++++++++++++
src/core/load-fragment.h | 1 +
src/shared/bus-unit-util.c | 31 +++++++
src/systemctl/systemctl.c | 22 +++++
9 files changed, 320 insertions(+), 12 deletions(-)
diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
index 4329742e94..b0064bf98f 100644
--- a/man/systemd.resource-control.xml
+++ b/man/systemd.resource-control.xml
@@ -417,11 +417,11 @@
<listitem>
<para>Set the per-device overall block I/O weight for the executed processes, if the unified control group
hierarchy is used on the system. Takes a space-separated pair of a file path and a weight value to specify
- the device specific weight value, between 1 and 10000. (Example: "/dev/sda 1000"). The file path may be
- specified as path to a block device node or as any other file, in which case the backing block device of the
- file system of the file is determined. This controls the <literal>io.weight</literal> control group
- attribute, which defaults to 100. Use this option multiple times to set weights for multiple devices. For
- details about this control group attribute, see <ulink
+ the device specific weight value, between 1 and 10000. (Example: <literal>/dev/sda 1000</literal>). The file
+ path may be specified as path to a block device node or as any other file, in which case the backing block
+ device of the file system of the file is determined. This controls the <literal>io.weight</literal> control
+ group attribute, which defaults to 100. Use this option multiple times to set weights for multiple devices.
+ For details about this control group attribute, see <ulink
url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>.</para>
<para>Implies <literal>IOAccounting=true</literal>.</para>
@@ -482,6 +482,25 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>IODeviceLatencyTargetSec=<replaceable>device</replaceable> <replaceable>target</replaceable></varname></term>
+
+ <listitem>
+ <para>Set the per-device average target I/O latency for the executed processes, if the unified control group
+ hierarchy is used on the system. Takes a file path and a timespan separated by a space to specify
+ the device specific latency target. (Example: "/dev/sda 25ms"). The file path may be specified
+ as path to a block device node or as any other file, in which case the backing block device of the file
+ system of the file is determined. This controls the <literal>io.latency</literal> control group
+ attribute. Use this option multiple times to set latency target for multiple devices. For details about this
+ control group attribute, see <ulink
+ url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>.</para>
+
+ <para>Implies <literal>IOAccounting=true</literal>.</para>
+
+ <para>These settings are supported only if the unified control group hierarchy is used.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>IPAccounting=</varname></term>
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 9e4c3c7dac..ad8219bd79 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -114,6 +114,15 @@ void cgroup_context_free_io_device_weight(CGroupContext *c, CGroupIODeviceWeight
free(w);
}
+void cgroup_context_free_io_device_latency(CGroupContext *c, CGroupIODeviceLatency *l) {
+ assert(c);
+ assert(l);
+
+ LIST_REMOVE(device_latencies, c->io_device_latencies, l);
+ free(l->path);
+ free(l);
+}
+
void cgroup_context_free_io_device_limit(CGroupContext *c, CGroupIODeviceLimit *l) {
assert(c);
assert(l);
@@ -147,6 +156,9 @@ void cgroup_context_done(CGroupContext *c) {
while (c->io_device_weights)
cgroup_context_free_io_device_weight(c, c->io_device_weights);
+ while (c->io_device_latencies)
+ cgroup_context_free_io_device_latency(c, c->io_device_latencies);
+
while (c->io_device_limits)
cgroup_context_free_io_device_limit(c, c->io_device_limits);
@@ -171,6 +183,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
_cleanup_free_ char *cpuset_mems = NULL;
CGroupIODeviceLimit *il;
CGroupIODeviceWeight *iw;
+ CGroupIODeviceLatency *l;
CGroupBlockIODeviceBandwidth *b;
CGroupBlockIODeviceWeight *w;
CGroupDeviceAllow *a;
@@ -256,11 +269,18 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
LIST_FOREACH(device_weights, iw, c->io_device_weights)
fprintf(f,
- "%sIODeviceWeight=%s %" PRIu64,
+ "%sIODeviceWeight=%s %" PRIu64 "\n",
prefix,
iw->path,
iw->weight);
+ LIST_FOREACH(device_latencies, l, c->io_device_latencies)
+ fprintf(f,
+ "%sIODeviceLatencyTargetSec=%s %s\n",
+ prefix,
+ l->path,
+ format_timespan(u, sizeof(u), l->target_usec, 1));
+
LIST_FOREACH(device_limits, il, c->io_device_limits) {
char buf[FORMAT_BYTES_MAX];
CGroupIOLimitType type;
@@ -573,6 +593,7 @@ static bool cgroup_context_has_io_config(CGroupContext *c) {
c->io_weight != CGROUP_WEIGHT_INVALID ||
c->startup_io_weight != CGROUP_WEIGHT_INVALID ||
c->io_device_weights ||
+ c->io_device_latencies ||
c->io_device_limits;
}
@@ -646,6 +667,26 @@ static void cgroup_apply_blkio_device_weight(Unit *u, const char *dev_path, uint
"Failed to set blkio.weight_device: %m");
}
+static void cgroup_apply_io_device_latency(Unit *u, const char *dev_path, usec_t target) {
+ char buf[DECIMAL_STR_MAX(dev_t)*2+2+7+DECIMAL_STR_MAX(uint64_t)+1];
+ dev_t dev;
+ int r;
+
+ r = lookup_block_device(dev_path, &dev);
+ if (r < 0)
+ return;
+
+ if (target != USEC_INFINITY)
+ xsprintf(buf, "%u:%u target=%" PRIu64 "\n", major(dev), minor(dev), target);
+ else
+ xsprintf(buf, "%u:%u target=max\n", major(dev), minor(dev));
+
+ r = cg_set_attribute("io", u->cgroup_path, "io.latency", buf);
+ if (r < 0)
+ log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set io.latency on cgroup %s: %m", u->cgroup_path);
+}
+
static void cgroup_apply_io_device_limit(Unit *u, const char *dev_path, uint64_t *limits) {
char limit_bufs[_CGROUP_IO_LIMIT_TYPE_MAX][DECIMAL_STR_MAX(uint64_t)];
char buf[DECIMAL_STR_MAX(dev_t)*2+2+(6+DECIMAL_STR_MAX(uint64_t)+1)*4];
@@ -827,13 +868,11 @@ static void cgroup_context_apply(
if (has_io) {
CGroupIODeviceWeight *w;
- /* FIXME: no way to reset this list */
LIST_FOREACH(device_weights, w, c->io_device_weights)
cgroup_apply_io_device_weight(u, w->path, w->weight);
} else if (has_blockio) {
CGroupBlockIODeviceWeight *w;
- /* FIXME: no way to reset this list */
LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
weight = cgroup_weight_blkio_to_io(w->weight);
@@ -843,9 +882,15 @@ static void cgroup_context_apply(
cgroup_apply_io_device_weight(u, w->path, weight);
}
}
+
+ if (has_io) {
+ CGroupIODeviceLatency *l;
+
+ LIST_FOREACH(device_latencies, l, c->io_device_latencies)
+ cgroup_apply_io_device_latency(u, l->path, l->target_usec);
+ }
}
- /* Apply limits and free ones without config. */
if (has_io) {
CGroupIODeviceLimit *l;
@@ -902,7 +947,6 @@ static void cgroup_context_apply(
if (has_io) {
CGroupIODeviceWeight *w;
- /* FIXME: no way to reset this list */
LIST_FOREACH(device_weights, w, c->io_device_weights) {
weight = cgroup_weight_io_to_blkio(w->weight);
@@ -914,13 +958,11 @@ static void cgroup_context_apply(
} else if (has_blockio) {
CGroupBlockIODeviceWeight *w;
- /* FIXME: no way to reset this list */
LIST_FOREACH(device_weights, w, c->blockio_device_weights)
cgroup_apply_blkio_device_weight(u, w->path, w->weight);
}
}
- /* Apply limits and free ones without config. */
if (has_io) {
CGroupIODeviceLimit *l;
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index da10575394..f7365b4c46 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -13,6 +13,7 @@ typedef struct CGroupContext CGroupContext;
typedef struct CGroupDeviceAllow CGroupDeviceAllow;
typedef struct CGroupIODeviceWeight CGroupIODeviceWeight;
typedef struct CGroupIODeviceLimit CGroupIODeviceLimit;
+typedef struct CGroupIODeviceLatency CGroupIODeviceLatency;
typedef struct CGroupBlockIODeviceWeight CGroupBlockIODeviceWeight;
typedef struct CGroupBlockIODeviceBandwidth CGroupBlockIODeviceBandwidth;
@@ -52,6 +53,12 @@ struct CGroupIODeviceLimit {
uint64_t limits[_CGROUP_IO_LIMIT_TYPE_MAX];
};
+struct CGroupIODeviceLatency {
+ LIST_FIELDS(CGroupIODeviceLatency, device_latencies);
+ char *path;
+ usec_t target_usec;
+};
+
struct CGroupBlockIODeviceWeight {
LIST_FIELDS(CGroupBlockIODeviceWeight, device_weights);
char *path;
@@ -85,6 +92,7 @@ struct CGroupContext {
uint64_t startup_io_weight;
LIST_HEAD(CGroupIODeviceWeight, io_device_weights);
LIST_HEAD(CGroupIODeviceLimit, io_device_limits);
+ LIST_HEAD(CGroupIODeviceLatency, io_device_latencies);
uint64_t memory_low;
uint64_t memory_high;
@@ -137,6 +145,7 @@ CGroupMask cgroup_context_get_mask(CGroupContext *c);
void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a);
void cgroup_context_free_io_device_weight(CGroupContext *c, CGroupIODeviceWeight *w);
void cgroup_context_free_io_device_limit(CGroupContext *c, CGroupIODeviceLimit *l);
+void cgroup_context_free_io_device_latency(CGroupContext *c, CGroupIODeviceLatency *l);
void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w);
void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b);
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index 30d4e83932..a1d3014d61 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -140,6 +140,36 @@ static int property_get_io_device_limits(
return sd_bus_message_close_container(reply);
}
+static int property_get_io_device_latency(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ CGroupContext *c = userdata;
+ CGroupIODeviceLatency *l;
+ int r;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+ r = sd_bus_message_open_container(reply, 'a', "(st)");
+ if (r < 0)
+ return r;
+
+ LIST_FOREACH(device_latencies, l, c->io_device_latencies) {
+ r = sd_bus_message_append(reply, "(st)", l->path, l->target_usec);
+ if (r < 0)
+ return r;
+ }
+
+ return sd_bus_message_close_container(reply);
+}
+
static int property_get_blockio_device_weight(
sd_bus *bus,
const char *path,
@@ -314,6 +344,7 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
SD_BUS_PROPERTY("IOWriteBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0),
SD_BUS_PROPERTY("IOReadIOPSMax", "a(st)", property_get_io_device_limits, 0, 0),
SD_BUS_PROPERTY("IOWriteIOPSMax", "a(st)", property_get_io_device_limits, 0, 0),
+ SD_BUS_PROPERTY("IODeviceLatencyTargetUSec", "a(st)", property_get_io_device_latency, 0, 0),
SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
SD_BUS_PROPERTY("BlockIOWeight", "t", NULL, offsetof(CGroupContext, blockio_weight), 0),
SD_BUS_PROPERTY("StartupBlockIOWeight", "t", NULL, offsetof(CGroupContext, startup_blockio_weight), 0),
@@ -898,6 +929,86 @@ int bus_cgroup_set_property(
return 1;
+ } else if (streq(name, "IODeviceLatencyTargetUSec")) {
+ const char *path;
+ uint64_t target;
+ unsigned n = 0;
+
+ r = sd_bus_message_enter_container(message, 'a', "(st)");
+ if (r < 0)
+ return r;
+
+ while ((r = sd_bus_message_read(message, "(st)", &path, &target)) > 0) {
+
+ if (!path_is_normalized(path))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ CGroupIODeviceLatency *a = NULL, *b;
+
+ LIST_FOREACH(device_latencies, b, c->io_device_latencies) {
+ if (path_equal(b->path, path)) {
+ a = b;
+ break;
+ }
+ }
+
+ if (!a) {
+ a = new0(CGroupIODeviceLatency, 1);
+ if (!a)
+ return -ENOMEM;
+
+ a->path = strdup(path);
+ if (!a->path) {
+ free(a);
+ return -ENOMEM;
+ }
+ LIST_PREPEND(device_latencies, c->io_device_latencies, a);
+ }
+
+ a->target_usec = target;
+ }
+
+ n++;
+ }
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ _cleanup_free_ char *buf = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ char ts[FORMAT_TIMESPAN_MAX];
+ CGroupIODeviceLatency *a;
+ size_t size = 0;
+
+ if (n == 0) {
+ while (c->io_device_latencies)
+ cgroup_context_free_io_device_latency(c, c->io_device_latencies);
+ }
+
+ unit_invalidate_cgroup(u, CGROUP_MASK_IO);
+
+ f = open_memstream(&buf, &size);
+ if (!f)
+ return -ENOMEM;
+
+ (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+
+ fputs("IODeviceLatencyTargetSec=\n", f);
+ LIST_FOREACH(device_latencies, a, c->io_device_latencies)
+ fprintf(f, "IODeviceLatencyTargetSec=%s %s\n",
+ a->path, format_timespan(ts, sizeof(ts), a->target_usec, 1));
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
+ unit_write_setting(u, flags, name, buf);
+ }
+
+ return 1;
+
} else if (STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
const char *path;
bool read = true;
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 8883818ff2..23879c001f 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -185,6 +185,7 @@ $1.IOReadBandwidthMax, config_parse_io_limit, 0,
$1.IOWriteBandwidthMax, config_parse_io_limit, 0, offsetof($1, cgroup_context)
$1.IOReadIOPSMax, config_parse_io_limit, 0, offsetof($1, cgroup_context)
$1.IOWriteIOPSMax, config_parse_io_limit, 0, offsetof($1, cgroup_context)
+$1.IODeviceLatencyTargetSec, config_parse_io_device_latency, 0, offsetof($1, cgroup_context)
$1.BlockIOAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.blockio_accounting)
$1.BlockIOWeight, config_parse_blockio_weight, 0, offsetof($1, cgroup_context.blockio_weight)
$1.StartupBlockIOWeight, config_parse_blockio_weight, 0, offsetof($1, cgroup_context.startup_blockio_weight)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 9b2724307d..1e22013b75 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -3383,6 +3383,77 @@ int config_parse_io_device_weight(
return 0;
}
+int config_parse_io_device_latency(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_free_ char *path = NULL, *resolved = NULL;
+ CGroupIODeviceLatency *l;
+ CGroupContext *c = data;
+ const char *p = rvalue;
+ usec_t usec;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ while (c->io_device_latencies)
+ cgroup_context_free_io_device_latency(c, c->io_device_latencies);
+
+ return 0;
+ }
+
+ r = extract_first_word(&p, &path, NULL, EXTRACT_QUOTES);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Invalid syntax, ignoring: %s", rvalue);
+ return 0;
+ }
+ if (r == 0 || isempty(p)) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Failed to extract device path and latency from '%s', ignoring.", rvalue);
+ return 0;
+ }
+
+ r = unit_full_printf(userdata, path, &resolved);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
+ return 0;
+ }
+
+ r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
+ if (r < 0)
+ return 0;
+
+ if (parse_sec(p, &usec) < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", p);
+ return 0;
+ }
+
+ l = new0(CGroupIODeviceLatency, 1);
+ if (!l)
+ return log_oom();
+
+ l->path = TAKE_PTR(resolved);
+ l->target_usec = usec;
+
+ LIST_PREPEND(device_latencies, c->io_device_latencies, l);
+ return 0;
+}
+
int config_parse_io_limit(
const char *unit,
const char *filename,
@@ -4572,6 +4643,7 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_device_policy, "POLICY" },
{ config_parse_io_limit, "LIMIT" },
{ config_parse_io_device_weight, "DEVICEWEIGHT" },
+ { config_parse_io_device_latency, "DEVICELATENCY" },
{ config_parse_blockio_bandwidth, "BANDWIDTH" },
{ config_parse_blockio_weight, "WEIGHT" },
{ config_parse_blockio_device_weight, "DEVICEWEIGHT" },
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 424fa478a7..65a94d53cc 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -68,6 +68,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_tasks_max);
CONFIG_PARSER_PROTOTYPE(config_parse_delegate);
CONFIG_PARSER_PROTOTYPE(config_parse_device_policy);
CONFIG_PARSER_PROTOTYPE(config_parse_device_allow);
+CONFIG_PARSER_PROTOTYPE(config_parse_io_device_latency);
CONFIG_PARSER_PROTOTYPE(config_parse_io_device_weight);
CONFIG_PARSER_PROTOTYPE(config_parse_io_limit);
CONFIG_PARSER_PROTOTYPE(config_parse_blockio_weight);
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index e0b2cfb170..3c1ecf2027 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -566,6 +566,37 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
return 1;
}
+ if (streq(field, "IODeviceLatencyTargetSec")) {
+ const char *field_usec = "IODeviceLatencyTargetUSec";
+
+ if (isempty(eq))
+ r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", USEC_INFINITY);
+ else {
+ const char *path, *target, *e;
+ usec_t usec;
+
+ e = strchr(eq, ' ');
+ if (!e) {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ path = strndupa(eq, e - eq);
+ target = e+1;
+
+ r = parse_sec(target, &usec);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s: %m", field, target);
+
+ r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 1, path, usec);
+ }
+
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+ }
+
if (STR_IN_SET(field, "IPAddressAllow", "IPAddressDeny")) {
unsigned char prefixlen;
union in_addr_union prefix = {};
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index a3074bc5e3..559e49f104 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -4875,6 +4875,28 @@ static int print_property(const char *name, sd_bus_message *m, bool value, bool
return 1;
+ } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN &&
+ streq(name, "IODeviceLatencyTargetUSec")) {
+ char ts[FORMAT_TIMESPAN_MAX];
+ const char *path;
+ uint64_t target;
+
+ r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ while ((r = sd_bus_message_read(m, "(st)", &path, &target)) > 0)
+ print_prop(name, "%s %s", strna(path),
+ format_timespan(ts, sizeof(ts), target, 1));
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_exit_container(m);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ return 1;
+
} else if (contents[0] == SD_BUS_TYPE_BYTE && streq(name, "StandardInputData")) {
_cleanup_free_ char *h = NULL;
const void *p;

Some files were not shown because too many files have changed in this diff Show More