OSEC

Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com
 
From: Alex van den Bogaerdt (alex_at_ergens.op.HET.NET)
Date: Sun Jul 28 2002 - 06:55:13 CDT

  • Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]

    All of the following should be parsed as questions in the
    form of "is it correct to think ..." and is included as stuff
    to discuss about.

    I wouldn't be surprised if there is a logic flaw somewhere in
    the following. After all, it is just the first try. That of
    course doesn't mean I didn't try my best. If there is such
    a flaw, please explain so that I can learn from it.

    > In this specific case, the purpose is to create a directory that
    > is owned by the recipient, with appropriate permissions. Any solution
    > is acceptable if it does exactly that and nothing more.

    I think there's one more prerequisite: the directory must be
    created in a place previously defined by the systems administrator.
    $mail_spool_directory seems to be right. If it's not going to
    happen there, it's not going to happen with elevated privileges.
    Also, $mail_spool_directory needs to be owned by root and there
    shouldn't be another way of creating the necessary directory.
    For instance: write permissions to group mail or group postfix
    indicates postfix should use group privileges. This is not
    covered in this mail but using a subset of the logic could
    probably do the trick.

    > The solution should be safe even when the postfix account (or any
    > other non-root account) is compromised.
    >
    > The solution should not allow a malicious user to trick Postfix
    > into creating an object other than the target directory.
    >
    > The solution should not allow a malicious user to trick Postfix
    > into changing the ownership or access permissions of an object
    > other than the target directory.
    >
    > The solution should gracefully handle any errors. For example, two
    > different processes may try to perform this operation at the same
    > time. Another example: the solution should gracefully deal with
    > the case that a process did not fully complete the operation
    > because of some software or system failure.

    When postfix is trying to deliver mail, we may assume all checks
    done by postfix are enough to know it is an account that does
    receive mail. The sysadmin/system should have created the directory
    and if he/she/it didn't do so, this is an error situation which
    postfix can try and recover from.

    Compromised accounts:
    If postfix, or a part of postfix, is started by another user then
    the directory cannot be created -or- the user doesn't need postfix
    to create the directory. This is because postfix isn't run suid.
    If there currently is a way to talk to postfix from a non-privileged
    client and trick postfix into doing something, then this can also be
    done from an entirely other program written by an ordinary user.

    Only $mail_spool_directory/$user:
    This also is something postfix can handle pretty safe. It won't
    try and create, for instance, /bin/$user. This doesn't mean there
    shouldn't be a check, just in case. We need to be able to rely on
    the content of $mail_spool_directory and $user. I think that's the
    case anyway with or without the proposed change.

    Changing other objects:
    I'm not sure if I fully understand what you mean by this. If
    postfix is only touching $mail_spool_directory/* then little
    should be possible. I will get back to this after the next
    paragraph.

    Handling errors:
    From the mkdir(2) documentation:
           EEXIST pathname already exists (not necessarily as a
                  directory). This includes the case where pathname
                  is a symbolic link, dangling or not.
    This means postfix will know when something bad is happening.
    If the call succeeds, a new directory will have been created and
    it will have be done by the current process.

    Possible problems in $mail_spool_directory:
    -1- no directory for the user
    -2- directory is present but with wrong permissions
    -3- something there, not a directory

    (1) is the cause of this discussion and is obvious.
    (2) could be the result of a failed attempt by postfix to create
        the directory. This because mkdir and surrounding parts will
        not be canonical. Clean up or report to postmaster.
    (3) could be the result of a migration from mailbox to maildir
        without actually migrating the stuff (i.e. only in main.cf).

        Move it away and notify the postmaster
          -or-
        Defer delivery and notify the postmaster
        

    These steps should do the trick, I think:
    -1- Check if there is a directory with the right permissions. If
         there is, skip to (10). Also check the $mail_spool_directory
         for certain other parameters such as owned by root, not world
         writable and so on.
    -2- use elevated privileges but only if we're in $mail_spool_directory
    -3- Try and create a lock file. If this fails, don't bother
         creating a directory. skip to (9).
    -4- Check if there already is an entry named $user. Whatever it is,
         it didn't satisfy (1) so it has to be renamed, for instance into
         BOGUS.$user.$inode. Great care is needed to not overwrite
         something already there. More on this below.
    -5- create a directory with permissions 0. This shouldn't fail
         according to (4). If it does fail, something is really wrong and
         the postmaster needs to be alerted. Something wrong includes the
         NFS case. There's nothing we can do about that. If it fails,
         jump to (9).
    -6- change the owner and group of the directory entry.
    -7- change the permissions of the directory entry.
    -8- remove the lock
    -9- use normal privileges again
    -10- try to deliver the mail by creating $mail_spool_directory/$user/tmp
         and so on. If it fails, be smart about what to do. If it is the
         user's fault (such as quota exceeded) then bounce, else defer.

    (3) should cover the case where two postfix processes try to do the
        same thing in parallel.
    (4) covers postmaster errors.
    (5) makes sure only postfix will access the directory while it is
        creating it.

    There's one possible problem with this approach (I'm not sure). If
    chown(2) doesn't modify quota, the directory $user (and nothing more)
    will not be counted until quotacheck(8) is run.

    Bogus stuff from (4):
    Details are not entirely specified yet. It can be done in several ways,
    if at all. Some possibilities:
    -1- Have a directory where this bogus stuff is moved into. The
        directory is accessible by root only. Appropriate locking is
        done in order to accommodate for parallel processes.
    -2- First create a directory or file, rename this file to the suggested
        name, then rename(2) the bogus entry over the newly created one.
    -3- Never create other objects. Delivery will fail due to system
        problems and the mail is deferred without further checking.

    Please let me know what you think so far.

    cheers,
    Alex
    -
    To unsubscribe, send mail to majordomopostfix.org with content
    (not subject): unsubscribe postfix-users