[systemd-devel] A missing SELinux unit access check due to unexpected UNIT_NOT_FOUND unit object
HATAYAMA Daisuke
d.hatayama at jp.fujitsu.com
Thu Jun 18 02:14:33 PDT 2015
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.
I'm investigating this now but I don't figure out whether this is a
really a bug or not because this happens only in a kind of rough
operation.
Could anyone tell me this is a bug? Is there any documentation to
avoid this kind of operation?
Here is how to reproduce the situation.
There are 2 unit files: A.service and B.service. A.service has After=
dependency to B.service.
~]# cat ./A.service
[Unit]
After=B.service
[Service]
ExecStart=/usr/bin/true
[Install]
WantedBy=multi-user.target
~]# cat ./B.service
[Service]
ExecStart=/usr/bin/true
[Install]
WantedBy=multi-user.target
Then, copy these unit files into some unit file path and try to enable
them *first A.service and then B.service*. Then, we see:
~]# cp A.service /usr/lib/systemd/system; systemctl enable A.service; cp B.service /usr/lib/systemd/system; systemctl enable B.service
Created symlink from /etc/systemd/system/multi-user.target.wants/A.service to /usr/lib/systemd/system/A.service.
Created symlink from /etc/systemd/system/multi-user.target.wants/B.service to /usr/lib/systemd/system/B.service.
~]#
Although both systemctl enable looks performed successfully, at the
latter systemctl enable B.services, SELinux unit access check is not
performed as follows.
Using gdb:
int mac_selinux_unit_access_check_strv(char **units,
sd_bus_message *message,
Manager *m,
const char *permission,
sd_bus_error *error) {
#ifdef HAVE_SELINUX
char **i;
Unit *u;
int r;
STRV_FOREACH(i, units) {
u = manager_get_unit(m, *i);
=> if (u) {
r = mac_selinux_unit_access_check(u, message, permission, error);
if (r < 0)
return r;
}
}
#endif
return 0;
}
Looking at the returned object u, this remains UNIT_NOT_FOUND.
(gdb) s
mac_selinux_unit_access_check_strv (units=0x7f01e7ac71e0, message=0x7f01e7af3d10, m=0x7f01e7a93680, permission=0x7f01e5bd7d36 "enable", error=0x7ffd21b54d70) at src/core/selinux-access.c:294
294 STRV_FOREACH(i, units) {
(gdb) n
295 u = manager_get_unit(m, *i);
(gdb)
296 if (u) {
(gdb) p u->load_state
$7 = UNIT_NOT_FOUND
(gdb) p *u
I think the left unit object in UNIT_NOT_FOUND was generated when
A.service was loaded in the following path:
(gdb) p text
$1 = 0x7f01e7ad73a0 "B.service"
(gdb) bt
#0 unit_add_name (u=0x7f01e7aa9980, text=0x7f01e7ad73a0 "B.service") at src/core/unit.c:139
#1 0x00007f01e5a53ffa in manager_load_unit_prepare (m=0x7f01e7a93680, name=0x7f01e7ad73a0 "B.service", path=0x0, e=0x0, _ret=0x7ffd21b53f40) at src/core/manager.c:1344
#2 0x00007f01e5a540bb in manager_load_unit (m=0x7f01e7a93680, name=0x7f01e7ad73a0 "B.service", path=0x0, e=0x0, _ret=0x7ffd21b53f40) at src/core/manager.c:1374
#3 0x00007f01e5b744b0 in unit_add_dependency_by_name (u=0x7f01e7b34030, d=UNIT_AFTER, name=0x7f01e7ad73a0 "B.service", path=0x0, add_reference=true) at src/core/unit.c:2351
#4 0x00007f01e5a60b34 in config_parse_unit_deps (unit=0x7f01e7b34730 "A.service", filename=0x7f01e7a90040 "/usr/lib/systemd/system/A.service", line=6, section=0x7f01e7ad7740 "Unit", section_line=5, lvalue=0x7ffd21b542d0 "Aft\
er", ltype=17, rvalue=0x7ffd21b542d6 "B.service", data=0x7f01e7b34030, userdata=0x7f01e7b34030) at src/core/load-fragment.c:128
#5 0x00007f01e5acba34 in next_assignment (unit=0x7f01e7b34730 "A.service", filename=0x7f01e7a90040 "/usr/lib/systemd/system/A.service", line=6, lookup=0x7f01e5acb688 <config_item_perf_lookup>, table=0x7f01e5abee29 <load_frag\
ment_gperf_lookup>, section=0x7f01e7ad7740 "Unit", section_line=5, lvalue=0x7ffd21b542d0 "After", rvalue=0x7ffd21b542d6 "B.service", relaxed=false, userdata=0x7f01e7b34030) at src/shared/conf-parser.c:141
#6 0x00007f01e5acc298 in parse_line (unit=0x7f01e7b34730 "A.service", filename=0x7f01e7a90040 "/usr/lib/systemd/system/A.service", line=6, sections=0x7f01e5bd1117 "Unit", lookup=0x7f01e5acb688 <config_item_perf_lookup>, tabl\
e=0x7f01e5abee29 <load_fragment_gperf_lookup>, relaxed=false, allow_include=true, section=0x7ffd21b542a0, section_line=0x7ffd21b5427c, section_ignored=0x7ffd21b5427a, l=0x7ffd21b542d0 "After", userdata=0x7f01e7b34030) at src/\
shared/conf-parser.c:266
#7 0x00007f01e5acc814 in config_parse (unit=0x7f01e7b34730 "A.service", filename=0x7f01e7a90040 "/usr/lib/systemd/system/A.service", f=0x7f01e7b35e30, sections=0x7f01e5bd1117 "Unit", lookup=0x7f01e5acb688 <config_item_perf_l\
ookup>, table=0x7f01e5abee29 <load_fragment_gperf_lookup>, relaxed=false, allow_include=true, warn=false, userdata=0x7f01e7b34030) at src/shared/conf-parser.c:366
#8 0x00007f01e5a6efeb in load_from_path (u=0x7f01e7b34030, path=0x7f01e7b34730 "A.service") at src/core/load-fragment.c:3577
#9 0x00007f01e5a6f1ec in unit_load_fragment (u=0x7f01e7b34030) at src/core/load-fragment.c:3613
#10 0x00007f01e5a71b76 in service_load (u=0x7f01e7b34030) at src/core/service.c:601
#11 0x00007f01e5b70006 in unit_load (u=0x7f01e7b34030) at src/core/unit.c:1203
#12 0x00007f01e5a53dca in manager_dispatch_load_queue (m=0x7f01e7a93680) at src/core/manager.c:1290
#13 0x00007f01e5a540d5 in manager_load_unit (m=0x7f01e7a93680, name=0x7f01e7b21010 "sound.target", path=0x0, e=0x0, _ret=0x7ffd21b54dd0) at src/core/manager.c:1378
#14 0x00007f01e5b744b0 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 0x00007f01e5b86b31 in device_add_udev_wants (u=0x7f01e7b56700, dev=0x7f01e7b3fca0) at src/core/device.c:283
#16 0x00007f01e5b870e3 in device_setup_unit (m=0x7f01e7a93680, dev=0x7f01e7b3fca0, path=0x7f01e7ac86a0 "/sys/devices/pci0000:00/0000:00:04.0/sound/card0", main=true) at src/core/device.c:351
#17 0x00007f01e5b87287 in device_process_new (m=0x7f01e7a93680, dev=0x7f01e7b3fca0) at src/core/device.c:382
#18 0x00007f01e5b88107 in device_enumerate (m=0x7f01e7a93680) at src/core/device.c:670
#19 0x00007f01e5a52d7a in manager_enumerate (m=0x7f01e7a93680) at src/core/manager.c:1002
#20 0x00007f01e5a595e6 in manager_reload (m=0x7f01e7a93680) at src/core/manager.c:2571
#21 0x00007f01e5a4e0f7 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
More information about the systemd-devel
mailing list