2018-01-25 17:17 GMT+01:00 Ricardo Wurmus : > Hi Guix, > > attached is a patch that adds an SELinux policy for the guix-daemon. > The policy defines the guix_daemon_t domain and specifies what labels > may be accessed and how by processes running in that domain. > > These file labels are defined: > > * guix_daemon_conf_t > for Guix configuration files (in localstatedir and sysconfdir) > * guix_daemon_exec_t > for executables spawned by the daemon (which are allowed to run in the > guix_daemon_t domain) > * guix_daemon_socket_t > for the daemon socket file > * guix_profiles_t > for the contents of the profiles directory > > The “filecon” statements near the bottom of the file specify which > labels are to be used for what file names. > > I tested this with “guix build --no-grafts --check hello”, “guix build > samtools”, “guix gc -C 1k”, and “guix package -p ~/foo -i hello”; > no operations were blocked by SELinux. > > If you want to test this on Fedora, set SELinux to permissive, and make > sure to configure Guix properly (i.e. set localstatedir, prefix, and > sysconfdir). Then install the policy with “sudo semodule -i > etc/guix-daemon.cil”. Then relabel the filesystem (at least /gnu, > $localstatedir, $sysconfdir, and $prefix) with something like this: > > sudo restorecon -R /gnu $localstatedir $sysconfdir $prefix > > This will take a very long time (a couple of hours). > > Restart the daemon. Check that it now runs in the guix_daemon_t > context: > > ps -Zax | grep /bin/guix-daemon > > This should return something like this > > system_u:system_r:guix_daemon.guix_daemon_t:s0 14886 ? Ss 0:00 > /root/.guix-profile/bin/guix-daemon --build-users-group=guix-builder > > Check the audit log for violations: > > sudo tail -f /var/log/audit/audit.log | grep x-daemon > > And then use Guix: > > guix build --no-grafts --check hello > > The audit log shouldn’t show you any complaints. At this point you > could probably switch to enforcing mode, but I haven’t tested this > myself for no particular reason. > > Open issues: > > * guix_daemon_socket_t isn’t actually used. All of the socket > operations that I observed involve contexts that don’t have anything > to do with guix_daemon_socket_t. It doesn’t hurt to have this unused > label, but I would have preferred to define socket rules for only this > label. Oh well. > > * “guix gc” cannot access arbitrary links to profiles. By design, the > file label of the destination of a symlink is independent of the file > label of the link itself. Although all profiles under $localstatedir > are labelled, the links to these profiles inherit the label of the > directory they are in. For links in the user’s home directory this > will be “user_home_t” (for which I’ve added a rule). But for links > from root’s home directory, or /tmp, or the HTTP server’s working > directory … this won’t work. “guix gc” would be prevented from > reading and following these links. > > * I don’t know if the daemon’s TCP listen feature still works. I didn’t > test it and assume that it would require extra rules, because SELinux > treats network sockets differently from files. > > * Is this all correct? I don’t know! I only just learned about the > SELinux Common Intermediate Language (CIL), and the documentation is > very sparse, so I have no idea if I did something stupid. It seems > fine to me, but I must admit that I find it a bit uncomfortable to see > so many access types in the rules. > > * I allowed type transitions from init_t to guix_daemon_t via > guix_daemon_exec_t, but also from guix_store_content_t to > guix_daemon_t via guix_daemon_exec_t. Type transitions are necessary > to get from an allowed entry point to a domain. On Fedora “init_t” is > the domain in which processes are that are spawned by the init > system. With the first type transition I permit these processes to > transition to the guix_daemon_t domain when the executables are > labeled as guix_daemon_exec_t (such as the daemon executable itself, > and all the helpers it spawns). > > This much is obvious. But the second type transition is less obvious. > It is needed to make sure that we can enter the guix_daemon_t domain > even when running the daemon from an executable in the store (which > will be running in the “guix_store_content_t” domain). Thinking of > this, I wonder if maybe that’s actually a mistake and shouldn’t be > permitted. > > * A possible problem is that I assign all files with a name matching > “/gnu/store/.+-(guix-.+|profile)/bin/guix-daemon” the label > “guix_daemon_exec_t”; this means that *any* file with that name in any > profile would be permitted to run in the guix_daemon_t domain. This > is not ideal. An attacker could build a package that provides this > executable and convince a user to install and run it, which lifts it > into the guix_daemon_t domain. At that point SELinux could not > prevent it from accessing files that are allowed for processes in that > domain (such as the actual daemon). > > This makes me wonder if we could do better by generating a much more > restrictive policy at installation time, so that only the *exact* file > name of the currently installed guix-daemon executable would be > labelled with guix_daemon_exec_t, instead of using a regular > expression like that. This means that root would have to > install/upgrade the policy at installation time whenever the Guix > package that provides the effectively running guix-daemon executable > is upgraded. Food for thought. > > Without further ado, here’s the patch: > > > > -- > Ricardo > > Ok, I followed all these steps While processing guix build --no-grafts --check hello I got some violations, an example follows SELinux impedisce a .guix-real un accesso write su sock_file /var/guix/daemon-socket/socket. ⏎ ⏎ ***** Plugin catchall(100. confidenza) suggerisce************************** If you believe that .guix-real should be allowed write access on the socket sock_file by default. Quindi si dovrebbe riportare il problema come bug. E' possibile generare un modulo di politica locale per consentire questo accesso. Fai allow this access for now by executing: # ausearch -c '.guix-real' --raw | audit2allow -M my-guixreal # semodule -X 300 -i my-guixreal.pp Informazioni addizionali: Contesto della sorgente unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1 023 Contesto target system_u:object_r:guix_daemon.guix_daemon_conf_t:s 0 Oggetti target /var/guix/daemon-socket/socket [ sock_file ] Sorgente .guix-real Percorso della sorgente .guix-real Porta Host localhost.localdomain Sorgente Pacchetti RPM Pacchetti RPM target RPM della policy selinux-policy-3.13.1-283.24.fc27.noarch Selinux abilitato True Tipo di politica targeted Modalità Enforcing Permissive Host Name localhost.localdomain Piattaforma Linux localhost.localdomain 4.14.16-300.fc27.x86_64 #1 SMP Wed Jan 31 19:24:27 UTC 2018 x86_64 x86_64 Conteggio avvisi 1 Primo visto 2018-02-13 16:26:40 CET Ultimo visto 2018-02-13 16:26:40 CET ID locale 795369db-8842-4253-ac70-bfab33d85c47 Messaggi Raw Audit type=AVC msg=audit(1518535600.232:493): avc: denied { write } for pid=2978 comm=".guix-real" name="socket" dev="dm-0" ino=2754019 scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:guix_daemon.guix_daemon_conf_t:s0 tclass=sock_file permissive=1 Hash: .guix-real,unconfined_t,guix_daemon.guix_daemon_conf_t,sock_file,write There are some more, it' s just that fetching them in the Gnome GUI is not immediate But I can publish my /var/log/audit/audit.log file somewhere Oh wait, i could catch another one right now, here it is SELinux impedisce a .guix-real un accesso write su sock_file /var/guix/daemon-socket/socket. ⏎ ⏎ ***** Plugin catchall(100. confidenza) suggerisce************************** If you believe that .guix-real should be allowed write access on the socket sock_file by default. Quindi si dovrebbe riportare il problema come bug. E' possibile generare un modulo di politica locale per consentire questo accesso. Fai allow this access for now by executing: # ausearch -c '.guix-real' --raw | audit2allow -M my-guixreal # semodule -X 300 -i my-guixreal.pp Informazioni addizionali: Contesto della sorgente unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1 023 Contesto target system_u:object_r:guix_daemon.guix_daemon_conf_t:s 0 Oggetti target /var/guix/daemon-socket/socket [ sock_file ] Sorgente .guix-real Percorso della sorgente .guix-real Porta Host localhost.localdomain Sorgente Pacchetti RPM Pacchetti RPM target RPM della policy selinux-policy-3.13.1-283.24.fc27.noarch Selinux abilitato True Tipo di politica targeted Modalità Enforcing Permissive Host Name localhost.localdomain Piattaforma Linux localhost.localdomain 4.14.16-300.fc27.x86_64 #1 SMP Wed Jan 31 19:24:27 UTC 2018 x86_64 x86_64 Conteggio avvisi 1 Primo visto 2018-02-13 16:26:40 CET Ultimo visto 2018-02-13 16:26:40 CET ID locale 795369db-8842-4253-ac70-bfab33d85c47 Messaggi Raw Audit type=AVC msg=audit(1518535600.232:493): avc: denied { write } for pid=2978 comm=".guix-real" name="socket" dev="dm-0" ino=2754019 scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:guix_daemon.guix_daemon_conf_t:s0 tclass=sock_file permissive=1 Hash: .guix-real,unconfined_t,guix_daemon.guix_daemon_conf_t,sock_file,write I' ll keep following this Thanks Ciao