-
-
Notifications
You must be signed in to change notification settings - Fork 480
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: catch ELOOP #259
fix: catch ELOOP #259
Conversation
/cc @jasnell who did all the dirty work in solving this one. |
s/ev_fs_realpath/uv_fs_realpath/ |
Wow, didn't notice that uv has realpath now. Someone should confirm that it's not using the realpath(3) UNIX function, since that's notoriously insecure. (That's why node had a realpath in JS in the first place.) If it is, then it's better for glob to refuse to use realpath in those versions of node. |
b973ce3
to
bdf89d1
Compare
@isaacs it is using realpath(3). I see you've joined the discussion in nodejs/node#2680 (comment) I'll keep this thread updated with what happens in the Node project |
protect against realpath(3) exploit ref: isaacs/node-glob#259 (comment) Original commit message: unix: error on realpath if PATH_MAX is undefined Currently when PATH_MAX is undefined realpath will default to using 4096. There is a potential stack overflow attack that can be mitigated by having PATH_MAX defined. This change conservatively errors if a system does not have PATH_MAX defined. This change also explicitly includes `limits.h` to ensure that all platforms have PATH_MAX defined if it is available. Ref: http://pubs.opengroup.org/onlinepubs/9699919799/functions/realpath.html Refs: nodejs#2680 (comment) PR-URL: nodejs#843 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Fedor Indutny <fedor@indutny.com> Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
@isaacs if we update the version of libuv in node to include the fix for realpath(3) would you be opposed to this landing in node-glob? |
@thealphanerd I haven't followed the conversation in depth, but I see the some ^Lift folks got involved. If @jlamendo is happy with where node 6 lands on this, then I'm happy supporting it. |
@thealphanerd From my understanding, node 6 is landing on throwing an error when PATH_MAX is undefined. If that's correct, I'm ok with that solution. While I don't want to break anyone's build, it's better to do that than deal with a compromised machine. There seems to be a few conflicting threads on that, so I'm not sure what the actual accepted solution was. That said, I do have a concern with the comment about encoding being in the cache. Unfortunately I didn't have time to root this out on my own today, so hopefully you know, but are there any controls in place to prevent that from happening, and are such controls possible? If it does happen, what is the impact? |
the changes to libuv landed in v6.2. Any system that does not have PATH_MAX will have an error thrown during compilation @jlamendo can you elaborate on what you meant by encoding in the cache? |
@@ -62,6 +62,8 @@ GlobSync.prototype._finish = function () { | |||
} catch (er) { | |||
if (er.syscall === 'stat') | |||
set[self._makeAbs(p)] = true | |||
else if (er.code === 'ELOOP') | |||
if (real) set[real] = true | |||
else |
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.
What is the intent of this bit? The indentation is incorrect, making it look like any error that isn't a stat
or ELOOP
will get thrown, but in fact, the only error that'll get thrown is an ELOOP
when real
is falsey.
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.
For example:
if (false)
console.log(1)
else if (false)
if (true) console.log(2)
else
console.log(3)
is actually
if (false)
console.log(1)
else if (false)
if (true)
console.log(2)
else
console.log(3)
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.
Also, how can real
be set if an error occurred? Does fs.realpath
ever return a value if it raises an error? That seems really strange.
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.
added braces to fix the error. I'm going to have to dig back into the code to figure out exactly why we went with setting real... although based on your response at the end of this PR it may not be worth putting in the time.
Digging into this more, it's almost impossible to fix without either (a) making a significant breaking change to glob, or (b) porting the pre-node6 fs.realpath into a standalone module and using that instead. Both options are nontrivial. The tests are breaking because Node broke behavior. The patch here simply ignores It's going to take some time to fix issues like this. In the meantime, in my opinion, people should either know that they're using a not-ready-for-prime-time version of the platform (and thus, expect test failures), or avoid Node 6 until it and the ecosystem have had time to get stable. This new work lands on the laps of many part-time maintainers who weren't planning for it. I have no idea when I'll even get to it, but it's not at the top of my list. I've already spent several hours debugging new issues that Node 6 raised. Breaking changes break stuff. This is what it looks like when a platform is unstable. It's costly. |
fs.realpath has been optimized to utilize `uv_fs_realpath()`, a new api in libuv. The libuv api has slightly different behavior. There are two particular issues that are causing problems for glob * `ev_fs_realpath()` throwing before `fs.readdir` ELOOP * The removal of the cache In the past glob was relying on `fs.readdir` to throw when handling recursive symbolically linked directories. It is now possible that the call to libuv can throw before. The behavior is currently different on osx and linux causing the test suite to fail on all of the flavors of linux we are running in CI. This commit adds an extra check for 'ELOOP' and sets appropriately. The commit includes an extra check to make sure that `real` is truthy Without that extra check the test suite was reporting garbage data in the results. This was only happening with the async implementation. This commit has not done anything regarding the removal of the cache As long as the cache doesn't include a value called "encoding" everything will be fine. There has not been any benchmarking done on this change. ref: libuv/libuv#531 ref: nodejs/node#3594
@thealphanerd What is the impact if it is included in the cache, and are there any mechanisms in place to detect that before it causes problems or prevent it from being there in the first place? It may be a minor issue, and I suspect that it is the case, but I wanted to be sure. |
fs.realpath has been optimized to utilize
uv_fs_realpath()
, a new apiin libuv. The libuv api has slightly different behavior. There are two
particular issues that are causing problems for glob
ev_fs_realpath()
throwing beforefs.readdir
ELOOPIn the past glob was relying on
fs.readdir
to throw when handlingrecursive symbolically linked directories. It is now possible that the
call to libuv can throw before. The behavior is currently different on
osx and linux causing the test suite to fail on all of the flavors of
linux we are running in CI.
This commit adds an extra check for 'ELOOP' and sets appropriately.
The commit includes an extra check to make sure that
real
is truthyWithout that extra check the test suite was reporting garbage data in the results.
This was only happening with the async implementation.
This commit has not done anything regarding the removal of the cache
As long as the cache doesn't include a value called "encoding"
everything will be fine.
There has not been any benchmarking done on this change.
ref: libuv/libuv#531
ref: nodejs/node#3594