New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix rm rf v2 #5655
Fix rm rf v2 #5655
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed on IRC, I'm in favor of using path_is_safe() everywhere for consistency, and relaxing it a bit. In particular, double slashes (/foo//bar) commonly happen when unit files are autogenerated by scripts (think of path="$base/$resource" where $base itself has a trailing '/'), and these are perfectly safe; same argument for /./. I don't see why we should have a different behaviour for tmpfiles than for e. g. RequiresMountsFor= and other places where we use path_is_safe().
So in general I agree with this, but I ask you to split this into two commits. Thanks!
|
Ok, waiting for Zbyszek before splitting the commit. |
|
@jsynacek semaphore fails on |
The "//" and "/./" are harmless.
Use path_is_safe() to be consistent with the rest of the code.
|
v2. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for splitting! LGTM now, but still would like to get a second opinion from @keszybz or @poettering .
|
I think @martinpitt's point about autogenerated paths is very valid. We shouldn't disallow things unless there's a clear reason. So I think the restrictions which are left after patch 1/2 are OK. It certainly doesn't help it isn't defined anywhere what 2/2 looks OK too. |
|
Does anybody know what precisely |
|
Well, See my comment — I don't think anyone knows what it's supposed to mean exactly. Do any of the callers actually care if the path is normalized? |
Right. Sorry.
Hm, I don't know. If nothing cares why do we need to call |
|
I've just updated diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
index 22df20a..ad30794 100644
--- a/src/test/test-path-util.c
+++ b/src/test/test-path-util.c
@@ -38,6 +38,12 @@
assert_se(path_equal(b, a) == !result); \
}
+static void test_path_is_safe(void) {
+ assert_se(path_is_safe("///") == true);
+ assert_se(path_is_safe("/etc/..////") == false);
+ assert_se(path_is_safe("/etc/.////") == true);
+}
+
static void test_path(void) {
_cleanup_close_ int fd = -1;
@@ -563,6 +569,7 @@ int main(int argc, char **argv) {
test_file_in_same_dir();
test_filename_is_valid();
test_hidden_or_backup_file();
+ test_path_is_safe();
test_systemd_installation_has_version(argv[1]); /* NULL is OK */
It looks strange. Sorry, but I think |
|
The way I understand it, repeated slashes and |
It depends on a caller.
Well, it depends on a caller too. Going outside is not always a problem. |
|
Hm, + assert_se(path_is_safe("///.//") == true);
+ assert_se(path_equal("///.//", "/") == false);passes. I've already asked #5653 (comment), but why don't we try to normalise |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is_path_safe is not sufficient because rm_rf("//.//", REMOVE_ROOT|REMOVE_PHYSICAL); destroys everything. I think we shouldn't relax path_is_safe. Instead, we should normalise path somewhere in the code and path_is_safe should check that path is normalised (or, maybe, path_is_safe should normalise path by itself).
|
I don't understand why |
@martinpitt , sorry, I am a bit confused. What is the point of this PR and #5653? |
|
The point, as far as I understood it, was to avoid path traversal with an implied |
| return false; | ||
|
|
||
| if (strstr(p, "//")) | ||
| if (startswith(p, "./") || endswith(p, "/.")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uh? why this change? as the comment says, we check here not only for things that are actively dangerous, but also confusing. I am not seeing why "/./" would ever be a good thing to permit here...
|
I really don't understand why relaxing path_is_safe() would be a good idea. As the comments in the function clarify, we check for "confusing" paths here too. The idea really is that we consider anything "unsafe" that is not a properly build, normalized path. Or to say this differently: it's supposed to detect paths that are the result of "dirty" path concatenations... |
|
I'm mostly concerned about backwards compatibility with existing |
I can agree to that, but my suggestion would be to first call path_kill_slashes() on all parsed strings to remove duplicate slashes. |
|
Dropping the first patch (changing However, long-term I still wonder why |
|
maybe rename |
Note that |
|
It seems to me that the original bug: is that whatever glob function is used to expand Agree that this particular PR does help, but the real bug has not been fixed. |
|
FWIW |
|
Agreed with @Rudd-O , the only bug to be fixed is in the glob & recursion. You only have to skip the "." and ".." entries. Do not add restrictions on valid use-cases, like "//" or "/abs/path/to/bin/../var/tmp". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the approach of filter out . and .. from any glob seems like the right thing to do. Literal paths with . and .. should be accepted.
We should also refuse to remove / (under whatever name), just like rm does. There is no circumstance where this would be useful.
(I checked "×", not because I think there's anything wrong with the code, but because a different approach seems warranted.)
|
Correct. The initial fix that went in, is incorrect, and this fix, is also superstitious. The right fix is to (a) comply with POSIX rm, (b) prevent globbing from snarfing dot and dot dot, as it ought to be in this scenario. Even Python glob gets it right. We can get it right too.
…On April 20, 2017 5:53:11 PM GMT+02:00, Adrien Mahieux ***@***.***> wrote:
Agreed with @Rudd-O , the only bug to be fixed is in the glob &
recursion. You only have to skip the "." and ".." entries.
Do not add restrictions on valid use-cases, like "//" or
"/abs/path/to/bin/../var/tmp".
the "./" can also be a valid case for entries generated with tools like
"find".
--
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub:
#5655 (comment)
--
Sent from my Android device with K-9 Mail. Please excuse my brevity.
|
LOL From OpenBSD libc glob.c: |
|
And now we know why :-D
…On April 23, 2017 5:48:11 PM GMT+02:00, Pavan Maddamsetti ***@***.***> wrote:
> Even Python glob gets it right
LOL
From OpenBSD libc glob.c:
```
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Guido van Rossum.
```
--
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub:
#5655 (comment)
--
Sent from my Android device with K-9 Mail. Please excuse my brevity.
|
|
@Rudd-O well, we use glibc glob(), which will expand to ".." if needed, and so will bash, as you can easily see: Moreover, coreutils "rm" command line tool doesn't actually do any globbing, it's bash which does that and just passes the resolved strins to "rm". It's "rm" then which filters stuff ending in some specific suffixes, regardless whether those suffixes where the result of globbing or not. I must say I find the "rm" logic pretty weird, as it checks for suffixes only, but globbing can be anywhere in the path... That all said, I think it would be wise for us, if we'd add a wrapper for glibc glob() that filters out "." and ".." from any expansion, and that we'd use in all our own cases. We can do this relatively nicely through the GLOB_ALTDIRFUNC logic. |
|
I posted #5792 about that now, to keep track. |
|
@poettering if you specify a EDIT: no, Lennart is right and I am wrong, I misremembered the reproducer. |
This filters out "." and ".." from glob results. This fixes systemd#5655. Any judgements on whether the path is "safe" are removed. We will not remove "/" under any name (including "/../" and such), but we will remove stuff that is specified using paths that include "/./" and "/../". Such paths can be created when joining strings automatically, or for other reasons, and people generally know what ".." and "." is. Tests are added to make sure that the helper functions behave as expected.
This filters out "." and ".." from glob results. Fixes systemd#5655 and systemd#5644. Any judgements on whether the path is "safe" are removed. We will not remove "/" under any name (including "/../" and such), but we will remove stuff that is specified using paths that include "/./" and "/../". Such paths can be created when joining strings automatically, or for other reasons, and people generally know what ".." and "." is. Tests are added to make sure that the helper functions behave as expected.
This filters out "." and ".." from glob results. Fixes systemd#5655 and systemd#5644. Any judgements on whether the path is "safe" are removed. We will not remove "/" under any name (including "/../" and such), but we will remove stuff that is specified using paths that include "//", "/./" and "/../". Such paths can be created when joining strings automatically, or for other reasons, and people generally know what ".." and "." is. Tests are added to make sure that the helper functions behave as expected. Original commit: 84e72b5 Resolves: #1436004
This filters out "." and ".." from glob results. Fixes systemd#5655 and systemd#5644. Any judgements on whether the path is "safe" are removed. We will not remove "/" under any name (including "/../" and such), but we will remove stuff that is specified using paths that include "//", "/./" and "/../". Such paths can be created when joining strings automatically, or for other reasons, and people generally know what ".." and "." is. Tests are added to make sure that the helper functions behave as expected.
No description provided.