On Thu, 21.01.16 18:12, Charles Duffy (char...@dyfis.net) wrote: > Howdy -- > > I have a setuid-root executable from which I'm trying to start or stop a > service. However, when invoking systemctl from this executable -- for which > geteuid() returns 0 -- the control socket is rejected when the ruid does > not match (such that the executable was invoked from a less-privileged > user). > > 2042 17:02:00.508893788 0 systemd (1) > recvmsg > fd=14(<u>ffff883f648b4280->ffff883f648b4980 /run/systemd/private) > 2043 17:02:00.508897318 0 systemd (1) < recvmsg res=45 size=45 data=.AUTH > EXTERNAL 30..NEGOTIATE_UNIX_FD..BEGIN.. tuple=NULL > > 2068 17:02:00.510329428 0 systemd (1) > sendmsg > fd=14(<u>ffff883f648b4280->ffff883f648b4980 /run/systemd/private) size=24 > tuple=NULL > 2069 17:02:00.510344760 0 systemd (1) < sendmsg res=24 > data=REJECTED..ERROR..ERROR.. > > What's going on, and why?
D-Bus authentication includes the UID in text form in the protocol, and compares that with the kernel supplied connection metadata included in the socket ucred stuff. The former currently passes along the UID, the latter the EUID. If you invoke systemctl with uid != euid then we'll consider the two bits of data to be out of sync, and not allow the connection. Of course, one could argue that if euid is 0, we should accept any value for the uid included in the auth protocol. However, the current logic instead suggests: if you have the rights to fake creds data then please also fake the data in the ucred structure... Which however won't take place in systemctl however, since it doesn't expect to be used from suid binaries... Now, I'd be willing to change the current logic: a) we could either pass the UID in both ucred and the auth protocol. In this case, the connection would be conisdered coming from the UID. b) or we could pass the EUID in both. In this case the connection would be considered coming from the EUID. c) or we could continue to pass the UID in the auth proto, but allow it to be any desired value if the ucred-indicated EUID is 0. The auth proto would count, and hence the connection would be considered coming from the the UID. d) or we could continue to pass the UID in the auth proto, but ignore it completely if the ucred-indicated EUID is 0. The ucred supplied euid would count in this case, and the connection would be coming from the EUID. From all these options, I figure b) or d) would be the behaviour you would prefer, as only then the connection would be owned by the EUID and thus your euid of root would be considered for method calls. However I am pretty sure a) or c) would be more in-line with UNIX logic: i.e. the euid data would be used for permissions but the ownership of objects such as the connection would still be bound to the uid. So not sure what I could recommend you, as I don't think we should change the sd-bus behaviour to anything you'd like... One option of course would be to do the equivalent of setresuid(geteuid(), geteuid(), geteuid()); in your app after forking but before you exec systemctl. Or, even better, just do the bus call directly from your app, and rely on PK permitting access for unprivileged clients. Lennart -- Lennart Poettering, Red Hat _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel