Re: [systemd-devel] A missing SELinux unit access check due to unexpected UNIT_NOT_FOUND unit object
From: Lennart Poettering lenn...@poettering.net Subject: Re: [systemd-devel] A missing SELinux unit access check due to unexpected UNIT_NOT_FOUND unit object Date: Fri, 19 Jun 2015 12:34:40 +0200 On Fri, 19.06.15 12:06, HATAYAMA Daisuke (d.hatay...@jp.fujitsu.com) wrote: From: Lennart Poettering lenn...@poettering.net Subject: Re: [systemd-devel] A missing SELinux unit access check due to unexpected UNIT_NOT_FOUND unit object Date: Thu, 18 Jun 2015 13:23:25 +0200 On Thu, 18.06.15 18:14, HATAYAMA Daisuke (d.hatay...@jp.fujitsu.com) wrote: Currently, there's a behavior that an unit object in UNIT_NOT_FOUND generated via After= dependency is unexpectedly? left in manager-units hash table and SELinux unit access check is not performed. No this is expected and intended behaviour. All units that are *referenced* have a Unit object that is in the manager-units hash table, and that includes units that do not exist on disk. I am note sure what this means for SELinux though. It probably should fall back to some generic label or so if a Unit object doesn't have a unit file associated on disk. Thanks for your explanation. I have one more quesiton. That is, this is a kind of backpatching technique used in compiler parsers to represent different symbol references by a unique single object, is this correct? Yes, that does play a role: units may have multiple names, and while loading the units we learn which ones belong together, and only then can merge them and possibly find the backing unit file. That means we need to make sure that we track unit files in the dependency tree even if we don't have a unit file for them. Thanks for your explanation. I read the code wrongly and I had understood that each unit file is always represented by a unique single unit file, but in fact, there's some period that there are multiple unit files with the same name and they get merged if necessary. I'll try to understand the behaviour more. That said, it's also beneficial in other cases, like for example for debugging purposes, to get a full idea of what's going on. I see. It's useful to figure out a situation if structure of the object tree is similar to actual unit files'. Also, there are some unit types (for example .device units) that are synthesized dynamically, and usually don't have any unit file. I see. -- Thanks. HATAYAMA, Daisuke ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Re: [systemd-devel] A missing SELinux unit access check due to unexpected UNIT_NOT_FOUND unit object
From: Lennart Poettering lenn...@poettering.net Subject: Re: [systemd-devel] A missing SELinux unit access check due to unexpected UNIT_NOT_FOUND unit object Date: Thu, 18 Jun 2015 13:23:25 +0200 On Thu, 18.06.15 18:14, HATAYAMA Daisuke (d.hatay...@jp.fujitsu.com) wrote: Currently, there's a behavior that an unit object in UNIT_NOT_FOUND generated via After= dependency is unexpectedly? left in manager-units hash table and SELinux unit access check is not performed. No this is expected and intended behaviour. All units that are *referenced* have a Unit object that is in the manager-units hash table, and that includes units that do not exist on disk. I am note sure what this means for SELinux though. It probably should fall back to some generic label or so if a Unit object doesn't have a unit file associated on disk. Thanks for your explanation. I have one more quesiton. That is, this is a kind of backpatching technique used in compiler parsers to represent different symbol references by a unique single object, is this correct? -- Thanks. HATAYAMA, Daisuke ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
[systemd-devel] [PATCH v3 2/2] selinux: fix unnecessary generic SELinux check due to unit objects in UNIT_NOT_FOUND
systemd creates a unit object of A.service when it is referenced in various contexts such as that systemd parses a unit file and finds a dependency, like After=A.service, in some unit file or via systemd is requested a D-Bus operation such as systemctl status A.service, and then registers it in manager-units hash table. If the referenced unit file actually doesn't exist, load state of the unit object becomes UNIT_NOT_FOUND and is left in manager-units until it is cleaned up at the next manager loop. The problem here is that mac_selinux_unit_access_check_strv() overlooks the situation that some unit object of A.service in UNIT_NOT_FOUND could still be left in the manager-units hash table but a new unit file A.service has just been created. Then, the unit object in UNIT_NOT_FOUND state hides presence of the A.service. As a result, we don't lead to an SELinux unit access check with a SELinux context label of the A.service. To fix this, if manager_load_unit() returns a unit object in UNIT_NOT_FOUND from the manager-units hash table, clean up the unit object and retry loading unit files. --- src/core/manager.c|4 ++-- src/core/manager.h|2 ++ src/core/selinux-access.c | 14 ++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/core/manager.c b/src/core/manager.c index a1c5433..d05d6fb 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -771,7 +771,7 @@ static int manager_connect_bus(Manager *m, bool reexecuting) { return bus_init(m, try_bus_connect); } -static unsigned manager_dispatch_cleanup_queue(Manager *m) { +unsigned manager_dispatch_cleanup_queue(Manager *m) { Unit *u; unsigned n = 0; @@ -847,7 +847,7 @@ good: u-gc_marker = gc_marker + GC_OFFSET_GOOD; } -static unsigned manager_dispatch_gc_queue(Manager *m) { +unsigned manager_dispatch_gc_queue(Manager *m) { Unit *u; unsigned n = 0; unsigned gc_marker; diff --git a/src/core/manager.h b/src/core/manager.h index 4ef869d..bea7a17 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -322,6 +322,8 @@ void manager_dump_jobs(Manager *s, FILE *f, const char *prefix); void manager_clear_jobs(Manager *m); +unsigned manager_dispatch_cleanup_queue(Manager *m); +unsigned manager_dispatch_gc_queue(Manager *m); unsigned manager_dispatch_load_queue(Manager *m); int manager_environment_add(Manager *m, char **minus, char **plus); diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c index f52bc6d..5921898 100644 --- a/src/core/selinux-access.c +++ b/src/core/selinux-access.c @@ -292,10 +292,24 @@ int mac_selinux_unit_access_check_strv(char **units, int r; STRV_FOREACH(i, units) { +retry: r = manager_load_unit(m, *i, NULL, error, u); if (r 0) return r; if (u) { +/* Clean up an unit object in UNIT_NOT_FOUND + * load state if it's still left in m-units, + * and then retry to load a given unit file. + * Give up UNIT_ERROR case to aovid such as + * infinite loop due to ENOMEM. + */ +if (r == 1 u-load_state == UNIT_NOT_FOUND) { +unit_add_to_gc_queue(u); +manager_dispatch_gc_queue(m); +unit_add_to_cleanup_queue(u); +manager_dispatch_cleanup_queue(m); +goto retry; +} r = mac_selinux_unit_access_check(u, message, permission, error); if (r 0) return r; ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
[systemd-devel] [PATCH v3 1/2] selinux: fix missing SELinux unit access check
Currently, SELinux unit access check is not performed if a given unit file has not been registered in a hash table. This is because function manager_get_unit() only tries to pick up a Unit object from a Unit hash table. Instead, we use function manager_load_unit() searching Unit file pathes for the given Unit file. --- src/core/selinux-access.c |4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c index decd42f..f52bc6d 100644 --- a/src/core/selinux-access.c +++ b/src/core/selinux-access.c @@ -292,7 +292,9 @@ int mac_selinux_unit_access_check_strv(char **units, int r; STRV_FOREACH(i, units) { -u = manager_get_unit(m, *i); +r = manager_load_unit(m, *i, NULL, error, u); +if (r 0) +return r; if (u) { r = mac_selinux_unit_access_check(u, message, permission, error); if (r 0) ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Re: [systemd-devel] [PATCH v2] selinux: fix missing SELinux unit access check
From: Lennart Poettering lenn...@poettering.net Subject: Re: [systemd-devel] [PATCH v2] selinux: fix missing SELinux unit access check Date: Thu, 18 Jun 2015 13:30:43 +0200 On Thu, 18.06.15 18:29, HATAYAMA Daisuke (d.hatay...@jp.fujitsu.com) wrote: int r; STRV_FOREACH(i, units) { -u = manager_get_unit(m, *i); +r = manager_load_unit(m, *i, NULL, error, u); +if (r 0) +return r; if (u) { +if (u-load_error != 0) +return u-load_error; r = mac_selinux_unit_access_check(u, message, permission, error); if (r 0) return r; I commented on the issue now in github, could you please follow up there? https://github.com/systemd/systemd/pull/145 Thanks for your reviewing. However, unfortunately, I cannot use github for some reason for now. So, please let me discuss in the mailing list. I'm sorry for the inconvenience. I don't think we should check this, it doesn't matter if we managed to successfully load the unit or not, we should still allow access either way. Sorry, I don't understand well. Do you mean removing this SELinux unit access check? If so, it means that current logic since the following commit, is changed, right? No, I meant tjust the u-load_error != 0 check, and the one line following it. The SELinux check following that should stay. I see. I guess this related to the question you raised in the other thread: Unit objects may or may not have a unit file on disk attached, and that's completely OK. We should do the access check on the label of the unit file if we have one, and otherwise fall back to some more generic selinux access check. Specifically that means here that u-load_error is nothing we need to explicitly check, as mac_selinux_unit_access_check() already has a generic fallback if the unit doesn't have a file associated. Long story short: just remove the two lines I pointed out, and leave the mac_selinux_unit_access_check() in place and all should be good. I see. I'll post v3 patch soon. Also, I'll include in the v3 patch set, a patch related to the question I raised in http://lists.freedesktop.org/archives/systemd-devel/2015-June/033104.html. -- Thanks. HATAYAMA, Daisuke ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Re: [systemd-devel] [PATCH v2] selinux: fix missing SELinux unit access check
From: Lennart Poettering lenn...@poettering.net Subject: Re: [systemd-devel] [PATCH v2] selinux: fix missing SELinux unit access check Date: Wed, 17 Jun 2015 18:25:32 +0200 On Wed, 10.06.15 14:40, HATAYAMA Daisuke (d.hatay...@jp.fujitsu.com) wrote: From 398deee74edb06b54b8a74c25697cd6d977d8f2d Mon Sep 17 00:00:00 2001 From: HATAYAMA Daisuke d.hatay...@jp.fujitsu.com Date: Wed, 10 Jun 2015 14:10:31 +0900 Subject: [PATCH] selinux: fix missing SELinux unit access check Currently, SELinux unit access check is not performed if a given unit file has not been registered in a hash table. This is because function manager_get_unit() only tries to pick up a Unit object from a Unit hash table. Instead, we use function manager_load_unit() searching Unit file pathes for the given Unit file. --- src/core/selinux-access.c | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) v2: - checking an error status by u-load_error to cover UNIT_ERROR case. diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c index decd42f..ac52906 100644 --- a/src/core/selinux-access.c +++ b/src/core/selinux-access.c @@ -292,8 +292,12 @@ int mac_selinux_unit_access_check_strv(char **units, int r; STRV_FOREACH(i, units) { -u = manager_get_unit(m, *i); +r = manager_load_unit(m, *i, NULL, error, u); +if (r 0) +return r; if (u) { +if (u-load_error != 0) +return u-load_error; r = mac_selinux_unit_access_check(u, message, permission, error); if (r 0) return r; I commented on the issue now in github, could you please follow up there? https://github.com/systemd/systemd/pull/145 Thanks for your reviewing. However, unfortunately, I cannot use github for some reason for now. So, please let me discuss in the mailing list. I'm sorry for the inconvenience. I don't think we should check this, it doesn't matter if we managed to successfully load the unit or not, we should still allow access either way. Sorry, I don't understand well. Do you mean removing this SELinux unit access check? If so, it means that current logic since the following commit, is changed, right? $ git log -1 -p 4f7385fa496242f06aaf358b66b28d71348607b3 commit 4f7385fa496242f06aaf358b66b28d71348607b3 Author: Lubomir Rintel lkund...@v3.sk Date: Fri Dec 6 14:05:49 2013 +0100 selinux: Check access vector for enable/disable perm for each unit file SELinux check will be done using the context of the unit file as as a target instead of the default init_t context, allowing selinux control on the level of individual units. https://bugzilla.redhat.com/show_bug.cgi?id=1022762 -- Thanks. HATAYAMA, Daisuke ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
[systemd-devel] A missing SELinux unit access check due to unexpected UNIT_NOT_FOUND unit object
:366 #8 0x7f01e5a6efeb in load_from_path (u=0x7f01e7b34030, path=0x7f01e7b34730 A.service) at src/core/load-fragment.c:3577 #9 0x7f01e5a6f1ec in unit_load_fragment (u=0x7f01e7b34030) at src/core/load-fragment.c:3613 #10 0x7f01e5a71b76 in service_load (u=0x7f01e7b34030) at src/core/service.c:601 #11 0x7f01e5b70006 in unit_load (u=0x7f01e7b34030) at src/core/unit.c:1203 #12 0x7f01e5a53dca in manager_dispatch_load_queue (m=0x7f01e7a93680) at src/core/manager.c:1290 #13 0x7f01e5a540d5 in manager_load_unit (m=0x7f01e7a93680, name=0x7f01e7b21010 sound.target, path=0x0, e=0x0, _ret=0x7ffd21b54dd0) at src/core/manager.c:1378 #14 0x7f01e5b744b0 in unit_add_dependency_by_name (u=0x7f01e7b56700, d=UNIT_WANTS, name=0x7f01e7b21010 sound.target, path=0x0, add_reference=true) at src/core/unit.c:2351 #15 0x7f01e5b86b31 in device_add_udev_wants (u=0x7f01e7b56700, dev=0x7f01e7b3fca0) at src/core/device.c:283 #16 0x7f01e5b870e3 in device_setup_unit (m=0x7f01e7a93680, dev=0x7f01e7b3fca0, path=0x7f01e7ac86a0 /sys/devices/pci:00/:00:04.0/sound/card0, main=true) at src/core/device.c:351 #17 0x7f01e5b87287 in device_process_new (m=0x7f01e7a93680, dev=0x7f01e7b3fca0) at src/core/device.c:382 #18 0x7f01e5b88107 in device_enumerate (m=0x7f01e7a93680) at src/core/device.c:670 #19 0x7f01e5a52d7a in manager_enumerate (m=0x7f01e7a93680) at src/core/manager.c:1002 #20 0x7f01e5a595e6 in manager_reload (m=0x7f01e7a93680) at src/core/manager.c:2571 #21 0x7f01e5a4e0f7 in main (argc=5, argv=0x7ffd21b55618) at src/core/main.c:1767 On the other hand, if we copy both unit service files and then try to enable both in order, this doesn't look to happen. Of course, I think this latter one that tries to enable *after* copies seems more natural than the first operation. -- Thanks. HATAYAMA, Daisuke ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
[systemd-devel] [PATCH v2] selinux: fix missing SELinux unit access check
I found an oversight in the previous v1 patch, found at http://lists.freedesktop.org/archives/systemd-devel/2015-June/032796.html, that u-load_state == UNIT_ERROR in the error path of unit_load(), that is: int unit_load(Unit *u) { int r; ...cut... fail: u-load_state = u-load_state == UNIT_STUB ? UNIT_NOT_FOUND : UNIT_ERROR; u-load_error = r; unit_add_to_dbus_queue(u); unit_add_to_gc_queue(u); log_unit_debug_errno(u, r, Failed to load configuration: %m); return r; } To fix this, this v2 version looks at u-load_error to check error status instead of u-load_state. How to reproduce Assume that test.service has not been loaded (even tried to get loaded) in this boot. Then, ~]# cat ./foo.sh #! /bin/sh mv test.service /etc/systemd/system systemctl daemon-reload systemctl enable test.service ~]# ./foo.sh Test I used selinux-context branch of https://github.com/keszybz/systemd.git in this test to avoid the issue in https://bugzilla.redhat.com/show_bug.cgi?id=1224211. -- Thanks. HATAYAMA, Daisuke From 398deee74edb06b54b8a74c25697cd6d977d8f2d Mon Sep 17 00:00:00 2001 From: HATAYAMA Daisuke d.hatay...@jp.fujitsu.com Date: Wed, 10 Jun 2015 14:10:31 +0900 Subject: [PATCH] selinux: fix missing SELinux unit access check Currently, SELinux unit access check is not performed if a given unit file has not been registered in a hash table. This is because function manager_get_unit() only tries to pick up a Unit object from a Unit hash table. Instead, we use function manager_load_unit() searching Unit file pathes for the given Unit file. --- src/core/selinux-access.c | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) v2: - checking an error status by u-load_error to cover UNIT_ERROR case. diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c index decd42f..ac52906 100644 --- a/src/core/selinux-access.c +++ b/src/core/selinux-access.c @@ -292,8 +292,12 @@ int mac_selinux_unit_access_check_strv(char **units, int r; STRV_FOREACH(i, units) { -u = manager_get_unit(m, *i); +r = manager_load_unit(m, *i, NULL, error, u); +if (r 0) +return r; if (u) { +if (u-load_error != 0) +return u-load_error; r = mac_selinux_unit_access_check(u, message, permission, error); if (r 0) return r; -- 2.1.0 ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Re: [systemd-devel] [PATCH] selinux: fix missing SELinux unit access check
From: HATAYAMA Daisuke d.hatay...@jp.fujitsu.com Subject: Re: [systemd-devel] [PATCH] selinux: fix missing SELinux unit access check Date: Wed, 10 Jun 2015 12:18:48 +0900 (JST) From: Lennart Poettering lenn...@poettering.net Subject: Re: [systemd-devel] [PATCH] selinux: fix missing SELinux unit access check Date: Mon, 8 Jun 2015 12:37:14 +0200 On Mon, 08.06.15 19:00, HATAYAMA Daisuke (d.hatay...@jp.fujitsu.com) wrote: Currently, SELinux unit access check is not performed if a given unit file has not been registered in a hash table. This is because function manager_get_unit() only tries to pick up a Unit object from a Unit hash table. Instead, we use function manager_load_unit() searching Unit file pathes for the given Unit file. Were precisely is this relevant? I mean, we generally invoke operations on units that are already loaded? The SELinux unit access check is performed in terms of the following rule: ~]# sesearch -A -s init_t | grep systemd_unit_file_type | grep service allow init_t systemd_unit_file_type : service { start stop status reload kill load enable disable } ; where systemd_unit_file_type is the attribute that is assigned to context types that unit files have, e.g. systemd_unit_file_t. Because this SELinux unit access check uses context types that unit files have, we need to be able to refer to given unit files when we perform requested unit operations. Here's how to reproduce this issue. Note that: - the systemd used here is with the fixing patch, and - test.service has not been loaded (even tried to get loaded) throughout this boot to guarantee that test.service is not registered in the unit hash table. Then, ~]# cat ./test.service [Unit] Description=test [Service] Type=oneshot ExecStart=/usr/bin/true RemainAfterExit=yes [Install] WantedBy=multi-user.target ~]# cat ./foo.sh #! /bin/sh mv test.service /etc/systemd/system systemctl daemon-reload systemctl enable test.service ~]# ./foo.sh Then, here is a gdb log: break mac_selinux_unit_access_check_strv Breakpoint 1 at 0x7f5339807a28: file src/core/selinux-access.c, line 288. (gdb) continue Continuing. Detaching after fork from child process 2198. Breakpoint 1, mac_selinux_unit_access_check_strv (units=0x7f533a1324f0, message=0x7f533a166a10, m=0x7f533a07c680, permission=0x7f533992bdb6 enable, error=0x7ffe80abaec0) at src/core/selinux-access.c:288 288 sd_bus_error *error) { (gdb) l 283 284 int mac_selinux_unit_access_check_strv(char **units, 285 sd_bus_message *message, 286 Manager *m, 287 const char *permission, 288 sd_bus_error *error) { 289 #ifdef HAVE_SELINUX 290 char **i; 291 Unit *u; 292 int r; (gdb) n 294 STRV_FOREACH(i, units) { (gdb) n 295 r = manager_load_unit(m, *i, NULL, error, u); (gdb) s manager_load_unit (m=0x7f533a07c680, name=0x7f533a11ef30 test.service, path=0x0, e=0x7ffe80abaec0, _ret=0x7ffe80abad80) at src/core/manager.c:1369 1369assert(m); (gdb) n 1374r = manager_load_unit_prepare(m, name, path, e, _ret); (gdb) n 1375if (r != 0) (gdb) n 1378manager_dispatch_load_queue(m); (gdb) p r $1 = 0 Here variable r has a return value of manager_load_unit_prepare() and its value is 0 here, meaning that now there's no unit file with the requested unit file name in the unit hash table. (gdb) p *_ret $2 = (Unit *) 0x7f533a166ea0 (gdb) p *_ret-load_state Attempt to take contents of a non-pointer value. (gdb) p (*_ret)-load_state $3 = UNIT_STUB Actually, its load_state is still UNIT_STUB. (gdb) n 1380if (_ret) (gdb) p (*_ret)-load_state $4 = UNIT_LOADED After dipatching the load queue by manager_dispatch_load_queue(), the given unit file has just been loaded and the load_state has been changed into UNIT_LOADED. (gdb) finish Run till exit from #0 manager_load_unit (m=0x7f533a07c680, name=0x7f533a11ef30 test.service, path=0x0, e=0x7ffe80abaec0, _ret=0x7ffe80abad80) at src/core/manager.c:1380 0x7f5339807a6a in mac_selinux_unit_access_check_strv (units=0x7f533a1324f0, message=0x7f533a166a10, m=0x7f533a07c680, permission=0x7f533992bdb6 enable, error=0x7ffe80abaec0) at src/core/selinux-access.c:295 295 r = manager_load_unit(m, *i, NULL, error, u); (gdb) continue Also, I used selinux-context branch of https://github.com/keszybz/systemd.git in this test to avoid the issue in https://bugzilla.redhat.com/show_bug.cgi?id=1224211. -- Thanks. HATAYAMA, Daisuke ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Re: [systemd-devel] [PATCH] selinux: fix missing SELinux unit access check
From: Lennart Poettering lenn...@poettering.net Subject: Re: [systemd-devel] [PATCH] selinux: fix missing SELinux unit access check Date: Mon, 8 Jun 2015 12:37:14 +0200 On Mon, 08.06.15 19:00, HATAYAMA Daisuke (d.hatay...@jp.fujitsu.com) wrote: Currently, SELinux unit access check is not performed if a given unit file has not been registered in a hash table. This is because function manager_get_unit() only tries to pick up a Unit object from a Unit hash table. Instead, we use function manager_load_unit() searching Unit file pathes for the given Unit file. Were precisely is this relevant? I mean, we generally invoke operations on units that are already loaded? The SELinux unit access check is performed in terms of the following rule: ~]# sesearch -A -s init_t | grep systemd_unit_file_type | grep service allow init_t systemd_unit_file_type : service { start stop status reload kill load enable disable } ; where systemd_unit_file_type is the attribute that is assigned to context types that unit files have, e.g. systemd_unit_file_t. Because this SELinux unit access check uses context types that unit files have, we need to be able to refer to given unit files when we perform requested unit operations. Here's how to reproduce this issue. Note that: - the systemd used here is with the fixing patch, and - test.service has not been loaded (even tried to get loaded) throughout this boot to guarantee that test.service is not registered in the unit hash table. Then, ~]# cat ./test.service [Unit] Description=test [Service] Type=oneshot ExecStart=/usr/bin/true RemainAfterExit=yes [Install] WantedBy=multi-user.target ~]# cat ./foo.sh #! /bin/sh mv test.service /etc/systemd/system systemctl daemon-reload systemctl enable test.service ~]# ./foo.sh Then, here is a gdb log: break mac_selinux_unit_access_check_strv Breakpoint 1 at 0x7f5339807a28: file src/core/selinux-access.c, line 288. (gdb) continue Continuing. Detaching after fork from child process 2198. Breakpoint 1, mac_selinux_unit_access_check_strv (units=0x7f533a1324f0, message=0x7f533a166a10, m=0x7f533a07c680, permission=0x7f533992bdb6 enable, error=0x7ffe80abaec0) at src/core/selinux-access.c:288 288 sd_bus_error *error) { (gdb) l 283 284 int mac_selinux_unit_access_check_strv(char **units, 285 sd_bus_message *message, 286 Manager *m, 287 const char *permission, 288 sd_bus_error *error) { 289 #ifdef HAVE_SELINUX 290 char **i; 291 Unit *u; 292 int r; (gdb) n 294 STRV_FOREACH(i, units) { (gdb) n 295 r = manager_load_unit(m, *i, NULL, error, u); (gdb) s manager_load_unit (m=0x7f533a07c680, name=0x7f533a11ef30 test.service, path=0x0, e=0x7ffe80abaec0, _ret=0x7ffe80abad80) at src/core/manager.c:1369 1369assert(m); (gdb) n 1374r = manager_load_unit_prepare(m, name, path, e, _ret); (gdb) n 1375if (r != 0) (gdb) n 1378manager_dispatch_load_queue(m); (gdb) p r $1 = 0 Here variable r has a return value of manager_load_unit_prepare() and its value is 0 here, meaning that now there's no unit file with the requested unit file name in the unit hash table. (gdb) p *_ret $2 = (Unit *) 0x7f533a166ea0 (gdb) p *_ret-load_state Attempt to take contents of a non-pointer value. (gdb) p (*_ret)-load_state $3 = UNIT_STUB Actually, its load_state is still UNIT_STUB. (gdb) n 1380if (_ret) (gdb) p (*_ret)-load_state $4 = UNIT_LOADED After dipatching the load queue by manager_dispatch_load_queue(), the given unit file has just been loaded and the load_state has been changed into UNIT_LOADED. (gdb) finish Run till exit from #0 manager_load_unit (m=0x7f533a07c680, name=0x7f533a11ef30 test.service, path=0x0, e=0x7ffe80abaec0, _ret=0x7ffe80abad80) at src/core/manager.c:1380 0x7f5339807a6a in mac_selinux_unit_access_check_strv (units=0x7f533a1324f0, message=0x7f533a166a10, m=0x7f533a07c680, permission=0x7f533992bdb6 enable, error=0x7ffe80abaec0) at src/core/selinux-access.c:295 295 r = manager_load_unit(m, *i, NULL, error, u); (gdb) continue Signed-off-by: HATAYAMA Daisuke d.hatay...@jp.fujitsu.com We don't use S-o-b in systemd. Sorry, I'll not use the tag next. I decided to use it becuase I found commits with the tag in git log (of course, I found the commits without the tag, too). -- Thanks. HATAYAMA, Daisuke ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
[systemd-devel] [PATCH] selinux: fix missing SELinux unit access check
Currently, SELinux unit access check is not performed if a given unit file has not been registered in a hash table. This is because function manager_get_unit() only tries to pick up a Unit object from a Unit hash table. Instead, we use function manager_load_unit() searching Unit file pathes for the given Unit file. Signed-off-by: HATAYAMA Daisuke d.hatay...@jp.fujitsu.com --- src/core/selinux-access.c | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c index decd42f..36bdbcc 100644 --- a/src/core/selinux-access.c +++ b/src/core/selinux-access.c @@ -292,8 +292,12 @@ int mac_selinux_unit_access_check_strv(char **units, int r; STRV_FOREACH(i, units) { -u = manager_get_unit(m, *i); +r = manager_load_unit(m, *i, NULL, error, u); +if (r 0) +return r; if (u) { +if (u-load_state == UNIT_NOT_FOUND) +return -ENOENT; r = mac_selinux_unit_access_check(u, message, permission, error); if (r 0) return r; -- 2.1.0 ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Re: [systemd-devel] [PATCH] tty-ask-password-agent: reset a signal handler for SIGTERM to the default
(2014/08/28 4:46), Lennart Poettering wrote: On Wed, 27.08.14 09:47, HATAYAMA, Daisuke (d.hatay...@jp.fujitsu.com) wrote: Sounds like the right option here... I have now added a slightly different patch (1dedb74a2e1d840b531b76b01a76979f3b57456b) that does this. Thanks! But this could still hang in very rare case becuase the reset is done in a child process after fork(). Please consider the case where the child process continue sleeping after fork() before resetting signal handlers until it receives SIGTERM. For such reason, my patch resets SIGTERM signal handler in the parent systemctl side. Hmm, there's indeed a race here. I add a commit now that will block all signals before forking, and unblocks them afterwards. The new process will hence be created with all signals blocked, and we will hence not lose them until we after we reset the signal handlers... Hope this makes sense? (Blocking the signals temporarily, instead of resetting the signal handlers has the benefit, that we signal masks are per-thread, and not per-process, like signal handlers are. The code hence stays generic enough to not break should the call ever get invoked from a threaded process...) Thanks! It's smarter than my patch. Also, I verified your fix by artifically creating the problematic case by making prctl() sleep 5 seconds using kprobes, and I think this now works well. For example, systemctl with the first patch applied only hangs like this ]# strace -ff -F -e trace=clone,execve,rt_sigprocmask,signalfd4,poll,kill,waitid systemctl stop kdump execve(/usr/bin/systemctl, [systemctl, stop, kdump], [/* 29 vars */]) = 0 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0 poll([{fd=4, events=POLLOUT}], 1, 9) = 1 ([{fd=4, revents=POLLOUT}]) poll([{fd=4, events=POLLIN}], 1, 9) = 1 ([{fd=4, revents=POLLIN}]) poll([{fd=4, events=POLLOUT}], 1, 9) = 1 ([{fd=4, revents=POLLOUT}]) poll([{fd=4, events=POLLIN}], 1, 9) = 1 ([{fd=4, revents=POLLIN}]) poll([{fd=4, events=POLLOUT}], 1, 9) = 1 ([{fd=4, revents=POLLOUT}]) clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f41511c7b50) = 9723 poll([{fd=4, events=POLLIN}], 1, 25000) = 1 ([{fd=4, revents=POLLIN}]) poll([{fd=4, events=POLLIN}], 1, 25000) = 1 ([{fd=4, revents=POLLIN}]) poll([{fd=4, events=POLLIN}], 1, 25000) = 1 ([{fd=4, revents=POLLIN}]) poll([{fd=4, events=POLLIN}], 1, 25000) = 1 ([{fd=4, revents=POLLIN}]) poll([{fd=4, events=POLLIN}], 1, 25000) = 1 ([{fd=4, revents=POLLIN}]) kill(9723, SIGTERM) = 0 kill(9723, SIGCONT) = 0 waitid(P_PID, 9723, Process 9723 attached unfinished ... [pid 9723] --- SIGTERM {si_signo=SIGTERM, si_code=SI_USER, si_pid=9722, si_uid=0} --- [pid 9723] --- SIGCONT {si_signo=SIGCONT, si_code=SI_USER, si_pid=9722, si_uid=0} --- [pid 9723] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 [pid 9723] execve(/usr/bin/systemd-tty-ask-password-agent, [/usr/bin/systemd-tty-ask-passwor..., --watch], [/* 29 vars */]) = 0 [pid 9723] rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0 [pid 9723] rt_sigprocmask(SIG_SETMASK, [INT TERM], NULL, 8) = 0 [pid 9723] signalfd4(-1, [INT TERM], 8, O_NONBLOCK|O_CLOEXEC) = 5 [pid 9723] poll([{fd=4, events=POLLIN}, {fd=5, events=POLLIN}], 2, 4294967295 while systemctl with the second patch doesn't hang like this ]# strace -ff -F -e trace=clone,execve,rt_sigprocmask,signalfd4,poll,kill,waitid systemctl stop kdump execve(/usr/bin/systemctl, [systemctl, stop, kdump], [/* 29 vars */]) = 0 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0 poll([{fd=4, events=POLLOUT}], 1, 9) = 1 ([{fd=4, revents=POLLOUT}]) poll([{fd=4, events=POLLIN}], 1, 9) = 1 ([{fd=4, revents=POLLIN}]) poll([{fd=4, events=POLLOUT}], 1, 9) = 1 ([{fd=4, revents=POLLOUT}]) poll([{fd=4, events=POLLIN}], 1, 9) = 1 ([{fd=4, revents=POLLIN}]) poll([{fd=4, events=POLLOUT}], 1, 9) = 1 ([{fd=4, revents=POLLOUT}]) rt_sigprocmask(SIG_SETMASK, ~[RTMIN RT_1], [], 8) = 0 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fc2780dcb50) = 9794 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 poll([{fd=4, events=POLLIN}], 1, 25000) = 1 ([{fd=4, revents=POLLIN}]) poll([{fd=4, events=POLLIN}], 1, 25000) = 1 ([{fd=4, revents=POLLIN}]) poll([{fd=4, events=POLLIN}], 1, 25000) = 1 ([{fd=4, revents=POLLIN}]) poll([{fd=4, events=POLLIN}], 1, 25000) = 1 ([{fd=4, revents=POLLIN}]) poll([{fd=4, events=POLLIN}], 1, 25000) = 1 ([{fd=4, revents=POLLIN}]) kill(9794, SIGTERM) = 0 kill(9794, SIGCONT) = 0 waitid(P_PID, 9794, Process 9794 attached unfinished ... [pid 9794] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 [pid 9794] --- SIGTERM {si_signo=SIGTERM, si_code=SI_USER, si_pid=9793, si_uid=0} --- [pid 9794] +++ killed by SIGTERM +++ ... waitid resumed {si_signo=SIGCHLD, si_code=CLD_KILLED, si_pid=9794, si_status=SIGTERM, si_utime=0, si_stime=0}, WEXITED, NULL) = 0
Re: [systemd-devel] [PATCH] tty-ask-password-agent: reset a signal handler for SIGTERM to the default
(2014/08/27 4:17), Lennart Poettering wrote: On Mon, 25.08.14 12:32, HATAYAMA Daisuke (d.hatay...@jp.fujitsu.com) wrote: Hello, Heya! When trapping SIGTERM in a script and running systemctl from the script, systemctl sometimes hangs with tty-ask-password agent process. Hmm, so in general, if people invoke our tools with weird signal masks I'd blame it on them, we shouldn't have to reset the signal masks in all our tools all the time... I mean, of course, if SIGTERM then doesn't work on the process, we can just blame the process that invoked us... However in this case, where we fork off the agent process on our own, and rely on sending SIGTERM to it, and actually work I think it's our duty to fix things up, so that we don't leave processes around... I have no idea whether systemd developpers think this is a bug or not. If this is a bug, I have three ideas to fix this. This patch is based on the 1). 1) Reset a signal handler for SIGTERM to the default before spawning an agent process from systemctl. Sounds like the right option here... I have now added a slightly different patch (1dedb74a2e1d840b531b76b01a76979f3b57456b) that does this. Thanks! But this could still hang in very rare case becuase the reset is done in a child process after fork(). Please consider the case where the child process continue sleeping after fork() before resetting signal handlers until it receives SIGTERM. For such reason, my patch resets SIGTERM signal handler in the parent systemctl side. -- Thanks. HATAYAMA, Daisuke ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
[systemd-devel] [PATCH] tty-ask-password-agent: reset a signal handler for SIGTERM to the default
Hello, When trapping SIGTERM in a script and running systemctl from the script, systemctl sometimes hangs with tty-ask-password agent process. I have no idea whether systemd developpers think this is a bug or not. If this is a bug, I have three ideas to fix this. This patch is based on the 1). 1) Reset a signal handler for SIGTERM to the default before spawning an agent process from systemctl. 2) Prepare a timeout limit in systemctl. If it exceeds the limit, kill the agent process forsively by SIGKILL. 3) Use another IPC instead signal mechanism to kill the agent process such as pipe. == Subject: [PATCH] tty-ask-password-agent: reset a signal handler for SIGTERM to the default If a signal handler for SIGTERM is SIG_IGN, SIGTERM could be immediately processed before sigprocmask(). Then, as a result, systemctl hangs at waitid() and agent at poll(). The actual case where a signal handler for SIGTERM becomes SIG_IGN is when systemctl is used in a service script that traps SIGTERM. Here is an example. ~]# trap 15 ~]# strace -ff -F -e trace=clone,execve,rt_sigprocmask,signalfd4,poll,kill,waitid systemctl stop kdump execve(/usr/bin/systemctl, [systemctl, stop, kdump], [/* 30 vars */]) = 0 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0 poll([{fd=4, events=POLLOUT}], 1, 9) = 1 ([{fd=4, revents=POLLOUT}]) poll([{fd=4, events=POLLIN}], 1, 9) = 1 ([{fd=4, revents=POLLIN}]) poll([{fd=4, events=POLLOUT}], 1, 9) = 1 ([{fd=4, revents=POLLOUT}]) poll([{fd=4, events=POLLIN}], 1, 9) = 1 ([{fd=4, revents=POLLIN}]) poll([{fd=4, events=POLLOUT}], 1, 9) = 1 ([{fd=4, revents=POLLOUT}]) clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fe39df60b50) = 19820 poll([{fd=4, events=POLLIN}], 1, 25000) = 1 ([{fd=4, revents=POLLIN}]) poll([{fd=4, events=POLLIN}], 1, 25000) = 1 ([{fd=4, revents=POLLIN}]) poll([{fd=4, events=POLLIN}], 1, 25000) = 1 ([{fd=4, revents=POLLIN}]) poll([{fd=4, events=POLLIN}], 1, 25000) = 1 ([{fd=4, revents=POLLIN}]) poll([{fd=4, events=POLLIN}], 1, 25000) = 1 ([{fd=4, revents=POLLIN}]) kill(19820, SIGTERM)= 0 kill(19820, SIGCONT)= 0 waitid(P_PID, 19820, Process 19820 attached unfinished ... [pid 19820] --- SIGTERM {si_signo=SIGTERM, si_code=SI_USER, si_pid=19819, si_uid=0} --- [pid 19820] --- SIGCONT {si_signo=SIGCONT, si_code=SI_USER, si_pid=19819, si_uid=0} --- [pid 19820] execve(/usr/bin/systemd-tty-ask-password-agent, [/usr/bin/systemd-tty-ask-passwor..., --watch], [/* 30 vars */]) = 0 [pid 19820] rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0 [pid 19820] rt_sigprocmask(SIG_SETMASK, [INT TERM], NULL, 8) = 0 [pid 19820] signalfd4(-1, [INT TERM], 8, O_NONBLOCK|O_CLOEXEC) = 5 [pid 19820] poll([{fd=4, events=POLLIN}, {fd=5, events=POLLIN}], 2, 4294967295 --- src/shared/spawn-ask-password-agent.c | 16 1 file changed, 16 insertions(+) diff --git a/src/shared/spawn-ask-password-agent.c b/src/shared/spawn-ask-password-agent.c index c1a9c58..604fad6 100644 --- a/src/shared/spawn-ask-password-agent.c +++ b/src/shared/spawn-ask-password-agent.c @@ -34,6 +34,10 @@ static pid_t agent_pid = 0; int ask_password_agent_open(void) { +struct sigaction sa_old, sa_new = { +.sa_handler = SIG_DFL, +.sa_flags = SA_RESTART, +}; int r; if (agent_pid 0) @@ -44,6 +48,15 @@ int ask_password_agent_open(void) { if (!isatty(STDIN_FILENO)) return 0; +/* If a signal handler for SIGTERM is SIG_IGN, it's + * immediately processed by systemd-tty-ask-password process + * before sigprocmask() and then systemctl hangs at waitid() + * and agent at poll(). To avoid such case, reset a signal + * hander for SIGTERM to the default. + */ +if (sigaction(SIGTERM, sa_new, sa_old) 0) +return -errno; + r = fork_agent(agent_pid, NULL, 0, SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, @@ -51,6 +64,9 @@ int ask_password_agent_open(void) { if (r 0) log_error(Failed to fork TTY ask password agent: %s, strerror(-r)); +if (sigaction(SIGTERM, sa_old, NULL) 0) +return -errno; + return r; } -- 1.9.3 ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
[systemd-devel] [Question] How to specify LimitCORE=infinity for all the daemon processes?
Hello, I'm now looking for a way of specifying DefaultLimitCORE for all the daemon processes using systemd. I've already tried the following things: - Specify DefaultLimitCORE=infinity in /etc/systemd/system.conf but by which only normal processes were configured; daemon processes were not configured. - Specify LimitCORE=infinity in each *.service unit file by which I confirmed the corresponding daemon process was configured as I intended. So, is there a way to specify LimitCORE=infinity for all the daemon processes uniformly using systemd framework? On sysvinit, this can be done by defining DAEMON_COREFILE_LIMIT in /etc/sysconfig/init. BTW, I know abrt can collect daemon process's coredump and can be used for this purpose, but the question is the case where abrt is not used. Thanks. HATAYAMA, Daisuke ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Re: [systemd-devel] [Question] How to specify LimitCORE=infinity for all the daemon processes?
From: Oleksii Shevchuk shevc...@iit.kharkov.ua Subject: Re: [systemd-devel] [Question] How to specify LimitCORE=infinity for all the daemon processes? Date: Wed, 20 Feb 2013 11:53:00 +0200 By default services has infty limit, afaik If you have 25M truncated cores, that's because of systemd-coredump limitation. Feel free to try this patch: http://lists.freedesktop.org/archives/systemd-devel/2013-February/009065.html Thanks for your suggestion. But, sadly, it would be different from what I mean. I want to specify soft limit for daemon processes only and uniformly in one configuration; I don't want to write configuration over and over for each service. What I look at for the soft limit is, for example: $ cat /proc/$(pgrep crond)/limits Limit Soft Limit Hard Limit Units Max cpu time unlimitedunlimitedseconds Max file size unlimitedunlimitedbytes Max data size unlimitedunlimitedbytes Max stack size8388608 unlimitedbytes Max core file size0unlimitedbytes -- this cut This is under default configuration. - Specify LimitCORE=infinity in each *.service unit file by this, daemon process has unlimited for soft limit. $ cat /proc/$(pgrep crond)/limits Limit Soft Limit Hard Limit Units Max cpu time unlimitedunlimitedseconds Max file size unlimitedunlimitedbytes Max data size unlimitedunlimitedbytes Max stack size8388608 unlimitedbytes Max core file sizeunlimitedunlimitedbytes -- this cut For normal processes, - Specify DefaultLimitCORE=infinity in /etc/systemd/system.conf by this, normal processes, deamon, has unlimited for soft limit, like: $ sleep 1000 [1] 2750 $ cat /proc/2750/limits Limit Soft Limit Hard Limit Units Max cpu time unlimitedunlimitedseconds Max file size unlimitedunlimitedbytes Max data size unlimitedunlimitedbytes Max stack size872 unlimitedbytes Max core file sizeunlimitedunlimitedbytes -- cut cut So, I've already understood we can get daemon processes. My question is how to configure for each daemon to have unlimited in their soft limit by one configuration in systemd framework. BTW, I heard systemd-coredump for the first time. Does this mean some particular feature of systemd concerning core dump? Thanks. HATAYAMA, Daisuke ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Re: [systemd-devel] [Question] How to specify LimitCORE=infinity for all the daemon processes?
From: Colin Guthrie gm...@colin.guthr.ie Subject: Re: [systemd-devel] [Question] How to specify LimitCORE=infinity for all the daemon processes? Date: Wed, 20 Feb 2013 14:10:13 + 'Twas brillig, and Oleksii Shevchuk at 20/02/13 09:53 did gyre and gimble: By default services has infty limit, afaik If you have 25M truncated cores, that's because of systemd-coredump limitation. Feel free to try this patch: http://lists.freedesktop.org/archives/systemd-devel/2013-February/009065.html Or you can configure the journal to not capture coredumps at all, either via a compile time option or a sysctl tweak (kernel.core_pattern I think). Hello, thanks for your reaction. For the sysctl tweak, yes, kernel core dumper ignores soft limit if target is pipe specified by kernel.core_pattern. I said abrt works well in the question mail and abrt is one of the users using kernel.core_pattern; more precisely, it's abrt-ccpp. And, from your suggestion, I found that systemd framework does something similar to abrt such as systemd-coredumpctl, although this appears not to used fedora 18 at default; abrt is used. $ cat /proc/sys/kernel/core_pattern |/usr/libexec/abrt-hook-ccpp %s %c %p %u %g %t e Hmm, I'm beginning with considering that some particular journaling daemon collects core dumps via core_pattern's pipe is becoming standard, manually collecting each process's corefiles are obsolete, and so there's no configuring daemon's soft limit at the same time in one configuration on systemd framework? Thanks. HATAYAMA, Daisuke ___ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel