OpenDKIM icon indicating copy to clipboard operation
OpenDKIM copied to clipboard

Daemon not running with all groups when "UserID usr:grp" is used

Open rseichter opened this issue 6 years ago • 17 comments

We're currently making several changes to the Gentoo Linux ebuild of OpenDKIM to address security issues. While doing so, we came across a problem which is bugging us. We have a user opendkim which is member of groups opendkim and dkimsocket. Group opendkim is meant to regulate read access to the private key file:

$ ls -l /var/lib/opendkim/
total 8.2M
-r--r----- 1 root     opendkim 1.7K Feb  3  2019 mumble.key
-r--r--r-- 1 root     opendkim  451 Feb  3  2019 mumble.pub
...

Group dkimsocket is meant to regulate write access to a local socket file via the following settings:

$ cat /etc/opendkim/opendkim.conf
Socket local:/run/opendkim/socket
UserID opendkim:dkimsocket
UMask 0117
...

$ ls -l /run/opendkim/
total 0
srw-rw---- 1 opendkim dkimsocket 0 Apr  1 19:38 socket=

Unfortunately the resulting process runs as only one group, namely dkimsocket, instead of running as both opendkim and dkimsocket:

$ cat /proc/26389/status
Name:    opendkim
...
Uid:    108   108   108   108
Gid:    1007  1007  1007  1007
FDSize: 64
Groups: 1007

When using only UserID opendkim (no group), and when dkimsocket is that user's primary group, the process picks up both groups, dkimsocket and opendkim:

$ cat /proc/26778/status
Name:    opendkim
...
Uid:    108   108   108   108
Gid:    1007  1007  1007  1007
FDSize: 64
Groups: 108 1007

The combined result is that we cannot enforce access to the private key and the local socket using distinct groups. This matters because the MTA needs to write to the socket but should not have access to the key file, while OpenDKIM should not be able to access any of the MTA's files.

I can set the owner of mumble.key to opendkim:opendkim instead of root:opendkim, but from a security standpoint this means that if some adversary manages to run code as opendkim he can overwrite the key material.

rseichter avatar Apr 01 '19 17:04 rseichter

You wrote, that if no groups are explicitly provided in the configuration file, the process runs under both groups. Isn’t that good?

What do you propose to do here?

dilyanpalauzov avatar May 02 '19 18:05 dilyanpalauzov

We need UserID opendkim:dkimsocket because this is currently the only way to specify a group (shared with the MTA) for the local socket file. Alas, if we use this setting, the process is not using group opendkim and thus cannot read the private key file.

A possible solution is to make OpenDKIM's process run with all groups assigned to the opendkim user.

rseichter avatar May 02 '19 18:05 rseichter

Why UserID opendkim does not help?

Why don’t you set the user and groups before starting opendkim, so that the latter is started with the correct identity and does not have to change anything?

dilyanpalauzov avatar May 02 '19 18:05 dilyanpalauzov

Why UserID opendkim does not help?

As I already wrote, we need to specify the group for the local socket, and that can only be done using UserID opendkim:dkimsocket.

Why don’t you set the user and groups before starting opendkim, so that the latter is started with the correct identity and does not have to change anything?

I don't know what you mean? OpenDKIM is started as root and then drops privileges. This is standard daemon behaviour, and it means the OpenDKIM process is responsible for handling this correctly.

rseichter avatar May 02 '19 20:05 rseichter

You wrote, that with just UserId opendkim the process has two runtime groups and this implies that the process can access both keys and socket.

OpenDKIM could be started with dropped privileges (e.g. by systemd) and not drop them further by itself.

dilyanpalauzov avatar May 02 '19 20:05 dilyanpalauzov

Does it help, if the primary and secondary groups are switched?

dilyanpalauzov avatar May 02 '19 20:05 dilyanpalauzov

Does Gentoo use the develop branch from here, as it contains fixes, not on master?

dilyanpalauzov avatar May 02 '19 20:05 dilyanpalauzov

You wrote, that with just UserId opendkim the process has two runtime groups and this implies that the process can access both keys and socket.

If no group is specified via UserId, we cannot be certain which of the two groups is used for the socket.

OpenDKIM could be started with dropped privileges (e.g. by systemd) and not drop them further by itself.

Gentoo allows users to choose between various init systems. Writing workarounds for each of these is not a practical solution.

Does Gentoo use the develop branch from here, as it contains fixes, not on master?

We currently only package stable OpenDKIM relases. I can of course build manually if you need help with testing changes.

rseichter avatar May 02 '19 20:05 rseichter

I would say that for the socket (file creation) the primary group is used, so is a matter of having opendkim belonging to two groups. The primary group is shared with the socket file, the secondary group is shared with the dkim key files.

OpenDKIM on the master branch, does not normalize correctly headers, if there is immediately new line after the colon; does not work properly in sign+verify mode for emails bigger that 64kb, does not document how to tweak sendmail not to break signatures, when relaying emails to other servers, does not compile with recent gnutls, has concurrent races… You better distribute the code from the develop branch.

dilyanpalauzov avatar May 02 '19 21:05 dilyanpalauzov

The primary group is shared with the socket file, the secondary group is shared with the dkim key files.

How difficult would it be to add a config parameter like SocketId SocketOwner:SocketGroup to specifically set ownership of a local socket file? We cannot reliably enforce primary or secondary group membership. The user may choose one or the other as primary group, or altogether different groups, depending on his personal setup. For example, a user could use the postfix or milter groups for the local socket.

You better distribute the code from the develop branch.

Well, we need some form of stability, because we are patching OpenDKIM to better integrate with our various init systems. We have provided our changes in pull request #41 but have not had any response at all so far. 🙁

rseichter avatar May 02 '19 22:05 rseichter

OpenDKIM on github is not maintained, therefore doing any change is very difficult. E.g. replacing == with = in configure.ac for better portability is very difficult.

How many more programs you have that require running under two groups?

The master branch/tagged releases do not offer the stability you are looking for. You better put your time in offereng OpenDKIM which has no known errors, mitigating the fact, that the project is not maintained, rather than running the process under several groups.

dilyanpalauzov avatar May 03 '19 03:05 dilyanpalauzov

Just call chgrp of the socket in the start script with the right group, once OpenDKIM is started.

dilyanpalauzov avatar May 03 '19 04:05 dilyanpalauzov

Thanks, but like I already wrote, adding workarounds for multiple init systems is not a practical solution. I hope @mskucherawy will eventually comment on this issue.

rseichter avatar May 03 '19 16:05 rseichter

Hi, sorry for the delay in getting back to you. I don't have a Gentoo environment so I'm left to guess a bit as to what's going on here.

If I understand correctly, you're hoping that the process of changing to the opendkim user will inherit not only the group specified for it in the password file, but the groups listed for it in /etc/group.

The code in main() that does this follows this sequence when you're running as root and requested a user that is not root:

  • call initgroups() to set your group memberships to those of the requested user and group
  • call setgid() to change your real and effective gid to that of the requested user
  • call setuid() to change your real and effective uid to that of the requested user

These calls are all completing, because we consider it fatal if any of them fail, and you're not reporting a crash. So all of the groups you need should in theory be there in the process.

mskucherawy avatar Jul 24 '19 18:07 mskucherawy

I wonder if this might be related:

https://archives.gentoo.org/gentoo-user/message/434564ff134f8400bf080822200dfb4d

mskucherawy avatar Jul 24 '19 18:07 mskucherawy

I don't have a Gentoo environment so I'm left to guess a bit as to what's going on here.

@mskucherawy If you like, I can provide you with a VirtualBox based Gentoo VM (which I am using with macOS host systems) to save you the effort of setting up Gentoo yourself.

If I understand correctly, you're hoping that the process of changing to the opendkim user will inherit not only the group specified for it in the password file, but the groups listed for it in /etc/group.

Yes. That's the expected behaviour on our end, and it would solve our problems. Also, because it is related to this issue, please consider our pull request #41.

https://archives.gentoo.org/gentoo-user/message/434564ff134f8400bf080822200dfb4d

That could indeed be related. You wrote that you are already using initgroups() et al, but this does not seem to suffice. Gentoo is not really exotic in that regard, and I don't know what is causing the problems.

rseichter avatar Jul 24 '19 19:07 rseichter

My understanding of the problem is, that each process and user have a primary group (per /etc/passwd) and other groups (from /etc/group). Newly created files are owned by the primary group. Gentoo wants to specify in the configuration file the primary group (the group owning the milter socket), and not extract the information by default (from /etc/passwd). The reason is, that the user can change the primary group in /etc/passwd as the user wants, but this shall not have impact on the owning group of the milter socket.

dilyanpalauzov avatar Jul 24 '19 19:07 dilyanpalauzov