[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