Disallow execution of logrotate with an insecure logfile path#237
Disallow execution of logrotate with an insecure logfile path#237whotwagner wants to merge 1 commit intologrotate:masterfrom
Conversation
|
The checks work locally(at least with debian stretch and gcc-6). I believe that the Travis-CI fails because $TRAVIS_BUILD_DIR is group-writeable. My changes prevent using logrotate on directories where the group can write at some point of the path. The following lines in .travis.yml should make sure that the TRAVIS_BUILD_DIR isn't writeable by the group:
|
14cbd98 to
887ecef
Compare
It is dangerous to rotate logfiles that located in a directory-path which could be modified by another user. Due to race conditions a privilege escalation could happen. This was already discussed at the pull-request logrotate#235 This commit makes logrotate skipping logfiles that are located in a insecure directory. The function is_trusted_dir() is introduced. It checks the complete path of a logfile-directory including symlinks for insecure configurations.
|
Sorry but this code is overly complex and I am afraid that it introduces more problems than it could ever solve. For example, you first count the directories using your hard-wired open-coded implementation of There is an existing permission check implemented in Line 1171 in 7fae5f2 |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Hi, thank you very much for your feedback. I allocated the memory first because traversing with dirname() starts from the last directory up to the root. In order to prevent that during the check somebody just exchanges the directories(because the check would then start from the last directory up to the root), I do the checks the other way(from root to the last part of the path). I am aware that this check breaks some installations. I tried to make it a little bit tighter and hoped that we find a good solution by discussing it. The check now prevents both: race-conditions by changing the directories and race-condition by replacing the files(if that is even possible). We could weaken the checks by just preventing changing the directories. Then we would not check the logdir itself but start checking it's parent. I believe that we would break less, but with the price that we won't cover filebased race-conditions. |
|
As far as I know the function findNeedRotating() doesn't check the complete path. It just checks the parent directory. So lets say we have the following directory: in such a scenario the user could simply replace logdir(even if its owned by root) because he has write access to /home/user. If user could replace the logdir by a symlink using the exploit I mentioned on my blog, he could gain write access to a file in any directory. If we ignore the prevention for file-rotating, we could just check with is_trusted_dir() everything above logdir. In this example that would be: /home If those have proper permissions, it seems to me that just replacing the logdir by a user isn't possible anymore. This would have a much lesser impact on existing installations, and could nevertheless give additional security. So configurations like the following would then not suffer from the changes: PS: About the hard-wired open-coded implementation of dirname() for counting the numDirs: I would change that so that it also uses dirname() instead |
|
On Tuesday, January 22, 2019 12:22:48 PM CET whotwagner wrote:
Hi, thank you very much for your feedback. I allocated the memory first
because traversing with dirname() starts from the last directory up to the
root. In order to prevent that during the check somebody just exchanges the
directories(because the check would then from the last directory up to the
root), I do the checks the other way(from root to the last part of the
path).
I do not think that the order of checks matters as long as you call lstat()
on paths only. The attacker could wait till all your checks are complete and
then change the file system arbitrarily.
|
|
On Tuesday, January 22, 2019 10:29:01 PM CET whotwagner wrote:
As far as I know the function findNeedRotating() doesn't check the complete
path. It just checks the parent directory.
True but that was not the reason why your attack vector was successful, was it?
The actual reason was that logrotate did not check the owner of the directory
because logrotate currently checks permission bits and group only.
It is technically not so difficult to extend the current check for owner, too.
I am only afraid that it could also break some valid setups. People sometimes
use logrotate on file systems like FAT, which are not able to track ownership
properly.
Moreover, I am not sure whether it is logrotate's job to check permissions of
the root directory etc. If these directories are writable by non-privileged
users, then logrotate is likely not the only program that is affected by such
bogus setup.
|
I think the order matters. The permissions on the parent directory defines if someone can rename the directory itself. If / is safe /var can't be renamed. If /var/ is safe /var/log can't be renamed. If /var/log/ is safe /var/log/mysql can't be renamed. Aso. |
In my attack, it is possible to write into an arbitary directory as soon as the attacker is able to change any point of the path to the logdirectory. A check of the owner on the logdirectory would not fix this. If the path to the logdirectory could be modified at any point, an attacker could simply replace the the logdirectory during the time window of the racecondition. Even though my exploit targets the weak permissions of the parent of the logdirectory(the example i used was /tmp and the logdirectory was /tmp/log), it could easily be rewritten to use any other point in the whole path. I was checking some servers and found a paths like this: This scenario is defacto vulnerable. since www-data could replace logdir and has write-permissions to the file that gets created. Similar scenarios might occur at servers of webhosting providers. I believe that checking the permissions of the whole path until the logdir itself makes sense, since the problem isn't always obvious. |
|
On Wednesday, January 23, 2019 8:21:21 PM CET whotwagner wrote:
I think the order matters.
And I am trying to explain you that it does not.
The permissions on the parent directory defines
if someone can rename the directory itself. If / is safe /var can't be
renamed. If /var/ is safe /var/log can't be renamed. If /var/log/ is safe
/var/log/mysql can't be renamed. Aso.
You can see that I already mentioned this while reviewing your previous PR:
#235 (comment)
The problem is that the code stats file paths instead of file descriptors. So
the actual state of the file system may change arbitrarily before/during/after
all the checks.
|
|
On Wednesday, January 23, 2019 8:48:21 PM CET whotwagner wrote:
I was checking some servers and found a paths like this:
/var (root)
/var/www (root)
/var/www/projektname (www-data)
/var/www/projektname/logdir (root) (but with additional acls so that the
files are writeable by www-data)
I think we are mixing apples and oranges here. Let's discuss each problem
separately:
(1) Assuming www-data is a user, we are already in trouble because logrotate
currently does not check owners of directories at all. Luckily www-data does
not look like a typical shell user, so it is not a big problem in practise.
(2) This example uses file ACLs, which logrotate currently does not check
either, despite ACLs can be used to grant write access to directories to
non-privileged users.
(3) logrotate does not check permissions and ownership on indirect parent
directories.
You insist on fixing (3), which most of your (IMO unnecessarily complex) code
is about. I am trying to explain that fixing (3) does not make any sense
without fixing (1) first. The problem is that fixing (1) is risky because it
could break some valid setups, as explained earlier in this PR.
|
This time, I read the SEI CERT C Coding Standard first, before I started to write this commit. The algorithm is the recommendation from the following site: https://wiki.sei.cmu.edu/confluence/display/c/FIO15-C.+Ensure+that+file+operations+are+performed+in+a+secure+directory So I am a bit confused now. Maybe their recommendation does not solve the problem . Then we could discuss this with them. Or my implementation is wrong, then please tell me where it differs from the original one in a bad way so that I fix it. |
|
The page you refer to says:
It does not say any details about where the race condition comes from, or why changing the order of checks would help here. If you go from leaf to root and check that all parts of the path are not writable by non-privileged users, how could a non-privileged user rename and re-create a directory after the check? Back to logrotate ... the basic question is: Can we ever change logrotate to insist on using If the answer is no, then all the other proposals are irrelevant, as I understand it. |
I would say: "yes we can". The problem is too complex to leave the user/admins alone with it. I know that applying those changes would mean that maintainer of linux distributions would have some more work. It also means that existing installations need some configuration changes. But it would improve the security of the affected systems. And it would ensure, that also future installations/configurations of logrotate aren't prone to such race conditions. |
|
It's not obvious to me how using |
If one uses |
|
The concept of insecure directories also affects the configuration directive All these attacks can be stopped by setting the Linux kernel sysctl Should we check if |
|
I am not sure whether this is logrotate's job really. Are there any similar programs that have implemented such a check already? |
Logrotate is known to be affected by race conditions when operating on files in "insecure" directories[1]. Since logrotate is commonly run as root this can lead to privilege escalation[2,3]. Ensure log and olddir directories are "secure"[4], i.e. owned by a foreign non-root user or group-writable and owned by a foreign non-root user or world-writable and sticky-bit not set. Add a new directive 'allowinsecuredir' as last resort to allow rotation in such directories. [1]: https://github.com/whotwagner/logrotten [2]: https://bugzilla.redhat.com/show_bug.cgi?id=1705143 [3]: https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4380 [4]: https://wiki.sei.cmu.edu/confluence/display/c/FIO15-C.+Ensure+that+file+operations+are+performed+in+a+secure+directory Supersedes: logrotate#237
Logrotate is known to be affected by race conditions when operating on files in "insecure" directories[1]. Since logrotate is commonly run as root this can lead to privilege escalation[2,3]. Ensure log and olddir directories are "secure"[4], i.e. owned by a foreign non-root user or group-writable and owned by a foreign non-root user or world-writable and sticky-bit not set. Add a new directive 'allowinsecuredir' as last resort to allow rotation in such directories. [1]: https://github.com/whotwagner/logrotten [2]: https://bugzilla.redhat.com/show_bug.cgi?id=1705143 [3]: https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4380 [4]: https://wiki.sei.cmu.edu/confluence/display/c/FIO15-C.+Ensure+that+file+operations+are+performed+in+a+secure+directory Supersedes: logrotate#237
Logrotate is known to be affected by race conditions when operating on files in "insecure" directories[1]. Since logrotate is commonly run as root this can lead to privilege escalation[2,3]. Ensure log and olddir directories are "secure"[4], i.e. owned by a foreign non-root user or group-writable and owned by a foreign non-root user or world-writable and sticky-bit not set. Add a new directive 'allowinsecuredir' as last resort to allow rotation in such directories. [1]: https://github.com/whotwagner/logrotten [2]: https://bugzilla.redhat.com/show_bug.cgi?id=1705143 [3]: https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4380 [4]: https://wiki.sei.cmu.edu/confluence/display/c/FIO15-C.+Ensure+that+file+operations+are+performed+in+a+secure+directory Supersedes: logrotate#237
Logrotate is known to be affected by race conditions when operating on files in "insecure" directories[1]. Since logrotate is commonly run as root this can lead to privilege escalation[2,3]. Ensure log and olddir directories are "secure"[4], i.e. owned by a foreign non-root user or group-writable and owned by a foreign non-root user or world-writable and sticky-bit not set. Add a new directive 'allownonsecuredir' as last resort to allow rotation in such directories. [1]: https://github.com/whotwagner/logrotten [2]: https://bugzilla.redhat.com/show_bug.cgi?id=1705143 [3]: https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4380 [4]: https://wiki.sei.cmu.edu/confluence/display/c/FIO15-C.+Ensure+that+file+operations+are+performed+in+a+secure+directory Supersedes: logrotate#237
Logrotate is known to be affected by race conditions when operating on files in "insecure" directories[1]. Since logrotate is commonly run as root this can lead to privilege escalation[2,3]. Ensure log and olddir directories are "secure"[4], i.e. owned by a foreign non-root user or group-writable and owned by a foreign non-root user or world-writable and sticky-bit not set. Add a new directive 'allownonsecuredir' as last resort to allow rotation in such directories. [1]: https://github.com/whotwagner/logrotten [2]: https://bugzilla.redhat.com/show_bug.cgi?id=1705143 [3]: https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4380 [4]: https://wiki.sei.cmu.edu/confluence/display/c/FIO15-C.+Ensure+that+file+operations+are+performed+in+a+secure+directory Supersedes: logrotate#237
|
How would this effect non-privledged users with logs and state files in their own directory? |
Logrotate is known to be affected by race conditions when operating on files in "insecure" directories[1]. Since logrotate is commonly run as root this can lead to privilege escalation[2,3]. Ensure log and olddir directories are "secure"[4], i.e. owned by a foreign non-root user or group-writable and owned by a foreign non-root user or world-writable and sticky-bit not set. Add a new directive 'allownonsecuredir' as last resort to allow rotation in such directories. [1]: https://github.com/whotwagner/logrotten [2]: https://bugzilla.redhat.com/show_bug.cgi?id=1705143 [3]: https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4380 [4]: https://wiki.sei.cmu.edu/confluence/display/c/FIO15-C.+Ensure+that+file+operations+are+performed+in+a+secure+directory Supersedes: logrotate#237
Logrotate is known to be affected by race conditions when operating on files in "insecure" directories[1]. Since logrotate is commonly run as root this can lead to privilege escalation[2,3]. Ensure log and olddir directories are "secure"[4], i.e. owned by a foreign non-root user or group-writable and owned by a foreign non-root user or world-writable and sticky-bit not set. Add a new directive 'allownonsecuredir' as last resort to allow rotation in such directories. [1]: https://github.com/whotwagner/logrotten [2]: https://bugzilla.redhat.com/show_bug.cgi?id=1705143 [3]: https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4380 [4]: https://wiki.sei.cmu.edu/confluence/display/c/FIO15-C.+Ensure+that+file+operations+are+performed+in+a+secure+directory Supersedes: logrotate#237
Logrotate is known to be affected by race conditions when operating on files in "insecure" directories[1]. Since logrotate is commonly run as root this can lead to privilege escalation[2,3]. Ensure log and olddir directories are "secure"[4], i.e. owned by a foreign non-root user or group-writable and owned by a foreign non-root user or world-writable and sticky-bit not set. Add a new directive 'allownonsecuredir' as last resort to allow rotation in such directories. [1]: https://github.com/whotwagner/logrotten [2]: https://bugzilla.redhat.com/show_bug.cgi?id=1705143 [3]: https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4380 [4]: https://wiki.sei.cmu.edu/confluence/display/c/FIO15-C.+Ensure+that+file+operations+are+performed+in+a+secure+directory Supersedes: logrotate#237
Logrotate is known to be affected by race conditions when operating on files in "insecure" directories[1]. Since logrotate is commonly run as root this can lead to privilege escalation[2,3]. Ensure log and olddir directories are "secure"[4], i.e. owned by a foreign non-root user or group-writable and owned by a foreign non-root user or world-writable and sticky-bit not set. Add a new directive 'allownonsecuredir' as last resort to allow rotation in such directories. [1]: https://github.com/whotwagner/logrotten [2]: https://bugzilla.redhat.com/show_bug.cgi?id=1705143 [3]: https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4380 [4]: https://wiki.sei.cmu.edu/confluence/display/c/FIO15-C.+Ensure+that+file+operations+are+performed+in+a+secure+directory Supersedes: logrotate#237
Logrotate is known to be affected by race conditions when operating on files in "insecure" directories[1]. Since logrotate is commonly run as root this can lead to privilege escalation[2,3]. Ensure log and olddir directories are "secure"[4], i.e. owned by a foreign non-root user or group-writable and owned by a foreign non-root user or world-writable and sticky-bit not set. Add a new directive 'allownonsecuredir' as last resort to allow rotation in such directories. [1]: https://github.com/whotwagner/logrotten [2]: https://bugzilla.redhat.com/show_bug.cgi?id=1705143 [3]: https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4380 [4]: https://wiki.sei.cmu.edu/confluence/display/c/FIO15-C.+Ensure+that+file+operations+are+performed+in+a+secure+directory Supersedes: logrotate#237
Logrotate is known to be affected by race conditions when operating on files in "insecure" directories[1]. Since logrotate is commonly run as root this can lead to privilege escalation[2,3]. Ensure log and olddir directories are "secure"[4], i.e. owned by a foreign non-root user or group-writable and owned by a foreign non-root user or world-writable and sticky-bit not set. Add a new directive 'allownonsecuredir' as last resort to allow rotation in such directories. [1]: https://github.com/whotwagner/logrotten [2]: https://bugzilla.redhat.com/show_bug.cgi?id=1705143 [3]: https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4380 [4]: https://wiki.sei.cmu.edu/confluence/display/c/FIO15-C.+Ensure+that+file+operations+are+performed+in+a+secure+directory Supersedes: logrotate#237
It is dangerous to rotate logfiles that are located in a directory-path which could be modified by another user. Due to race conditions a privilege escalation could happen. This was already discussed at the pull-request #235
This commit makes logrotate skipping logfiles that are located in a insecure directory. A function is_trusted_dir() is introduced. It checks the complete path of a logfile-directory including symlinks for insecure configurations.
Please note that is_trusted_dir() doesn't handle ACL's yet.