Patch: eliminate postfix-script warnings about symlinks

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Patch: eliminate postfix-script warnings about symlinks

Luc Pardon
Hello,

Running Postfix 3.3.1 under Linux, postfix-script produces pointless
warnings if/when there are symbolic links in or below $config_directory.

1. I installed (CA root) certificates in a subdir of /etc/postfix and
rehash with "openssl rehash <subdir>. This will of course create a
symlink to each certificate.

But to reproduce, any symlink in (a subdir of) /etc/postfix will do.

Now restart Postfix, since you can't run "postfix-script check-warn"
directly.

For each symlink, a warning is written in the log, like this:

postfix/postfix-script[23592]: warning: group or other writable:
/etc/postfix/./tls/CAcerts/02265526.0

This should not happen, as the permissions of symbolic links are
irrelevant on Linux. They are never used, it is those of the pointed-to
file that count.

See "man 1 chmod" or - if you have it installed - "man 7 symlink".

Of course, these "bogus" warnings do not really hurt, but they do
clutter the logs and thereby obscure the real thing.

The following (very) simple patch to postfix-script 3.3.1 takes care of
them :

====================
@@ -302,7 +302,7 @@
  find $todo ! -user root \
     -exec $WARN not owned by root: {} \;

- find $todo \( -perm -020 -o -perm -002 \) \
+ find -L $todo \( -perm -020 -o -perm -002 \) \
     -exec $WARN group or other writable: {} \;

  # Check Postfix mail_owner-owned directory tree owner/permissions.
====================

I suppose the -L parameter could be added to the other occurrences of
"find", but I didn't bother with that.



2. As an aside, it would be cool if those warnings could give the real
name of the offending file. That is, instead of:

     /etc/postfix/./tls/CAcerts/....

it really should be:

     /etc/postfix/tls/CAcerts/....

But that is a cosmetic issue only.

NB: my copy of "find" is from an older findutils 4.5.11 package, current
seems to be 4.6.0.



3. What is maybe more important, that is that there were no such
warnings about the symlinks in the chroot jail.

Yet I did copy all the certificates from that CAcerts dir over into its
jail counterpart, and rehashed there as well. So I would have expected
the same bogus warnings about the symlinks in there.

However, the postfix-script doesn't seem to check (all) the subdirs of
the $queue_directory for owner- and permission-related issues. It just
looks at /var/spool/postfix/pip.

Maybe it should check the others as well? Or at least
"/var/spool/postfix/etc/postfix" ?

Luc
Reply | Threaded
Open this post in threaded view
|

Re: Patch: eliminate postfix-script warnings about symlinks

Wietse Venema
Luc Pardon:
> Hello,
>
> Running Postfix 3.3.1 under Linux, postfix-script produces pointless
> warnings if/when there are symbolic links in or below $config_directory.

The problem is that the symlink may point to any location including
a file under an unsafe directory such as /var/tmp or /home/user.

Unless you are constraining the target of the symlink (and your
patch does not), this is a security hole waiting to happen.

        Wietse
Reply | Threaded
Open this post in threaded view
|

Patch: eliminate postfix-script warnings about symlinks

Luc Pardon


On 05-09-18 13:26, Wietse Venema wrote:

> Luc Pardon:
>> Hello,
>>
>> Running Postfix 3.3.1 under Linux, postfix-script produces pointless
>> warnings if/when there are symbolic links in or below $config_directory.
>
> The problem is that the symlink may point to any location including
> a file under an unsafe directory such as /var/tmp or /home/user.
>
> Unless you are constraining the target of the symlink (and your
> patch does not), this is a security hole waiting to happen.
>
> Wietse
>

True enough, of course.

But that is a wholly different check than the owner/permission check.

Besides, flooding the logs with unhelpful warnings actually has the
effect of obscuring the security holes.

Finding those would call for a separate check, specifically looking for
symlinks pointing outside the Postfix root-owned directory tree.

And I'd say that this check would belong in the "check-fatal" section of
postfix-script, rather than in "check-warning".

The Q&D shell scriptlet below my sig would probably do the trick for
$config_directory, but it requires the "realpath" command, part of the
GNU core utilities package. Not sure how portable that would be. Some
obscure incantation of "find" could probably do the job, too.

The first question is obviously: can we disallow symlinks to the outside
world by definition? I'd say the answer is yes, but $(whoami) ?

Luc

==================================
#!/bin/sh

# This would not be needed if integrated into postfix-script:
BASE=$(postconf -hx config_directory | sed "s/\n$//")

# Search for dangerous symlinks in $1 and its subdirs
function inspect
{
   DIR=$1

   for f in $DIR/* ; do
      if [ -L $f ]; then
        # if it points outside $BASE, it starts with "../.."
        DOT=$(realpath --relative-to $BASE $f | cut -d'/' -f1)
        if [ $DOT = ".." ]; then
          echo "ALARM: $f is a symlink to $(realpath $f)"
        fi
      elif [ -d $f ]; then
         inspect $f
      fi
   done
}

inspect $BASE
==================================

Reply | Threaded
Open this post in threaded view
|

Re: Patch: eliminate postfix-script warnings about symlinks

Luc Pardon


On 05-09-18 15:04, Luc Pardon wrote:

> The Q&D shell scriptlet below my sig would probably do the trick
>
> ==================================
> #!/bin/sh
>
> # This would not be needed if integrated into postfix-script:
> BASE=$(postconf -hx config_directory | sed "s/\n$//")
>
> # Search for dangerous symlinks in $1 and its subdirs
> function inspect
> {
>    DIR=$1
>
>    for f in $DIR/* ; do
>       if [ -L $f ]; then
>         # if it points outside $BASE, it starts with "../.."
>         DOT=$(realpath --relative-to $BASE $f | cut -d'/' -f1)
>         if [ $DOT = ".." ]; then
>           echo "ALARM: $f is a symlink to $(realpath $f)"
>         fi
>       elif [ -d $f ]; then
>          inspect $f
>       fi
>    done
> }
>
> inspect $BASE
> ==================================
>

Q&D for sure.

Of course that two lines about "DOT" should better read:

      DOT=$(realpath --relative-to $BASE $f | cut -d'/' -f1-2)
      if [ $DOT = "../.." ]; then

Sorry about that, and also about breaking the message thread.

Luc
Reply | Threaded
Open this post in threaded view
|

Re: Patch: eliminate postfix-script warnings about symlinks

Wietse Venema
In reply to this post by Luc Pardon
Luc Pardon:
> The first question is obviously: can we disallow symlinks to the outside
> world by definition? I'd say the answer is yes, but $(whoami) ?

Here is some background on pathname safety.

A symlink is unsafe if it resolves to an unsafe pathname.

A pathname is unsafe is the target itself has unsafe permissions,
or if any parent directories have unsafe permissions, or if it
resolves thrugh an unsafe symlink.

That's a recursive definition, because pathnames are recursive.

And what exactly is a safe pathname?

A pathname is safe-for-root if only root has write permission to
the target itself or to its parents.

A pathname is safe-for-user if only the user and root can write to
to the target itself or to its parents.

Pathnames under $config_directory files must be safe-for-root.

Pathnames under $data_directory files must be safe-for-postfix.

Postfix queue files must be safe-for-postfix.

The non-queue files under $queue_directory must be safe-for-root.

See also: https://www.ndss-symposium.org/ndss2010/where-do-you-want-go-today-escalating-privileges-pathname-manipulation/

That is a bit beyond what can be done with portable shell utilities
alone.

I think that it would not be a good idea to make GNU binutils a
hard dependency for Postfix. The pathname check would need to be
done in a more portable language: possible candidates are Perl (this
is already a build dependency) or C.

> Luc
>
> ==================================
> #!/bin/sh
>
> # This would not be needed if integrated into postfix-script:
> BASE=$(postconf -hx config_directory | sed "s/\n$//")
>
> # Search for dangerous symlinks in $1 and its subdirs
> function inspect
> {
>    DIR=$1
>
>    for f in $DIR/* ; do
>       if [ -L $f ]; then
>         # if it points outside $BASE, it starts with "../.."

May also be unsafe if it starts with '/'.

        Wietse
Reply | Threaded
Open this post in threaded view
|

Re: Patch: eliminate postfix-script warnings about symlinks

Luc Pardon


On 05-09-18 18:18, Wietse Venema wrote:
> Luc Pardon:
>> The first question is obviously: can we disallow symlinks to the outside
>> world by definition? I'd say the answer is yes, but $(whoami) ?
>
> Here is some background on pathname safety.
>

Thanks for that. Also, the paper - at a first cursory reading - is very
helpful, and thought-provoking as well.

But we have to be clear about the problem that we are trying to solve
here in this particular case.

So allow me to re-iterate for a moment.

* My problem is that, after pointing "smtpd_tls_CApath" and
"smtp_tls_CApath" to a subdir of /etc/postfix, and installing a bunch of
root CA certificates in it, my logs are flooded with something like 150
(!) bogus warnings about the symlinks to these certs having the wrong
permission.

* You correctly observed that my proposed "-L" patch does too much: it
suppresses _all_ warnings about _all_ symlinks, safe or not. I do agree
that this is an unacceptable loss of functionality.

However, you propose to compensate for it by adding - necessarily
elaborate - safety checks on symlinks.

I don't think we need to go that far.


For starters, I'd venture to say that, in the past, symlinks inside the
safe_for_X Postfix dirs were never needed nor used in the first place.

Neither were they expected, it seems. In any case the postfix-script
doesn't "see" that it is dealing with a symlink. It treats it just like
a regular file - and trips over its permissions (which are 0777 by
definition, hence wrong by definition inside a safe_for_X dir).

That also means that _all_ symlinks get warned about - as I found out.

The only way for the admin to get rid of such a warning is to remove the
symlink altogether, since, unlike a regular file, chmod won't help here.

Conclusion: any symlink, that happened to trespass into Postfix
territory, must in the past have been systematically removed by those
admins that read their logs and heed the warnings (meaning, of course,
_all_ admins <g>).



However, although symlinks inside the Postfix dirs were not needed in
the past, that has changed by now. They have become necessary because
OpenSSL needs them to find its certificates, so we can't just tell the
admin to get rid of them.

Also, with initiatives like "Let's Encrypt" and "STARTTLS Everywhere"
gaining ground, more and more Postfix users will start making real use
of certificates, and they too will eventually start complaining about
the bogus warnings - or worse: ignore them, together with the important
ones.


We could of course sidestep the issue by patching the docs, telling
people to store their certificates _outside_ /etc/postfix.

However, that doesn't feel right.

One reason is that, if they are used for handling the mail, they are
effectively part of the Postfix config, and /etc/postfix is their proper
home.

Also, those of us who run SELinux would have to invent and add some
custom rules, just to allow Postfix to access those certificates and
their dirs. That is cumbersome, tricky to get it right, and - above all
- not needed when we store them in /etc/postfix, where they belong.



Fortunately, I think that we can remain safe by continuing to warn about
symlinks, much as before, except that we would from now on remain silent
about symlinks that:

     a) live inside a "safe_for_X" directory structure, and
     b) point to a target inside that very same dir structure.

And by "safe_for_X dir structure", I do mean of course one of the dirs
that are monitored by postfix-script.

Such symlinks are inherently safe_for_X, simply because they point to a
safe_for_X target. No need to pick them apart to find that out.

We can indeed rely on the target being safe, because if it is not, the
regular file check of postfix-script would issue a "wrong permission"
warning for this target, and the admin would step in to fix that with
chmod. And when the target is made safe, the symlink pointing to it
automatically becomes safe as well.

Case in point: the OpenSSL symlinks happen to live in the same dir as
the certificate they point to, and the certs themselves are monitored by
postfix-script because they are in $config_directory.



It is a different story with symlinks that point to a target  _outside_
one of the "safe_for_X" Postfix dirs. Here we know nothing about the
target, so we would normally have to go out and investigate closely - as
you propose to do.

However, such symlinks, pointing all over the place, are not needed
today, no more than they were needed yesterday. So we can continue to
issue a warning as we did before, and thereby incite the admin to remove
them, as before.

It doesn't matter whether they are good or bad or ugly. They don't
belong in there and they must go, period.


Also, I am not convinced that the elaborate checks would have much added
value. Quite to the contrary - at least for this particular case of Postfix.

For example, if I understand it correctly, a symlink somewhere inside
the safe_for_root /etc/postfix dir, pointing to /etc/passwd, would get
the green light, simply because both the /etc dir and the passwd file
itself satisfy the condition of "writable by root only".

That means that such a link would _not_ be flagged if we really did the
full check, as you propose.

Yet it doesn't feel good to have such a link in /etc/postfix. I'd rather
have the admin remove it ASAP. But if the proposed elaborate checks
don't feel the need to flag it "because it is safe_for_root", the admin
won't know it's there.

Furthermore, that too could be considered a "loss of functionality", as
the current implementation would issue a warning and the future one
(with the elaborate checks) would not.


In short: my proposed solution would behave just like the current one,
except for the "internal" symlinks (where the warnings have no purpose
anyway).


Of course I'd have to review my position if somebody comes up with a
real use case for such an "outlandish" link.

Or maybe not. The current postfix-script would have been issuing the
inevitable warning in the logs for ages, so that must have been dealt
with somehow (e.g. by ignoring it). With my proposed solution, the
warning would continue to be logged, and it can be dealt with in the
same way as before.


> I think that it would not be a good idea to make GNU binutils a
> hard dependency for Postfix. The pathname check would need to be
> done in a more portable language: possible candidates are Perl (this
> is already a build dependency) or C.

Agreed on the new dependency not being a good idea.

So "realpath" is out of the picture.


Still:

>>    for f in $DIR/* ; do
>>       if [ -L $f ]; then
>>         # if it points outside $BASE, it starts with "../.."
>
> May also be unsafe if it starts with '/'.

Yes but no.

No, because by virtue of the "--relative-to" parameter to realpath, it
will never answer with an absolute path to the target. So it will never
start with a "/".

OTOH, if it starts with "../", that means we're climbing up in the
directory tree on our way to the target. That will eventually take us
out of our sale $BASE haven and into unknown territory, precisely the
thing that I propose to disallow.

There is more to say about the leading dots and their number, as it
won't work as proposed, but it is all moot since we won't use the
realpath utility anyway.

Luc
Reply | Threaded
Open this post in threaded view
|

Re: Patch: eliminate postfix-script warnings about symlinks

Viktor Dukhovni


> On Sep 6, 2018, at 2:19 PM, Luc Pardon <[hidden email]> wrote:
>
> However, although symlinks inside the Postfix dirs were not needed in
> the past, that has changed by now. They have become necessary because
> OpenSSL needs them to find its certificates, so we can't just tell the
> admin to get rid of them.

There is no need to put your certificate trust store in /etc/postfix/
What's wrong with /etc/ssl/postfix/ or similar?  The /etc/postfix
directory does not presently support symlinks.

--
        Viktor.

Reply | Threaded
Open this post in threaded view
|

Re: Patch: eliminate postfix-script warnings about symlinks

@lbutlr
In reply to this post by Luc Pardon
On 06 Sep 2018, at 12:19, Luc Pardon <[hidden email]> wrote:
> However, although symlinks inside the Postfix dirs were not needed in
> the past, that has changed by now. They have become necessary because
> OpenSSL needs them to find its certificates, so we can't just tell the
> admin to get rid of them.

The way I deal with certs is that when the cert renews, it fires off a post script that copies the certs to the places it needs to be. Symlinking seems to fail more often than not due to permission issues anyway.

--
'(...) And the Patrician has been ironical at me,' said Mr. Clete. 'I'm
not having that again.’